From 8681c66a40b6fb0c455e64866c38ecfa5a9d2cb2 Mon Sep 17 00:00:00 2001 From: Packit Date: Aug 20 2020 13:34:20 +0000 Subject: opencryptoki-3.14.0 base --- diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100644 index 0000000..e5257af --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,58 @@ +#!/bin/sh +# +# Check that the code follows the coding style +# +# If the code does not follow the coding style a warning will be printed. +# + +version=`gnuindent --version 2> /dev/null` +if [ "x$version" = "x" ]; then + version=`indent --version 2> /dev/null` + if [ "x$version" = "x" ] || [[ "$version" != *GNU* ]]; then + echo "Git pre-commit hook:" + echo "Did not find GNU indent, please install it before continuing." + exit 1 + fi + INDENT=indent +else + INDENT=gnuindent +fi + +echo "*******************" + +for file in `git diff-index --cached --name-only HEAD --diff-filter=ACMR`; do + ext=$(expr "$file" : ".*\(\..*\)") + case $ext in + .c|.h) + echo "Checking code style" + # ckfile is the temporary checkout and we indent it + ckfile=`git checkout-index --temp ${file} | cut -f 1` + newfile=`mktemp /tmp/${ckfile}.XXXXXX` || exit 1 + $INDENT $ckfile -o $newfile 2>> /dev/null + $INDENT $newfile 2>> /dev/null + diff -u -p "${ckfile}" "${newfile}" + r=$? + rm "${ckfile}" + rm "${newfile}" + rm "${newfile}~" + if [ $r != 0 ]; then + echo "Warning: Code style error in $file" + read -n1 -p "Do you want to CONTINUE committing? [Y/n]" opt < /dev/tty + case $opt in + n|N) + echo + exit 1 + ;; + *) + ;; + esac + echo "*******************" + fi + exit 0 + ;; + *) + echo "Not checking code style for this type of file" + echo "*******************" + ;; + esac +done diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4400b26 --- /dev/null +++ b/.gitignore @@ -0,0 +1,450 @@ +Makefile.in +aclocal.m4 +autom4te.cache +compile +config.guess +config.sub +configure +depcomp +install-sh +ltmain.sh +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 +missing +ylwrap + + +Makefile +config.log +config.status +libtool +man/man1/pkcscca.1 +man/man1/pkcsconf.1 +man/man1/pkcsep11_migrate.1 +man/man1/pkcsep11_session.1 +man/man1/pkcsicsf.1 +man/man1/p11sak.1 +man/man5/opencryptoki.conf.5 +man/man7/opencryptoki.7 +man/man8/pkcsslotd.8 +testcases/common/.deps/ +testcases/crypto/.deps/ +testcases/login/.deps/ +testcases/misc_tests/.deps/ +testcases/pkcs11/.deps/ +usr/lib/api/.deps/ +usr/lib/api/shrd_mem.c +usr/lib/cca_stdll/.deps/ +usr/lib/common/.deps/ +usr/lib/ep11_stdll/.deps/ +usr/lib/ica_s390_stdll/.deps/ +usr/lib/icsf_stdll/.deps/ +usr/lib/soft_stdll/.deps/ +usr/lib/tpm_stdll/.deps/ +usr/sbin/pkcscca/.deps/ +usr/sbin/pkcsconf/.deps/ +usr/sbin/pkcsep11_migrate/.deps/ +usr/sbin/pkcsep11_session/.deps/ +usr/sbin/pkcsicsf/.deps/ +usr/sbin/pkcsslotd/.deps/ +usr/sbin/p11sak/.deps/ + + +misc/pkcsslotd +opencryptoki/ +testcases/common/.dirstamp +testcases/common/.libs/ +testcases/common/libcommon.la +testcases/common/testcases_common_libcommon_la-common.lo +testcases/crypto/.dirstamp +testcases/crypto/aes_tests +testcases/crypto/des3_tests +testcases/crypto/des_tests +testcases/crypto/dh_tests +testcases/crypto/digest_tests +testcases/crypto/dsa_tests +testcases/crypto/ec_tests +testcases/crypto/rsa_tests +testcases/crypto/rsaupdate_tests +testcases/crypto/ssl3_tests +testcases/crypto/testcases_crypto_aes_tests-aes_func.o +testcases/crypto/testcases_crypto_des3_tests-des3_func.o +testcases/crypto/testcases_crypto_des_tests-des_func.o +testcases/crypto/testcases_crypto_dh_tests-dh_func.o +testcases/crypto/testcases_crypto_digest_tests-digest_func.o +testcases/crypto/testcases_crypto_dsa_tests-dsa_func.o +testcases/crypto/testcases_crypto_ec_tests-ec_func.o +testcases/crypto/testcases_crypto_rsa_tests-rsa_func.o +testcases/crypto/testcases_crypto_rsaupdate_tests-rsaupdate_func.o +testcases/crypto/testcases_crypto_ssl3_tests-ssl3_func.o +testcases/init_token.sh +testcases/log-slot_*.txt +testcases/login/.dirstamp +testcases/login/digest_init +testcases/login/init_pin +testcases/login/init_tok +testcases/login/login +testcases/login/login_flags_test +testcases/login/set_pin +testcases/login/testcases_login_digest_init-digest_init.o +testcases/login/testcases_login_init_pin-init_pin.o +testcases/login/testcases_login_init_tok-init_tok.o +testcases/login/testcases_login_login-login.o +testcases/login/testcases_login_login_flags_test-login_flags.o +testcases/login/testcases_login_set_pin-set_pin.o +testcases/misc_tests/.dirstamp +testcases/misc_tests/obj_mgmt_lock_tests +testcases/misc_tests/obj_mgmt_tests +testcases/misc_tests/speed +testcases/misc_tests/testcases_misc_tests_obj_mgmt_lock_tests-obj_mgmt_lock.o +testcases/misc_tests/testcases_misc_tests_obj_mgmt_tests-obj_mgmt.o +testcases/misc_tests/testcases_misc_tests_speed-speed.o +testcases/misc_tests/testcases_misc_tests_threadmkobj-threadmkobj.o +testcases/misc_tests/testcases_misc_tests_tok_des-tok_des.o +testcases/misc_tests/testcases_misc_tests_tok_obj-tok_obj.o +testcases/misc_tests/testcases_misc_tests_tok_rsa-tok_rsa.o +testcases/misc_tests/threadmkobj +testcases/misc_tests/tok_des +testcases/misc_tests/tok_obj +testcases/misc_tests/tok_rsa +testcases/ock_tests.sh +testcases/pkcs11/.dirstamp +testcases/pkcs11/attribute +testcases/pkcs11/copyobjects +testcases/pkcs11/destroyobjects +testcases/pkcs11/findobjects +testcases/pkcs11/gen_purpose +testcases/pkcs11/generate_keypair +testcases/pkcs11/getobjectsize +testcases/pkcs11/hw_fn +testcases/pkcs11/sess_bench +testcases/pkcs11/sess_mgmt_tests +testcases/pkcs11/sess_opstate +testcases/pkcs11/testcases_pkcs11_attribute-attribute.o +testcases/pkcs11/testcases_pkcs11_copyobjects-copyobjects.o +testcases/pkcs11/testcases_pkcs11_destroyobjects-destroyobjects.o +testcases/pkcs11/testcases_pkcs11_findobjects-findobjects.o +testcases/pkcs11/testcases_pkcs11_gen_purpose-gen_purpose.o +testcases/pkcs11/testcases_pkcs11_generate_keypair-generate_keypair.o +testcases/pkcs11/testcases_pkcs11_getobjectsize-getobjectsize.o +testcases/pkcs11/testcases_pkcs11_hw_fn-hw_fn.o +testcases/pkcs11/testcases_pkcs11_sess_bench-sess_perf.o +testcases/pkcs11/testcases_pkcs11_sess_mgmt_tests-sess_mgmt.o +testcases/pkcs11/testcases_pkcs11_sess_opstate-sess_opstate.o +usr/lib/api/.dirstamp +usr/lib/api/.libs/ +usr/lib/api/opencryptoki_libopencryptoki_la-api_interface.lo +usr/lib/api/opencryptoki_libopencryptoki_la-apiutil.lo +usr/lib/api/opencryptoki_libopencryptoki_la-shrd_mem.lo +usr/lib/api/opencryptoki_libopencryptoki_la-socket_client.lo +usr/lib/cca_stdll/.dirstamp +usr/lib/cca_stdll/.libs/ +usr/lib/cca_stdll/opencryptoki_stdll_libpkcs11_cca_la-cca_specific.lo +usr/lib/common/.dirstamp +usr/lib/common/.libs/ +usr/lib/common/opencryptoki_libopencryptoki_la-lock_btree.lo +usr/lib/common/opencryptoki_libopencryptoki_la-trace.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-asn1.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-cert.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-data_obj.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-decr_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-dig_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-dp_obj.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-encr_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-globals.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-hwf_obj.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-key.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-key_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-loadsave.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-lock_btree.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-lock_sess_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-mech_aes.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-mech_des.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-mech_des3.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-mech_dh.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-mech_ec.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-mech_list.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-mech_md2.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-mech_md5.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-mech_rng.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-mech_rsa.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-mech_sha.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-mech_ssl3.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-new_host.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-obj_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-object.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-p11util.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-shared_memory.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-sign_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-sw_crypt.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-template.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-trace.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-utility.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_cca_la-verify_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-asn1.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-attributes.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-cert.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-data_obj.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-decr_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-dig_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-dp_obj.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-encr_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-globals.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-hwf_obj.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-key.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-key_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-loadsave.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-lock_btree.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-lock_sess_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-mech_aes.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-mech_des.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-mech_des3.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-mech_dh.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-mech_dsa.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-mech_ec.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-mech_list.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-mech_md2.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-mech_md5.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-mech_rng.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-mech_rsa.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-mech_sha.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-mech_ssl3.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-obj_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-object.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-p11util.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-shared_memory.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-sign_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-sw_crypt.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-template.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-trace.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-utility.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ep11_la-verify_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-asn1.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-cert.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-data_obj.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-decr_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-dig_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-dp_obj.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-encr_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-globals.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-hwf_obj.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-key.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-key_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-loadsave.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-lock_btree.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-lock_sess_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-mech_aes.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-mech_des.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-mech_des3.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-mech_ec.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-mech_list.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-mech_md2.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-mech_md5.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-mech_rng.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-mech_rsa.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-mech_sha.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-mech_ssl3.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-new_host.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-obj_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-object.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-p11util.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-shared_memory.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-sign_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-sw_crypt.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-template.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-trace.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-utility.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_ica_la-verify_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-asn1.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-attributes.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-cert.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-data_obj.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-decr_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-dig_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-dp_obj.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-encr_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-globals.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-hwf_obj.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-key.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-key_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-loadsave.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-lock_btree.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-lock_sess_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-mech_aes.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-mech_des.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-mech_des3.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-mech_dh.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-mech_ec.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-mech_list.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-mech_md2.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-mech_md5.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-mech_rng.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-mech_rsa.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-mech_sha.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-mech_ssl3.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-obj_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-object.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-p11util.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-shared_memory.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-sign_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-sw_crypt.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-template.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-trace.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-utility.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_icsf_la-verify_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-asn1.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-cert.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-data_obj.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-decr_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-dig_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-dp_obj.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-encr_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-globals.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-hwf_obj.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-key.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-key_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-loadsave.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-lock_btree.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-lock_sess_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-mech_aes.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-mech_des.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-mech_des3.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-mech_dh.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-mech_ec.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-mech_list.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-mech_md2.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-mech_md5.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-mech_rng.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-mech_rsa.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-mech_sha.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-mech_ssl3.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-new_host.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-obj_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-object.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-p11util.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-shared_memory.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-sign_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-sw_crypt.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-template.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-trace.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-utility.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_sw_la-verify_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-asn1.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-cert.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-data_obj.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-decr_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-dig_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-dp_obj.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-encr_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-globals.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-hwf_obj.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-key.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-key_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-loadsave.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-lock_btree.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-lock_sess_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-mech_aes.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-mech_des.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-mech_des3.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-mech_dh.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-mech_ec.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-mech_list.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-mech_md2.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-mech_md5.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-mech_rng.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-mech_rsa.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-mech_sha.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-mech_ssl3.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-new_host.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-obj_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-object.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-p11util.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-shared_memory.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-sign_mgr.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-sw_crypt.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-template.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-trace.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-utility.lo +usr/lib/common/opencryptoki_stdll_libpkcs11_tpm_la-verify_mgr.lo +usr/lib/common/testcases_common_libcommon_la-p11util.lo +usr/lib/common/testcases_crypto_aes_tests-p11util.o +usr/lib/common/testcases_login_login-p11util.o +usr/lib/common/testcases_login_login_flags_test-p11util.o +usr/lib/common/testcases_misc_tests_speed-p11util.o +usr/lib/common/testcases_misc_tests_threadmkobj-p11util.o +usr/lib/common/testcases_misc_tests_tok_obj-p11util.o +usr/lib/common/usr_sbin_pkcscca_pkcscca-p11util.o +usr/lib/common/usr_sbin_pkcscca_pkcscca-sw_crypt.o +usr/lib/common/usr_sbin_pkcscca_pkcscca-trace.o +usr/lib/common/usr_sbin_pkcsconf_pkcsconf-p11util.o +usr/lib/common/usr_sbin_pkcsep11_migrate_pkcsep11_migrate-p11util.o +usr/lib/common/usr_sbin_pkcsep11_session_pkcsep11_session-p11util.o +usr/lib/common/usr_sbin_pkcsicsf_pkcsicsf-trace.o +usr/lib/ep11_stdll/.dirstamp +usr/lib/ep11_stdll/.libs/ +usr/lib/ep11_stdll/opencryptoki_stdll_libpkcs11_ep11_la-ep11_specific.lo +usr/lib/ep11_stdll/opencryptoki_stdll_libpkcs11_ep11_la-new_host.lo +usr/lib/ica_s390_stdll/.dirstamp +usr/lib/ica_s390_stdll/.libs/ +usr/lib/ica_s390_stdll/opencryptoki_stdll_libpkcs11_ica_la-ica_specific.lo +usr/lib/icsf_stdll/.dirstamp +usr/lib/icsf_stdll/.libs/ +usr/lib/icsf_stdll/icsf_config_lexer.c +usr/lib/icsf_stdll/icsf_config_parse.c +usr/lib/icsf_stdll/icsf_config_parse.h +usr/lib/icsf_stdll/icsf_config_parse.output +usr/lib/icsf_stdll/opencryptoki_stdll_libpkcs11_icsf_la-icsf.lo +usr/lib/icsf_stdll/opencryptoki_stdll_libpkcs11_icsf_la-icsf_config_lexer.lo +usr/lib/icsf_stdll/opencryptoki_stdll_libpkcs11_icsf_la-icsf_config_parse.lo +usr/lib/icsf_stdll/opencryptoki_stdll_libpkcs11_icsf_la-icsf_specific.lo +usr/lib/icsf_stdll/opencryptoki_stdll_libpkcs11_icsf_la-new_host.lo +usr/lib/icsf_stdll/opencryptoki_stdll_libpkcs11_icsf_la-pbkdf.lo +usr/lib/icsf_stdll/usr_sbin_pkcsicsf_pkcsicsf-icsf.o +usr/lib/icsf_stdll/usr_sbin_pkcsicsf_pkcsicsf-pbkdf.o +usr/lib/soft_stdll/.dirstamp +usr/lib/soft_stdll/.libs/ +usr/lib/soft_stdll/opencryptoki_stdll_libpkcs11_sw_la-soft_specific.lo +usr/lib/tpm_stdll/.dirstamp +usr/lib/tpm_stdll/.libs/ +usr/lib/tpm_stdll/opencryptoki_stdll_libpkcs11_tpm_la-tpm_openssl.lo +usr/lib/tpm_stdll/opencryptoki_stdll_libpkcs11_tpm_la-tpm_specific.lo +usr/lib/tpm_stdll/opencryptoki_stdll_libpkcs11_tpm_la-tpm_util.lo +usr/sbin/pkcscca/.dirstamp +usr/sbin/pkcscca/pkcscca +usr/sbin/pkcscca/usr_sbin_pkcscca_pkcscca-pkcscca.o +usr/sbin/pkcsconf/.dirstamp +usr/sbin/pkcsconf/pkcsconf +usr/sbin/pkcsconf/usr_sbin_pkcsconf_pkcsconf-pkcsconf.o +usr/sbin/pkcsep11_migrate/.dirstamp +usr/sbin/pkcsep11_migrate/pkcsep11_migrate +usr/sbin/pkcsep11_migrate/usr_sbin_pkcsep11_migrate_pkcsep11_migrate-pkcsep11_migrate.o +usr/sbin/pkcsep11_session/.dirstamp +usr/sbin/pkcsep11_session/pkcsep11_session +usr/sbin/pkcsep11_session/usr_sbin_pkcsep11_session_pkcsep11_session-pkcsep11_session.o +usr/sbin/pkcsicsf/.dirstamp +usr/sbin/pkcsicsf/pkcsicsf +usr/sbin/pkcsicsf/usr_sbin_pkcsicsf_pkcsicsf-pkcsicsf.o +usr/sbin/pkcsslotd/.dirstamp +usr/sbin/pkcsslotd/lexer.c +usr/sbin/pkcsslotd/parser.c +usr/sbin/pkcsslotd/parser.h +usr/sbin/pkcsslotd/parser.output +usr/sbin/pkcsslotd/pkcsslotd +usr/sbin/pkcsslotd/usr_sbin_pkcsslotd_pkcsslotd-daemon.o +usr/sbin/pkcsslotd/usr_sbin_pkcsslotd_pkcsslotd-err.o +usr/sbin/pkcsslotd/usr_sbin_pkcsslotd_pkcsslotd-garbage_linux.o +usr/sbin/pkcsslotd/usr_sbin_pkcsslotd_pkcsslotd-lexer.o +usr/sbin/pkcsslotd/usr_sbin_pkcsslotd_pkcsslotd-log.o +usr/sbin/pkcsslotd/usr_sbin_pkcsslotd_pkcsslotd-mutex.o +usr/sbin/pkcsslotd/usr_sbin_pkcsslotd_pkcsslotd-parser.o +usr/sbin/pkcsslotd/usr_sbin_pkcsslotd_pkcsslotd-pkcsslotd_util.o +usr/sbin/pkcsslotd/usr_sbin_pkcsslotd_pkcsslotd-shmem.o +usr/sbin/pkcsslotd/usr_sbin_pkcsslotd_pkcsslotd-signal.o +usr/sbin/pkcsslotd/usr_sbin_pkcsslotd_pkcsslotd-slotmgr.o +usr/sbin/pkcsslotd/usr_sbin_pkcsslotd_pkcsslotd-socket_server.o +usr/sbin/p11sak/.dirstamp +usr/sbin/p11sak/p11sak +usr/sbin/p11sak/usr_sbin_p11sak_p11sak-p11sak.o \ No newline at end of file diff --git a/.indent.pro b/.indent.pro new file mode 100644 index 0000000..44b7eb1 --- /dev/null +++ b/.indent.pro @@ -0,0 +1,17 @@ +-nbad -bap -nsob // blank lines +-nbc // comma separated declarations +-bbo -hnl // breaking long lines before boolean operators +-br -ce -sai // if statements +-brs // struct declarations +-c33 -cd33 -ncdb -d0 -nfc1 -nsc -nfca // comments +-nut -ci4 -i4 -ip0 -lp // indentation +-cli0 // switch statements +-di1 //declarations +-l80 // line length +-npcs // no space after function call names +-nprs // no space after every '(' and before every ')' +-npsl // put the type of a procedure on the same line as its name +-saf -saw -nss -cdw // loop statements +-cs // cast operators +-cp33 // #else #endif +-il0 // labels diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6d315a0 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,67 @@ +sudo: required +dist: bionic + +language: c + +before_install: + - sudo apt-get -qq update + - sudo apt-get install -y expect trousers libldap2-dev libtspi-dev wget + - 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 + +matrix: + include: + # TODO: Appease -Wclobbered in tm builds. + - name: "linux-x86-clang-locks" + os: linux + compiler: clang + env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-testcases --enable-locks" CFLAGS="-O3 -Wextra -std=c99 -pedantic -Werror -DDEBUG" + - name: "linux-x86-gcc-tm" + os: linux + compiler: gcc + env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-testcases --disable-locks" CFLAGS="-O3 -Wno-clobbered -Wextra -std=c99 -pedantic -Werror" + - name: "linux-ppc64le-clang-locks" + os: linux-ppc64le + compiler: clang + env: CONFIG_OPTS="--enable-swtok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-testcases --enable-locks" CFLAGS="-O3 -Wextra -std=c99 -pedantic -Werror" + - name: "linux-ppc64le-gcc-tm" + os: linux-ppc64le + compiler: gcc + env: CONFIG_OPTS="--enable-swttok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-testcases --disable-locks" CFLAGS="-O3 -Wno-clobbered -Wextra -std=c99 -pedantic -Werror -DDEBUG" + - name: "linux-s390x-clang-locks" + os: linux + arch: s390x + compiler: clang + env: CONFIG_OPTS="--enable-swttok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-icatok --enable-ep11tok --enable-testcases --enable-locks" CFLAGS="-O3 -Wextra -std=c99 -pedantic -Werror -DDEBUG" + - name: "linux-s390x-gcc-tm" + os: linux + arch: s390x + compiler: gcc + env: CONFIG_OPTS="--enable-swttok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-icatok --enable-ep11tok --enable-testcases --disable-locks" CFLAGS="-O3 -Wno-clobbered -Wextra -std=c99 -pedantic -Werror" + - name: "linux-arm64-clang-locks" + os: linux + arch: arm64 + compiler: clang + env: CONFIG_OPTS="--enable-swttok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-testcases --enable-locks" CFLAGS="-O3 -Wextra -std=c99 -pedantic -Werror" + - name: "linux-arm64-gcc-tm" + os: linux + arch: arm64 + compiler: gcc + env: CONFIG_OPTS="--enable-swttok --enable-icsftok --enable-ccatok --enable-tpmtok --enable-testcases --disable-locks" CFLAGS="-O3 -Wno-clobbered -Wextra -std=c99 -pedantic -Werror -DDEBUG" + +before_script: + - sudo groupadd pkcs11 + - ./bootstrap.sh + +script: + - ./configure $CONFIG_OPTS && make + - sudo make install + - sudo ldconfig + - sudo pkcsslotd + - sudo pkcsconf -i + - sudo pkcsconf -s + - sudo pkcsconf -t + - cd testcases + - sudo PKCS11_SO_PIN=87654321 PKCS11_USER_PIN=01234567 PKCSLIB=/usr/local/lib/pkcs11/libopencryptoki.so ./ock_tests.sh -s 3 diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..01e9634 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,19 @@ + +Base function Design and IBM Device support + +Steven Bade - sbade@us.ibm.com +Jimmie Mayfield + +Dan Rabinovitz - dsrabino@us.ibm.com +Shannon Macalpine +Kent Yoder - yoder1@us.ibm.com +Kapil Sood - kapil@corrent.com, soodkapil@yahoo.com + +Broadcom capabilitiy +Anton Stiglic astiglic@okiok.com + +AEP capability +Carlos Cid carlos.cid@sepsystems.com + +Corrent capability +Kapil Sood kapil.sood@corrent.com diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..fae457f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,69 @@ +# How to contribute + +Patches are more than welcome at OpenCryptoki, be it to fix a bug or to add a +new feature. To make your life, and also our life, easy there are a few steps +that we need the contributors to follow. + +## Getting started + +* Read and study the [PKCS #11 standard](https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=pkcs11) v2.20 or, preferably, v2.40. +* Make sure to subscribe to our [technical discussion mailing-list](https://sourceforge.net/projects/opencryptoki/lists/opencryptoki-tech) +* Make sure you have a [GitHub account](https://github.com/signup/free) +* Submit a ticket for your issue, assuming one does not already exist. + * Clearly describe the issue, including steps to reproduce when it is a bug. + * Make sure you fill in the earliest version that you know has the issue. + * In case of a bug, try to attach some logs. Enable tracing on OpenCryptoki by + running `export OPENCRYPTOKI_TRACE_LEVEL=`. For more information about + trace level check the [FAQ](FAQ). + * Include information from your environment (OS, gcc version, and any other + related packages version). + * In case of a new hardware token, please provide a way for us to have access + to an environment that contains such hardware or a way to run automated tests + through Jenkins or other similar tool. +* Fork the repository on GitHub. + +## Making changes +* Create a topic/issue branch from the `master` branch. +* Please avoid working directly on the `master` branch. +* If the changes are too big, please separate it into smaller, logical, commits. +This will improve commit history and code review. +* Follow the [coding style](doc/coding_style.md) guidelines. +* Check for unnecessary whitespace with `git diff --check` before committing. +* Make sure your commit messages are in the proper format and sign your patch: +``` + Add CONTRIBUTING guideline + + The CONTRIBUTING.md file describes the guidelines that every Contributor + should follow to get their code integrated into OpenCryptoki. This will + improve Contributors/Maintainers work. + + Signed-off-by: YOUR_NAME +``` + +* Make sure you have added the necessary tests for your changes. +* Run _all_ the tests to assure nothing else was accidentally broken. If you do +not have the necessary hardware to run _all_ tests, please write it down to us, +so we can manage to do the testing for you. + +## Submitting Changes + +* Sign your commits, as mentioned above. +* There are two ways to submit patches: + * If you prefer the old school way of sending patches to a mailing-list, then + feel free to send your patch to the [technical discussion mailing-list](https://sourceforge.net/projects/opencryptoki/lists/opencryptoki-tech) . We will keep you posted as the code review goes by. + * If you like GitHub and all the tools it has, then submit a pull request to + * the opencryptoki repository on opencryptoki organization. +* Include test information/results on the email thread of your patch or on the +pull request. +* Wait for the Maintainers feedback about your changes. Although we are always +working on the project, sometimes we have our attention caught up on higher +priority tasks for the project. +* Be ready to answer any doubts that we might have about your changes, otherwise +if we do not get an answer we will not be able to merge your code. + +## Final thoughts + +* Feel free to ask questions, there is no such thing as a stupid question, just +stupid people. +* You can find us on the mailing list mentioned above. +* Have fun in the process, coding is fun! diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..b5d97b1 --- /dev/null +++ b/COPYING @@ -0,0 +1,217 @@ + +Common Public License Version 1.0 (CPL) + +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC +LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM +CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + + a) in the case of the initial Contributor, the initial code and + documentation distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + + i) changes to the Program, and + + ii) additions to the Program; + + where such changes and/or additions to the Program originate from and are + distributed by that particular Contributor. A Contribution 'originates' + from a Contributor if it was added to the Program by such Contributor + itself or anyone acting on such Contributor's behalf. Contributions do not + include additions to the Program which: (i) are separate modules of + software distributed in conjunction with the Program under their own + license agreement, and (ii) are not derivative works of the Program. + +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents " mean patent claims licensable by a Contributor which are +necessarily infringed by the use or sale of its Contribution alone or when +combined with the Program. + +"Program" means the Contributions distributed in accordance with this Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, +including all Contributors. + +2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby grants + Recipient a non-exclusive, worldwide, royalty-free copyright license to + reproduce, prepare derivative works of, publicly display, publicly perform, + distribute and sublicense the Contribution of such Contributor, if any, and + such derivative works, in source code and object code form. + + b) Subject to the terms of this Agreement, each Contributor hereby grants + Recipient a non-exclusive, worldwide, royalty-free patent license under + Licensed Patents to make, use, sell, offer to sell, import and otherwise + transfer the Contribution of such Contributor, if any, in source code and + object code form. This patent license shall apply to the combination of the + Contribution and the Program if, at the time the Contribution is added by + the Contributor, such addition of the Contribution causes such combination + to be covered by the Licensed Patents. The patent license shall not apply + to any other combinations which include the Contribution. No hardware per + se is licensed hereunder. + + c) Recipient understands that although each Contributor grants the licenses + to its Contributions set forth herein, no assurances are provided by any + Contributor that the Program does not infringe the patent or other + intellectual property rights of any other entity. Each Contributor + disclaims any liability to Recipient for claims brought by any other entity + based on infringement of intellectual property rights or otherwise. As a + condition to exercising the rights and licenses granted hereunder, each + Recipient hereby assumes sole responsibility to secure any other + intellectual property rights needed, if any. For example, if a third party + patent license is required to allow Recipient to distribute the Program, + it is Recipient's responsibility to acquire that license before + distributing the Program. + + d) Each Contributor represents that to its knowledge it has sufficient + copyright rights in its Contribution, if any, to grant the copyright + license set forth in this Agreement. + +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under +its own license agreement, provided that: + + a) it complies with the terms and conditions of this Agreement; and + + b) its license agreement: + + i) effectively disclaims on behalf of all Contributors all warranties and + conditions, express and implied, including warranties or conditions of + title and non-infringement, and implied warranties or conditions of + merchantability and fitness for a particular purpose; + + ii) effectively excludes on behalf of all Contributors all liability for + damages, including direct, indirect, special, incidental and consequential + damages, such as lost profits; + + iii) states that any provisions which differ from this Agreement are + offered by that Contributor alone and not by any other party; and + + iv) states that source code for the Program is available from such + Contributor, and informs licensees how to obtain it in a reasonable manner + on or through a medium customarily used for software exchange. + +When the Program is made available in source code form: + + a) it must be made available under this Agreement; and + + b) a copy of this Agreement must be included with each copy of the Program. + +Contributors may not remove or alter any copyright notices contained within the +Program. + +Each Contributor must identify itself as the originator of its Contribution, if +any, in a manner that reasonably allows subsequent Recipients to identify the +originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with +respect to end users, business partners and the like. While this license is +intended to facilitate the commercial use of the Program, the Contributor who +includes the Program in a commercial product offering should do so in a manner +which does not create potential liability for other Contributors. Therefore, if +a Contributor includes the Program in a commercial product offering, such +Contributor ("Commercial Contributor") hereby agrees to defend and indemnify +every other Contributor ("Indemnified Contributor") against any losses, damages +and costs (collectively "Losses") arising from claims, lawsuits and other legal +actions brought by a third party against the Indemnified Contributor to the +extent caused by the acts or omissions of such Commercial Contributor in +connection with its distribution of the Program in a commercial product +offering. The obligations in this section do not apply to any claims or Losses +relating to any actual or alleged intellectual property infringement. In order +to qualify, an Indemnified Contributor must: a) promptly notify the Commercial +Contributor in writing of such claim, and b) allow the Commercial Contributor +to control, and cooperate with the Commercial Contributor in, the defense and +any related settlement negotiations. The Indemnified Contributor may +participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product +offering, Product X. That Contributor is then a Commercial Contributor. If that +Commercial Contributor then makes performance claims, or offers warranties +related to Product X, those performance claims and warranties are such +Commercial Contributor's responsibility alone. Under this section, the +Commercial Contributor would have to defend claims against the other +Contributors related to those performance claims and warranties, and if a court +requires any other Contributor to pay any damages as a result, the Commercial +Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR +IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each +Recipient is solely responsible for determining the appropriateness of using +and distributing the Program and assumes all risks associated with its exercise +of rights under this Agreement, including but not limited to the risks and +costs of program errors, compliance with applicable laws, damage to or loss of +data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY +CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST +PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS +GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable +law, it shall not affect the validity or enforceability of the remainder of the +terms of this Agreement, and without further action by the parties hereto, such +provision shall be reformed to the minimum extent necessary to make such +provision valid and enforceable. + +If Recipient institutes patent litigation against a Contributor with respect to +a patent applicable to software (including a cross-claim or counterclaim in a +lawsuit), then any patent licenses granted by that Contributor to such +Recipient under this Agreement shall terminate as of the date such litigation +is filed. In addition, if Recipient institutes patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging that the +Program itself (excluding combinations of the Program with other software or +hardware) infringes such Recipient's patent(s), then such Recipient's rights +granted under Section 2(b) shall terminate as of the date such litigation is +filed. + +All Recipient's rights under this Agreement shall terminate if it fails to +comply with any of the material terms or conditions of this Agreement and does +not cure such failure in a reasonable period of time after becoming aware of +such noncompliance. If all Recipient's rights under this Agreement terminate, +Recipient agrees to cease use and distribution of the Program as soon as +reasonably practicable. However, Recipient's obligations under this Agreement +and any licenses granted by Recipient relating to the Program shall continue +and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in +order to avoid inconsistency the Agreement is copyrighted and may only be +modified in the following manner. The Agreement Steward reserves the right to +publish new versions (including revisions) of this Agreement from time to time. +No one other than the Agreement Steward has the right to modify this Agreement. +IBM is the initial Agreement Steward. IBM may assign the responsibility to +serve as the Agreement Steward to a suitable separate entity. Each new version +of the Agreement will be given a distinguishing version number. The Program +(including Contributions) may always be distributed subject to the version of +the Agreement under which it was received. In addition, after a new version of +the Agreement is published, Contributor may elect to distribute the Program +(including its Contributions) under the new version. Except as expressly stated +in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to +the intellectual property of any Contributor under this Agreement, whether +expressly, by implication, estoppel or otherwise. All rights in the Program not +expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the +intellectual property laws of the United States of America. No party to this +Agreement will bring a legal action under this Agreement more than one year +after the cause of action arose. Each party waives its rights to a jury trial +in any resulting litigation. diff --git a/COPYRIGHTS b/COPYRIGHTS new file mode 100644 index 0000000..d252bb0 --- /dev/null +++ b/COPYRIGHTS @@ -0,0 +1,40 @@ +Base openCryptoki Code and IBM submissions + +(C) COPYRIGHT International Business Machines Corp. 2001, 2006 + + + + + + +For Code originating from AEP Systems Ltd. + + * Copyright (c) 1999-2002 AEP Systems Ltd. + * Bray Business Park, Southern Cross Route, Bray, Co. Wicklow, Ireland. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of AEP Systems Ltd. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..d59a0a4 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,297 @@ ++ Opencryptoki 3.14 +- EP11: Dilitium support stage 2 +- Common: Rework on process and thread locking +- Common: Rework on btree and object locking +- ICSF: minor fixes +- TPM, ICA, ICSF: support multiple token instances +- new tool p11sak + ++ openCryptoki 3.13.0 +- EP11: Dilithium support +- EP11: EdDSA support +- EP11: support RSA-OAEP with non-SHA1 hash and MGF + ++ openCryptoki 3.12.1 +- Fix pkcsep11_migrate tool + ++ openCryptoki 3.12.0 +- Update token pin and data store encryption for soft,ica,cca and ep11 +- EP11: Allow importing of compressed EC public keys +- EP11: Add support for the CMAC mechanisms +- EP11: Add support for the IBM-SHA3 mechanisms +- SOFT: Add AES-CMAC and 3DES-CMAC support to the soft token +- ICA: Add AES-CMAC and 3DES-CMAC support to the ICA token +- EP11: Add config option USE_PRANDOM +- CCA: Use Random Number Generate Long for token_specific_rng() +- Common rng function: Prefer /dev/prandom over /dev/urandom +- ICA: add SHA*_RSA_PKCS_PSS mechanisms +- Bug fixes + ++ openCryptoki 3.11.1 +- Bug fixes + +* opencryptoki 3.11.0 +- EP11 enhancements +- A lot of bug fixes + +* opencryptoki 3.10.0 +- Add support to ECC on ICA token and to common code. +- Add SHA224 support to SOFT token. +- Improve pkcsslotd logging. +- Fix sha512_hmac_sign and rsa_x509_verify for ICA token. +- Fix tracing of session id. +- Fix and improve testcases. +- Fix spec file permission for log directory. +- Fix build warnings. + +* opencryptoki 3.9.0 +- Fix token reinitialization +- Fix conditional man pages +- EP11 enhancements +- EP11 EC Key import +- Increase RSA max key length +- Fix broken links on documentation +- Define CK_FALSE and CK_TRUE macros +- Improve build flags + +* opencryptoki 3.8.2 +- Update man pages. +- Improve ock_tests for parallel execution. +- Fix FindObjectsInit for hidden HW-feature. +- Fix to allow vendor defined hardware features. +- Fix unresolved symbols. +- Fix tracing. +- Code/project cleanup. + +* opencryptoki 3.8.1 +- Fix TPM data-structure reset function. +- Fix error message when dlsym fails. +- Update configure.ac +- Update travis. + +* opencryptoki 3.8.0 +- Multi token instance feature. +- Added possibility to run opencryptoki with transactional memory or locks +(--enable-locks on configure step). +- Updated documentation. +- Fix segfault on ec_test. +- Bunch of small fixes. + +* opencryptoki 3.7.0 +- Update example spec file +- Performance improvement. Moving from mutexes to transactional memory. +- Add ECDSA SHA2 support for EP11 and CCA. +- Fix declaration of inline functions. +- Fix wrong testcase and ber en/decoding for integers. +- Check for 'flex' and 'YACC' on configure. +- EP11 config file rework. +- Add enable-debug on travis build. +- Add testcase for C_GetOperationState/C_SetOperationState. +- Upgrade License to CPL-1.0 +- Ica token: fix openssh/ibmpkcs11 engine/libica crash. +- Fix segfault and logic in hardware feature test. +- Fix spelling of documentation and manuals. +- Fix the retrieval of p from a generated rsa key. +- Coverity scan fixes - incompatible pointer type and unused variables. + +* opencryptoki 3.6.2 +- Support OpenSSL-1.1. +- Add Travis CI support. +- Update autotools scripts and documentation. +- Fix SegFault when a invalid session handle is passed in SC_EncryptUpdate and +SC_DecryptUpdate. + +* opencryptoki 3.6.1 +- Fix SOFT token implementation of digest functions. +- Replace deprecated OpenSSL interfaces. + +* opencryptoki 3.6 +- Replace deprecated libica interfaces. +- Performance improvement for ICA. +- Improvement in documentation on system resources. +- Improvement in testcases. +- Added support for rc=8, reasoncode=2028 in icsf token. +- Fix for session handle not set in session issue. +- Multiple fixes for lock and log directories. +- Downgraded a syslog error to warning. +- Multiple fixes based on coverity scan results. +- Added pkcs11 mapping for icsf reason code 72 for return code 8. + +* opencryptoki 3.5.1 +- Fix Illegal Intruction on pkcscca tool. + +* opencryptoki 3.5 +- Full Coverity scan fixes. +- Fixes for compiler warnings. +- Added support for C_GetObjectSize in icsf token. +- Various bug fixes and memory leak fixes. +- Removed global read permissions from token files. +- Added missing PKCS#11v2.2 constants. +- Fix for symbol resolution issue seen in Fedora 22 and 23 for + ep11 and cca tokens. +- Improvements in socket read operation when a token comes up. +- Replaced 32 bit CCA API declarations with latest header from + version 5.0 libsculcca rpm. + +* opencryptoki 3.4.1 +- fix 32-bit compiler error for ep11 +- fix buffer overflow for cca token +- fix a testcase + +* opencryptoki 3.4 +- CCA master key migration added to the pkcscca tool. When the masterkey on + the CCA adapter changes, this allows the token key objects containing + keys wrapped with the card's former masterkey to be wrapped under the + card's new masterkey. And thus "migrated". +- AES GCM support added to ica token. +- Ability to generate generic secret keys for CKM_GENERIC_SECRET_KEY_GEN + added to opencryptoki. +- The soft, cca, ep11, and icsf tokens support HMAC single and multipart for + SHA1, SHA256, SHA384, and SHA512. +- CCA token, a secure key token, can now import AES, DES3 and + Generic Secret keys. +- Add -Wall and fix various compiler warnings. +- Coverity scan cleanup. +- Additional test vectors and various testcase improvements made. +- Various bugfixes + +* opencryptoki 3.3 +- Dynamic tracing introduced via the new environment variable, + OPENCRYPTOKI_TRACE_LEVEL=. The opencryptoki base as well as all + tokens changed to use the new tracing. +- Allow root to run pkcs11 commands without being in pkcs11 group. +- EncryptUpdate, DecryptUpdate, DigestUpdate, SignUpdate, VerifyUpdate + now allow zero length data. +- Refactored ICA token's SHA . +- Various testcase improvements. +- Various bugfixes. + +* opencryptoki 3.2 +- New pkcscca tool. Currently it assists in migrating cca private token + objects from opencryptoki version 2 to the clear key encryption method + used in opencryptoki version 3. Includes a manpage for pkcscca tool. + Changes to README.cca_stdll to assist in using the CCA token and + migrating the private token objects. +- Support for CKM_RSA_PKCS_OAEP and CKM_RSA_PKCS_PSS algorithms. +- Various bugfixes. +- New testcases for various crypto algorithms. + +* opencryptoki-3.1 +- New ep11 token to support IBM Crypto Express adpaters (starting with + Crypto Express 4S adapters) configured with Enterprise PKCS#11(EP11) + firmware. +- New pkcsep11_migrate utility (and manpage) to migrate token objects + when card's masterkey changes. +- Various bugfixes. + +* opencryptoki-3.0 +- Aggregated source files in common, tpm, and cca directories. +- Re-factored shared memory functions in the stdlls. +- New opencryptoki.conf file to replace pk_config_data and pkcs11_starup. + The opencryptoki.conf contains slot entry information for tokens. +- New manpage for opencryptoki.conf +- Removed pkcs_slot and pkcs11_startup shell scripts. +- New ICSF token to do remote crypto. +- New pkcsicsf utility to setup the ICSF token. +- New manpage for pkcsicsf utility. +- ICA token supports CKM_DES_OFB64, CKM_DES_CFB8, CKM_DES_CFB6 mechanisms + using 3DES keys. +- ICA token supports CKM_DES3_MAC and CKM_DES3_MAC_GENERAL mechanisms. +- ICA token supports CKM_AES_OFB, CKM_AES_CFB8, CKM_AES_CFB64, CKM_AES_CFB128, + CKM_AES_MAC, and CKM_AES_MAC_GENERAL mechanisms. +- Some code cleanup in pkcsslotd. +- pkcsslotd daemon uses a socket rather than shared memory to pass + slot information to the opencryptoki library. +- New testcases added for various crypto algorithms and pkcs#11 api calls. +- Add README to docs directory for how to setup ICSF token. + +* opencryptoki-2.4.3.1 (May 17, 2013) +- Allow imported rsa private keys in cca to also decrypt. + +* opencryptoki-2.4.3 (April 29, 2013) +- CKM_SHA256_RSA_PKCS,CKM_SHA384_RSA_PKCS,CKM_SHA512_RSA_PKCS support + for ICA token. +- Allow import of RSA public and private keys into CCA token. +- Systemd support added. +- Various bugfixes and additional testcases. + +* opencryptoki-2.4.2 (April 27, 2012) +- Re-factored spinlocks, such that each token has its own spinlock + in its own directory relative to /var/locks/opencryptoki. + +* opencryptoki-2.4.1 (February 21, 2012) +- SHA256 support added for CCA token +- Several crypto algorithm testcases refactored to include published + test vectors. +- Testcase directory restructured for future improvements. +- Allow tpm stdll to get SRK passwd and mode from new env variables. + See [1] for info on how to use this feature and please report any bugs. +- Renamed spinlocks for shared memory to /var/lock dir and did + some cleanup of unused locking schemes. +- Various bugfixes and cleanup. + +[1] http://opencryptoki.git.sourceforge.net/git/gitweb.cgi?p=opencryptoki/opencryptoki;a=blob;f=doc/README.tpm_stdll;h=dda0d2263cfbb3df8c65ebc64b8006e3242f6321;hb=HEAD#l58 + + +* opencryptoki-2.4 +- Support for Elliptic Curve Support in CCA token. +- Support for AES CTR in ICA token. +- Session handling refactored from using a reference to memory to + using a handle that references a binray tree node. +- Cleanup logging. Debug messages now go to a file referenced in + OPENCRYPTOKI_DEBUG_FILE env variable. +- Various bugfixes and cleanup. + +* opencryptoki-2.3.3 (Jan 13 2011) +- Moderate fixes and clean-ups to key unwrapping mechanisms +- several pkcsconf fixes, some minor changes +- Important fix to CCA library name in pkcs11_startup +- PKCS padding length fix for symmetric ciphers +- Better RSA public exponent validations in all supported tokens +- Huge testsuite refactor +- Several other minor fixes and cleanups + +* opencryptoki-2.3.2 (Jul 29 2010) +- Significant clean-ups to the building and packaging systems and many + small fixes by Klaus Heinrich Kiwi +- Various minor fixes to slot daemon and init script by Dan Horák + +- Some RSA PKCS#1 v1.5 padding clean-ups by Ramon de Carvalho Valle + +- Human-readable flags output to pkcsconf, some minor soft-token + fixes by Kent Yoder +- Improved overall session/object look-up performance. Note that this + change might crash buggy callers with badly-written session/object + handle tracking - Klaus Heinrich Kiwi + +* openCryptoki-2.3.1 +- Moved ICA token to use libica-2.0, supporting newer hardware and 4K + RSA modulus. Libica-2.x is now *required* to build the ICA token. +- Moved CCA token to use CCA-4.0, supporting AES, SHA-2 and 4K RSA + keys in newer hardware. Although not required for building, CCA-4.0 + is *required* for running the CCA token. + +* openCryptoki-2.2.5 + +- Fixed bug in comparison of PINs in pkcsconf. +- Added code to set the encryption and signature schemes of keys imported +into the TPM token. +- Added tpm token message to warn when only owner can read the pub SRK. +- Fixed return code of function failed when it should be buffer too small in +various mech_des.c mech_des3.c and mech_aes.c files. +- Moved doc/*.txt to manpage format and integrated them into the build/install +- Updated testcases to query env vars for PINs and call a set of common +routines for common operations +- Added SHA256 support for all tokens +- Fixed object cleanup when max number of token objects is hit +- Fixed fd exhaustion bug with spin lock fd +- Updated TPM stdll for TSS policy handling changes. Trousers 0.2.9+ now +required with openCryptoki 2.2.5 +- Updated TPM stdll to use TSS_TSPATTRIB_KEYINFO_RSA_MODULUS when retrieving +the public modulus +- pkcs11_startup fix for use with s/w fallback support in libica on s390 +- Added the CCA secure key token and migration utility +- Replaced bcopy/bzero with memcpy/memset throughout the code +- Removed unused variables throughout the code + +* openCryptoki-2.2.4 diff --git a/FAQ b/FAQ new file mode 100644 index 0000000..9b7491d --- /dev/null +++ b/FAQ @@ -0,0 +1,104 @@ + + + openCryptoki FAQ - Kent Yoder +----------------------------------------------------------------------------- + + 1. Q. All openCryptoki applications are returning CKR_TOKEN_NOT_PRESENT, + even though the token is there, and its STDLL is in the right place. + What's the problem? + + A1. The user who's executing the application is probably not a member + of the pkcs11 group. + + A2. Check that the device driver for your hardware token is loaded. + (`lsmod` in Linux). + + A3. If you're doing development, this error will also be returned of your + token's STDLL has unresolved symbols in it. Enable debugging and + check the debug log to find out what symbols are undefined. + + 2. Q. When C_Initialize() gets called by my app, openCryptoki returns + CKR_HOST_MEMORY, even though I've got lots of free memory. What's + the problem? + + A1. CKR_HOST_MEMORY is returned also if openCryptoki cannot attach + to shared memory. This can happen if: + + a1. The user who's executing the application is not a member of + the pkcs11 group. + + a2. pkcsslotd is not running. + + 3. Q. pkcsconf is returning: + + Error getting token info: 0x2 + This is CKR_HOST_MEMORY, see question 2. + + Error getting token info: 0x3 + The slot ID you're providing is invalid. + + 4. Q. How can I get the complete debug logs from openCryptoki? + + A. In opencryptoki version 3.3, tracing was introduced. There is no + longer a need to compile opencryptoki with debug enabled via + "configure --enable-debug" to debug problems. Trace messages are + enabled via the environment variable, OPENCRYPTOKI_TRACE_LEVEL=. + Set this environment variable to one of several trace levels available: + 1 - log error messages + 2 - log warning messages + 3 - log informational messages + 4 - log development debug messages; these messages may help debug + while developing pkcs#11 applications. + 5 - debug messages that are useful to opencryptoki developers; + this level must be enabled via --enable-debug option in the + configure script. + + Note: Trace messages increase as the trace level increases. + In other words, trace level 4 includes all the messages from + trace levels 1, 2 and 3. + + An additional level 5 is included for those implementing new + features into opencryptoki source code. This level 5 allows for more + debug output. Level 5 is enabled when compiling opencryptoki + source code using "configure --enable-debug" and exporting + OPENCRYPTOKI_TRACE_LEVEL=5. + + All trace output is logged into trace. file in the + /var/log/opencryptoki directory. A trace file is created per + process. + + Prior to opencryptoki version 3.3, opencryptoki had to be compiled + with debugging enabled, i.e configure --enable-debug. Debug messages + were then logged to the file specified with the + OPENCRYPTOKI_DEBUG_FILE environment variable. If the environment + variable was not set, then opencryptoki debug messages were not logged. + Debugging does not have to be enabled for syslog messages to be + logged. Syslog messages are logged according to the system's syslog + configuration. + + For versions of openCryptoki starting with openCryptoki-2.0 and before + openCryptoki-2.4, define the environment variable PKCS11_API_LOG_DEBUG=1 + (in versions of openCryptoki before 2.0, define + AIX_PKCS11_API_LOG_DEBUG=1). + + Also, apparently by default syslogd does not have an entry in + /etc/syslogd.conf for debug messages, so even if you have debug + messages enabled in your openCryptoki compile, you'll not get them in + the system log until you edit /etc/syslogd.conf and restart syslogd. + Add an entry in /etc/syslogd.conf such as: + + # vi /etc/syslogd.conf + --- + [...] + + *.debug /var/log/debuglog + --- + # killall -HUP syslogd + + Now, when openCryptoki is configured with the --enable-debug + option (or if you install the -debug rpms), /var/log/debuglog + will receive its debugging messages. + + +----------------------------------------------------------------------------- + openCryptoki FAQ diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..de3196e --- /dev/null +++ b/INSTALL @@ -0,0 +1,159 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.ac' is used to create `configure' by a program +called `autoconf'. You only need `configure.ac' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and + type `sh ./bootstrap.sh', then type `./configure' to configure the + package for your system. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the pkcs11 API in the directory +`/usr/lib/pkcs11/', any STDLLs that were built in `/usr/lib/pkcs11/stdll', +the config programs in `/usr/lib/pkcs11/methods', and the slot daemon in +`/usr/sbin/'. You can specify an installation prefix other than `/usr/local' +bygiving `configure' the option `--prefix=PATH'. + +Optional Features +================= + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b5d97b1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,217 @@ + +Common Public License Version 1.0 (CPL) + +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC +LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM +CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + + a) in the case of the initial Contributor, the initial code and + documentation distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + + i) changes to the Program, and + + ii) additions to the Program; + + where such changes and/or additions to the Program originate from and are + distributed by that particular Contributor. A Contribution 'originates' + from a Contributor if it was added to the Program by such Contributor + itself or anyone acting on such Contributor's behalf. Contributions do not + include additions to the Program which: (i) are separate modules of + software distributed in conjunction with the Program under their own + license agreement, and (ii) are not derivative works of the Program. + +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents " mean patent claims licensable by a Contributor which are +necessarily infringed by the use or sale of its Contribution alone or when +combined with the Program. + +"Program" means the Contributions distributed in accordance with this Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, +including all Contributors. + +2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby grants + Recipient a non-exclusive, worldwide, royalty-free copyright license to + reproduce, prepare derivative works of, publicly display, publicly perform, + distribute and sublicense the Contribution of such Contributor, if any, and + such derivative works, in source code and object code form. + + b) Subject to the terms of this Agreement, each Contributor hereby grants + Recipient a non-exclusive, worldwide, royalty-free patent license under + Licensed Patents to make, use, sell, offer to sell, import and otherwise + transfer the Contribution of such Contributor, if any, in source code and + object code form. This patent license shall apply to the combination of the + Contribution and the Program if, at the time the Contribution is added by + the Contributor, such addition of the Contribution causes such combination + to be covered by the Licensed Patents. The patent license shall not apply + to any other combinations which include the Contribution. No hardware per + se is licensed hereunder. + + c) Recipient understands that although each Contributor grants the licenses + to its Contributions set forth herein, no assurances are provided by any + Contributor that the Program does not infringe the patent or other + intellectual property rights of any other entity. Each Contributor + disclaims any liability to Recipient for claims brought by any other entity + based on infringement of intellectual property rights or otherwise. As a + condition to exercising the rights and licenses granted hereunder, each + Recipient hereby assumes sole responsibility to secure any other + intellectual property rights needed, if any. For example, if a third party + patent license is required to allow Recipient to distribute the Program, + it is Recipient's responsibility to acquire that license before + distributing the Program. + + d) Each Contributor represents that to its knowledge it has sufficient + copyright rights in its Contribution, if any, to grant the copyright + license set forth in this Agreement. + +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under +its own license agreement, provided that: + + a) it complies with the terms and conditions of this Agreement; and + + b) its license agreement: + + i) effectively disclaims on behalf of all Contributors all warranties and + conditions, express and implied, including warranties or conditions of + title and non-infringement, and implied warranties or conditions of + merchantability and fitness for a particular purpose; + + ii) effectively excludes on behalf of all Contributors all liability for + damages, including direct, indirect, special, incidental and consequential + damages, such as lost profits; + + iii) states that any provisions which differ from this Agreement are + offered by that Contributor alone and not by any other party; and + + iv) states that source code for the Program is available from such + Contributor, and informs licensees how to obtain it in a reasonable manner + on or through a medium customarily used for software exchange. + +When the Program is made available in source code form: + + a) it must be made available under this Agreement; and + + b) a copy of this Agreement must be included with each copy of the Program. + +Contributors may not remove or alter any copyright notices contained within the +Program. + +Each Contributor must identify itself as the originator of its Contribution, if +any, in a manner that reasonably allows subsequent Recipients to identify the +originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with +respect to end users, business partners and the like. While this license is +intended to facilitate the commercial use of the Program, the Contributor who +includes the Program in a commercial product offering should do so in a manner +which does not create potential liability for other Contributors. Therefore, if +a Contributor includes the Program in a commercial product offering, such +Contributor ("Commercial Contributor") hereby agrees to defend and indemnify +every other Contributor ("Indemnified Contributor") against any losses, damages +and costs (collectively "Losses") arising from claims, lawsuits and other legal +actions brought by a third party against the Indemnified Contributor to the +extent caused by the acts or omissions of such Commercial Contributor in +connection with its distribution of the Program in a commercial product +offering. The obligations in this section do not apply to any claims or Losses +relating to any actual or alleged intellectual property infringement. In order +to qualify, an Indemnified Contributor must: a) promptly notify the Commercial +Contributor in writing of such claim, and b) allow the Commercial Contributor +to control, and cooperate with the Commercial Contributor in, the defense and +any related settlement negotiations. The Indemnified Contributor may +participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product +offering, Product X. That Contributor is then a Commercial Contributor. If that +Commercial Contributor then makes performance claims, or offers warranties +related to Product X, those performance claims and warranties are such +Commercial Contributor's responsibility alone. Under this section, the +Commercial Contributor would have to defend claims against the other +Contributors related to those performance claims and warranties, and if a court +requires any other Contributor to pay any damages as a result, the Commercial +Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR +IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each +Recipient is solely responsible for determining the appropriateness of using +and distributing the Program and assumes all risks associated with its exercise +of rights under this Agreement, including but not limited to the risks and +costs of program errors, compliance with applicable laws, damage to or loss of +data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY +CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST +PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS +GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable +law, it shall not affect the validity or enforceability of the remainder of the +terms of this Agreement, and without further action by the parties hereto, such +provision shall be reformed to the minimum extent necessary to make such +provision valid and enforceable. + +If Recipient institutes patent litigation against a Contributor with respect to +a patent applicable to software (including a cross-claim or counterclaim in a +lawsuit), then any patent licenses granted by that Contributor to such +Recipient under this Agreement shall terminate as of the date such litigation +is filed. In addition, if Recipient institutes patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging that the +Program itself (excluding combinations of the Program with other software or +hardware) infringes such Recipient's patent(s), then such Recipient's rights +granted under Section 2(b) shall terminate as of the date such litigation is +filed. + +All Recipient's rights under this Agreement shall terminate if it fails to +comply with any of the material terms or conditions of this Agreement and does +not cure such failure in a reasonable period of time after becoming aware of +such noncompliance. If all Recipient's rights under this Agreement terminate, +Recipient agrees to cease use and distribution of the Program as soon as +reasonably practicable. However, Recipient's obligations under this Agreement +and any licenses granted by Recipient relating to the Program shall continue +and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in +order to avoid inconsistency the Agreement is copyrighted and may only be +modified in the following manner. The Agreement Steward reserves the right to +publish new versions (including revisions) of this Agreement from time to time. +No one other than the Agreement Steward has the right to modify this Agreement. +IBM is the initial Agreement Steward. IBM may assign the responsibility to +serve as the Agreement Steward to a suitable separate entity. Each new version +of the Agreement will be given a distinguishing version number. The Program +(including Contributions) may always be distributed subject to the version of +the Agreement under which it was received. In addition, after a new version of +the Agreement is published, Contributor may elect to distribute the Program +(including its Contributions) under the new version. Except as expressly stated +in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to +the intellectual property of any Contributor under this Agreement, whether +expressly, by implication, estoppel or otherwise. All rights in the Program not +expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the +intellectual property laws of the United States of America. No party to this +Agreement will bring a legal action under this Agreement more than one year +after the cause of action arose. Each party waives its rights to a jury trial +in any resulting litigation. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..6f6826f --- /dev/null +++ b/Makefile.am @@ -0,0 +1,210 @@ +ACLOCAL_AMFLAGS = -I m4 +EXTRA_DIST = opencryptoki.map opencryptoki_tok.map +CLEANFILES = +AM_YFLAGS = -d -v +BUILT_SOURCES = + +man1_MANS = +man5_MANS = +man7_MANS = +man8_MANS = +sbin_PROGRAMS = +nobase_lib_LTLIBRARIES = +noinst_HEADERS = +noinst_LTLIBRARIES = +noinst_PROGRAMS = +noinst_SCRIPTS = + +if ENABLE_LIBRARY +include misc/misc.mk +else +if ENABLE_DAEMON +include misc/misc.mk +endif +endif +if ENABLE_TESTCASES +include testcases/testcases.mk +endif + +include man/man.mk +include usr/usr.mk + + +install-data-hook: +if ENABLE_LIBRARY + $(MKDIR_P) $(DESTDIR)$(libdir)/opencryptoki/stdll + $(MKDIR_P) $(DESTDIR)$(libdir)/pkcs11 + cd $(DESTDIR)$(libdir)/opencryptoki && \ + ln -fs libopencryptoki.so PKCS11_API.so + cd $(DESTDIR)$(libdir)/opencryptoki && \ + ln -nfs $(sbindir) methods + cd $(DESTDIR)$(libdir)/pkcs11 && \ + ln -nfs $(sbindir) methods + cd $(DESTDIR)$(libdir)/pkcs11 && \ + ln -fs ../opencryptoki/libopencryptoki.so PKCS11_API.so + cd $(DESTDIR)$(libdir)/pkcs11 && \ + ln -fs ../opencryptoki/libopencryptoki.so libopencryptoki.so + cd $(DESTDIR)$(libdir)/pkcs11 && \ + ln -nfs ../opencryptoki/stdll/ stdll +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 + $(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 + $(CHMOD) 0770 $(DESTDIR)$(lockdir)/ccatok +endif +if ENABLE_EP11TOK + 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 + $(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 + $(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 + test -f $(DESTDIR)$(sysconfdir)/opencryptoki/ep11cpfilter.conf || $(INSTALL) -m 644 $(srcdir)/usr/lib/ep11_stdll/ep11cpfilter.conf $(DESTDIR)$(sysconfdir)/opencryptoki/ep11cpfilter.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 + $(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 + $(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 + $(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 + $(CHMOD) 0770 $(DESTDIR)$(lockdir)/swtok +endif +if ENABLE_TPMTOK + $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/opencryptoki/tpm + 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 + $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/tpm + $(MKDIR_P) $(DESTDIR)$(lockdir)/tpm + $(CHGRP) pkcs11 $(DESTDIR)$(lockdir)/tpm + $(CHMOD) 0770 $(DESTDIR)$(lockdir)/tpm +endif +if ENABLE_ICSFTOK + $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/opencryptoki/icsf + 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 + $(CHMOD) 0770 $(DESTDIR)$(localstatedir)/lib/opencryptoki/icsf + $(MKDIR_P) $(DESTDIR)$(lockdir)/icsf + $(CHGRP) pkcs11 $(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 +if ENABLE_SYSTEMD + mkdir -p $(DESTDIR)/usr/lib/tmpfiles.d + cp $(srcdir)/misc/tmpfiles.conf $(DESTDIR)/usr/lib/tmpfiles.d/opencryptoki.conf + $(CHMOD) 0644 $(DESTDIR)/usr/lib/tmpfiles.d/opencryptoki.conf + rm -f $(DESTDIR)/usr/lib/systemd/system/tmpfiles.conf +endif +endif + $(MKDIR_P) $(DESTDIR)/etc/ld.so.conf.d + echo "$(libdir)/opencryptoki" >\ + $(DESTDIR)/etc/ld.so.conf.d/opencryptoki-$(target_cpu).conf + echo "$(libdir)/opencryptoki/stdll" >>\ + $(DESTDIR)/etc/ld.so.conf.d/opencryptoki-$(target_cpu).conf + @echo "--------------------------------------------------------------" + @echo "Remember you must run ldconfig before using the above settings" + @echo "--------------------------------------------------------------" + $(MKDIR_P) $(DESTDIR)$(lockdir) $(DESTDIR)$(logdir) + $(CHGRP) pkcs11 $(DESTDIR)$(lockdir) $(DESTDIR)$(logdir) + $(CHMOD) 0770 $(DESTDIR)$(lockdir) $(DESTDIR)$(logdir) + + +uninstall-hook: +if ENABLE_LIBRARY + if test -d $(DESTDIR)$(libdir)/opencryptoki/stdll; then \ + cd $(DESTDIR)$(libdir)/opencryptoki && \ + rm -f PKCS11_API.so && \ + rm -f methods; fi + if test -d $(DESTDIR)$(libdir)/pkcs11; then \ + cd $(DESTDIR)$(libdir)/pkcs11 && \ + rm -f methods && \ + rm -f PKCS11_API.so && \ + rm -f libopencryptoki.so && \ + rm -f stdll; fi +endif +if ENABLE_CCATOK + if test -d $(DESTDIR)/$(libdir)/opencryptoki/stdll; then \ + cd $(DESTDIR)/$(libdir)/opencryptoki/stdll && \ + rm -f PKCS11_CCA.so; fi +endif +if ENABLE_EP11TOK + if test -d $(DESTDIR)$(libdir)/opencryptoki/stdll; then \ + cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ + rm -f PKCS11_EP11.so; fi +endif +if ENABLE_ICATOK + if test -d $(DESTDIR)$(libdir)/opencryptoki/stdll; then \ + cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ + rm -f PKCS11_ICA.so; fi +endif +if ENABLE_SWTOK + if test -d $(DESTDIR)$(libdir)/opencryptoki/stdll; then \ + cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ + rm -f PKCS11_SW.so; fi +endif +if ENABLE_TPMTOK + if test -d $(DESTDIR)$(libdir)/opencryptoki/stdll; then \ + cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ + rm -rf PKCS11_TPM.so; fi +endif + rm -f $(DESTDIR)/etc/ld.so.conf.d/opencryptoki-$(target_cpu).conf +if ENABLE_ICSFTOK + if test -d $(DESTDIR)$(libdir)/opencryptoki/stdll; then \ + cd $(DESTDIR)$(libdir)/opencryptoki/stdll && \ + rm -rf PKCS11_ICSF.so; fi +endif +if ENABLE_DAEMON +if ENABLE_SYSTEMD + if test -e $(DESTDIR)/usr/lib/tmpfiles.d/opencryptoki.conf; then \ + rm -f $(DESTDIR)/usr/lib/tmpfiles.d/opencryptoki.conf; fi +endif +endif + rm -f $(DESTDIR)$(sysconfdir)/opencryptoki/opencryptoki.conf || true + + +if ENABLE_TESTCASES +installcheck-local: all + killall -HUP pkcsslotd || true + @sbindir@/pkcsslotd + if test ! -z ${PKCS11_TEST_USER}; then \ + cd ${srcdir}/testcases && su ${PKCS11_TEST_USER} -c "PKCS11_SO_PIN=76543210 PKCS11_USER_PIN=01234567 PKCSLIB=@libdir@/opencryptoki/libopencryptoki.so sh ./ock_tests.sh"; \ + else \ + cd ${srcdir}/testcases && PKCS11_SO_PIN=76543210 PKCS11_USER_PIN=01234567 PKCSLIB=@libdir@/opencryptoki/libopencryptoki.so sh ./ock_tests.sh; \ + fi + killall -HUP pkcsslotd +endif + diff --git a/README.md b/README.md new file mode 100644 index 0000000..9a72606 --- /dev/null +++ b/README.md @@ -0,0 +1,257 @@ +['![Travis CI Build Status](https://travis-ci.org/opencryptoki/opencryptoki.svg?branch=master)'](https://travis-ci.org/opencryptoki/opencryptoki) +['![Coverity Scan Build Status](https://img.shields.io/coverity/scan/16802.svg)'](https://scan.coverity.com/projects/opencryptoki-opencryptoki) + +# openCryptoki + +Package version 3.14 + +Please see [ChangeLog](ChangeLog) for release specific information. + +## OVERVIEW + +openCryptoki version 3.14 implements the PKCS#11 specification version 2.20. + +This package includes several cryptographic tokens: +CCA, ICA, TPM , SWToken, ICSF and EP11. + +For a more in-depth overview of openCryptoki, please refer to the +[HOWTO](doc/opencryptoki-howto.md) + +## REQUIREMENTS: + +- IBM ICA - requires libica library version 3.3.0 or higher for accessing ICA +hardware crypto on IBM zSeries. + +- IBM CCA - requires IBM XCrypto CEX3C card (or higher) and the CEX3C host +libraries and tools version 4.1 (or higher). + +- TPM - requires a TPM, TPM tools, and TCG software stack. + +- SWToken - The software token uses OpenSSL version 1.0.2 or higher. + +- ICSF - The Integrated Cryptographic Service Facility (ICSF) token requires +openldap and openldap client software version 2.4.23 or higher. Lex and Yacc are +also required to build this token. + +- EP11 - The EP11 token is a token that uses the IBM Crypto Express adapters +(starting with Crypto Express 4S adapters) configured with Enterprise PKCS#11 +(EP11) firmware. + +## BUILD PROCESS + +The simplest way to compile this package is to enter the source code main +directory and do the following: + +1. Run the bootstrap.sh script by typing: + +``` + $ ./bootstrap.sh +``` + +2. Configure the source code by typing: + +``` + $ ./configure +``` + + If you're planning to install the package into your home directory or to a + location other than `/usr/local` then add the flag `--prefix=PATH` to + `configure`. Fox example, if your home directory is `/home/luser` you can + configure the package to install itself there by invoking: + +``` + $ ./configure --prefix=/home/luser +``` + + If your stdll headers and libraries are not under any standard path, you will + need to pass the paths to your files to the configure script. For instance: + +``` + $ CPPFLAGS="-L/path/lib" LDFLAGS="-I/path/include" ./configure +``` + + See `./configure --help` for info on various options. The default behavior is + to build a default token implicitly. For the s390 platform, the default token + is ICA. For other platforms, the default token is the software token. Other + tokens may be enabled using the corresponding `--enable-` configuration + option provided the appropriate libraries are available. + + While running, `configure` prints some messages telling which features is it + checking for. + +3. Compile the package by typing: + +``` + $ make +``` + +4. openCryptoki defaults to be usable by anyone who is in the group ``pkcs11``. +Add the pkcs11 group before installing it, by typing as root the command: + +``` + # groupadd pkcs11 +``` + + In addition, add the necessary user to the pkcs11 group (root doesn't need to + be in pkcs11 group): + +``` + # usermod -G pkcs11 +``` + +5. Type `make install` (as root) to install the programs and any data files and +documentation. During installation, the following files go to the following +directories: + +``` + /prefix/sbin/pkcsconf + /prefix/sbin/pkcsslotd + /prefix/sbin/pkcsicsf + /prefix/libdir/libopencryptoki.so + /prefix/libdir/libopencryptoki.so.0 + /prefix/libdir/opencryptoki/libopencryptoki.so + /prefix/libdir/opencryptoki/libopencryptoki.so.0 + /prefix/libdir/opencryptoki/libopencryptoki.so.0.0.0 + /prefix/var/lib/opencryptoki + /prefix/etc/opencryptoki/opencryptoki.conf +``` + + Token objects, which may be optionally built, go to the following locations: + +``` + /prefix/libdir/opencryptoki/stdll/libpkcs11_cca.so + /prefix/libdir/opencryptoki/stdll/libpkcs11_cca.so.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_cca.so.0.0.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_ep11.so + /prefix/libdir/opencryptoki/stdll/libpkcs11_ep11.so.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_ep11.so.0.0.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_ica.so + /prefix/libdir/opencryptoki/stdll/libpkcs11_ica.so.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_ica.so.0.0.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_icsf.so + /prefix/libdir/opencryptoki/stdll/libpkcs11_icsf.so.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_icsf.so.0.0.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_sw.so + /prefix/libdir/opencryptoki/stdll/libpkcs11_sw.so.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_sw.so.0.0.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_tpm.so + /prefix/libdir/opencryptoki/stdll/libpkcs11_tpm.so.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_tpm.so.0.0.0 +``` + + where `prefix` is either `/usr/local` or the PATH that you specified in the + `--prefix` flag. `libdir` is the name of the library directory, for 32-bit + libraries it is usually `lib` and for 64-bit libraries it is usually `lib64`. + + To maintain backwards compatibility, some additional symlinks are generated + (note that these are deprecated and applications should migrate to use the + LSB-compliant names and locations for libraries and executable): + +``` + /prefix/lib/opencryptoki/PKCS11_API.so + - Symlink to /prefix/lib/opencryptoki/libopencryptoki.so + + /prefix/lib/opencryptoki/stdll/PKCS11_CCA.so + - Symlink to /prefix/lib/opencryptoki/stdll/libpkcs11_cca.so + + /prefix/lib/opencryptoki/stdll/PKCS11_EP11.so + - Symlink to /prefix/lib/opencryptoki/stdll/libpkcs11_ep11.so + + /prefix/lib/opencryptoki/stdll/PKCS11_ICA.so + - Symlink to /prefix/lib/opencryptoki/stdll/libpkcs11_ica.so + + /prefix/lib/opencryptoki/stdll/PKCS11_ICSF.so + - Symlink to /prefix/lib/opencryptoki/stdll/libpkcs11_icsf.so + + /prefix/lib/opencryptoki/stdll/PKCS11_SW.so + - Symlink to /prefix/lib/opencryptoki/stdll/libpkcs11_sw.so + + /prefix/lib/pkcs11/PKCS11_API.so + - Symlink to /prefix/lib/opencryptoki/libopencryptoki.so + + /prefix/lib/pkcs11 + - Directory created if non-existent + + /prefix/lib/pkcs11/methods + - Symlink to /prefix/sbin + + /prefix/lib/pkcs11/stdll + - Symlink to /prefix/lib/opencryptoki/stdll + + /prefix/etc/pkcs11 + - Symlink to /prefix/var/lib/opencryptoki +``` + + If any of these directories do not presently exist, they will be created on + demand. Note that if `prefix` is `/usr`, then `/prefix/var` and `/prefix/etc` + resolve to `/var` and `/etc`. On the `make install` stage, if content exists + in the old `/prefix/etc/pkcs11` directory, it will be migrated to the new + '/prefix/var/lib/opencryptoki` location. + + If you are installing in your home directory make sure that `/home/luser/bin` + is in your path. If you're using the bash shell add this line at the end of + your `.bashrc` file: + +``` + PATH="/home/luser/bin:${PATH}" + export PATH +``` + + If you are using csh or tcsh, then use this line instead: + +``` + setenv PATH /home/luser/bin:${PATH} +``` + + By prepending your home directory to the rest of the PATH you can override + systemwide installed software with your own custom installation. + + For more installation information, please check [INSTALL](INSTALL). + +## CONFIGURATION + +See: +https://www.ibm.com/support/knowledgecenter/linuxonibm/com.ibm.linux.z.lxce/lxce_stackoverview.html + +Prior to version 3, openCryptoki used `pk_config_data` as its configuration +file. This file was created upon running `pkcs11_startup`. In version 3, +`pkcs11_startup` and `pk_config_data` have been removed and replaced with a +customizable config file named, `opencryptoki.conf`. It contains an entry for +each token currently supported by openCryptoki. However, only those token, whose +hardware and software requirements are available on the local system, will show +up as present and available upon running the `pkcsconf -t` command. + +Before using, each token must be first initialized. You can select the token +with the `-c` command line option; refer to the documentation linked to above +for further instructions. + +Initialize a particular token by running `pkcsconf`: + +``` + $ pkcsconf -I -c +``` + +In this version of openCryptoki, the default SO PIN is `87654321`. This should +be changed to a different PIN value before use. + +You can change the SO PIN by running pkcsconf: + +``` + $ pkcsconf -P -c +``` + +You can initialize and change the user PIN by typing: + +``` + $ pkcsconf -u -c +``` + +You can later change the user PIN again by typing: + +``` + $ pkcsconf -p -c +``` + +## CONTRIBUTING + +See [CONTRIBUTING.md](CONTRIBUTING.md). diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 0000000..d8b71c7 --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# +# 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 +# + +autoreconf --force --install --verbose --warnings=all diff --git a/cleanup.sh b/cleanup.sh new file mode 100755 index 0000000..110dbe7 --- /dev/null +++ b/cleanup.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +rm -rf `cat .gitignore`; diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..289c505 --- /dev/null +++ b/configure.ac @@ -0,0 +1,656 @@ +dnl Process this file with autoconf to produce a configure script. +AC_PREREQ([2.69]) +AC_INIT([openCryptoki],[3.14.0],[opencryptoki-tech@lists.sourceforge.net],[],[https://github.com/opencryptoki/opencryptoki]) +AC_CONFIG_SRCDIR([testcases/common/common.c]) + +dnl Needed for $target! +AC_CANONICAL_TARGET + +AM_INIT_AUTOMAKE([-Wall -Wno-portability foreign subdir-objects]) + +dnl Checks for header files. +AC_DISABLE_STATIC +LT_INIT + +AC_HEADER_STDC +AC_CHECK_HEADER_STDBOOL +AC_CHECK_HEADERS([arpa/inet.h fcntl.h libintl.h limits.h locale.h malloc.h \ + nl_types.h stddef.h sys/file.h sys/socket.h sys/time.h \ + sys/timeb.h syslog.h termios.h]) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_INLINE +AC_C_RESTRICT +AC_C_CONST +AC_TYPE_UID_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_TYPE_MODE_T +AC_TYPE_INT8_T +AC_TYPE_INT16_T +AC_TYPE_INT32_T +AC_TYPE_UINT8_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT64_T +AC_STRUCT_TM + +dnl Checks for library functions. +AC_FUNC_ALLOCA +AC_FUNC_CHOWN +AC_FUNC_FORK +AC_FUNC_MALLOC +AC_FUNC_MKTIME +AC_FUNC_MMAP +AC_FUNC_REALLOC +AC_FUNC_STRERROR_R +AC_CHECK_FUNCS([atexit ftruncate gettimeofday localtime_r memchr memmove \ + memset mkdir munmap regcomp select socket strchr strcspn \ + strdup strerror strncasecmp strrchr strstr strtol strtoul]) + +dnl Used in various scripts +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([CAT], [cat], [/bin/cat]) +AC_PATH_PROG([CHMOD], [chmod], [/bin/chmod]) +AC_PATH_PROG([CHGRP], [chgrp], [/bin/chgrp]) +AC_PROG_AWK +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET + +AM_PROG_LEX +if test "x$LEX" != "xflex"; then + AC_MSG_ERROR(['flex' is missing on your system. Please install 'flex'.]) +fi + +AC_PROG_YACC +if test "x$YACC" = "xyacc"; then + # AC_PROG_YACC only checks for yacc replacements, not for yacc itself + AC_CHECK_PROG([YACC_FOUND], [yacc], [yes], [no]) + if test "x$YACC_FOUND" = "xno"; then + AC_MSG_ERROR(['YACC' program is missing on your system. Please install 'bison'.]) + fi +fi + +AC_CHECK_LIB([itm], [_ITM_commitTransaction], [itm=yes], [itm=no]) + +OPENLDAP_LIBS= +AC_CHECK_HEADERS([lber.h ldap.h], + [OPENLDAP_LIBS="-llber -lldap"], + [AC_MSG_ERROR([lber.h and ldap.h are missing. Please install + 'openldap-devel'.])]) +LIBS="$LIBS $OPENLDAP_LIBS" +AC_SUBST([OPENLDAP_LIBS]) + +dnl Define custom variables + +lockdir=$localstatedir/lock/opencryptoki +AC_SUBST(lockdir) + +logdir=$localstatedir/log/opencryptoki +AC_SUBST(logdir) + +dnl --- +dnl --- Check all --enable/--disable-features +dnl --- + +dnl --- Debugging support +AC_ARG_ENABLE([debug], + AS_HELP_STRING([--enable-debug],[enable debugging build @<:@default=no@:>@]), + [], + [enable_debug=no]) + +dnl --- build testcases +AC_ARG_ENABLE([testcases], + AS_HELP_STRING([--enable-testcases],[build the test cases @<:@default=no@:>@]), + [], + [enable_testcases=no]) + +dnl --- Check if building daemon +AC_ARG_ENABLE([daemon], + AS_HELP_STRING([--enable-daemon],[build pkcsslotd daemon @<:@default=yes@:>@]), + [], + [enable_daemon=yes]) + +dnl --- Check if building library +AC_ARG_ENABLE([library], + AS_HELP_STRING([--enable-library],[build opencryptoki libraries @<:@default=yes@:>@]), + [], + [enable_library=yes]) + +dnl --- Enable/disable tokens +dnl --- those have an additional 'check' state, which essentially means +dnl --- that it will enable it by default it dependencies are met + +dnl --- ICA token +AC_ARG_ENABLE([icatok], + AS_HELP_STRING([--enable-icatok],[build ica token @<:@default=enabled if + libica is present@:>@]), + [], + [enable_icatok=check]) + +dnl --- CCA token +AC_ARG_ENABLE([ccatok], + AS_HELP_STRING([--enable-ccatok],[build cca token (IBM Common Cryptographic + Architecture) @<:@default=enabled@:>@]), + [], + [enable_ccatok=yes]) + +dnl --- software token +AC_ARG_ENABLE([swtok], + AS_HELP_STRING([--enable-swtok],[build software token @<:@default=enabled@:>@]), + [], + [enable_swtok=yes]) + +dnl --- EP11 token +AC_ARG_ENABLE([ep11tok], + AS_HELP_STRING([--enable-ep11tok],[build ep11 token @<:@default=enabled + if zcrypt is present@:>@]), + [], + [enable_ep11tok=check]) + +dnl --- TPM token +AC_ARG_ENABLE([tpmtok], + AS_HELP_STRING([--enable-tpmtok],[build tpm token (Trusted Platform Module) + @<:@default=enabled if TrouSerS is present@:>@]), + [], + [enable_tpmtok=check]) + +dnl -- icsf token (Integrated Cryptographic Service Facility remote token) +AC_ARG_ENABLE([icsftok], + AS_HELP_STRING([--enable-icsftok],[build icsf token (Integrated + Cryptographic Service Facility) @<:@default=enabled if OpenLDAP library + is present@:>@]), + [], + [enable_icsftok=check]) + +dnl --- token-specific stuff +dnl --- pkcsep11_migrate +AC_ARG_ENABLE([pkcsep11_migrate], + AS_HELP_STRING([--enable-pkcsep11_migrate],[build pkcsep11_migrate (EP11 token key migration tool) @<:@default=enabled if EP11 library is present@:>@]), + [], + [enable_pkcsep11_migrate=check]) + +dnl --- pkcsep11_session +AC_ARG_ENABLE([pkcsep11_session], + AS_HELP_STRING([--enable-pkcsep11_session],[build pkcsep11_session (EP11 token session logout tool) @<:@default=enabled if EP11 library is present@:>@]), + [], + [enable_pkcsep11_session=check]) + +dnl --- locking support +AC_ARG_ENABLE([locks], + AS_HELP_STRING([--disable-locks],[build opencryptoki with transactional memory instead of locks])) + +dnl --- p11sak tool +AC_ARG_ENABLE([p11sak], + AS_HELP_STRING([--enable-p11sak],[build p11sak tool @<:@default=enabled@:>@]), + [], + [enable_p11sak=yes]) + +dnl --- +dnl --- Check for external software +dnl --- Define what to check based on enabled features + +dnl --- Openssl development files +AC_ARG_WITH([openssl], + AS_HELP_STRING([--with-openssl@<:@=DIR@:>@],[OpenSSL development files location]), + [], + [with_openssl=check]) + +dnl --- Libica development files +AC_ARG_WITH([libica], + AS_HELP_STRING([--with-libica@<:@=DIR@:>@],[libica development files location]), + [], + [with_libica=check]) + +dnl --- zcrypt development files +AC_ARG_WITH([zcrypt], + AS_HELP_STRING([--with-zcrypt@<:@=DIR@:>@],[zcrypt development files location]), + [], + [with_zcrypt=check]) + +dnl --- TSS (TrouSerS) development files +AC_ARG_WITH([tss], + AS_HELP_STRING([--with-tss@<:@=DIR@:>@],[TrouSerS development files location]), + [], + [with_tss=check]) + +dnl --- xcryptolinz development files (IBM CCA development files) +AC_ARG_WITH([xcryptolinz], + AS_HELP_STRING([--with-xcryptolinz@<:@=DIR@:>@],[CCA library (xcryptolinz) location]), + [], + [with_xcryptolinz=check]) + +dnl --- systemd system unit files location +AC_ARG_WITH([systemd], + AS_HELP_STRING([--with-systemd@<:@=DIR@:>@],[systemd system unit files location]), + [], + [with_systemd=no]) + +dnl --- +dnl --- +dnl --- Now that we have all the options, let's check for a valid build +dnl --- + +case $target in + *s390x*) + ;; + *s390*) + CFLAGS="$CFLAGS -m31" + ;; + *ppc64* | *x86_64*) + ;; + *ppc* | i*86*) + CFLAGS="$CFLAGS -m32" + ;; +esac + +dnl --- enable_debug +if test "x$enable_debug" = "xyes"; then + CFLAGS="$CFLAGS -gdwarf-2 -g3 -O0 -DDEBUG" +fi + +dnl --- first, check what external software is present or specified +dnl --- with --with-package=DIR + +dnl --- with_openssl +OPENSSL_CFLAGS= +OPENSSL_LIBS= +if test "x$with_openssl" != "xno"; then + if test "x$with_openssl" != "xyes" -a "x$with_openssl" != "xcheck"; then + OPENSSL_CFLAGS="-I$with_openssl" + OPENSSL_LIBS="-L$with_openssl" + fi + old_cflags="$CFLAGS" + old_libs="$LIBS" + CFLAGS="$CFLAGS $OPENSSL_CFLAGS" + LIBS="$LIBS $OPENSSL_LIBS" + AC_CHECK_HEADER([openssl/ssl.h], [], [ + if test "x$with_openssl" != "xcheck"; then + AC_MSG_ERROR([Build with OpenSSL requested but OpenSSL headers couldn't be found]) + fi + with_openssl=no + ]) + if test "x$with_openssl" != "xno"; then + AC_CHECK_LIB([crypto], [RSA_generate_key], [ + OPENSSL_LIBS="$OPENSSL_LIBS -lcrypto" + with_openssl=yes + ], [ + if test "x$with_openssl" != "xcheck"; then + AC_MSG_ERROR([Build with OpenSSL requested but OpenSSL libraries couldn't be found]) + fi + with_openssl=no + ]) + fi + if test "x$with_openssl" = "xno"; then + CFLAGS="$old_cflags" + LIBS="$old_libs" + fi +fi +AC_SUBST([OPENSSL_CFLAGS]) +AC_SUBST([OPENSSL_LIBS]) + +dnl --- with_libica +LIBICA_CFLAGS= +LIBICA_LIBS= +if test "x$with_libica" != "xno"; then + if test "x$with_libica" != "xyes" -a "x$with_libica" != "xcheck"; then + LIBICA_CFLAGS="-I$with_libica" + LIBICA_LIBS="-L$with_libica" + fi + old_cflags="$CFLAGS" + old_libs="$LIBS" + CFLAGS="$CFLAGS $LIBICA_CFLAGS" + LIBS="$LIBS $LIBICA_LIBS" + AC_CHECK_HEADER([ica_api.h], [], [ + if test "x$with_libica" != "xcheck"; then + AC_MSG_ERROR([Build with Libica requested but Libica headers couldn't be found]) + fi + with_libica=no + ]) + if test "x$with_libica" != "xno"; then + AC_CHECK_LIB([ica], [ica_open_adapter], + [with_libica=yes], [ + if test "x$with_libica" != "xcheck"; then + AC_MSG_ERROR([Build with Libica requested but Libica libraries (v 2.x or higher) couldn't be found]) + fi + with_libica=no + ]) + fi + if test "x$with_libica" = "xno"; then + CFLAGS="$old_cflags" + LIBS="$old_libs" + fi +fi +AC_SUBST([LIBICA_CFLAGS]) +AC_SUBST([LIBICA_LIBS]) + + +dnl --- with_zcrypt +ZCRYPT_CFLAGS= +ZCRYPT_LIBS= +if test "x$with_zcrypt" != "xno"; then + if test "x$with_zcrypt" != "xyes" -a "x$with_zcrypt" != "xcheck"; then + ZCRYPT_CFLAGS="-I$with_zcrypt" + ZCRYPT_LIBS="-L$with_zcrypt" + fi + old_cflags="$CFLAGS" + old_libs="$LIBS" + CFLAGS="$CFLAGS $ZCRYPT_CFLAGS" + LIBS="$LIBS $ZCRYPT_LIBS" + AC_CHECK_HEADER([asm/zcrypt.h], [], [ + if test "x$with_zcrypt" != "xcheck"; then + AC_MSG_ERROR([Build with zcrypt requested but zcrypt headers couldn't be found]) + fi + with_zcrypt=no + ]) + + if test "x$with_zcrypt" != "xno"; then + with_zcrypt=yes + fi + + if test "x$with_zcrypt" = "xno"; then + CFLAGS="$old_cflags" + LIBS="$old_libs" + fi + +fi +AC_SUBST([ZCRYPT_CFLAGS]) +AC_SUBST([ZCRYPT_LIBS]) + + +dnl --- with_tss +TSS_CFLAGS= +TSS_LIBS= +if test "x$with_tss" != "xno"; then + if test "x$with_tss" != "xyes" -a "x$with_tss" != "xcheck"; then + TSS_CFLAGS="-I$with_tss" + TSS_LIBS="-L$with_tss" + fi + old_cflags="$CFLAGS" + old_libs="$LIBS" + CFLAGS="$CFLAGS $TSS_CFLAGS" + LIBS="$LIBS $TSS_LIBS" + AC_CHECK_HEADER([tss/platform.h], [], [ + if test "x$with_tss" != "xcheck"; then + AC_MSG_ERROR([Build with TSS requested but TSS headers couldn't be found]) + fi + with_tss=no + ]) + if test "x$with_tss" != "xno"; then + AC_CHECK_LIB([tspi], [Tspi_Context_Create], + [with_tss=yes], [ + if test "x$with_tss" != "xcheck"; then + AC_MSG_ERROR([Build with TSS requested but TSS libraries couldn't be found]) + fi + with_tss=no + ]) + fi + if test "x$with_tss" = "xno"; then + CFLAGS="$old_cflags" + LIBS="$old_libs" + fi +fi +AC_SUBST([TSS_CFLAGS]) +AC_SUBST([TSS_LIBS]) + +dnl --- with_xcryptolinz +XCRYPTOLINZ_CFLAGS= +XCRYPTOLINZ_LIBS= +if test "x$with_xcryptolinz" != "xno"; then + if test "x$with_xcryptolinz" != "xyes" -a "x$with_xcryptolinz" != "xcheck"; then + XCRYPTOLINZ_CFLAGS="-I$with_xcryptolinz" + XCRYPTOLINZ_LIBS="-L$with_xcryptolinz" + fi + old_cflags="$CFLAGS" + old_libs="$LIBS" + CFLAGS="$CFLAGS $XCRYPTOLINZ_CFLAGS" + LIBS="$LIBS $XCRYPTOLINZ_LIBS" +dnl - The above may not be necessary since opencryptoki brings this header file anyway. + AC_CHECK_HEADER([csulincl.h], [], [ + if test "x$with_xcryptolinz" != "xcheck"; then + AC_MSG_ERROR([Build with xcryptolinz requested but xcryptolinz headers couldn't be found]) + fi + with_xcryptolinz=no + ]) + if test "x$with_xcryptolinz" != "xno"; then + AC_CHECK_LIB([csulcca], [CSNBKTC], + [with_xcryptolinz=yes], [ + if test "x$with_xcryptolinz" != "xcheck"; then + AC_MSG_ERROR([Build with xcryptolinz requested but xcryptolinz libraries couldn't be found]) + fi + with_xcryptolinz=no + ]) + fi + if test "x$with_xcryptolinz" = "xno"; then + CFLAGS="$old_cflags" + LIBS="$old_libs" + fi +fi +AC_SUBST([XCRYPTOLINZ_CFLAGS]) +AC_SUBST([XCRYPTOLINZ_LIBS]) + + +dnl --- +dnl --- Now check enabled features, while making sure every required +dnl --- package is available +dnl --- + +dnl --- enable_testcases +if test "x$enable_testcases" = "xyes"; then + AC_CHECK_PROG([HAVE_EXPECT], [expect], [yes], [no]) + + if test "x$HAVE_EXPECT" = "xno"; then + AC_MSG_ERROR([*** testcases requires 'expect' interpreter, which wasn't found]) + enable_testcases=no + fi +fi +AM_CONDITIONAL([ENABLE_TESTCASES], [test "x$enable_testcases" = "xyes"]) + +dnl --- enable_daemon +AM_CONDITIONAL([ENABLE_DAEMON], [test "x$enable_daemon" = "xyes"]) + +dnl --- enable_library +AM_CONDITIONAL([ENABLE_LIBRARY], [test "x$enable_library" = "xyes"]) + +dnl --- enable systemd and set unit dir +if test "x$with_systemd" != "xno"; then + if test "x$with_systemd" != "xyes" -a "x$with_systemd" != "xcheck"; then + unitdir=$with_systemd + enable_systemd=yes + else + if test "x$with_systemd" = "xyes"; then + unitdir=${ac_default_prefix}/lib/systemd/system + enable_systemd=yes + else + enable_systemd=no + fi + fi +else + enable_systemd=no +fi +AM_CONDITIONAL([ENABLE_SYSTEMD], [test "x$enable_systemd" = "xyes"]) +AC_SUBST(unitdir) + +dnl --- enable_icatok +if test "x$enable_icatok" = "xyes"; then + if test "x$with_libica" != "xyes"; then + AC_MSG_ERROR([ica token build requested but libica development files not found]) + enable_icatok=no + fi + + if test "x$with_openssl" != "xyes"; then + AC_MSG_ERROR([ica token build requested but OpenSSL development files not found]) + enable_icatok=no + fi +fi +if test "x$enable_icatok" != "xno" -a "x$with_libica" != "xno" -a "x$with_openssl" != "xno"; then + enable_icatok=yes +else + enable_icatok=no +fi +AM_CONDITIONAL([ENABLE_ICATOK], [test "x$enable_icatok" = "xyes"]) + +dnl --- enable_ccatok +AM_CONDITIONAL([ENABLE_CCATOK], [test "x$enable_ccatok" = "xyes"]) + +dnl --- enable_swtok +if test "x$enable_swtok" = "xyes"; then + if test "x$with_openssl" != "xyes"; then + AC_MSG_ERROR([software token build requested but OpenSSL development files not found]) + enable_swtok=no + fi +fi +if test "x$enable_swtok" != "xno" -a "x$with_openssl" != "xno"; then + enable_swtok=yes +else + enable_swtok=no +fi +AM_CONDITIONAL([ENABLE_SWTOK], [test "x$enable_swtok" = "xyes"]) + +dnl --- enable_ep11tok +if test "x$enable_ep11tok" = "xyes"; then + if test "x$with_zcrypt" != "xyes"; then + AC_MSG_ERROR([ep11 token build requested but ep11 development files not found]) + enable_ep11=no + fi + AC_CHECK_HEADER([ica_api.h], [], [ + AC_MSG_ERROR([ep11 token build requested but Libica headers couldn't be found]) + ]) +fi +if test "x$enable_ep11tok" != "xno" -a "x$with_zcrypt" != "xno"; then + enable_ep11tok=yes + AC_CHECK_HEADER([ica_api.h], [], [ + enable_ep11tok=no + ]) +else + enable_ep11tok=no +fi +AM_CONDITIONAL([ENABLE_EP11TOK], [test "x$enable_ep11tok" = "xyes"]) + +dnl --- enable_icsftok +if test "x$enable_icsftok" = "xyes"; then + if test "x$with_openssl" != "xyes"; then + AC_MSG_ERROR([ICSF token build requested but OpenSSL development files not found]) + enable_icsftok=no + fi +fi +if test "x$enable_icsftok" != "xno" -a "x$with_openssl" != "xno"; then + enable_icsftok=yes +else + enable_icsftok=no +fi +AM_CONDITIONAL([ENABLE_ICSFTOK], [test "x$enable_icsftok" = "xyes"]) + +dnl --- enable_tpmtok +if test "x$enable_tpmtok" = "xyes"; then + if test "x$with_tss" != "xyes"; then + AC_MSG_ERROR([tpm token build requested but TSS development files not found]) + enable_tpmtok=no + fi +fi +if test "x$enable_tpmtok" != "xno" -a "x$with_tss" != "xno"; then + enable_tpmtok=yes +else + enable_tpmtok=no +fi +AM_CONDITIONAL([ENABLE_TPMTOK], [test "x$enable_tpmtok" = "xyes"]) + + +dnl --- enable_pkcsep11_migrate +if test "x$enable_pkcsep11_migrate" = "xyes"; then + if test "x$with_zcrypt" != "xyes"; then + AC_MSG_ERROR([pkcsep11_migrate build requested but no ep11 libraries found]) + enable_pkcsep11_migrate=no + fi +fi +if test "x$enable_pkcsep11_migrate" != "xno" -a "x$with_zcrypt" != "xno"; then + enable_pkcsep11_migrate=yes +else + enable_pkcsep11_migrate=no +fi +AM_CONDITIONAL([ENABLE_PKCSEP11_MIGRATE], [test "x$enable_pkcsep11_migrate" = "xyes"]) + +dnl --- enable_pkcsep11_session +if test "x$enable_pkcsep11_session" = "xyes"; then + if test "x$with_zcrypt" != "xyes"; then + AC_MSG_ERROR([pkcsep11_session build requested but no ep11 libraries found]) + enable_pkcsep11_session=no + fi +fi + +if test "x$enable_pkcsep11_session" != "xno" -a "x$with_zcrypt" != "xno"; then + enable_pkcsep11_session=yes +else + enable_pkcsep11_session=no +fi + +AM_CONDITIONAL([ENABLE_PKCSEP11_SESSION], [test "x$enable_pkcsep11_session" = "xyes"]) + +dnl --- enable_p11sak +AM_CONDITIONAL([ENABLE_P11SAK], [test "x$enable_p11sak" = "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 +fi +AM_CONDITIONAL([ENABLE_LOCKS], [test "x$enable_locks" = "xyes"]) + +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)\"' + +# At this point, CFLAGS is set to something sensible +AC_PROG_CC + +AC_CONFIG_MACRO_DIRS([m4]) + +AC_CONFIG_FILES([Makefile \ + usr/lib/api/shrd_mem.c \ + man/man1/pkcsconf.1 \ + man/man1/pkcsicsf.1 \ + man/man1/pkcscca.1 \ + man/man1/p11sak.1 \ + man/man1/pkcsep11_migrate.1 \ + man/man1/pkcsep11_session.1 \ + man/man5/opencryptoki.conf.5 \ + man/man7/opencryptoki.7 \ + man/man8/pkcsslotd.8]) + +AC_OUTPUT + +echo "Enabled features:" +echo " Debug build: $enable_debug" +echo " Testcases: $enable_testcases" +echo " Daemon build: $enable_daemon" +echo " Library build: $enable_library" +echo " Systemd service: $enable_systemd" +echo " Build with locks: $enable_locks" +echo " Build p11sak tool: $enable_p11sak" +echo +echo "Enabled token types:" +echo " ICA token: $enable_icatok" +echo " CCA token: $enable_ccatok" +echo " Software token: $enable_swtok" +echo " EP11 token: $enable_ep11tok" +echo " TPM token: $enable_tpmtok" +echo " ICSF token: $enable_icsftok" +echo +echo "Token-specific features:" +echo " pkcsep11migrate build: $enable_pkcsep11_migrate" +echo " pkcsep11session build: $enable_pkcsep11_session" +echo +echo "CFLAGS=$CFLAGS" +echo diff --git a/doc/README.cca_stdll b/doc/README.cca_stdll new file mode 100644 index 0000000..e05b3ac --- /dev/null +++ b/doc/README.cca_stdll @@ -0,0 +1,219 @@ +CCA TOKEN + +Overview +-------- +The CCA token is a secure key token. +A Secure key - key value does not exist in the clear outside of the HSM +(secure, tamper-resistent boundary of the card). It is a clear key wrapped +with the appropriate MasterKey that has been installed into the secure hardware. +A clear key is generated in the hardware, wrapped with the appropriate +master key that has been installed into the hardware. The wrapped key is then +passed back to the invoker. Upon an encryption and/or decryption request, +the wrapped key and the data to be encrypted are passed into the hardware. +The wrapped key is verified, and the clear key is used to encrypt and/or +decrypt the data. All this is done in the CCA hardware. + +Within openCryptoki, this wrapped key value is stored in the CKA_IBM_OPAQUE +attribute rather than the CKA_VALUE attribute. + +Pre-requisites: +The CCA token requires cca library, libcsulcca.so, which is part of the +csulcca rpm. +It also requires proper configuration and installation of the MK keys into +the hardware which is outside the scope of this document. + +Configuration +------------- + +To use the CCA token a slot entry must be defined in the +opencryptoki.conf configuration file that sets the stdll attribute to +libcsulcca.so. + +The CCA token also requires that the appropriate master keys have +been installed into the hardware. The corresponding driver must also be +loaded, i.e. modprobe z90crypt. + +CCA Token Objects +------------------------- + +openCryptoki stores token objects on disk. Public token objects are not +encrypted. Private token objects are encrypted. +Versions of openCryptoki prior to version 3, used a CCA generated secure key +(des3 key) and the crypto adapter to encrypt the private token object's data. +In version 3, a clear key (des3 key) and software crypto (openssl) are used +to encrypt this data. + +Migration Information +--------------------- + +Migrating version 2 private token objects to version 3 is ONLY required if +the system will run openCryptoki version 3 and will use private token +objects saved or preserved from version 2. +Note, public token objects do not need to be migrated. +If there are no private token objects from version 2, then the version 3 +does not require any migrating. + +In version 2 private token objects are encrypted and decrypted with a secure +key in the crypto adapter. In version 3, this encryption and decryption is +done with a clear key using software crypto. Therefore, openCryptoki +version 3, will not successfully decrypt a version 2 private token object. + +Version 2 private token objects must be "migrated" to version 3 so that +openCryptoki version 3 can access these objects. This migration will +decrypt the objects using the CCA call, CSNBDEC and the current +openCryptoki key stored in MK_USER. The objects will then be re-encrypted +using software crypto. The key bits that are stored in MK_USER will then be +used as a clear key. + +Once the migration has completed, these private token objects should then be +accessible to version 3. + +Migration Steps +--------------- + +1. Either update or install version 3. +a. Update to openCryptoki version 3. In most Linux distributions, an update +from version 2 to version 3 will preserve the contents of the CCA data-store. + +b. Install openCryptoki version 3. In most distributions, an install will +remove the contents of the CCA data-store. You will essentially be starting +from the beginning and have to initialize the CCA token. + +In this scenario, if a prior version of openCryptoki had been running on the +system, and you wanted to preserve your token objects, you will have saved +or backed them up somewhere. + +2. Backup the CCA data-store before migrating. It is always a good idea to +back up the data in case the migration is unsuccessful or data is corrupted. +The data-store is the directory in which the CCA token information is stored +on disk. In most distributions it can be found in /var/lib/opencryptoki/ccatok. +Within this directory there is, + +MK_USER: The des3 key used for internal on-disk encryption, encrypted + under the USER's PIN by software routines + +MK_SO: The des3 key used for internal on-disk encryption, encrypted + under the SO's PIN by software routines + +NKTOK.DAT: Token information. + +TOK_OBJ: The directory in which token objects are stored. + +TOK_OBJ/OBJ.IDX: A list of current token objects. + +**NOTE: MK_USER and MK_SO contain the same key, encrypted under +different PINs + +3. Ensure no openCryptoki processes are running. Stop the pkcsslotd daemon +if it is running. + +4. Run the pkcscca tool to perform the migration. +For example, + pkcscca -m v2objectsv3 -v + +Note that the "-v" option will allow you to see which objects did and did not +get migrated. Specify the "-d" flag if you wish to migrate CCA token objects +stored in a data-store different from the default, /var/lib/opencryptoki/ccatok. + +5. (Optional) Removing shared memory may be required to pick up +the newly migrated objects. + +CCA token's shared memory segment tracks its token objects. +Token objects stored on disk are only loaded into shared memory +when the shared memory is created. The shared memory is usually +created after a reboot, an install, or an update of the openCryptoki package. + +If another openCryptoki process accessed the CCA token after install +or update, then openCryptoki will have loaded all the token objects into +shared memory, except for the private token objects requiring migration, +since they will have failed decryption. Subsequent calls to the +openCryptoki api will not find these objects since they have not +been loaded into shared memory. openCryptoki won't read the +objects from disk and load into shared memory again until the next time +shared memory is created. + +So, in this case, shared memory must be removed and created again so +that openCryptoki can successfully load all the token objects including the +newly migrated private token objects into CCA token's shared memory segment. + +Remove shared memory if, + - after updating or installing, any openCryptoki processes or tools tried + to access the CCA token before migrating CCA token's private token + objects. For example, the pkcsconf command was run. + + The pre-migrated objects will have failed decryption and not + been loaded into shared memory. A reboot or removing shared memory + will cause the token to create shared memory again and load the newly + migrated private token objects into it. + +CCA's shared memory can be removed two ways. + 1. a reboot + + 2. remove the shared memory file, + i.e. "rm /dev/shm/var.lib.opencryptoki.ccatok" + + Notes: (1). Ensure that no openCryptoki processes are running + before removing the shared memory. Otherwise, you risk corrupting + any running openCryptoki processes. + (2). If you have installed openCryptoki manually (not via a distro + rpm) the CCA token shared memory segment may be named + usr.local.var.lib.opencryptoki.ccatok. + +The next openCryptoki process to run will cause openCryptoki to create +a shared memory segment for the token and load the newly migrated objects +as well as any other token objects for the token. + +6. After a successful migration, the CCA private token objects should be +encrypted and ready to be accessed by openCryptoki version 3. + +TroubleShooting: +1. If version 3 cannot find the newly migrated CCA private token objects, +reboot or remove the shared memory file. This will cause token to create +shared memory again and load the newly migrated private token objects +into shared memory. + +Key Migration Information +------------------------- + +There may be situations when CCA master keys must be changed. All CCA secret +and private keys are enciphered (wrapped) with a master key (MK). After a CCA +master key is changed, the keys wrapped with an old master key need to be +re-enciphered with the new master key. Only openCryptoki keys with attribute +CKA_EXTRACTABLE=TRUE can be migrated. + +Key Migration Steps +------------------- + +The key migration tool pkcscca can be used to perform the migration of the +old CCA master key to the new master key. After a new master key is loaded +and set, perform the following steps: + +1. Stop all processes that are currently using openCryptoki with the +CCA token. + +2. Make sure pkcsslotd is running. + +3. Back up the token object repository of the CCA token. For example, you can +use the following commands: + + cd /var/lib/opencryptoki/cca/ + tar -cvzf ~/cca/TOK_OBJ_backup.tgz TOK_OBJ + +4. Migrate the keys of the CCA token object repository with the pkcscca +migration tool. + + pkcscca -m keys -s -k + +The following parameters are mandatory: + +-s + - slot number for the CCA token +-k + - master key type to be migrated: aes, apka, asym, or sym + +All the specified token objects representing extractable keys that are +found for the CCA token, are re-encrypted and ready for use. Keys with an +attribute CKA_EXTRACTABLE=FALSE are not migratable.The keys that failed to +migrate are displayed to the user. + +5. Re-start the previously stopped openCryptoki processes. diff --git a/doc/README.ep11_stdll b/doc/README.ep11_stdll new file mode 100644 index 0000000..9ae8055 --- /dev/null +++ b/doc/README.ep11_stdll @@ -0,0 +1,126 @@ +EP11 Token +========== + +The EP11 token is a token that uses the IBM Crypto Express adapters (starting +with Crypto Express 4S adapters) configured with Enterprise PKCS#11 (EP11) +firmware. By convention, Crypto Express n adapters with that firmware load are +also called CEXnP adapters for n >= 4. + +The EP11 token is only supported on the System z architecture and requires a +Crypto Express adapter with EP11 firmware load, a zcrypt/ap device driver loaded +into the kernel and the availability of EP11 library libep11. + +The token directory of the EP11 token is opencryptoki/ep11tok typically located +in /var/lib. + +There is a new possibility to configure multiple EP11 tokens. +Thus dedicated adapter/domains can be assigned to different tokens respectively +applications. That ensures data isolation between multiple applications. + +Configuration +------------- + +To use the EP11 token a slot entry must be defined in the general openCryptoki +configuration file that sets the stdll attribute to libpkcs11_ep11.so. + +A EP11 token specific configuration file must be set up to define the target +adapters and target adapter domains. The name of the configuration file must be +defined in the global openCryptoki configuration opencryptoki.conf file as part +of the token specification using the confname attribute. In case of using +multiple ep11 tokens a token directory name must be specified for each token +using the tokname attribute. +E.g. + +slot 4 +{ +stdll = libpkcs11_ep11.so +confname = ep11tok01.conf +tokname = ep11token01 +} + +slot 5 +{ +stdll = libpkcs11_ep11.so +confname = ep11tok02.conf +tokname = ep11token02 +} + +The sample entry define the name of the configuration files of the EP11 token +to be e.g. ep11tok01.conf. Per default this file is searched in the directory +where openCryptoki searches its global configuration file. This default path +can be overriden using the OCK_EP11_TOKEN_DIR environment variable. + +The tokname attribute specifies the name of the individual token directory. +Typically it's located in /var/lib/opencryptoki/. Each token directory contain +it's own token individual objects that are separated from other ep11 tokens. + +EP11 token configuration files defines a list of adapter/domain pairs to which +the EP11 token sends its cryptographic requests. This list can be specified as a +white list starting with a line containing the key word APQN_WHITELIST followed +by one or more lines containing each two integers (in the range of 0 - 255) +separated by a white space. The white list is ended with a line containing the +key word END. In each of lines of the white list the first integer denotes the +adapter number and the second integer denotes the domain id. Alternatively the +keyword APQN_ANY can be used to define that all adapter/domain pairs with EP11 +firmware load that are available to the system shall be used as target adapters. +An adapter number corresponds to the numerical part xx of an adapter id of the +form cardxx as displayed by the lszcrypt tool or in the sys file system (e.g. in +/sys/bus/ap/devices). Currently Linux on z only supports a single domain. That +domain number can be displayed with lszcrypt -b (see the value of ap_domain) or +alternatively as contents of /sys/bus/ap/ap_domain. + +Crypto Express Adapter EP11 Master Key Management +------------------------------------------------- + +If master keys are changed on an EP11 adapter all key objects in the token +object repository (in the TOK_OBJ directory within the EP11 token directory) +become invalid. + +The key migration tool pkcsep11_migrate can be used to perform the migration of +the current EP11 master keys to new master keys. Therefore the following steps +must be performed: +1) On the Trusted Key Entry console (TKE): Submit and commit new master keys on +the EP11 adapter(s). +2) On Linux: Stop all processes using openCryptoki with the EP11 token. +3) On Linux: Back up the token object repository of the EP11 token. +4) On Linux: Migrate keys of object repository of EP11 token with migration +tool. If a failure occurs restore the backed up token repository and retry step +4. +5) On the TKE: Activate new master keys on the EP11 adapter(s). +6) On Linux: Restart applications using openCryptoki with the EP11 token. + +Token specifics +--------------- + +The EP11 token only supports secure keys (i.e. key wrapped by a master key of +the Crypto Express adapter). Therefore all keys must have the attribute +CKA_SENSITIVE set to CK_TRUE. Since the PKCS#11 standard does not define a +(token specific) default for secret keys the attribute must be explicitly +provided whenever a secret key is generated, unwrapped or build with +C_CreateObject. In addition all keys used with the EP11 token are extractable. +i.e. they must have the attribute CKA_EXTRACTABLE set to CK_TRUE. + +When creating keys the default values of the attributes CKA_ENCRYPT, +CKA_DECRYPT, CKA_VERYFY, CKA_SIGN, CKA_WRAP and CKA_UNWRAP are CK_TRUE. Note, no +EP11 mechanism supports the Sign/Recover or Verify/Recover functions. + +All RSA key must have a public exponent (CKA_PUBLIC_EXPONENT) greater than or +equal to 17. + +The CryptoExpress EP11 coprocessor restricts RSA keys (primes and moduli) +according to ANSI X9.31. Therefore in the EP11 token the lengths of the RSA +primes (p or q) must be a multiple of 128 bits and the length of the modulus +(CKA_MODULUS_BITS) must be a multiple of 256. + +The mechanisms CKM_DES3_CBC and CKM_AES_CBC can only wrap keys which have a +length that is a multiple of the block size of DES3 or AES respectively. + +See the mechanism list and mechanism info (pkcsconf -m) for supported mechanisms +together with supported functions and key sizes. Note the supported mechanism +list is currently fix and matches the most stringent setting of the Crypto +Express adapter. + +Note, the EP11 coprocessor adapter can be configured to restrict the +cryptographic capabilities in order for the adapter to comply with specific +security requirements and regulations. Such restrictions on the adapter impact +the capabilitiy of the EP11 token. diff --git a/doc/README.icsf_stdll b/doc/README.icsf_stdll new file mode 100644 index 0000000..5063caf --- /dev/null +++ b/doc/README.icsf_stdll @@ -0,0 +1,299 @@ +THE ICSF TOKEN + +Overview +-------- + +The ICSF token is a clear-key, remote crypto token. The actual crypto operations +are performed remotely on a 390x server and all the PKCS#11 key objects are +stored remotely on the server. + +openCryptoki's ICSF token sends ICSF service calls to the remote server via +LDAP. Extensions to LDAP and the addition of a remote crypto plugin allow the +remote LDAP server to receive the request and interface with ICSF to service the +request. ICSF interfaces with the crypto hardware and the z/OS keystore to +service the request. Upon completion, the result is passed back through the same +channels. + +The PKCS#11 key objects are created or generated remotely. The remote z/OS +keystore stores all the created or generated key objects, allowing for +centralized storage and key management. + +The remote server's configuration is outside the scope of this README. + +Please see XXXXX for more information on the z/OS LDAP server requirements and +remote crypto configuration. +For more information on ICSF PKCS#11, see "Writing PKCS#11 Applications" manual +at +http://www-01.ibm.com/support/docview.wss?uid=isg24664157d6cdc890485257a7c0054dc3d&aid=1. + +Pre-requisites: +1. ICSF token communicates to the remote via LDAP. + On Linux install openldap, openldap-clients, and openldap-devel. + +2. You will also need lex and yacc packages installed. + +----------------------------------------------------------------------- + +CONFIGURING THE ICSF TOKEN + +Some setup of the ICSF token must be done for openCryptoki before initializing +it with the pkcsconf utility. + +You will need, + - LDAP bind information + - The name of an ICSF token created on the remote server. + + +LDAP Bind Information +--------------------- +openCryptoki must bind and authenticate to the remote LDAP server. openCryptoki +supports the Simple and SASL authentication methods when authenticating with the +remote LDAP server to send an ICSF service request. + +You have the option of using, + 1. existing LDAP config files for the information required to bind and + authenticate to the LDAP server. + + OR + + 2. you can give the information to openCryptoki to store and use when + binding and authenticating to LDAP server. This is done through the + pkcsiscf utility. + +The first option involves using an existing LDAP config file to bind and +authenticate to the remote server. + +When openCryptoki calls the openldap function to bind and authenticate, the +openldap function call will look for the ldaprc config file to acquire the +information it needs to bind and authenticate to the server. + +When using this option, + - with Simple authentication, you need to specify the authentication + mechanism as simple when adding the ICSF token into openCryptoki with the + pkcsicsf utility. You will also be prompted for the RACF password, which + will be securely stored on disk by openCryptoki for subsequent use. + + - with SASL authentication, you need to specify the authentication mechanism + as sasl when adding the ICSF token into opecryptoki with the pkcsicsf + utility. SASL does not require an RACF password, so you will not be + prompted for this information. + +**Note, when using the first option, users should have the same information in +their .ldaprc files. + +The second option, chooses to give openCryptoki the necessary ldap credentials +to store in an openCryptoki config file for subsequent use. With this option +the credentials are stored in one place for all who access openCryptoki's ICSF +token. + +When openCryptoki calls the openldap function to bind and authenticate, it will +pass along the information stored in the ICFS config file to the function call. +For example, when simple authentication, it will pass the BINDDN and URI found +in this config file to the function. + +When using this option, + - with Simple authentication, you need to specify the authentication + mechanism as simple, along with the BINDDN, and the URI when adding the + ICSF token into openCryptoki with the pkcsicsf utility. You will also be + prompted for the RACF password, which will be securely stored on disk for + subsequent use by openCryptoki. + + - with SASL authentication, you need to specify the authentication mechanism + as sasl, along with the CERT, CACERT, and KEY when adding the ICSF token + into openCryptoki with the pkcsiscf utility. SASL does not require an RACF + password, so you will not be prompted for it. + +When required, the RACF password is stored securely on disk for subsequent use +in /prefix/var/lib/opencryptoki/icsf/RACF. + +**Note: Setup of LDAP and SASL are outside the scope of this README. + + +openCryptoki's ICSF token setup +------------------------------- +The installed opencryptoki.conf does not contain an entry for the ICSF token. An +entry is created upon setting up the ICSF token with the pkcsicsf utility. + +openCryptoki's ICSF token must first be set up with the pkcsiscf utility before +the token can be initialized with the pkcsconf utility. + +Setup +----- +ICSF token(s) originate on the remote server. It is likely that they are created +and destroyed by the remote's system administrator. openCryptoki queries the +remote server for a list of the available ICSF tokens via the pkcsicsf utility. +The list returned may contain more than one remote token. Note, which token(s) +returned depend on the caller's SAF authority on the remote server. + +openCryptoki can only handle one remote ICSF token. If a list of tokens are +returned from the query, a single token must be chosen and installed into +openCryptoki with the pkcsicsf utility. + +Upon adding the token into openCryptoki with the pkcsicsf utility, an ICSF token +entry will be created in the openCryptoki.conf file. + +For example, +slot 5 { +stdll = libpkcs11_icsf.so +confname = /usr/local/etc/opencryptoki/JML.conf +} + +Also, a separate ICSF token config file will be created, +/prefix/etc/opencryptoki/.conf, containing information required to +bind to the LDAP server if any was specified. It will also contain information +from the remote server about the particular ICSF token that was added. + +In this example, /usr/local/etc/opencryptoki/JML.conf was created. And since I +am using .ldaprc file, it only specifies the authentication method. +slot 5 { +TOKEN_NAME = "JML" +TOKEN_MANUFACTURE = "IBM" +TOKEN_MODEL = "ICSFModel" +TOKEN_SERIAL = "012345" +MECH = "SIMPLE" +} + +And lastly, when using simple authentication, a secured RACF password file will +have been created. + + +EXAMPLE OF HOW TO CONFIGURE THE ICSF TOKEN +------------------------------------------ +First, get a list of the available tokens from the remote server. From the list +choose one token and add it into openCryptoki. After successfully adding the +ICSF token and any relatedinformation into openCryptoki, initialize the ICSF +token. + +Examples to get a list of available tokens +------------------------------------------- +1. Using simple authentication and .ldaprc which has BINDDN and URI set in it, +get a list of the available tokens from the remote. + + pkcsicsf -l -m simple + + you will be prompted for the racf passwd and the SO PIN. + + you should get a list of the available tokens from the remote + +2. Using simple authentication and giving openCryptoki the credentials to use to +get a list of available tokens from the remote. + + pkcsicsf -l -b -u -m simple + + you will be prompted for the racf passwd and the SO PIN. + + you should get a list of the available tokens from the remote + +3. Using sasl authentication and ldap configuration files, get list of available +tokens from the remote. + + pkcsicsf -l -m sasl + +4. Using sasl authentication and giving openCryptoki the credentials to use to +get a list of available tokens from the remote. + + (TO DO) + + +Examples to add a token into openCryptoki +----------------------------------------- 1. Using simple authentication and +.ldaprc which has BINDDN and URI set in it, add the token named, Foo. + + pkcsicsf -a Foo -m simple + + you will be prompted for the racf passwd and the SO PIN. + + An entry for the token should have been added in the + /usr/local/etc/opencryptoki/opencryptoki.conf file AND + /usr/local/etc/opencryptoki/Foo.conf should have been created. + + The racf passwd should have been secured in + /usr/local/var/lib/opencryptoki/icsf/RACF. + +2. Using simple authentication and giving openCryptoki the credentials to use, +add the ICSF token named, Foo. In this case, the credentials (the BINDDN and +URI) will be stored in the Foo.conf file that will be created. + + pkcsicsf -a Foo -b -u -m simple + + pkcsicsf -l -b -u -m simple + + you will be prompted for the racf passwd and the SO PIN. + + An entry for the token should have been added in the + /usr/local/etc/opencryptoki/opencryptoki.conf file AND + /usr/local/etc/opencryptoki/Foo.conf should have been created. + + The racf passwd should have been secured in + /usr/local/var/lib/opencryptoki/icsf/RACF. + +3. Using sasl authentication and ldap configuration files to authenticate, add +an ICSF token named, Foo into openCryptoki. + + pkcsicsf -a Foo -m sasl + +4. Using sasl authentication and giving openCryptoki the credentials to use to +get a list of available tokens from the remote. (TO DO) + + +Configure openCryptoki +---------------------- + +Now initialize the ICSF token and set the USER and SO PINs using the pkcsconf +utility. + +1. Start the pkcsslotd daemon + pkcsslotd + +2. List the available tokens in openCryptoki + pkcsconf -t + +3. Initialize the ICSF token. + NOTE: For this example, my ICSF token is listed in slot 5. + pkcsconf -I -c 5 + + You will be prompted for the SO PIN. The default SO PIN is 87654321 + + You will also be prompted to enter a unique token label. You can press + enter since this will be ignored. The label or name has already been + created on the remote server. + +4. Set the user pin + pkcsconf -u -c 5 + + you will be prompted to enter the SO PIN. Enter the default SO PIN, + 87654321. + You will be prompted twice to enter the new user PIN. Enter 8 digits for + the new user pin. Remember it so you can use it later. + +6. Set a new SO PIN + pkcsconf -P -c 5 + + you will be prompted to enter the SO PIN. Enter the default SO PIN, + 87654321. + You will then be prompted to enter the new SO PIN. Enter 8 digits for + the new SO PIN. Remember it for later use. + +7. List the token and ensure it is ready. + pkcsconf -t -c 5 + +Sample output: +pkcsconf -t -c 5 +Token #5 Info: + Label: JML + Manufacturer: IBM + Model: ICSF + Model Serial Number: 012345 + Flags: 0x44D (RNG|LOGIN_REQUIRED|USER_PIN_INITIALIZED|CLOCK_ON_TOKEN|TOKEN_INITIALIZED) + Sessions: 0/-2 + R/W Sessions: -1/-2 + PIN Length: 4-8 + Public Memory: 0xFFFFFFFF/0xFFFFFFFF + Private Memory: 0xFFFFFFFF/0xFFFFFFFF + Hardware Version: 1.0 + Firmware Version: 1.0 + Time: 22:09:20 + + +You are now done configuring the ICSF token into openCryptoki and its ready to +be used. diff --git a/doc/README.pkcscca_migrate b/doc/README.pkcscca_migrate new file mode 100644 index 0000000..47e50bc --- /dev/null +++ b/doc/README.pkcscca_migrate @@ -0,0 +1,87 @@ +README for the CCA secure-key token migration utility + +The CCA secure-key token migration utility consists of two programs: + + pkcscca_migrate.sh A shell script that invokes the pkcscca_migrate utility. + The script does some data location validation, token + validation and token data backup. It is recommended that + this script be used to perform the migration. + + pkcscca_migrate A utility that will migrate all of the CCA token data to + the new CCA master key. + +To use the migration utility, make sure that there are no applications actively +using the PKCS#11 interface to the CCA secure-key token by stopping any +applications that use the PKCS#11 interface to the CCA secure-key token. + +Using the pkcsconf utility, find/verify the slot number of the CCA secure-key +token: + + pkcsconf -s + pkcsconf -t + +The CCA secure-key token will have "(CCA)" at the end of the slot description +and the token information will identify the token as the "IBM CCA Token." + +Once you have determined the proper slot number of the CCA secure-key token, +invoke the CCA secure-key token migration script: + + pkcscca_migrate.sh --slot-id X + where "X" is the slot number of the CCA secure-key token + +Optionally, you can specify the "--dry-run" and/or "-v" options on the script +invocation. + + --dry-run This will cause the migration utility to perform all of the + steps in the migration but will not commit the changes needed to + run under the new CCA master key. Any errors encountered will be + reported. + + -v This will increase the verbosity of the migration utility. + Multiple "-v" arguments can be specified to increase the amount + of verbose information displayed. + +Using the pkcscca_migrate.sh script will create a backup copy of the CCA +secure-key token data in the openCryptoki main data store directory. Should any +errors be encountered during the migration, the original data will be restored. + +Here is a description of the steps involved in the migration: + + - The script will check to see if you are running as root or that you are a + member of the "pkcs11" group. If neither of these is the case, the script + will exit. + + - The script will look for the pkcsconf utility in two locations: + /usr/lib/pkcs11/methods or /usr/sbin. If the utility is not found, the + script will exit. + + - The script will look for the CCA token data store in two locations: + /etc/pkcs11/ccatok or /var/lib/opencryptoki/ccatok. If the data store is + not found, the script will exit. + + - The script will then validate the slot number: + - If a slot number has been supplied as an argument to the script, it + will be verified as a valid slot number. + + - If a slot number was not supplied as an argument to the script, then + the pkcsconf utility will be used to display a list of valid slots. + You must then choose the slot you wish to migrate. + + - The Security Office (SO) pin and the User pin are both required for the + migration. You will be prompted for both of these pins. + + - The selected slot information will be displayed and you will be prompted + to verify that you want to perform the migration. + + - The current CCA token data store will be backed up in the current + directory. Be sure that you have write access to the current directory. If + the backup file cannot be created, the script will exit. + + - The migration utility, pkcscca_migrate, will be invoked to perform the + actual migration. Any errors encountered will be reported. + + - Should an error have been encountered during the migration, the CCA token + data store will be restored from the backup that was created earlier. + + - If no errors have been encountered, then the migration has been + successful. diff --git a/doc/README.token_data b/doc/README.token_data new file mode 100644 index 0000000..08a7af8 --- /dev/null +++ b/doc/README.token_data @@ -0,0 +1,85 @@ +PKCS#11 TOKEN DATA + + As PKCS#11 apps create token objects, openCryptoki stores them by default in +/var/lib/opencryptoki, in a token-specific subdirectory. Each object is stored +in its own file and given a unique name that is never reused. Each object is +stored in a binary format that gives openCryptoki the ability to check for +corruption when reading in the object into memory. + +DATA CORRUPTION + + If corrupted token data is detected by openCryptoki, the name and location on +disk of the corrupted data is logged to syslog. You'll notice a message +something like one of the following: + +Aug 30 16:46:00 host openCryptoki[14491]: Cannot restore token object /var/lib/opencryptoki/swtok/TOK_OBJ/WJ000000 (ignoring it) +Aug 30 16:46:00 host openCryptoki[14491]: Cannot malloc 4294967290 bytes to read in token object /var/lib/opencryptoki/swtok/TOK_OBJ/WJ000000 (ignoring it) +Aug 30 16:46:00 host openCryptoki[14491]: Token object /var/lib/opencryptoki/swtok/TOK_OBJ/WJ000000 +appears corrupted (ignoring it) + + This means that something about the object has changed in such a way that makes +openCryptoki unable or unwilling to process it. + +BACKING UP TOKEN DATA + + The only way to recover from corrupted token data is to maintain backups. An +admin can schedule a repeating backup of /var/lib/opencryptoki to ensure token +data can be restored if it becomes corrupted. Token data can be restored +file-by-file (for instance, copying a backup of the WJ000000 file into the +/var/lib/opencryptoki/swtok/TOK_OBJ/ directory to use the example log entries +above), or the entire token data store can be restored from backup at once. + + Note that NVTOK.DAT, MK_SO and MK_USER store additional state for the token and +are dependent on the SO and USER PIN state at the time the backup was made. If +you've changed your SO or USER PINs since the last backup and then restore these +files, it will essentially roll back the PINs to their prior values. + +THE TPM TOKEN + + The TPM token is slightly different than the other tokens, in that it stores +its token data in a subdirectory for each user who runs a PKCS#11 app. The +subdirectory is the user ID of the user executing the app, such as: + +/var/lib/opencryptoki/tpm/${USER} + + This data is not readable by other users accessing the TPM token, unlike other +openCryptoki tokens, where all apps who know the SO or USER PIN can access all +public or private token data objects respectively. + + Keys and data generated on the TPM token will have as a parent a migratable TPM +key whose parent is an openssl-generated software key wrapped by the TPM's +Storage Root Key. These two parent keys will be unique per user of the TPM token +and so must be backed up separately. + + The wrapped openssl keys are generated by openCryptoki as part of initializing +the token, and are stored encrypted by an AES-256 key based on the SO and USER +PINs, then stored as: + +/var/lib/opencryptoki/tpm/${USER}/PRIVATE_ROOT_KEY.pem +/var/lib/opencryptoki/tpm/${USER}/PUBLIC_ROOT_KEY.pem + + Keep in mind these are software keys encrypted by the SO and USER PINs, which +means that they'll be vulnerable to brute force attacks on their passwords if an +attacker gets access to them. These are the only keys vulnerable to brute force +attacks in the TPM token -- all others are protected by the TPM's dictionary +attack prevention algorithms. + + If you choose not to move these keys off disk for backup, they will be +re-wrapped each time the USER or SO PIN changes, to stay in sync with the +current USER or SO PIN. + + If these keys are moved off disk for backup, be sure to remember the SO and +USER PINs at the time they were removed from disk. If your TPM hardware fails +and you're forced to migrate to a new TPM, the PINs set at the time you backed +them up will be required to decrypt them and restore your TPM key hierarchy. + + To restore your token data on a new TPM, just make sure all token data is +installed in the /var/lib/opencryptoki/tpm/${USER} directory and that the 2 pem +files and NVTOK.DAT are present. When you log in, the TPM key load operation +will fail, since the new TPM's Storage Root Key is different. openCryptoki will +detect this condition, then unwrap the appropriate pem file using the supplied +PIN and re-wrap it to the new Storage Root Key. All token data should then be +available on the TPM. At this point you can remove the pem files from disk again +for backup - they aren't used during normal operation of the token, except as we +mentioned above, to have their passwords updated each time the USER or SO PIN +changes. diff --git a/doc/README.tpm_stdll b/doc/README.tpm_stdll new file mode 100644 index 0000000..e487150 --- /dev/null +++ b/doc/README.tpm_stdll @@ -0,0 +1,94 @@ +TPM STDLL README +Kent Yoder + +Current architecture: + + SRK + | + + User Root Key (URK) + | | + | + [1..N] User Base Key (UBK) + | | + | + Migratable Leaf Key (MLK) + | | | + | | + Auth Data for User Created Keys + | | + | + [1..N] User Created Keys + | + + Migratable Root Key (MRK) + | + + Migratable Leaf Key (MLK) + +1. When the SO logs in: + A) its verified that she is root (currently commented out) + B) the token searches for the User Root Key (URK), and if found, the SO's key + chain is loaded, up to the SO's protection key. Some junk data is + encrypted and decrypted to challenge the auth data passed in and if that + test passes, the SO is logged in + C) if the URK isn't found, its assumed that the SO is logging in for the first + time, and + i. The URK is generated in software + ii. The URK's private key is wrapped with the public key of the SRK, and TSS + and PKCS#11 objects are created for it, storing it in the PKCS#11 data store + D) i and ii are repeated for the Migratable Root Key (MRK) + E) The Protection Key is generated by the TPM as a child of the MRK + F) Some junk data is encrypted and decrypted to challenge the auth data passed + in and if that test passes, the SO is logged in + +2. When the USER logs in: + A) The URK is searched for and if not found, failure (The SO has not + initialized the token) + B) If the URK is found, the User's Base Key (UBK) is searched for and if + found, the user's key chain is loaded, up to the USER's protection key. + Some junk data is encrypted and decrypted to challenge the auth data passed + in and if that test passes, the USER is logged in + C) if the UBK is not found: + i. The UBK is generated in software + ii.The UBK's private key is wrapped with the public key of the URK, and TSS + and PKCS#11 objects are created for it, storing it in the PKCS#11 data + store + D) The User's Protection Key is generated by the TPM as a child of the UBK + E) Some junk data is encrypted and decrypted to challenge the auth data passed + in and if that test passes, the USER is logged in + + +Prior to release 2.4.1, the tpm stdll has the password for the SRK hardcoded to +NULL and the policy secret mode set to TSS_SECRET_MODE_PLAIN. + +Starting in release 2.4.1, the environment variables, +OCK_SRK_SECRET and OCK_SRK_MODE can be set to indicate the Storage Root Key's +secret and it's policy's secret mode to the tpm stdll. + +OCK_SRK_MODE +The possible secret modes are: + - TSS_SECRET_MODE_NONE + - TSS_SECRET_MODE_PLAIN + - TSS_SECRET_MODE_SHA1 + - TSS_SECRET_MODE_POPUP + - TSS_SECRET_MODE_CALLBACK + +OCK_SRK_SECRET +The storage root key may be: + - a text string. + OCK_SRK_MODE should be set to TSS_SECRET_MODE_PLAIN. + i.e. export OCK_SRK_SECRET="MyBigSecret" + + - SHA1 hash string. + The SHA1 hash must be expressed as a 40 byte hexadecimal string. Recall a + byte value is represented by two hexadecimal digits. So a SHA1 hash length + of 20 bytes requires 40 hexadecimal digits to represent it. + + This option also requires that OCK_SRK_MODE is set to TSS_SECRET_MODE_SHA1 + to indicate the string is a sha1 hash. + + i.e. export OCK_SRK_SECRET="22596363b3de40b06f981fb85d82312e8c0ed511" + export OCK_SRK_MODE=TSS_SECRET_MODE_SHA1 + + Note: If using the well known secret, then express as a 40 byte hex string + of zeroes. + + i.e. export OCK_SRK_SECRET="0000000000000000000000000000000000000000" + export OCK_SRK_MODE=TSS_SECRET_MODE_SHA1 + +If neither OCK_SRK_MODE nor OCK_SRK_SECRET are set, then the passwd will be set +to NULL, and the mode to TSS_SECRET_MODE_PLAIN. diff --git a/doc/coding_style.md b/doc/coding_style.md new file mode 100644 index 0000000..0511d9e --- /dev/null +++ b/doc/coding_style.md @@ -0,0 +1,193 @@ +# OpenCryptoki coding style + +This document describes the preferred coding style for the OpenCryptoki project +and its related projects (openssl-ibmca and openssl-ibmpkcs11). Coding style is +always of personal taste, but defining one coding style makes the maintenance of +the project easier and gives a standard face for the source code, something that +this projects have been lacking for the past years. + +The inspiration and formatting of this document came from the Linux Kernel +coding style document, but make no assumption as the coding style differ from +each other on some aspects. + +## 0. Setting up automatic code style check + +To help developers on checking if their code changes are following the coding +style format, we created a pre-commit git hook which is shared under .githooks/ +directory. This hook will use GNU indent to check your code changes. + +You might wonder "why we ask for user confirmation?". Well, we don't want to +create a overhead for developers that are working on feature branches and their +code changes are not yet ready for a pull request. + +To set up the pre-commit hook, each developer after cloning the project needs +to run: +$ ln -s ../../.githooks/pre-commit .git/hooks/pre-commit + +## 1. Indentation + +Tabs are 4 space characters, differently from many projects that define it as 8 +characters. The main idea behind this is that 4 characters should give you a +clear idea about where a block of control starts and ends. + +## 2. Line length + +To keep the code readable and maintainable, the limit on the length of lines is +80 columns and this is a strongly preferred limit. + +## 3. Placing Braces and Spaces + +Here we follow Kernighan and Ritchie teachings. An opening brace is put last on +the line, and put the closing brace first, e.g.: + +``` + if (x == 0) { + do_y(); + } +``` + +This applies to all non-function statement blocks (if, switch, for, while, do). +Another example: + +``` + switch (value) { + case 1: + return "one"; + case 2: + return "two"; + case 3: + return "three"; + default: + return NULL; + } +``` + +However, there is one special case, functions: their opening brace stays at the +beginning of the next line, e.g.: + +``` + int func(int x) + { + do_something(); + } +``` + +Follow other examples: + +``` + do { + do_something(); + } while (condition); +``` + +``` + if (x == 1) { + do_one(); + } else if (x > 1) { + do_two(); + } else { + do_three(); + } +``` + +It is not necessary to use braces when there is only a single statement, e.g.: + +``` + if (x == 1) + do_something(); +``` + +and + +``` + if (x == 1) + do_something(); + else + do_something_else(); +``` + +This does not apply when only one branch in a conditional statement is a single +statement. In this, case use braces in all branches, e.g.: + +``` + if (x == 1) { + do_something(); + do_something_more(); + } else { + do_something_else(); + } +``` + +### 3.1. Spaces + +Always use a space after these keywords: +``` if, switch, case, for, do, while ``` + +E.g.: +``` + if (condition) { + .. + } +``` + +The following keywords should not have a space between them and their +parentheses: +``` sizeof, typeof ``` + +E.g.: +``` + s = sizeof(struct alg); +``` + +Do **not** add spaces around (inside) parenthesized expressions, e.g.: +``` + if ( x == 1 ) { + .. + } +``` + +When declaring a pointer or a function that returns a pointer type, the ``*`` +must be put adjacent to the data name or function name, e.g.: +``` + int *ptr; + void ptrcopy(int *dest, char *src); + int *get_address(int *ptr); +``` + +Use one space on each side of the following operators: +``` = + - < > * / % | & ^ <= >= == != ? : ``` + +but no space after unary operators: +``` & * + - ~ ! ``` + +no space before postfix/after prefix increment and decrement operators: +``` ++ -- ``` + +and no space around the ``.`` and ``->`` structure member operators. + +Do **not** leave trailing whitespace at the end of lines. + +## 4. Naming + +Avoid using CamelCase. It is preferred to name variables and functions by +including an underscore between words, e.g.: +``` + int person_counter; +``` + +## 5. Commenting + +Comments in the code make everyone's life easier, but don't be too verbose. +Focus on **what** your function does and less on **how** it does. + +The preferred style for long multi-line comments is: + +``` + /* + * This is a multi-line comment. + * + * A column of asterisks on the left side, with beginning and ending + * almost-blank lines. + */ +``` + diff --git a/doc/opencryptoki-howto.md b/doc/opencryptoki-howto.md new file mode 100644 index 0000000..bc5d116 --- /dev/null +++ b/doc/opencryptoki-howto.md @@ -0,0 +1,866 @@ +# PKCS #11 openCryptoki for Linux HOWTO + +v1 - Kristin Thomas - kristint@us.ibm.com + +v2 - Eduardo Barretto - ebarretto@linux.vnet.ibm.com + +This HOWTO describes the implementation of the RSA Security Inc./Organization +for the Advancement of Structured Information Standards (OASIS) Public Key +Cryptographic Standard #11 (PKCS #11) cryptoki application program interface +(API) on Linux (openCryptoki). The HOWTO explains what services openCryptoki +provides and how to build and install it. Additional resources and a simple +sample program are also provided. + +## Table of contents +1. [Copyright Notice and Disclaimer](#1-copyright-notice-and-disclaimer)
+2. [Introduction](#2-introduction)
+3. [What is openCryptoki?](#3-what-is-opencryptoki)
+4. [Architectural Overview](#4-architectural-overview)
+ 4.1. [Slot Manager](#41-slot-manager)
+ 4.2. [Main API](#42-main-api)
+ 4.3. [Slot Token Dynamic Link + Libraries](#43-slot-token-dynamic-link-libraries)
+ 4.4. [Shared Memory](#44-shared-memory)
+5. [Getting Started with openCryptoki](#5-getting-started-with-opencryptoki)
+ 5.1. [System Requirements](#51-system-requirements)
+ 5.2. [Obtaining openCryptoki](#52-obtaining-opencryptoki)
+ 5.3. [Compiling and Installing + openCryptoki](#53-compiling-and-installing-opencryptoki)
+6. [Configuring openCryptoki](#6-configuring-opencryptoki)
+7. [Components of openCryptoki](#7-components-of-opencryptoki)
+ 7.1. [Slot Manager Daemon](#71-slot-manager-daemon)
+ 7.2. [libopencryptoki.so](#72-libopencryptokiso)
+ 7.3. [Slot Token DLLs](#73-slot-token-dlls)
+  7.3.1. [Trusted Module Platform](#731-trusted-module-platform-tpm)
+  7.3.2. [IBM Cryptographic Architecture (ICA)](#732-ibm-cryptographic-architecture-ica)
+  7.3.3. [IBM Common Cryptographic Architecture (CCA)](#733-ibm-common-cryptographic-architecture-cca)
+  7.3.4. [Software Token](#734-software-token)
+  7.3.5. [IBM Enterprise PKCS #11 (EP11)](#735-ibm-enterprise-pkcs-11-ep11)
+  7.3.6. [IBM Integrated Cryptographic Service Facility (ICSF)](#736-ibm-integrated-cryptographic-service-facility-icsf)
+8. [Applications and openCryptoki](#8-application-and-opencryptoki)
+ 8.1. [Making openCryptoki Available to + Applications](#81-making-opencryptoki-available-to-applications)
+ 8.2. [Writing an Application](#82-writing-an-application)
+9. [Resources](#9-resources)
+10. [Appendix A: Sample Program](#10-appendix-a-sample-program)
+ 10.1. [Sample Program](#101-sample-program)
+ 10.2. [Makefile](#102-makefile)
+ + +### 1. Copyright Notice and Disclaimer + +Copyright © 2001 - 2017 IBM Corporation. All rights reserved. + +This document may be reproduced or distributed in any form without prior +permission provided the copyright notice is retained on all copies. Modified +versions of this document may be freely distributed, provided that they are +clearly identified as such, and this copyright is included intact. + +This document is provided "AS IS," with no express or implied warranties. Use +the information in this document at your own risk. + +**Special Notices** + +This publication/presentation was produced in the United States. IBM may not +offer the products, programs, services or features discussed herein in other +countries, and the information may be subject to change without notice. Consult +your local IBM business contact for information on the products, programs, +services, and features available in your area. Any reference to an IBM product, +program, service, or feature is not intended to state or imply that only IBM’s +product, program, service, or feature may be used. Any functionally equivalent +product, program, service, or feature that does not infringe on IBM’s +intellectual property rights may be used instead. + +Questions on the capabilities of non-IBM products should be addressed to +suppliers of those products. IBM may have patents or pending patent applications +covering subject matter in this presentation. Furnishing this presentation does +not give you any license to these patents. Send license inquiries, in writing, +to IBM Director of Licensing, IBM Corporation, New Castle Drive, Armonk, NY +10504-1785 USA. All statements regarding IBM’s future direction and intent are +subject to change or withdrawal without notice, and represent goals and +objectives only. Contact your local IBM office or IBM authorized reseller for +the full text of a specific Statement of General Direction. + +The information contained in this presentation has not been submitted to any +formal IBM test and is distributed "AS IS." While each item may have have been +reviewed by IBM for accuracy in a specific situation, there is no guarantee that +the same or similar results will be obtained elsewhere. The use of this +information or the implementation of any techniques described herein is a +customer responsibility and depends on the customer’s ability to evaluate and +integrate them into the customer’s operational environment. Customers attempting +to adapt these techniques to their own environments do so at their own risk. + +The information contained in this document represents the current views of IBM +on the issues discussed as of the date of publication. IBM cannot guarantee the +accuracy of any information presented after the date of publication. + +Any performance data in this document was determined in a controlled +environment. Therefore, the results obtained in other operating environments may +vary significantly. Some measurements quoted in this book may have been made on +development-level systems. There is no guarantee these measurements will be the +same on generally-available systems. Some measurements quoted in this book may +have been estimated through extrapolation. Actual results may vary. Users of +this book should verify the applicable data for their specific environment. + +A full list of U.S. trademarks owned by IBM may be found at +http://www.ibm.com/legal/copytrade.shtml. Linux is a trademark of Linus +Torvalds. Other company, product, and service names may be trademarks or service +marks of others. + + +### 2. Introduction + +Cryptography is rapidly becoming a critical part of our daily lives. However, +the application of cryptographic technology adds a heavy computational burden to +today's server platforms. More systems are beginning to use specialized hardware +to offload the computations, as well as to help ensure the security of secret +key material. In this HOWTO we will discuss openCryptoki, an API that is rapidly +becoming the defacto, non-Windows-platform industry standard for interfacing +between cryptographic hardware and user space applications. In particular we +will introduce the specifics of the PKCS #11 implementation to IBM cryptographic +hardware (openCryptoki). + + +### 3. What is openCryptoki? + +openCryptoki is an implementation of the PKCS #11 API that allows interfacing to +devices (such as a smart card, smart disk, or PCMCIA card) that hold +cryptographic information and perform cryptographic functions. openCryptoki +provides application portability by isolating the application from the details +of the cryptographic device. Isolating the application also provides an added +level of security because all cryptographic information stays within the device. +The openCryptoki API provides a standard programming interface between +applications and all kinds of portable cryptographic devices. + + +### 4. Architectural Overview + +openCryptoki consists of a slot manager and an API for Slot Token Dynamic Link +Libraries (STDLLs). The slot manager runs as a daemon to control the number of +slots provided to applications, and it interacts with applications using a +shared memory region. Each device that has a token associated with it places +that token into a slot in the slot manager database. The shared memory region +allows for proper sharing of state information between applications to help +ensure conformance with the PKCS #11 specification. + +#### 4.1. Slot Manager + +The Slot Manager Daemon (_pkcsslotd_) manages slots (and therefore tokens) in +the system. A fixed number of processes can be attached to _pkcsslotd_, so a +static table in shared memory is used. The current limit of the table is 1000 +processes using the subsystem. The daemon sets up this shared memory upon +initialization and acts as a garbage collector thereafter, helping to ensure +that only active processes remain registered. When a process attaches to a slot +and opens a session, _pkcsslotd_ will make future processes aware that a process +has a session open and will lock out certain function calls, if the they need +exclusive access to the given token. The daemon will constantly search through +its region of shared memory and make sure that when a process is attached to a +token it is actually running. If an attached process terminates abnormally, +_pkcsslotd_ will "clean up" after the process and free the slot for use by other +processes. + +#### 4.2. Main API + +The main API for the STDLLs lies in /usr/lib/opencryptoki/libopencryptoki.so. +This API includes all the functions as outlined in the PKCS #11 API +specification. The main API provides each application with the slot management +facility. The API also loads token specific modules (STDLLs) the provide the +token specific operations (cryptographic operations and session and object +management). STDLLs are customized for each token type and have specific +functions, such as an initialization routine, to allow the token to work with +the slot manager. When an application initializes the subsystem with the +__C_Initialize__ call, the API will load the STDLL shared objects for all the +tokens that exist in the configuration (residing in the shared memory) and +invoke the token specific initialization routines. + +#### 4.3. Slot Token Dynamic Link Libraries + +STDLLs are plug-in modules to the main API. They provide token-specific +functions beyond the main API functions. Specific devices can be supported by +building an STDLLs for the device. Each STDLLs must provide at least a token +specific initialization function. If the device is an intelligent device, such +as a hardware adapter that supports multiple mechanisms, the STDLL can be thin +because much of the session information can be stored on the device. If the +device only performs a simple cryptographic function, all of the objects must be +managed by the software. This flexibility allows the STDLLs to support any +cryptographic device. + +#### 4.4. Shared Memory + +The slot manager sets up its database in a region of shared memory. Since the +maximum number of processes allowed to attach to _pkcsslotd_ is finite, a +fixed amount of memory can be set aside for token management. This fixed memory +allotment management allows applications easier access to token state +information and helps ensure conformance with the PKCS #11 specification. + +### 5. Getting Started with openCryptoki + +This section describes the system requirements for openCryptoki. It also +explains where you can get openCryptoki and how to compile and install it. + +#### 5.1. System Requirements + +openCryptoki installs by default a software token that relies on software to +deliver the crypto functions. So it is possible to install it even if you don't +have physical (hardware) token. + +The following lists show the system requirements for running openCryptoki. + +**Hardware Requirements** + +- openCryptoki is supported on ppc64, s390x and x86. + +**Software Requirements** + +- Linux operating system running at least a 2.2.16 kernel +- Device drivers and associated support libraries for the installed tokens (some +of the header files from those distributions may also be required) + +#### 5.2. Obtaining openCryptoki + +The openCryptoki project and source code is hosted on +[GitHub](https://github.com/opencryptoki/opencryptoki). You can find +openCryptoki releases (tarball) on GitHub and, as well, on +[SourceForge](https://sourceforge.net/projects/opencryptoki/). +For any issue, questions or development related subjects, please contact us on +the [mailing list](https://sourceforge.net/p/opencryptoki/mailman/). + +#### 5.3. Compiling and Installing openCryptoki + +Assuming that the device support (and header files) for the required devices are +on the system, then you can build openCryptoki by entering the source code main +directory and do the following: + +1. Run the bootstrap.sh script by typing: + +``` $ ./bootstrap.sh ``` + +2. Configure the source code by typing: + +``` $ ./configure ``` + + If you're planning to install the package into your home directory or to a + location other than `/usr/local` then add the flag `--prefix=PATH` to + `configure`. For example, if your home directory is `/home/luser` you can + configure the package to install itself there by invoking: + +``` $ ./configure --prefix=/home/luser ``` + + If your stdll headers and libraries are not under any standard path, you will + need to pass the paths to your files for the configure script. For instance: + +``` $ CPPFLAGS="-L/path/lib" LDFLAGS="-I/path/include" ./configure ``` + + See `./configure --help` for info on various options. The default behavior is + to build a default token implicitly. For the s390 platform, the default token + is ICA. For other platforms, the default token is the software token. Other + tokens may be enabled using the corresponding `--enable-` configuration + option provided the appropriate libraries are available. + + While running, `configure` prints some messages telling which features is it + checking for. + +3. Compile the package by typing: + +``` $ make ``` + +4. openCryptoki defaults to be usable by anyone who is in the group ``pkcs11``, +Add the pkcs11 group before installing it, by typing as root the command: + +``` # groupadd pkcs11 ``` + + In addition, add the necessary user to the pkcs11 group (root doesn't need to + be in the pkcs11 group): + +``` # usermod -G pkcs11 ``` + +5. Type `make install` (as root) to install the programs and any data files and +documentation. During installation, the following files go to the following +directories: + +``` + /prefix/sbin/pkcsconf + /prefix/sbin/pkcsslotd + /prefix/sbin/pkcsicsf + /prefix/libdir/libopencryptoki.so + /prefix/libdir/libopencryptoki.so.0 + /prefix/libdir/opencryptoki/libopencryptoki.so + /prefix/libdir/opencryptoki/libopencryptoki.so.0 + /prefix/libdir/opencryptoki/libopencryptoki.so.0.0.0 + /prefix/var/lib/opencryptoki + /prefix/etc/opencryptoki/opencryptoki.conf +``` + + Token objects, which may be optionally built, go to the following locations: + +``` + /prefix/libdir/opencryptoki/stdll/libpkcs11_cca.so + /prefix/libdir/opencryptoki/stdll/libpkcs11_cca.so.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_cca.so.0.0.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_ep11.so + /prefix/libdir/opencryptoki/stdll/libpkcs11_ep11.so.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_ep11.so.0.0.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_ica.so + /prefix/libdir/opencryptoki/stdll/libpkcs11_ica.so.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_ica.so.0.0.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_icsf.so + /prefix/libdir/opencryptoki/stdll/libpkcs11_icsf.so.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_icsf.so.0.0.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_sw.so + /prefix/libdir/opencryptoki/stdll/libpkcs11_sw.so.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_sw.so.0.0.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_tpm.so + /prefix/libdir/opencryptoki/stdll/libpkcs11_tpm.so.0 + /prefix/libdir/opencryptoki/stdll/libpkcs11_tpm.so.0.0.0 +``` + + where `prefix` is either `/usr/local/` or the PATH that you specified in the + `--prefix` flag. `libdir` is the name of the library directory, for 32-bit + libraries it is usually `lib` and for 64-bit libraries it is usually `lib64`. + + To maintain backwards compatibility, some additional symlinks are generated + (note that these are deprecated and applications should migrate to use the + LSB-compliant name and locations for libraries and executable): + +``` + /prefix/lib/opencryptoki/PKCS11_API.so + - Symlink to /prefix/lib/opencryptoki/libopencryptoki.so + + /prefix/lib/opencryptoki/stdll/PKCS11_CCA.so + - Symlink to /prefix/lib/opencryptoki/stdll/libpkcs11_cca.so + + /prefix/lib/opencryptoki/stdll/PKCS11_EP11.so + - Symlink to /prefix/lib/opencryptoki/stdll/libpkcs11_ep11.so + + /prefix/lib/opencryptoki/stdll/PKCS11_ICA.so + - Symlink to /prefix/lib/opencryptoki/stdll/libpkcs11_ica.so + + /prefix/lib/opencryptoki/stdll/PKCS11_ICSF.so + - Symlink to /prefix/lib/opencryptoki/stdll/libpkcs11_icsf.so + + /prefix/lib/opencryptoki/stdll/PKCS11_SW.so + - Symlink to /prefix/lib/opencryptoki/stdll/libpkcs11_sw.so + + /prefix/lib/pkcs11/PKCS11_API.so + - Symlink to /prefix/lib/opencryptoki/libopencryptoki.so + + /prefix/lib/pkcs11 + - Directory created if non-existent + + /prefix/lib/pkcs11/methods + - Symlink to /prefix/sbin + + /prefix/lib/pkcs11/stdll + - Symlink to /prefix/lib/opencryptoki/stdll + + /prefix/etc/pkcs11 + - Symlink to /prefix/var/lib/opencryptoki +``` + + If any of these directories do not presently exist, they will be created on + demand. Note that if `prefix` is `/usr`, then `/prefix/var` and `/prefix/etc` + resolve to `/var` and `/etc`. On the `make install` stage, if content exists + in the old `/prefix/etc/pkcs11` directory, it will be migrated to the new + `/prefix/var/lib/opencryptoki` location. + + If you are installing in your home directory make sure that `/home/luser/bin` + is in your path. If you're using the bash shell add this line at the end of + your `.bashrc` file: + +``` + PATH="/home/luser/bin:${PATH}" + export PATH +``` + + If you are using csh or tcsh, then use this line instead: + +``` setenv PATH /home/luser/bin:${PATH} ``` + + By prepending your home directory to the rest of the PATH you can override + systemwide installed software with your own custom installation. + + +### 6. Configuring openCryptoki + +See: +https://www.ibm.com/support/knowledgecenter/linuxonibm/com.ibm.linux.z.lxce/lxce_stackoverview.html + +Prior to version 3, openCryptoki used `pk_config_data` as its configuration +file. This file was created upon running `pkcs11_startup`. In version 3, +`pkcs11_startup` and `pk_config_data` have been removed and replaced with a +customizable config file named, `opencryptoki.conf`. It contains an entry for +each token currently supported by openCryptoki. However, only those token, whose +hardware and software requirements are available on the local system, will show +up as present and available upon running the `pkcsconf -t` command. + +Before using, each token must be first initialized. You can select the token +with the `-c` command line option; refer to the documentation linked to above +for further instructions. + +Initialize a particular token by running `pkcsconf`: + +``` $ pkcsconf -I -c ``` + +In this version of openCryptoki, the default SO PIN is `87654321`. This should +be changed to a different PIN value before use. + +You can change the SO PIN by running pkcsconf : + +``` $ pkcsconf -P -c ``` + +You can initialize and change the user PIN by typing: + +``` $ pkcsconf -u -c ``` + +You can later change the user PIN again by typing: + +``` $ pkcsconf -p -c ``` + +### 7. Components of openCryptoki + +This section describes the different components of the openCryptoki subsystem. + +#### 7.1. Slot Manager Daemon + +The slot manager daemon is an executable (`/usr/sbin/pkcsslotd`) that reads in +`/etc/opencryptoki/opencryptoki.conf`, populating shared memory according to +what devices have been found within the system. `pkcsslotd` then continues +running as a daemon. Any other applications attempting to use the subsystem must +first attach to the shared memory region and register as part of the API +initialization process, so `pkcsslotd` is aware of the application. If +`/etc/opencryptoki/opencryptoki.conf/` is changed, `pkcsslotd` must be stopped +and restarted to read in the new configuration file. The daemon can be stopped +by issuing the `pkill pkcsslotd` command or through systemd `systemctl stop +pkcsslotd`. The daemon will not terminate if there are any applications using +the subsystem. + +#### 7.2. libopencryptoki.so + +This library contains the main API (`/usr/lib/opencryptoki/libopencryptoki.so`) +and is loaded by any application that uses any PKCS #11 token managed by the +subsystem. Before an application uses a token, it must load the API and call +`C_Initialize`, as per the PKCS #11 specification. The loading operation is +performed by the application using the dlopen facilities. + +#### 7.3. Slot Token DLLs + +Six STDLLs ship in the initial offering. These support Trusted Platfrom Module +(TPM, <2.0), IBM Cryptographic Architecture (ICA), IBM Common Cryptographic +Architecture (CCA), Soft Token, IBM Enterprise PKCS #11 (EP11) and IBM +Integrated Cryptographic Service Facility (ICSF). + + **Note**: The compilation process attempts to build all of the tokens that + are supported on the target platform, as well as all of the required support + programs. If some of the headers and libraries are not present, those + components will not be built. + +##### 7.3.1. Trusted Module Platform (TPM) + +In order to be able to build the TPM stdll you first need: + +1. Enable tpm in BIOS settings. + +2. Install trousers, trousers-devel, tpm-tools and tpm-tools-pkcs11 as root. +Package names can differ depending on the Linux distribution. + +3. As root run the following commands: + +``` + Start the tcsd daemon + # /etc/init.d/tcsd start or # systemctl start tcsd + + Enter tpm passwords + # tpm_takeownership + Enter owner password: + Confirm password: + Enter SRK password: + Confirm password: + + # tpm_setpresence + Enter owner password: + Physical Presence Status: + Command Enable: true + Hardware Enable: false + Lifetime Lock: true + Physical presence: false + Lock: true +``` + +After setting up the TPM the openCryptoki compilation should automatically +build the tpm stdll. If it doesn't, then please run: + +``` ./configure --enable-tpmtok ``` + +For more information check [README.tpm_stdll](README.tpm_stdll) + +##### 7.3.2. IBM Cryptographic Architecture (ICA) + +The IBM Cryptographic Architecture (ICA) is a hardware token that is available +only for s390 systems. If you are in this platform and have the necessary +hardware, you can build openCryptoki with the ICA stdll. To achieve it you need +first install the `libica` package. This package is available in the Linux +distributions repositories. + +##### 7.3.3. IBM Common Cryptographic Architecture (CCA) + +The IBM Common Cryptographic Architecture (CCA) is also a hardware token that is +only available for the s390 architecture. If you are in this platform and have +the necessary hardware then you can build openCryptoki with the CCA stdll. +First, you need to install the csulcca library on your system. To get this +package click +[here](https://www-03.ibm.com/security/cryptocards/pciecc2/lonzsoftware.shtml) +and be sure to choose the package corresponding to your crypto card version. + +For more information about CCA, read [README.cca_stdll](README.cca_stdll) +and [README.pkcscca_migrate](README.pkcscca_migrate). + +##### 7.3.4. Software Token + +This token is a software emulation of a token. All the cryptographic operations +needed will be run in a software implementation of such cryptographic +algorithms. This implementation is given by OpenSSL and the Soft token is built +by default with openCryptoki. + +##### 7.3.5. IBM Enterprise PKCS #11 (EP11) + +This is another hardware token for the s390 architecture. In order to be able to +build openCryptoki with EP11 stdll download the necessary library from +[here](https://www-03.ibm.com/security/cryptocards/pciecc2/lonzsoftware.shtml). +Be sure to choose the driver corresponding to your crypto card version. + +For more information about EP11, please refer to +[README.ep11_stdll](README.ep11_stdll). + +##### 7.3.6. IBM Integrated Cryptographic Service Facility (ICSF) + +The ICSF token is a remote crypto token. The actual crypto operations are +performed remotely on a s390 server and all the PKCS #11 key objects are stored +remotely on the server. This calls to the remote server are done via LDAP. + +So, to build openCryptoki with LDAP, you need to install on the client side: +`openldap, openldap-clients and openldap-devel`. + +For more information about ICSF, head over to +[README.icsf_stdll](README.icsf_stdll). + +### 8. Application and openCryptoki + +This section describes how to make openCryptoki available to applications and +provides an example of how to write such an application. + +#### 8.1. Making openCryptoki Available to Applications + +Many applications use PKCS #11 tokens. Most of these applications must be +configured to load specific shared object (DLL) for the token. In the case of +openCryptoki, only one module (`/usr/lib/opencryptoki/libopencryptoki.so`) must +be loaded for access to all the tokens currently running in the subsystem. +Multiple token types are supported, with each type taking up a slot in the +subsystem according to the implementation specifics of the plug-in module. + +If devices are added or removed, the PKCS #11 slot where the token resides may +change. For this reason, applications should locate the specific token by the +token label provided when the token is initialized and not assume that a +specific slot always contains the desired token. + +For application-specific configuration information relating to the exploitations +of PKCS #11, refer to the application's documentation. + +#### 8.2. Writing an Application + +To develop an application that uses openCryptoki, you must first load the shared +object using the dynamic library calls. Then call C_GetFunctionList. For +example, the following routines loads the shared library and gets the function +list for subsequent calls. + +``` +CK_FUNCTION_LIST *funcs; + +int do_GetFunctionList(void) +{ + CK_RV rc; + CK_RV (*pfoo)(); + void *d; + char *e; + char f[]="/usr/lib/pkcs11/PKCS11_API.so" + + printf("do_GetFunctionList...\n"); + + d = dlopen(f, RTLD_NOW); + if (d == NULL) + return FALSE; + + pfoo = (CK_RV (*)())dlsym(d, "C_GetFunctionList"); + if (pfoo == NULL) + return FALSE; + + rc = pfoo(&funcs); + + if (rc != CKR_OK) { + show_error("C_GetFunctionList rc=%d\n", rc); + return FALSE; + } + + printf("Looks okay...\n"); + return TRUE; +} +``` + +Once loaded, the application must call the `C_Initialize` function. In the +previous example, the function would be invoked with the following lines: + +``` +CK_C_INITIALIZE_ARGS cinit_args; +memset(&cinit_args, 0x0, sizeof(cinit_args)); +funcs->C_Initialize(&cinit_args); +``` + +Refer to the PKCS #11 specification available from the OASIS web site +(https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=pkcs11) for more +options. + + **Note**: openCryptoki requires that operating systems threads be allowed. If + other thread routines are passed in, they are ignored. If the `no-os` threads + argument is set in the initialize arguments structure, the call to + C_Initialize will fail. + + +### 9. Resources + +For additional information about PKCS #11 and openCryptoki, see the following +resources: + +* openCryptoki on [GitHub](https://github.com/opencryptoki/opencryptoki) +* OASIS [PKCS #11 Specification](https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=pkcs11) +* [IBM Cryptocards](https://www-03.ibm.com/security/cryptocards/) +* openCryptoki +[mailing-list](https://sourceforge.net/projects/opencryptoki/lists/opencryptoki-tech) + + +### 10. Appendix A: Sample Program + +The following sample program prints out all of the current tokens and slots in +use in the system. If you want to build the sample program, you will also need +the `Makefile` after the sample. + +#### 10.1. Sample Program + +``` +#include +#include +#include +#include +#include +#include + +#define CFG_SLOT 0x0004 +#define CFG_PKCS_INFO 0X0008 +#define CFG_TOKEN_INFO 0x0010 + +CK_RV init(void); +CK_RV cleanup(void); +CK_RV get_slot_list(int, CK_CHAR_PTR); +CK_RV display_slot_info(void); +CK_RV display_token_info(void); + +void *dll_ptr; +CK_FUNCTION_LIST_PTR function_ptr = NULL; +CK_SLOT_ID_PTR slot_list = NULL; +CK_ULONG slot_count = 0; +int in_slot; + +int main(int argc, char *argv[]) +{ + CK_RV rc; /* Return Code */ + CK_FLAGS flags = 0; /* Bit Mask for what options were passed in */ + CK_CHAR_PTR slot = NULL; /* The PKCS slot number */ + + /* Load the PKCS11 library */ + init(); + + /* Get the slot list and indicate if a slot number was passed in or not */ + get_slot_list(flags, slot); + + /* Display the current token and slot info */ + display_token_info(); + display_slot_info(); + + /* We are done, free the memory we may have allocated */ + free(slot); + return rc; +} + +CK_RV get_slot_list(int cond, CK_CHAR_PTR slot) +{ + CK_RV rc; /* Return code */ + + /* Find out how many tokens are present in the slots */ + rc = function_ptr->C_GetSlotList(TRUE, NULL_PTR, &slot_count); + if (rc != CKR_OK) { + printf("Error getting number of slots: 0x%X\n", rc); + return rc; + } + + /* Allocate enough space for the slots information */ + slot_list = (CK_SLOT_ID_PTR) malloc(slot_count*sizeof(CK_SLOT_ID)); + + rc = function_ptr->C_GetSlotList(TRUE, slot_list, &slot_count); + if (rc != CKR_OK) { + printf("Error getting slot list: 0x%X\n", rc); + return rc; + } + + return rc; +} + +CK_RV display_slot_info(void) +{ + CK_RV rc; /* Return Code */ + CK_SLOT_INFO slot_info; /* Structure to hold slot information */ + int lcv; /* Loop Control Variable */ + + for (lcv = 0; lcv < slot_count; lcv++) { + /* Get the info for the slot we are examining and store in slot_info */ + rc = function_ptr->C_GetSlotInfo(slot_list[lcv], &slot_info); + if (rc != CKR_OK) { + printf("Error getting the slot info: 0x%X\n", rc); + return rc; + } + + /* Display the slot information */ + printf("Slot #%d Info\n", slot_list[lcv]); + printf("\tDescription: %.64s\n", slot_info.slotDescription); + printf("\tManufacturer: %.32s\n", slot_info.manufacturerID); + printf("\tFlags: 0x%X\n", slot_info.flags); + printf("\tHardware Version: %d.%d\n", slot_info.hardwareVersion.major, + slot_info.hardwareVersion.minor); + printf("\tFirmware Version: %d.%d\n", slot_info.firmwareVersion.major, + slot_info.firmwareVersion.minor); + } + return CKR_OK; +} + +CK_RV display_token_info(void) +{ + CK_RV rc; /* Return Code */ + CK_TOKEN_INFO token_info; /* Structure to hold token information */ + int lcv; /* Loop Control Variable */ + + for (lcv = 0; lcv < slot_count; lcv++) { + /* Get the Token info for each slot in the system */ + rc = function_ptr->C_GetTokenInfo(slot_list[lcv], &token_info); + if (rc != CKR_OK) { + printf("Error getting token info: 0x%X\n", rc); + return rc; + } + + /* Display the token information */ + printf("Token #%d Info:\n", slot_list[lcv]); + printf("\tLabel: %.32s\n", token_info.label); + printf("\tManufacturer: %.32s\n", token_info.manufacturerID); + printf("\tModel: %.16s\n", token_info.model); + printf("\tSerial Number: %.16s\n", token_info.serialNumber); + printf("\tFlags: 0x%X\n", token_info.flags); + printf("\tSessions: %d/%d\n", token_info.ulSessionCount, + token_info.ulMaxSessionCount); + printf("\tR/W Sessions: %d/%d\n", token_info.ulRwSessionCount, + token_info.ulMaxRwSessionCount); + printf("\tPIN Length: %d-%d\n", token_info.ulMinPinLen, + token_info.ulMaxPinLen); + printf("\tPublic Memory: 0x%X/0x%X\n", token_info.ulFreePublicMemory, + token_info.ulTotalPublicMemory); + printf("\tPrivate Memory: 0x%X/0x%X\n", token_info.ulFreePrivateMemory, + token_info.ulTotalPrivateMemory); + printf("\tHardware Version: %d.%d\n", token_info.hardwareVersion.major, + token_info.hardwareVersion.minor); + printf("\tFirmware Version: %d.%d\n", token_info.firmwareVersion.major, + token_info.firmwareVersion.minor); + printf("\tTime: %.16s\n", token_info.utcTime); + } + return CKR_OK; +} + +CK_RV init(void) +{ + CK_RV rc; /* Return Code */ + void (*sym_ptr)(); /* Pointer for the DLL */ + + /* Open the PKCS11 API Shared Library, and inform the user if there is an + * error + */ + dll_ptr = dlopen("/usr/lib/opencryptoki/libopencryptoki.so", RTLD_NOW); + if (!dll_ptr) { + rc = errno; + printf("Error loading PKCS#11 library: 0x%X\n", rc); + fflush(stdout); + return rc; + } + + /* Get the list of the PKCS11 functions this token supports */ + sym_ptr = (void (*) ())dlsym(dll_ptr, "C_GetFunctionList"); + if (!sym_ptr) { + rc = errno; + printf("Error getting function list: 0x%X\n", rc); + fflush(stdout); + cleanup(); + } + + sym_ptr(&function_ptr); + + /* If we get here, we know the slot manager is running and we can use PKCS11 + * calls, so we will execute the PKCS11 Initialize command. + */ + rc = function_ptr->C_Initialize(NULL); + if (rc != CKR_OK) { + printf("Error initializing the PKCS11 library: 0x%X\n", rc); + fflush(stdout); + cleanup(); + } + + return CKR_OK; +} + +CK_RV cleanup(void) +{ + CK_RV rc; /* Return Code */ + + /* To clean up we will free the slot list we create, call the Finalize + * routine for PKCS11 and close the dynamically linked library + */ + free(slot_list); + rc = function_ptr->C_Finalize(NULL); + if (dll_ptr) + dlclose(dll_ptr); + + exit(rc); +} +``` + +#### 10.2. Makefile + +``` +VPATH = ... + +INCS = -I../. -I../../../../../include/pkcs11 +CFLAGS = $(OPTLVL) $(INCS) -DAPI -DDEV -D_THREAD_SAFE -DLINUX -DDEBUG -DSPINXL + +CC = gcc +LD = gcc + +LIBS = -ldl -lpthread + +OBJS = sample.o + +.c.o: ; $(CC) -c $(CFLAGS) -o $@ $< + +all: sample + +sample: $(OBJS) +${CC} ${OBJS} $(LIBS) -o $@ + +TARGET = sample + +build: $(TARGET) + +clean: +rm -f *.so *.o $(TARGET) +``` diff --git a/doc/system_resources b/doc/system_resources new file mode 100644 index 0000000..00b741f --- /dev/null +++ b/doc/system_resources @@ -0,0 +1,76 @@ +The following are the system resources used by openCryptoki as of +openCryptoki-3.8 release. + +1.Shared memory = 1 per token + 1 segment between pkcsslotd & api = 7 max currently + a. Between pkcsslotd and api + The pkcsslotd daemon has its own shared memory segment that it creates + and shares with API. Part of the data is now passed through sockets but + there is still some data shared via shared memory. + + b. Each token has its own shared memory segment. Opencryptoki processes + attach to the token segment and shared memory acts as a global state + tracking mechanism. + # ls /dev/shm + var.lib.opencryptoki.ccatok var.lib.opencryptoki.swtok + var.lib.opencryptoki.ep11tok var.lib.opencryptoki.tpm.root + var.lib.opencryptoki.lite + +2. Sockets - 1 +Unix socket between pkcsslotd and api to transfer slot information. + +3. Files + a. Lock files - 1 global API LCK file + 1 per token (except tpm) = 6 max + currently + 1 lock file per user on tpm token + # ls -lh /var/lock/opencryptoki/ + LCK..APIlock + ccatok/LCK..ccatok + ep11tok/LCK..ep11tok + icsf/LCK..icsf + lite/LCK..lite + swtok/LCK..swtok + tpm//LCK..tpm + + b. Trace files - These are generated based on the environment variable + OPENCRYPTOKI_TRACE_LEVEL per process in /var/log/opencryptoki. No max + limit. + + c. Config files - 2 + # ls -lh /etc/opencryptoki/ + total 8.0K + -rw-r--r--. 1 root root 390 Mar 31 10:55 ep11tok.conf + -rw-r--r--. 1 root root 674 Mar 31 10:55 opencryptoki.conf + + d. Token data files - 3 files per token + 1 additional RACF file for icsf + token + 1 MK_PRIVATE file for tpm token = 20 + NVTOK.DAT - Token data like user pin, so pin etc + MK_SO - Master key used for internal encryption hashed with SOPIN. This + file does not exist on tpm token. + MK_USER - Master key used for internal encryption hashed with USERPIN. + This file does not exist on tpm token. + RACF - icsf racf password encrypted. tpm token has wrapped keys per user + /var/lib/opencryptoki/tpm/${USER}/PRIVATE_ROOT_KEY.pem + /var/lib/opencryptoki/tpm/${USER}/PUBLIC_ROOT_KEY.pem + + e. Token object files - 1 OBJ_IDX file per token and the private object + files. = 6 + as many number of private token objects for tokens + OBJ_IDX - A list of current token objects. + +4. Semaphores +The following depend on the number of processes accessing openCryptoki on the system. + a. The structure API_Proc_Struct_t is allocated per process. It has a thread + level mutex and a session level mutex to lock btree accesses. So two + mutexes per process. + + b. Per process Global Mutex used in API. - 1 + + c. There are 5 mutexes used in common directory per process - 5 + pthread_mutex_t native_mutex ; + MUTEX pkcs_mutex, obj_list_mutex, sess_list_mutex, login_mutex; + +The following are mutexes local to tokens. + d. Soft token has two mutexes - 1 + e. ica token - 1 + +5. There are 5 global btrees (in memory) for holding the session mapping +information, session objects, public token and private token objects +information. diff --git a/m4/.dont_remove b/m4/.dont_remove new file mode 100644 index 0000000..0dcfa20 --- /dev/null +++ b/m4/.dont_remove @@ -0,0 +1,4 @@ +REQUIRED FILE, PLEASE DON'T REMOVE IT. + +The current configure.ac requires the m4 directory, but git don't save empty +directories in the repository. diff --git a/man/man.mk b/man/man.mk new file mode 100644 index 0000000..01470f1 --- /dev/null +++ b/man/man.mk @@ -0,0 +1,4 @@ +include man/man1/man1.mk +include man/man5/man5.mk +include man/man7/man7.mk +include man/man8/man8.mk diff --git a/man/man1/man1.mk b/man/man1/man1.mk new file mode 100644 index 0000000..51d23d3 --- /dev/null +++ b/man/man1/man1.mk @@ -0,0 +1,20 @@ +man1_MANS += man/man1/pkcsconf.1 man/man1/pkcsicsf.1 + +if ENABLE_PKCSEP11_MIGRATE +man1_MANS += man/man1/pkcsep11_migrate.1 +endif + +if ENABLE_PKCSEP11_SESSION +man1_MANS += man/man1/pkcsep11_session.1 +endif + +if ENABLE_CCATOK +man1_MANS += man/man1/pkcscca.1 +endif + +if ENABLE_P11SAK +man1_MANS += man/man1/p11sak.1 +endif + +EXTRA_DIST += $(man1_MANS) +CLEANFILES += $(man1_MANS) diff --git a/man/man1/p11sak.1.in b/man/man1/p11sak.1.in new file mode 100644 index 0000000..1837ad1 --- /dev/null +++ b/man/man1/p11sak.1.in @@ -0,0 +1,386 @@ +.TH P11SAK 1 "May 2020" "@PACKAGE_VERSION@" "openCryptoki" +.SH NAME +p11sak \- generate and list token keys in an openCryptoki token repository. +. +. +.SH SYNOPSIS +.B p11sak +.I command +.RI [ ARGS ] +.RB [ OPTIONS ] +. +.PP +.B p11sak +.BR \-\-help | \-h +.br + +.SH DESCRIPTION +.B p11sak can be used to generate and list 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) and asymetric (RSA, EC) keys. +This tool is especially capable of a well defined listing of keys with their PKCS #11 attributes. +. +. +. +.SH COMMANDS +The \fBp11sak\fP tool can operate in two modes: when command +.I generate-key +is specified, it operates in the mode to generate a token key in the openCryptoki token repository. +When command +.I list-key +is given, it lists 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" +.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 ]. +The +.BR \-\-help | \-h +option will show the arguments and options available. + +. +.PP +.SS "Generating DES/3DES keys" +. +.B p11sak +.BR generate-key | gen-key | gen +.BR des | 3des +.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 +.PP +Use the +.B generate-key +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 [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). +. +.PP +.SS "Generating AES keys" +. +.B p11sak +.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 [M R L S E D G V W U A X N T] +.B \-\-help | \-h +.PP +Use the +.B generate-key +.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 [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). +. +.PP +.SS "Generating RSA keys" +. +.B p11sak +.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 [M R L S E D G V W U A X N T] +.B \-\-help | \-h +.PP +Use the +.B generate-key +.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 [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. +. +.PP +.SS "Generating EC keys" +. +.B p11sak +.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 [M R L S E D G V W U A X N T] +.B \-\-help | \-h +.PP +Use the +.B generate-key +.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 +.PP +.B Note: +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 [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). +. +.PP +.SS "Listing symmetric and asymmetric keys" +. +.B p11sak +.BR list-key | ls-key | ls +.BR des | 3des | aes | rsa | ec | public | private | secret +.B \-\-slot +.IR SLOTID +.B \-\-pin +.IR PIN +.B \-\-long | \-l +.B \-\-help | \-h +.PP +Use the +.B list-key | ls-key | ls +command and key argument to list DES, 3DES, AES, RSA or EC keys, respectively. Public, private or secret keys can also be listed irrespective of key type. +. +.PP +. +. +. +.SH ARGS +. +.SS "des | 3des | aes | rsa | ec | public | private | secret" + +selects the respective symmetric or asymetric key to be generated or listed. The +.B public|private|secret +argument can only be used with the +.B list-key +command to list either public, private or secret keys. +.PP +. +. +. +.SS "128|192|256" +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. +.PP +. +. +. +.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. +.PP +. +. +. +.SS "prime256v1 | prime192 | secp224 | secp384r1 | secp521r1 | secp265k1 | brainpoolP160r1 | brainpoolP160t1 | brainpoolP192r1 | brainpoolP192t1 | brainpoolP224r1 | brainpoolP224t1 | brainpoolP256r1 | brainpoolP256t1 | brainpoolP320r1 | brainpoolP320t1 | brainpoolP384r1 | brainpoolP384t1 | brainpoolP512r1 | brainpoolP512t1" +the +.B ec +argument has to be followed by either of these +.I CURVE +to select the EC curve used to generate the key. +.PP +. +. + +.SH OPTIONS + +.SS "\-\-slot SLOTID" +sets the token to +.IR SLOTID +.PP +. +. +. +.SS "\-\-pin PIN" +sets the token PIN to +.IR PIN +.PP +. +. +. +.SS "\-\-label LABEL" +sets the key label attribute to +.IR LABEL +.PP +. +. +. +.SS "\-\-exponent EXP" +sets the RSA exponent to +.IR EXP +.PP +. +. +. +.SS "\-\-attr [M R L S E D G V W U A X N T]" +sets the binary attributes of a key. +.PP +.B Note: +not all binary attributes are applicable to all keys and will be omitted if not applicable. +.PP +The attributes are set to +.B FALSE +by default and switched 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: +.IP "\(bu" 2 +.B M +- CKA_MODIFIABLE +.IP "\(bu" 2 +.B R +- CKA_DERIVE +.IP "\(bu" 2 +.B L +- CKA_LOCAL +.IP "\(bu" 2 +.B S +- CKA_SENSITIVE +.IP "\(bu" 2 +.B E +- CKA_ENCRYPT +.IP "\(bu" 2 +.B D +- CKA_DECRYPT +.IP "\(bu" 2 +.B G +- CKA_SIGN +.IP "\(bu" 2 +.B V +- CKA_VERIFY +.IP "\(bu" 2 +.B W +- CKA_WRAP +.IP "\(bu" 2 +.B U +- CKA_UNWRAP +.IP "\(bu" 2 +.B A +- CKA_ALWAYS_SENSITIVE +.IP "\(bu" 2 +.B X +- CKA_EXTRACTABLE +.IP "\(bu" 2 +.B N +- CKA_NEVER_EXTRACTABLE +.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'. +.PP +. +. +. +.SS "\-\-long | \-l" +prints the +.B list-key +output in long format. If omitted, the output is in a short, tabular format. +.PP +. +. +. +.SS "\-\-help | \-h" +prints help for the usage of +.B p11sak +and/or the respective command. +.PP diff --git a/man/man1/pkcscca.1.in b/man/man1/pkcscca.1.in new file mode 100644 index 0000000..1d1a829 --- /dev/null +++ b/man/man1/pkcscca.1.in @@ -0,0 +1,64 @@ +.TH PKCSCCA 1 "September 2014" "@PACKAGE_VERSION@" "openCryptoki" +.SH NAME +pkcscca \- configuration utility for the CCA token + +.SH SYNOPSIS +.SS "VERSION MIGRATION" +\fBpkcscca\fP +[\fB-m v2objectsv3\fP] +[\fIOPTIONS\fP] + +.SS "KEY MIGRATION" +\fBpkcscca\fP +[\fB-m keys\fP] +[\fB-s SLOTID\fP] +[\fB-k aes|apka|asym|sym\fP] +[\fIOPTIONS\fP] + +.SH DESCRIPTION +The \fBpkcscca\fP utility assists in administering the CCA token. + +In version 2 of opencryptoki, CCA private token objects were encrypted in CCA +hardware. In version 3 these objects are encrypted in software. The +\fBv2objectsv3\fP migration option migrates these v2 objects by +decrypting them in CCA hardware using a secure key and then re-encrypting +them in software using a software key. Afterwards, v2 objects can be accessed +in version 3. + +There may be situations where CCA master keys must be changed. All CCA secret +and private keys are wrapped with a master key. After a CCA master key is +changed, keys wrapped with the old master key need to be re-wrapped with the +current master key. The \fBkeys\fP migration option migrates these wrapped keys +by unwrapping them with the old master key and wrapping them with the current +master key. + +.SH "GENERAL OPTIONS" +.IP "\fB-d|--datastore\fP \fIdirectory\fp" 10 +the directory where the CCA token information is kept. This directory will be +used to locate the private token objects to be migrated. i.e. /var/lib/opencryptoki/ccatok +.IP "\fB-v|--verbose\fP" 5 +Provide more detailed output + +.SH "VERSION MIGRATION" +.IP "\fB-m v2objectsv3\fP" 5 +Migrates CCA private token objects from CCA encryption (used in v2) to software +encryption (used in v3). + +.SH "KEY MIGRATION" +.IP "\fB-m keys\fP" 5 +Unwraps private keys with an old CCA master key and wraps them with a new CCA +master key. +.IP "\fB-k aes|apka|asym|sym\fP" 5 +Migrate keys wrapped with the selected master key type. +.IP "\fB-s|--slotid\fP \fISLOTID\fP" 5 +The PKCS slot number. + +.SH "FILES" +.IP "/var/lib/opencryptoki/ccatok/TOK_OBJ/OBJ.IDX" +contains current list of public and private token objects for the CCA token. + +.SH SEE ALSO +.PD 0 +.TP +\fBREADME.cca_stdll\fP (in system's doc directory) +.PD diff --git a/man/man1/pkcsconf.1.in b/man/man1/pkcsconf.1.in new file mode 100644 index 0000000..76293ae --- /dev/null +++ b/man/man1/pkcsconf.1.in @@ -0,0 +1,54 @@ +.TH PKCSCONF 1 "May 2007" "@PACKAGE_VERSION@" "openCryptoki" +.SH NAME +pkcsconf \- configuration utility for the pkcsslotd daemon + +.SH SYNOPSIS +\fBpkcsconf\fP +[\fB-itsmlIupPh\fP] +[\fB-c\fP \fIslotnumber\fP \fB-U\fP \fIuserPIN\fP +\fB-S\fP \fISOPin\fP \fB-n\fP \fInewpin\fP] + +.SH DESCRIPTION +The \fBpkcsconf\fP utility displays and configures the state of the +pkcsslotd daemon and the tokens managed by the daemon. + +.SH "COMMAND SUMMARY" +.IP "\fB-i\fP" 10 +display PKCS11 info +.IP "\fB-t\fP" 10 +display token info +.IP "\fB-s\fP" 10 +display slot info +.IP "\fB-m\fP" 10 +display mechanism list +.IP "\fB-l\fP" 10 +display slot description +.IP "\fB-I\fP" 10 +initialize token +.IP "\fB-u\fP" 10 +initialize user PIN +.IP "\fB-p\fP" 10 +set the user PIN +.IP "\fB-P\fP" 10 +set the SO PIN +.IP "\fB-c\fP \fISLOT\fP" 10 +specify the token slot for the operation +.IP "\fB-U\fP \fIUSERPIN\fP" 10 +the current user pin (for use when changing the user pin; -u and -p options); +if not specified, user will be prompted +.IP "\fB-S\fP \fISOPIN\fP" 10 +the current Security Officer (SO) pin (for use when changing the SO pin; +-P option); if not specified, user will be prompted +.IP "\fB-n\fP \fINEWPIN\fP" 10 +the new pin (for use when changing either the user pin or the SO pin; -u, -p +and -P options); if not specified, user will be prompted +.IP "\fB-h\fP" 10 +show usage information + +.SH SEE ALSO +.PD 0 +.TP +\fBopencryptoki\fP(7), +.TP +\fBpkcsslotd\fP(8). +.PD diff --git a/man/man1/pkcsep11_migrate.1.in b/man/man1/pkcsep11_migrate.1.in new file mode 100644 index 0000000..d1b21b0 --- /dev/null +++ b/man/man1/pkcsep11_migrate.1.in @@ -0,0 +1,55 @@ +.TH PKCSEP11_MIGRATE 1 "Jan 2014" "@PACKAGE_VERSION@" "openCryptoki" +.SH NAME +pkcsep11_migrate \- utility to re-encrypt EP11 token keys to prepare a +change of master keys in the EP11 adapter + +.SH SYNOPSIS +\fBpkcep11_migrate\fP +[\fB-h\fP] +[\fB-slot\fP \fIslot-number\fP \fB-adapter\fP \fIadapter-ID\fP +\fB-domain\fP \fIdomain-ID\fP ] + +.SH DESCRIPTION +In case of a Master key change within an EP11 adapter all key objects that are +wrapped with this master key must be re-wrapped or re-encrypted. +The \fBpkcsep11_migrate\fP utility takes all EP11 token related key objects +that are wrapped with the EP11 adapter master key, decrypts each key object +with the current master key and encrypt it with the new master key. + +Notes: +.br +1. The new master key must be set and committed on the EP11 adapter via +Trusted Key Entry console (TKE) before using this utility. +.br +2. While using this tool no process using the EP11 token should be running. +.br +3. Before using this tool make a back-up of the token objects in ep11tok/TOK_OBJ/. +.br +4. After successfully execution of the migrate utility and before (re)starting + programs using the EP11 token the new master key must be activated using the TKE. + +.SH "COMMAND SUMMARY" +.IP "\fB-slot\fP \fIslot-number\fP" 10 +specifies the token slot of the EP11 token +.IP "\fB-adapter\fP \fIadapter-ID\fP" 10 +specifies an EP11 adapter ID. +(Refer to lszcrypt to get a list of installed crypto adapters. +The adapter ID will be the number xx in 'card\fBxx\fP' from the output.) +This value can be provided either in hexadecimal (e.g. 0x0A) or decimal (10) +notation. +.IP "\fB-domain\fP \fIdomain-ID\fP" 10 +specifies the usage domain for the EP11 adapter. (see /sys/bus/ap/ap_domain.) +This value can be provided either in hexadecimal (e.g. 0x0B) or decimal (11) +notation. +.IP "\fB-h\fP" 10 +show usage information + +.SH SEE ALSO +.PD 0 +.TP +\fBpkcsconf\fP(1), +.TP +\fBopencryptoki\fP(7), +.TP +\fBpkcsslotd\fP(8). +.PD diff --git a/man/man1/pkcsep11_session.1.in b/man/man1/pkcsep11_session.1.in new file mode 100644 index 0000000..6949e66 --- /dev/null +++ b/man/man1/pkcsep11_session.1.in @@ -0,0 +1,61 @@ +.TH PKCSEP11_SESSION 1 "Jan 2018" "@PACKAGE_VERSION@" "openCryptoki" +.SH NAME +pkcsep11_session \- manage EP11 sessions. + +.SH SYNOPSIS +\fBpkcep11_session\fP +[\fB-h\fP] +[\fBshow|logout|vhsmpin\fP \fB-slot\fP \fIslot-number\fP [\fB-id\fP \fIsession-ID\fP] +[\fB-pid\fP \fIprocess-ID\fP] [\fB-date\fP \fIyyyy/mm/dd\fP] [\fB-force\fP] ] + +.SH DESCRIPTION +Use pkcep11_session to list and logout leftover EP11 sessions. + +EP11 sessions are created and destroyed as a PKCS#11 session is logged +on and off, respectively. When an application terminates abnormally, without +logging out or closing the PKCS#11 session, the corresponding EP11 session +is not destroyed. + +When STRICT_MODE or VHSM_MODE is enabled in the EP11 configuration file, all +session-keys belong strictly to the PKCS#11 session or token that created it. +These PKCS#11 session keys expire when the session ends. +.br +.SH "COMMAND SUMMARY" +.IP "\fBshow\fP" 10 +displays all leftover EP11 sessions. Use the -session-ID, -pid or -date +options to filter the list of sessions. +.IP "\fBlogout\fP" 10 +logs out all leftover EP11 sessions. Use the -session-ID, -pid or -date +options to filter the list of sessions. +.IP "\fBvhsmpin\fP" 10 +sets the VHSM PIN used for the VHSM_MODE (virtual HSM). The VHSM PIN must +contain between 8 and 16 alphanumeric characters. +.br +\fBNote:\fP When changing the VHSM PIN, all existing keys stored as +token objects become unusable! + +.SH "OPTIONS" +.IP "\fB-slot\fP \fIslot-number\fP" 10 +specifies the slot of the EP11 token +.IP "\fB-force\fP" 10 +deletes a session even if logout fails on some adapters. +.IP "\fB-id\fP \fIsession-ID\fP" 10 +specifies the EP11 session ID. +.IP "\fB-pid\fP \fIprocess-ID\fP" 10 +specifies the process-ID (pid) for which to display or logout EP11 sessions. +.IP "\fB-date\fP \fIyyyy/mm/dd\fP" 10 +filters the EP11 sessions by the specified date. +Any EP11 session with a matching or earlier date are +displayed or logged out. +.IP "\fB-h\fP" 10 +show usage information + +.SH SEE ALSO +.PD 0 +.TP +\fBpkcsconf\fP(1), +.TP +\fBopencryptoki\fP(7), +.TP +\fBpkcsslotd\fP(8). +.PD diff --git a/man/man1/pkcsicsf.1.in b/man/man1/pkcsicsf.1.in new file mode 100644 index 0000000..962522b --- /dev/null +++ b/man/man1/pkcsicsf.1.in @@ -0,0 +1,76 @@ +.TH PKCSICSF 1 "April 2013" "@PACKAGE_VERSION@" "openCryptoki" +.SH NAME +pkcsicsf \- configuration utility for the ICSF token + +.SH SYNOPSIS +\fBpkcsicsf\fP +[\fB-h\fP] +[\fB-l|-a\fP \fItoken name\fP] +[\fB-b\fP \fIBINDDN\fP] +[\fB-c\fP \fIclient-cert-file\fP] +[\fB-C\fP \fICA-cert-file\fP] +[\fB-k\fP \fIprivatekey\fP] +[\fB-m\fP \fImechanism\fP] +[\fB-u\fP \fIURI\fP] + +.SH DESCRIPTION +The \fBpkcsicsf\fP utility lists available ICSF tokens and allows user +to add one specific ICSF token to opencryptoki. + +The ICSF token must be added first to opencryptoki. This creates an +entry in the opencryptoki.conf file for the ICSF token. It also creates + a \fItoken_name.conf\fP configuration file in the same directory as +the opencryptoki.conf file, containing ICSF specific information. +This information is read by the ICSF token. + +The ICSF token must bind and authenticate to an LDAP server. +The supported authentication mechanisms are simple and sasl. +One of these mechanisms must be entered when listing the available +ICSF tokens or when adding an ICSF token. Opencryptoki currently +supports adding only one ICSF token. + +The system admin can either allow the ldap calls to utilize existing +ldap configs, such as ldap.conf or .ldaprc for bind and +authentication information or set the bind and authentication +information within opencryptoki by using this utility and its options. +The information will then be placed in the \fItoken_name.conf\fP file +to be used in the ldap calls. When using simple authentication, +the user will be prompted for the racf password when listing +or adding a token. + +.SH "OPTIONS" +.IP "\fB-a\fP \fItoken name\fp" 10 +add the specified ICSF token to opencryptoki. +.IP "\fB-b\fP \fIBINDND\fp" 10 +the distinguish name to bind when using simple authentication +.IP "\fB-c\fP \fIclient-cert-file" 10 +the client certificate file when using SASL authentication +.IP "\fB-C\fP \fICA-cert-file\fp" 10 +the CA certificate file when using SASL authentication +.IP "\fB-h\fP" 10 +show usage information +.IP "\fB-k\fP \fIprivatekey\fP" 10 +the client private key file when using SASL authentication +.IP "\fB-m\fP \fImechanism\fp" 10 +the authentication mechanism to use when binding to the LDAP server +(this should be either \fBsimple\fP or \fBsasl\fP) +.IP "\fB-l\fP" 10 +list available ICSF tokens +.IP "\fB-h\fP" 10 +show usage information + +.SH "FILES" +.IP "/etc/opencryptoki/opencryptoki.conf" +the opencryptoki config file containing token configuration information +.IP "/etc/opencryptoki/\fItoken_name.conf\fP" +contains ICSF configuration information for the ICSF token + +.SH SEE ALSO +.PD 0 +.TP +\fBopencryptoki\fP(7), +.TP +\fBpkcsslotd\fP(8). +.TP +\fBpkcsconf\fP(8). +.PD diff --git a/man/man5/man5.mk b/man/man5/man5.mk new file mode 100644 index 0000000..438d81d --- /dev/null +++ b/man/man5/man5.mk @@ -0,0 +1,4 @@ +man5_MANS += man/man5/opencryptoki.conf.5 + +EXTRA_DIST += $(man5_MANS) +CLEANFILES += $(man5_MANS) diff --git a/man/man5/opencryptoki.conf.5.in b/man/man5/opencryptoki.conf.5.in new file mode 100644 index 0000000..71218f7 --- /dev/null +++ b/man/man5/opencryptoki.conf.5.in @@ -0,0 +1,83 @@ +.TH OPENCRYPTOKI.CONF 5 "September 2012" "@PACKAGE_VERSION@" "openCryptoki" +.SH NAME +opencryptoki.conf \- Configuration file for pkcsslotd. + +.SH DESCRIPTION +pkcsslotd uses a configuration file at /etc/opencryptoki/opencryptoki.conf + +This is a text file that contains information used to configure +pkcs#11 slots. At startup, the pkcsslotd daemon parses this file to +determine which slots will be made available. + +.SH SYNTAX +This file is made up of slot descriptions. Each slot description +is composed of a slot number, brackets and key-value pairs. + + slot number + { + key = value + ... + } + +More than one key-value pair may be used within a slot description. + +A key-value pair is composed of, +.B keyword = value. + +The following keywords are valid: + +.TP +.BR description +A Description of the slot. PKCS#11v2.20 defined this as a 64-byte max +character-string. +.TP +.BR stdll +This keyword is used to define the name of the stdll or token library that +will be used for this slot. The stdll is an available token library in +opencryptoki. +.TP +.BR manufacturer +This keyword is used to name the ID of the slot manufacturer. PKCS#11v2.20 +defines this as a 32 byte long string. +.TP +.BR hwversion +Version number of the slot's hardware, if any. The version number is composed +of a major version number (the integer portion of the version) and a +minor version number (the hundredths portion of the version). +For example, version 1.2, major = 1, minor = 2 +.TP +.BR firmwareversion +Version number of the slot's firmware, if any. The version number is composed +of a major version number (the integer portion of the version) and a +minor version number (the hundredths portion of the version). +.TP +.BR confname +If the slot is associated with a token that has its own configuration file, +this option identifies the name of that configuration file. +For example, confname=ep11tok.conf +.TP +.BR tokname +If a token want to have its own token directory name that is different from the +default name, especially if multiple tokens of the same type are configured, +this option defines the name of the token individual directory. +For example, tokname=ep11tok01 + +Note: This key-value pair is optional: If only one token per token type is used, +you don't need that entry. In that case the default directory name is used. +.TP +.BR tokversion +Version number of the slot's token of the form .. + +.SH Notes +The pound sign ('#') is used to indicate a comment. +Both the comment character and any text after it, up to the end of the line, +are ignored. The comment character cannot be used inside the brackets of +slot descriptions, as this will cause a syntax error. + +.SH "SEE ALSO" +.PD 0 +.TP +\fBopencryptoki\fP(7), +.TP +\fBpkcsslotd\fP(8), +.PD diff --git a/man/man7/man7.mk b/man/man7/man7.mk new file mode 100644 index 0000000..84abeb4 --- /dev/null +++ b/man/man7/man7.mk @@ -0,0 +1,4 @@ +man7_MANS += man/man7/opencryptoki.7 + +EXTRA_DIST += $(man7_MANS) +CLEANFILES += $(man7_MANS) diff --git a/man/man7/opencryptoki.7.in b/man/man7/opencryptoki.7.in new file mode 100644 index 0000000..bf5a65e --- /dev/null +++ b/man/man7/opencryptoki.7.in @@ -0,0 +1,35 @@ +.TH OPENCRYPTOKI 7 "May 2007" "@PACKAGE_VERSION@" "openCryptoki" +.SH NAME +openCryptoki \- A PKCS#11 implementation. + +.SH DESCRIPTION +\fBopenCryptoki\fP is an implementation of the PKCS#11 API standard. It +provides an interface to the functions of underlying cryptographic +tokens, which may be implemented via software or hardware. The PKCS#11 +specification has been released by RSA Labs. More information on PKCS#11 +can be found on the RSA labs website: http://www.rsa.com/rsalabs. + +To use openCryptoki, run the \fIpkcsslotd\fP daemon. The daemon will +read the \fIopencryptoki.conf\fP file to collect information about the +tokens and their slots. + +Use the \fIpkcsconf\fP utility to further configure openCryptoki once the +daemon is running. + +.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 +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, and execute arbitrary code with the +privileges of other openCryptoki users. + +.SH "SEE ALSO" +.PD 0 +.TP +\fBpkcsslotd\fP(8), +.TP +\fBpkcsconf\fP(1), +.TP +\fBopencryptoki.conf\fP(5). +.PD diff --git a/man/man8/man8.mk b/man/man8/man8.mk new file mode 100644 index 0000000..7380342 --- /dev/null +++ b/man/man8/man8.mk @@ -0,0 +1,4 @@ +man8_MANS += man/man8/pkcsslotd.8 + +EXTRA_DIST += $(man8_MANS) +CLEANFILES += $(man8_MANS) diff --git a/man/man8/pkcsslotd.8.in b/man/man8/pkcsslotd.8.in new file mode 100644 index 0000000..db113e9 --- /dev/null +++ b/man/man8/pkcsslotd.8.in @@ -0,0 +1,35 @@ +.TH PKCSSLOTD 8 "May 2007" "@PACKAGE_VERSION@" "openCryptoki" +.SH NAME +pkcsslotd - shared memory manager for opencryptoki + +.SH DESCRIPTION +The \fBpkcsslotd\fP daemon manages PKCS#11 objects between +PKCS#11-enabled applications. When 2 or more processes are accessing +the same cryptographic token, the daemon is notified and updates +each application when the token's objects change. + +.SH NOTES +Only one instance of the pkcsslotd daemon should be running on any +given host. If a prior instance of pkcsslotd did not shut down +cleanly, then it may leave an allocated shared memory segment on +the system. The allocated memory segment can be identified by its +key and can be safely removed once the daemon is stopped with the +ipcrm command, such as: + +\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 +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. + +.SH "SEE ALSO" +.PD 0 +.TP +\fBopencryptoki\fP(7), +.TP +\fBopencryptoki.conf\fP(5), +.TP +\fBpkcsconf\fP(1), +.PD diff --git a/misc/mech_list.c b/misc/mech_list.c new file mode 100644 index 0000000..ce65ee3 --- /dev/null +++ b/misc/mech_list.c @@ -0,0 +1,161 @@ +/* + * 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 + */ + +/** + * This is an example of how you might convert your library's internal + * mechanism descriptors into PKCS#11-compatible descriptors while + * generating a mechanism list for openCryptoki. + */ + +#include "mech_types.h" + +#ifndef NULL +#define NULL 0 +#endif + +/** + * Bogus internal data descriptors for various mechanisms. + */ +#define CUSTOM_MECH_TDES 1 +#define CUSTOM_MECH_BLOWFISH 2 +#define CUSTOM_MECH_RIPEMD160 3 +#define CUSTOM_MECH_DSA 4 + +/** + * An example of a library's way of representing a mechanism. + */ +struct custom_mech_descriptor { + int mech_type; + int min_key_size; + int max_key_size; + int is_hw_accelerated; + int support_encrypt; + int support_decrypt; + int support_digest; + int support_wrap; + int support_unwrap; + int support_sign; + int support_verify; +}; + +/** + * Something like this should actually be filled in by querying the + * driver for what is available; if the library supports software + * fallback, then the CKF_HW flag should not be set so openCryptoki is + * aware of what really is hardware accelerated and what is not. + */ +struct custom_mech_descriptor library_specific_mechs[] = { + {CUSTOM_MECH_TDES, 24, 24, 1, 1, 1, 0, 1, 1, 0, 0}, + {CUSTOM_MECH_BLOWFISH, 16, 16, 1, 1, 1, 0, 1, 1, 0, 0}, + {CUSTOM_MECH_RIPEMD160, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, + {CUSTOM_MECH_DSA, 512, 4096, 1, 0, 0, 0, 0, 0, 1, 1} +}; +#define CUSTOM_MECH_ARRAY_SIZE 4 + +/** + * Here is an example of how you might map your driver's type + * descriptors to the PKCS#11 type descriptors + */ +struct mech_type_mapping { + int internal_mech_type; + CK_MECHANISM_TYPE pkcs11_mech_type; +}; + +/** + * The mapping from the internal driver type to the PKCS#11 type. + */ +struct mech_type_mapping mech_type_map[] = { + {CUSTOM_MECH_TDES, CKM_DES3_CBC}, + {CUSTOM_MECH_BLOWFISH, CKM_VENDOR_DEFINED}, + {CUSTOM_MECH_RIPEMD160, CKM_RIPEMD160}, + {CUSTOM_MECH_DSA, CKM_DSA} +}; +#define MECH_TYPE_MAP_SIZE 4 + +static CK_MECHANISM_TYPE pkcs11_mech_type_for_internal_type(int internal_type) +{ + int i = 0; + CK_MECHANISM_TYPE pkcs11_type = CKM_VENDOR_DEFINED; + while (i < MECH_TYPE_MAP_SIZE) { + if (mech_type_map[i].internal_mech_type == internal_type) { + pkcs11_type = mech_type_map[i].pkcs11_mech_type; + break; + } + i++; + } + return pkcs11_type; +} + +/** + * Example method that converts a library's internal mechanism + * descriptor into a PKCS#11 mechanism descriptor. Yours may look very + * different from this one... + */ +static void convert_internal_element_to_pkcs11_method_element( + MECH_LIST_ELEMENT *element, + struct custom_mech_descriptor *internal_mech) +{ + element->mech_type = + pkcs11_mech_type_for_internal_type(internal_mech->mech_type); + element->mech_info.ulMinKeySize = internal_mech->min_key_size; + element->mech_info.ulMaxKeySize = internal_mech->max_key_size; + element->mech_info.flags = 0; + /* Partial example list of flags that could be set */ + if (internal_mech->is_hw_accelerated) { + element->mech_info.flags |= CKF_HW; + } + if (internal_mech->support_encrypt) { + element->mech_info.flags |= CKF_ENCRYPT; + } + if (internal_mech->support_decrypt) { + element->mech_info.flags |= CKF_DECRYPT; + } + if (internal_mech->support_digest) { + element->mech_info.flags |= CKF_DIGEST; + } + if (internal_mech->support_wrap) { + element->mech_info.flags |= CKF_WRAP; + } + if (internal_mech->support_unwrap) { + element->mech_info.flags |= CKF_UNWRAP; + } + if (internal_mech->support_sign) { + element->mech_info.flags |= CKF_SIGN; + } + if (internal_mech->support_verify) { + element->mech_info.flags |= CKF_VERIFY; + } + /* ... */ +} + +/** + * Generates a list of supported mechanisms. This is the function that + * openCryptoki will be calling directly with a pointer to a + * placeholder mech_list struct. + * + * @param head Pointer to placeholder mech_list struct; this function + * fills in the list by tagging on newly malloc'd + * mech_list structs off of this struct. + */ +void generate_pkcs11_mech_list(struct mech_list *head) +{ + struct mech_list *item; + int i = 0; + item = head; + while (i < CUSTOM_MECH_ARRAY_SIZE) { + item->next = malloc(sizeof(struct mech_list)); + item = item->next; + convert_internal_element_to_pkcs11_method_element( + &item->element, &library_specific_mechs[i]); + i++; + } + item->next = NULL; + return; +} diff --git a/misc/mech_types.h b/misc/mech_types.h new file mode 100644 index 0000000..bf83f97 --- /dev/null +++ b/misc/mech_types.h @@ -0,0 +1,344 @@ +/* + * 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 + */ + +#ifndef _MECH_LIST_TYPES_H +#define _MECH_LIST_TYPES_H + + +/** + * These defines are copied over from the pkcs11types.h file found in + * the openCryptoki package. + */ +/* An unsigned value, at least 32 bits long */ +typedef unsigned long int CK_ULONG; + +/* A signed value, the same size as a CK_ULONG */ +/* CK_LONG is new for v2.0 */ +typedef long int CK_LONG; + +/* At least 32 bits; each bit is a Boolean flag */ +typedef CK_ULONG CK_FLAGS; + +/* CK_MECHANISM_TYPE is a value that identifies a mechanism + * type */ +typedef CK_ULONG CK_MECHANISM_TYPE; + +/* The following mechanism types are defined: */ +#define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000 +#define CKM_RSA_PKCS 0x00000001 +#define CKM_RSA_9796 0x00000002 +#define CKM_RSA_X_509 0x00000003 + +/* CKM_MD2_RSA_PKCS, CKM_MD5_RSA_PKCS, and CKM_SHA1_RSA_PKCS + * are new for v2.0. They are mechanisms which hash and sign */ +#define CKM_MD2_RSA_PKCS 0x00000004 +#define CKM_MD5_RSA_PKCS 0x00000005 +#define CKM_SHA1_RSA_PKCS 0x00000006 +/* The following are new for v2.11: */ +#define CKM_RIPEMD128_RSA_PKCS 0x00000007 +#define CKM_RIPEMD160_RSA_PKCS 0x00000008 +#define CKM_RSA_PKCS_OAEP 0x00000009 +#define CKM_RSA_X9_31_KEY_PAIR_GEN 0x0000000A +#define CKM_RSA_X9_31 0x0000000B +#define CKM_SHA1_RSA_X9_31 0x0000000C +#define CKM_RSA_PKCS_PSS 0x0000000D +#define CKM_SHA1_RSA_PKCS_PSS 0x0000000E + +#define CKM_DSA_KEY_PAIR_GEN 0x00000010 +#define CKM_DSA 0x00000011 +#define CKM_DSA_SHA1 0x00000012 +#define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020 +#define CKM_DH_PKCS_DERIVE 0x00000021 +/* The following are new for v2.11 */ +#define CKM_X9_42_DH_KEY_PAIR_GEN 0x00000030 +#define CKM_X9_42_DH_DERIVE 0x00000031 +#define CKM_X9_42_DH_HYBRID_DERIVE 0x00000032 +#define CKM_X9_42_MQV_DERIVE 0x00000033 + +#define CKM_RC2_KEY_GEN 0x00000100 +#define CKM_RC2_ECB 0x00000101 +#define CKM_RC2_CBC 0x00000102 +#define CKM_RC2_MAC 0x00000103 + +/* CKM_RC2_MAC_GENERAL and CKM_RC2_CBC_PAD are new for v2.0 */ +#define CKM_RC2_MAC_GENERAL 0x00000104 +#define CKM_RC2_CBC_PAD 0x00000105 + +#define CKM_RC4_KEY_GEN 0x00000110 +#define CKM_RC4 0x00000111 +#define CKM_DES_KEY_GEN 0x00000120 +#define CKM_DES_ECB 0x00000121 +#define CKM_DES_CBC 0x00000122 +#define CKM_DES_MAC 0x00000123 + +/* CKM_DES_MAC_GENERAL and CKM_DES_CBC_PAD are new for v2.0 */ +#define CKM_DES_MAC_GENERAL 0x00000124 +#define CKM_DES_CBC_PAD 0x00000125 + +#define CKM_DES2_KEY_GEN 0x00000130 +#define CKM_DES3_KEY_GEN 0x00000131 +#define CKM_DES3_ECB 0x00000132 +#define CKM_DES3_CBC 0x00000133 +#define CKM_DES3_MAC 0x00000134 + +/* CKM_DES3_MAC_GENERAL, CKM_DES3_CBC_PAD, CKM_CDMF_KEY_GEN, + * CKM_CDMF_ECB, CKM_CDMF_CBC, CKM_CDMF_MAC, + * CKM_CDMF_MAC_GENERAL, and CKM_CDMF_CBC_PAD are new for v2.0 */ +#define CKM_DES3_MAC_GENERAL 0x00000135 +#define CKM_DES3_CBC_PAD 0x00000136 +#define CKM_DES3_CMAC_GENERAL 0x00000137 +#define CKM_DES3_CMAC 0x00000138 +#define CKM_CDMF_KEY_GEN 0x00000140 +#define CKM_CDMF_ECB 0x00000141 +#define CKM_CDMF_CBC 0x00000142 +#define CKM_CDMF_MAC 0x00000143 +#define CKM_CDMF_MAC_GENERAL 0x00000144 +#define CKM_CDMF_CBC_PAD 0x00000145 + +#define CKM_MD2 0x00000200 + +/* CKM_MD2_HMAC and CKM_MD2_HMAC_GENERAL are new for v2.0 */ +#define CKM_MD2_HMAC 0x00000201 +#define CKM_MD2_HMAC_GENERAL 0x00000202 + +#define CKM_MD5 0x00000210 + +/* CKM_MD5_HMAC and CKM_MD5_HMAC_GENERAL are new for v2.0 */ +#define CKM_MD5_HMAC 0x00000211 +#define CKM_MD5_HMAC_GENERAL 0x00000212 + +#define CKM_SHA_1 0x00000220 + +/* CKM_SHA_1_HMAC and CKM_SHA_1_HMAC_GENERAL are new for v2.0 */ +#define CKM_SHA_1_HMAC 0x00000221 +#define CKM_SHA_1_HMAC_GENERAL 0x00000222 + +/* The following are new for v2.11 */ +#define CKM_RIPEMD128 0x00000230 +#define CKM_RIPEMD128_HMAC 0x00000231 +#define CKM_RIPEMD128_HMAC_GENERAL 0x00000232 +#define CKM_RIPEMD160 0x00000240 +#define CKM_RIPEMD160_HMAC 0x00000241 +#define CKM_RIPEMD160_HMAC_GENERAL 0x00000242 + +/* All of the following mechanisms are new for v2.0 */ +/* Note that CAST128 and CAST5 are the same algorithm */ +#define CKM_CAST_KEY_GEN 0x00000300 +#define CKM_CAST_ECB 0x00000301 +#define CKM_CAST_CBC 0x00000302 +#define CKM_CAST_MAC 0x00000303 +#define CKM_CAST_MAC_GENERAL 0x00000304 +#define CKM_CAST_CBC_PAD 0x00000305 +#define CKM_CAST3_KEY_GEN 0x00000310 +#define CKM_CAST3_ECB 0x00000311 +#define CKM_CAST3_CBC 0x00000312 +#define CKM_CAST3_MAC 0x00000313 +#define CKM_CAST3_MAC_GENERAL 0x00000314 +#define CKM_CAST3_CBC_PAD 0x00000315 +#define CKM_CAST5_KEY_GEN 0x00000320 +#define CKM_CAST128_KEY_GEN 0x00000320 +#define CKM_CAST5_ECB 0x00000321 +#define CKM_CAST128_ECB 0x00000321 +#define CKM_CAST5_CBC 0x00000322 +#define CKM_CAST128_CBC 0x00000322 +#define CKM_CAST5_MAC 0x00000323 +#define CKM_CAST128_MAC 0x00000323 +#define CKM_CAST5_MAC_GENERAL 0x00000324 +#define CKM_CAST128_MAC_GENERAL 0x00000324 +#define CKM_CAST5_CBC_PAD 0x00000325 +#define CKM_CAST128_CBC_PAD 0x00000325 +#define CKM_RC5_KEY_GEN 0x00000330 +#define CKM_RC5_ECB 0x00000331 +#define CKM_RC5_CBC 0x00000332 +#define CKM_RC5_MAC 0x00000333 +#define CKM_RC5_MAC_GENERAL 0x00000334 +#define CKM_RC5_CBC_PAD 0x00000335 +#define CKM_IDEA_KEY_GEN 0x00000340 +#define CKM_IDEA_ECB 0x00000341 +#define CKM_IDEA_CBC 0x00000342 +#define CKM_IDEA_MAC 0x00000343 +#define CKM_IDEA_MAC_GENERAL 0x00000344 +#define CKM_IDEA_CBC_PAD 0x00000345 +#define CKM_GENERIC_SECRET_KEY_GEN 0x00000350 +#define CKM_CONCATENATE_BASE_AND_KEY 0x00000360 +#define CKM_CONCATENATE_BASE_AND_DATA 0x00000362 +#define CKM_CONCATENATE_DATA_AND_BASE 0x00000363 +#define CKM_XOR_BASE_AND_DATA 0x00000364 +#define CKM_EXTRACT_KEY_FROM_KEY 0x00000365 +#define CKM_SSL3_PRE_MASTER_KEY_GEN 0x00000370 +#define CKM_SSL3_MASTER_KEY_DERIVE 0x00000371 +#define CKM_SSL3_KEY_AND_MAC_DERIVE 0x00000372 +/* The following are new for v2.11 */ +#define CKM_SSL3_MASTER_KEY_DERIVE_DH 0x00000373 +#define CKM_TLS_PRE_MASTER_KEY_GEN 0x00000374 +#define CKM_TLS_MASTER_KEY_DERIVE 0x00000375 +#define CKM_TLS_KEY_AND_MAC_DERIVE 0x00000376 +#define CKM_TLS_MASTER_KEY_DERIVE_DH 0x00000377 + +#define CKM_SSL3_MD5_MAC 0x00000380 +#define CKM_SSL3_SHA1_MAC 0x00000381 +#define CKM_MD5_KEY_DERIVATION 0x00000390 +#define CKM_MD2_KEY_DERIVATION 0x00000391 +#define CKM_SHA1_KEY_DERIVATION 0x00000392 +#define CKM_PBE_MD2_DES_CBC 0x000003A0 +#define CKM_PBE_MD5_DES_CBC 0x000003A1 +#define CKM_PBE_MD5_CAST_CBC 0x000003A2 +#define CKM_PBE_MD5_CAST3_CBC 0x000003A3 +#define CKM_PBE_MD5_CAST5_CBC 0x000003A4 +#define CKM_PBE_MD5_CAST128_CBC 0x000003A4 +#define CKM_PBE_SHA1_CAST5_CBC 0x000003A5 +#define CKM_PBE_SHA1_CAST128_CBC 0x000003A5 +#define CKM_PBE_SHA1_RC4_128 0x000003A6 +#define CKM_PBE_SHA1_RC4_40 0x000003A7 +#define CKM_PBE_SHA1_DES3_EDE_CBC 0x000003A8 +#define CKM_PBE_SHA1_DES2_EDE_CBC 0x000003A9 +#define CKM_PBE_SHA1_RC2_128_CBC 0x000003AA +#define CKM_PBE_SHA1_RC2_40_CBC 0x000003AB +/* CKM_PKCS5_PBKD2 is new for v2.11 */ +#define CKM_PKCS5_PBKD2 0x000003B0 +#define CKM_PBA_SHA1_WITH_SHA1_HMAC 0x000003C0 +#define CKM_KEY_WRAP_LYNKS 0x00000400 +#define CKM_KEY_WRAP_SET_OAEP 0x00000401 + +/* Fortezza mechanisms */ +#define CKM_SKIPJACK_KEY_GEN 0x00001000 +#define CKM_SKIPJACK_ECB64 0x00001001 +#define CKM_SKIPJACK_CBC64 0x00001002 +#define CKM_SKIPJACK_OFB64 0x00001003 +#define CKM_SKIPJACK_CFB64 0x00001004 +#define CKM_SKIPJACK_CFB32 0x00001005 +#define CKM_SKIPJACK_CFB16 0x00001006 +#define CKM_SKIPJACK_CFB8 0x00001007 +#define CKM_SKIPJACK_WRAP 0x00001008 +#define CKM_SKIPJACK_PRIVATE_WRAP 0x00001009 +#define CKM_SKIPJACK_RELAYX 0x0000100a +#define CKM_KEA_KEY_PAIR_GEN 0x00001010 +#define CKM_KEA_KEY_DERIVE 0x00001011 +#define CKM_FORTEZZA_TIMESTAMP 0x00001020 +#define CKM_BATON_KEY_GEN 0x00001030 +#define CKM_BATON_ECB128 0x00001031 +#define CKM_BATON_ECB96 0x00001032 +#define CKM_BATON_CBC128 0x00001033 +#define CKM_BATON_COUNTER 0x00001034 +#define CKM_BATON_SHUFFLE 0x00001035 +#define CKM_BATON_WRAP 0x00001036 + +/* CKM_ECDSA_KEY_PAIR_GEN is deprecated in v2.11, + * CKM_EC_KEY_PAIR_GEN is preferred. */ +#define CKM_ECDSA_KEY_PAIR_GEN 0x00001040 +#define CKM_EC_KEY_PAIR_GEN 0x00001040 +#define CKM_ECDSA 0x00001041 +#define CKM_ECDSA_SHA1 0x00001042 +/* The following are new for v2.3 */ +#define CKM_ECDSA_SHA224 0x00001043 +#define CKM_ECDSA_SHA256 0x00001044 +#define CKM_ECDSA_SHA384 0x00001045 +#define CKM_ECDSA_SHA512 0x00001046 +/* The following are new for v2.11 */ +#define CKM_ECDH1_DERIVE 0x00001050 +#define CKM_ECDH1_COFACTOR_DERIVE 0x00001051 +#define CKM_ECMQV_DERIVE 0x00001052 + +#define CKM_JUNIPER_KEY_GEN 0x00001060 +#define CKM_JUNIPER_ECB128 0x00001061 +#define CKM_JUNIPER_CBC128 0x00001062 +#define CKM_JUNIPER_COUNTER 0x00001063 +#define CKM_JUNIPER_SHUFFLE 0x00001064 +#define CKM_JUNIPER_WRAP 0x00001065 +#define CKM_FASTHASH 0x00001070 +/* The following are new for v2.11 */ +#define CKM_AES_KEY_GEN 0x00001080 +#define CKM_AES_ECB 0x00001081 +#define CKM_AES_CBC 0x00001082 +#define CKM_AES_MAC 0x00001083 +#define CKM_AES_MAC_GENERAL 0x00001084 +#define CKM_AES_CBC_PAD 0x00001085 +#define CKM_AES_CMAC_GENERAL 0x00001089 +#define CKM_AES_CMAC 0x0000108A +#define CKM_DSA_PARAMETER_GEN 0x00002000 +#define CKM_DH_PKCS_PARAMETER_GEN 0x00002001 +#define CKM_X9_42_DH_PARAMETER_GEN 0x00002002 + +#define CKM_VENDOR_DEFINED 0x80000000 + +#define CK_PTR * +typedef void CK_PTR CK_VOID_PTR; +typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR; + +/* CK_MECHANISM is a structure that specifies a particular + * mechanism */ +typedef struct CK_MECHANISM { + CK_MECHANISM_TYPE mechanism; + CK_VOID_PTR pParameter; + CK_ULONG ulParameterLen; /* in bytes */ +} CK_MECHANISM; + +typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR; + +/* CK_MECHANISM_INFO provides information about a particular + * mechanism */ +typedef struct CK_MECHANISM_INFO { + CK_ULONG ulMinKeySize; + CK_ULONG ulMaxKeySize; + CK_FLAGS flags; +} CK_MECHANISM_INFO; + +/* The flags are defined as follows: + * Bit Flag Mask Meaning */ +#define CKF_HW 0x00000001 /* performed by HW */ + +/* The flags CKF_ENCRYPT, CKF_DECRYPT, CKF_DIGEST, CKF_SIGN, + * CKG_SIGN_RECOVER, CKF_VERIFY, CKF_VERIFY_RECOVER, + * CKF_GENERATE, CKF_GENERATE_KEY_PAIR, CKF_WRAP, CKF_UNWRAP, + * and CKF_DERIVE are new for v2.0. They specify whether or not + * a mechanism can be used for a particular task */ +#define CKF_ENCRYPT 0x00000100 +#define CKF_DECRYPT 0x00000200 +#define CKF_DIGEST 0x00000400 +#define CKF_SIGN 0x00000800 +#define CKF_SIGN_RECOVER 0x00001000 +#define CKF_VERIFY 0x00002000 +#define CKF_VERIFY_RECOVER 0x00004000 +#define CKF_GENERATE 0x00008000 +#define CKF_GENERATE_KEY_PAIR 0x00010000 +#define CKF_WRAP 0x00020000 +#define CKF_UNWRAP 0x00040000 +#define CKF_DERIVE 0x00080000 +/* The following are new for v2.11 */ +#define CKF_EC_F_P 0x00100000 +#define CKF_EC_F_2M 0x00200000 +#define CKF_EC_ECPARAMETERS 0x00400000 +#define CKF_EC_NAMEDCURVE 0x00800000 +#define CKF_EC_UNCOMPRESS 0x01000000 +#define CKF_EC_COMPRESS 0x02000000 + +#define CKF_EXTENSION 0x80000000 /* FALSE for 2.01 */ + +typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR; + +#define CKR_MECHANISM_INVALID 0x00000070 +#define CKR_MECHANISM_PARAM_INVALID 0x00000071 + + +/* From common/host_defs.h in openCryptoki */ +typedef struct _MECH_LIST_ELEMENT +{ + CK_MECHANISM_TYPE mech_type; + CK_MECHANISM_INFO mech_info; +} MECH_LIST_ELEMENT; + +struct mech_list; + +struct mech_list { + struct mech_list *next; + MECH_LIST_ELEMENT element; +}; + +#endif diff --git a/misc/migrate_from_2.1_to_2.2.sh b/misc/migrate_from_2.1_to_2.2.sh new file mode 100755 index 0000000..70ed618 --- /dev/null +++ b/misc/migrate_from_2.1_to_2.2.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# +# COPYRIGHT (c) International Business Machines Corp. 2006-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 +# + +# This script should be run after installing openCryptoki version 2.2.x on a +# machine where openCryptoki version 2.1.x has already been installed. + +# Make sure that no copies of pkcsslotd are running +ps -ef | grep pkcsslotd | grep sbin &> /dev/null +RES=$? +if [ $RES = 0 ]; then + killall pkcsslotd +fi + +# Copy files from /etc/pkcs11/ to /var/lib/opencryptoki/ +if [ -e "/etc/pkcs11" ]; then + mkdir -p /var/lib/opencryptoki + cp -aR /etc/pkcs11/* /var/lib/opencryptoki/ + cp -a /etc/pkcs11/.slotpid /var/lib/opencryptoki/ +fi + +# Run startup script +/usr/sbin/pkcs11_startup + +# Restart pkcsslotd if it was running before this script was run +if [ $RES = 0 ]; then + /usr/sbin/pkcsslotd +fi diff --git a/misc/misc.mk b/misc/misc.mk new file mode 100644 index 0000000..1273e2a --- /dev/null +++ b/misc/misc.mk @@ -0,0 +1,52 @@ +TOKENS = swtok + +if ENABLE_ICATOK +TOKENS += lite +endif + +if ENABLE_EP11TOK +TOKENS += ep11tok +endif + +if ENABLE_TPMTOK +TOKENS += tpm +endif + +if ENABLE_CCATOK +TOKENS += ccatok +endif + +if ENABLE_ICSFTOK +TOKENS += icsf +endif + +EXTRA_DIST += \ + misc/pkcsslotd.in misc/pkcsslotd.service.in misc/tmpfiles.conf.in + +if ENABLE_DAEMON +if ENABLE_SYSTEMD +servicedir = $(unitdir) +service_DATA = misc/pkcsslotd.service misc/tmpfiles.conf + +CLEANFILES += misc/pkcsslotd.service misc/tmpfiles.conf + +${srcdir}/misc/pkcsslotd.service: ${srcdir}/misc/pkcsslotd.service.in + @SED@ -e s!\@sbindir\@!"@sbindir@"!g < $< > $@-t + mv $@-t $@ + +${srcdir}/misc/tmpfiles.conf: ${srcdir}/misc/tmpfiles.conf.in + @SED@ -e s!\@lockdir\@!$(lockdir)!g < $< > $@-t + $(foreach TOK,$(TOKENS),\ + echo "D $(lockdir)/$(TOK) 0770 root pkcs11 -" >> $@-t;) + mv $@-t $@ +else +initddir = $(sysconfdir)/rc.d/init.d +initd_SCRIPTS = misc/pkcsslotd + +CLEANFILES += misc/pkcsslotd +${srcdir}/misc/pkcsslotd: ${srcdir}/misc/pkcsslotd.in + @SED@ -e s!\@sbindir\@!"@sbindir@"!g < $< > $@-t + @CHMOD@ a+x $@-t + mv $@-t $@ +endif +endif diff --git a/misc/opencryptoki.gdb b/misc/opencryptoki.gdb new file mode 100644 index 0000000..339d45f --- /dev/null +++ b/misc/opencryptoki.gdb @@ -0,0 +1,185 @@ +# +# COPYRIGHT (c) International Business Machines Corp. 2011-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 +# +# openCryptoki debugging helper script +# +# Kent Yoder +# April 29, 2011 +# +# Functions: +# +# ock_dump_obj_template +# ock_dump_object_map +# ock_dump_sess_btree +# ock_dump_sess_obj_btree +# ock_dump_priv_tok_obj_btree +# ock_dump_publ_tok_obj_btree +# + +set $OBJECT_MAP = 1 +set $OBJECT = 2 +set $SESSION = 3 + +# +# ock_dump_obj_template +# +# Dump an OBJECT's template of attributes +# +define ock_dump_obj_template + set $obj = ($arg0) + set $node = $obj->template->attribute_list + + while ($node) + print *(CK_ATTRIBUTE *)($node->data) + set $node = $node->next + end +end + +define __ock_print_node_type + if $arg1 == $OBJECT_MAP + print *((OBJECT_MAP *)($arg0)->value) + end + if $arg1 == $OBJECT + print *((OBJECT *)($arg0)->value) + end + if $arg1 == $SESSION + print *((SESSION *)($arg0)->value) + end +end + +define __ock_print_node + set $n = ($arg0) + set $loc = ($arg1) + + while ($loc > 1) + if ($loc & 1) + set $n = $n->right + else + set $n = $n->left + end + + set $loc = $loc >> 1 + printf " " + end + + if ($n->flags & 1) + printf "`- %d: (deleted node)\n", $arg1 + else + printf "`- %d: ", $arg1 + __ock_print_node_type $n $arg2 + end +end + +define __ock_dump_tree + set $size = ($arg0).size + 1 + set $i = 1 + + printf "tree: size %d, free nodes: %d\n", $arg0.size, ($arg0).free_nodes + while ($i < $size) + __ock_print_node ($arg0).top $i ($arg1) + set $i = $i + 1 + end +end + +define ock_dump_object_map + __ock_dump_tree object_map_btree $OBJECT_MAP +end + +define ock_dump_sess_btree + __ock_dump_tree sess_btree $SESSION +end + +define ock_dump_sess_obj_btree + __ock_dump_tree sess_obj_btree $OBJECT +end + +define ock_dump_priv_tok_obj_btree + __ock_dump_tree priv_token_obj_btree $OBJECT +end + +define ock_dump_publ_tok_obj_btree + __ock_dump_tree publ_token_obj_btree $OBJECT +end + +define dump_ec_key_token + set $tok = ($arg0) + printf "----------------------- HEADER SECTION -----------------------\n" + printf "Token ID: 0x%02X\n", $tok + printf "Token Version Number: 0x%02X\n", $tok[1] + printf "Length in bytes of token structure: 0x%02X%02X\n", $tok[2], $tok[3] + printf "----------------------- PRIVATE SECTION -----------------------\n" + set $priv = $tok[8] + printf "Section ID: 0x%02X\n", $priv + printf "\tX'20': ECC private key\n" + printf "Section version number: 0x%02X\n", $tok[9] + printf "Section len: 0x%02X%02X\n", $tok[10], $tok[11] + printf "Wrapping method: 0x%02X\n", $tok[12] + printf "\tX'00': Section is unencrypted (clear), X'01': AESKW, X'02: CBC\n" + printf "Hash method used for wrapping: 0x%02X\n", $tok[13] + printf "\tX'01': SHA-224, X'02': SHA-256\n" + printf "Key usage: 0x%02X\n", $tok[16] + printf "\tX'C0': Key agreement, X'80': Both signature gen & key agreement\n" + printf "\tX'00': Signature generation only, X'02': Translate allowed\n" + printf "Curve type: 0x%02X\n", $tok[17] + printf "\tX'00': Prime curve, X'01': Brainpool curve\n" + printf "Key format and security flag: 0x%02X\n", $tok[18] + printf "\tEncrypted internal ECC: X'08', " + printf "Unencrypted external ECC: X'40', " + printf "Encrypted external ECC: X'42'\n" + printf "Length of p in bits: 0x%02X%02X\n", $tok[20], $tok[21] + printf "\tX'00A0': Brainpool P-160\n" + printf "\tX'00C0': Prime P-192, Brainpol P-192\n" + printf "\tX'00E0': Brainpool P-224, Prime P-224\n" + printf "\tX'0100': Brainpool P-256, Prime P-256\n" + printf "\tX'0140': Brainpool P-320\n" + printf "\tX'0180': Prime P-384, Brainpool P-384\n" + printf "\tX'0200': Brainpool P-512\n" + printf "\tX'0209': Prime P-521\n" + printf "IBM associated data length in bytes: 0x%02X%02X\n", $tok[22], $tok[23] + printf "Master key verification pattern:\n\t" + set $i = 0 + while ($i < 8) + printf "%02X", $tok[24+$i] + set $i = $i+1 + end + printf "\n" + + printf "Associated data length: 0x%02X%02X\n", $tok[80], $tok[81] + printf "Length of formatted section in bytes: 0x%02X%02X\n", $tok[82], $tok[83] + printf "-------- Begin formatted section (include d) data --------\n" + set $dlen = $tok[83] + set $assclen = $tok[81] + set $i = 0 + while ($i < $dlen) + printf "%02X", $tok[84+$assclen+$i] + set $i = $i+1 + end + printf "\n-------- End formatted section data --------\n" + printf "----------------------- PUBLIC SECTION -----------------------\n" + set $privlen = $tok[11] + set $puboffset = $privlen+8 + printf "Section ID: 0x%02X\n", $tok[$puboffset] + printf "\tX'21': ECC public key\n" + printf "Section version number: 0x%02X\n", $tok[$puboffset+1] + printf "Section length: 0x%02X%02X\n", $tok[$puboffset+2], $tok[$puboffset+3] + printf "Curve type: 0x%02X\n", $tok[$puboffset+8] + printf "\tX'00': Prime curve, X'01': Brainpool curve\n" + printf "Length of p in bits: 0x%02X%02X\n", $tok[$puboffset+10], $tok[$puboffset+11] + printf "Length of public key q in bytes: 0x%02X%02X\n", $tok[$puboffset+12], $tok[$puboffset+13] + printf "-------- Begin q data --------\n" + set $qlen = $tok[$puboffset+13] + set $i = 0 + while ($i < $qlen) + printf "%02X", $tok[$puboffset+14+$i] + set $i = $i+1 + end + printf "\n-------- End q data --------\n" +end +document dump_ec_key_token +Print the Elliptic Curve key token generated by CSNDPKG. +end diff --git a/misc/pkcsslotd.in b/misc/pkcsslotd.in new file mode 100644 index 0000000..2abdff6 --- /dev/null +++ b/misc/pkcsslotd.in @@ -0,0 +1,71 @@ +#!/bin/bash +# +# pkcsslotd Starts pkcsslotd +# +# Authors: Kent E. Yoder +# Serge E. Hallyn +# Daniel H. Jones +# +# chkconfig: - 50 50 +# description: pkcsslotd is a daemon which manages cryptographic hardware +# tokens for the openCryptoki package. + +. /etc/init.d/functions + +PIDFILE=/var/run/pkcsslotd.pid +LOCKFILE=/var/lock/subsys/pkcsslotd +SLOTDBIN=@sbindir@/pkcsslotd + + +start() { + [ -x $SLOTDBIN ] || exit 5 + + echo -n $"Starting pkcsslotd: " + + daemon $SLOTDBIN + + RETVAL=$? + echo + [ $RETVAL -eq 0 ] && touch $LOCKFILE + return $RETVAL +} + +stop() { + echo -n $"Shutting down pkcsslotd:" + killproc pkcsslotd + RETVAL=$? + echo + [ $RETVAL -eq 0 ] && rm -f $LOCKFILE + return $RETVAL +} + +restart() { + stop + start +} + +RETVAL=0 +umask 077 + +case "$1" in + start) + start + ;; + stop) + stop + ;; + status) + status pkcsslotd $SLOTDBIN + ;; + restart|reload|force-reload) + restart + ;; + condrestart) + [ -f $LOCKFILE ] && restart || : + ;; + *) + echo $"Usage: $0 {start|stop|status|restart|condrestart|reload|force-reload}" + exit 2 +esac + +exit $? diff --git a/misc/pkcsslotd.service.in b/misc/pkcsslotd.service.in new file mode 100644 index 0000000..296b46f --- /dev/null +++ b/misc/pkcsslotd.service.in @@ -0,0 +1,11 @@ +[Unit] +Description=Daemon which manages cryptographic hardware tokens for the openCryptoki package +After=local-fs.target + +[Service] +Type=forking +PIDFile=/var/run/pkcsslotd.pid +ExecStart=@sbindir@/pkcsslotd + +[Install] +WantedBy=multi-user.target diff --git a/misc/rsa_parser.pl b/misc/rsa_parser.pl new file mode 100644 index 0000000..5bd8f30 --- /dev/null +++ b/misc/rsa_parser.pl @@ -0,0 +1,1664 @@ +#!/usr/bin/perl +# +# COPYRIGHT (c) International Business Machines Corp. 2011-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 +# +# This script parses the RSA test vectors found in $in_file +# and formats them for openCryptoki tests +# +# Fionnuala Gunter +# August 18, 2011 +# +# +# To run: +# download ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15sign-vectors.tx +# ./rsa_parser.pl > rsa.h +# +# +#TODO: For some reason, there are extra blank lines printed... +# + +# constants +$max_tv = 300; # maximum number of test vectors to add to file +$sub_max = 3; # maximum number of messages/signatures per key pair +$count = 0; # current number of test vectors added to file +$in_file = "pkcs1v15sign-vectors.txt"; # test vector source + +# tmp +$string; + +# input +$example = "# Example \d+: A \d+-bit RSA key pair"; +$key = '# Private key'; +$modulus = '# Modulus: '; +$publicexponent = '# Public exponent: '; +$privateexponent = '# Exponent: '; +$prime1_ = '# Prime 1: '; +$prime2_ = '# Prime 2: '; +$exponent1 = '# Prime exponent 1: '; +$exponent2 = '# Prime exponent 2: '; +$coefficient = '# Coefficient: '; +$msgblock = "# PKCS#1 v1.5 signing of 20 random messages "; +$msgsighead = "# PKCS#1 v1.5 Signature Example $num_msg "; +$msghead = '# Message to be signed:'; +$sighead = '# Signature:'; + +# output +$begin_struct = "//ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15sign-vectors.txt\n". + "struct RSA_PUBLISHED_TEST_VECTOR ". + "rsa_sha1_pkcs_sigver_published_tv[] = {\n"; +$end_struct = "};\n"; +$begin_ele = "\t{"; +$end_ele = "\t},\n"; +$begin_mod = "\t\t.mod = "; +$begin_pubexp = "\t\t.pub_exp = "; +$begin_privexp = "\t\t.priv_exp = "; +$begin_prime1 = "\t\t.prime1 = "; +$begin_prime2 = "\t\t.prime2 = "; +$begin_exp1 = "\t\t.exp1 = "; +$begin_exp2 = "\t\t.exp2 = "; +$begin_coef = "\t\t.coef = "; +$begin_msg = "\t\t.msg = "; +$begin_sig = "\t\t.sig = "; +$begin_modlen = "\t\t.mod_len = "; +$begin_pubexplen = "\t\t.pubexp_len = "; +$begin_privexplen = "\t\t.privexp_len = "; +$begin_prime1len = "\t\t.prime1_len = "; +$begin_prime2len = "\t\t.prime2_len = "; +$begin_exp1len = "\t\t.exp1_len = "; +$begin_exp2len = "\t\t.exp2_len = "; +$begin_coeflen = "\t\t.coef_len = "; +$begin_msglen = "\t\t.msg_len = "; +$begin_siglen = "\t\t.sig_len = "; + + +# giant block of generated tests that I copy-pasted here. +# this could be replaced with some functions that generate the data below +# TODO: CKM_CDMF_KEY_GEN doesn't seem to be supported by ICA, CCA or SoftTok, +# so those tests can be removed +$defheader = "#include \"pkcs11types.h\" +#define MAX_MODULUS_SIZE 256 +#define MAX_EXPONENT_SIZE 256 +#define MAX_MESSAGE_SIZE 512 +#define MAX_SIGNATURE_SIZE 512 +#define MAX_PRIME_SIZE 128 +#define MAX_COEFFICIENT_SIZE 128 +#define PKCS11_MAX_KEY_LEN 512 + + +struct RSA_GENERATED_TEST_VECTOR { + CK_ULONG modbits; + CK_ULONG publ_exp_len; + CK_BYTE publ_exp[4]; + CK_ULONG inputlen; + CK_MECHANISM keytype; + CK_ULONG keylen; +}; + +static struct RSA_GENERATED_TEST_VECTOR rsa_keywrap_generated_tv[] = { + { // 0 + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 1, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 1 + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, { // 2 + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, { // 3 + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, { // 4 + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 5 + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + },{ // 6 + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 64, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 7 + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 1, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 8 + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, { // 9 + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, { // 10 + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, { // 11 + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 12 + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 13 + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 64, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 14 + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 1, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 15 + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, { // 16 + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, { // 17 + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, { // 18 + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 19 + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + },{ // 20 + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 64, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 21 + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 1, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0} + }, { // 22 + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, { // 23 + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, { // 24 + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, { // 25 + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 26 + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + },{ // 27 + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 64, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 28 + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 1, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 29 + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, { // 30 + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, { // 31 + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0} + }, { // 32 + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 33 + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + },{ // 34 + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 64, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 35 + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 1, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 36 + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, { // 37 + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, { // 38 + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, { // 39 + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 40 + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 41 + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 96, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 42 + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 1, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 43 + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, { // 44 + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, { // 45 + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, { // 46 + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 47 + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + },{ // 48 + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 96, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 49 + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 1, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 50 + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, { // 51 + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, { // 52 + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, { // 53 + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 54 + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + },{ // 55 + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 128, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 56 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 1, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 57 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, { // 58 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, { // 59 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, { // 60 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 61 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 62 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 128, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 63 + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 1, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 64 + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, { // 65 + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, { // 66 + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, { // 67 + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 68 + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + },{ // 69 + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 256, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 70 + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 1, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 71 + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, { // 72 + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, { // 73 + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, { // 74 + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 75 + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + },{ // 76 + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 256, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 77 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 1, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + },{ // 78 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, { // 79 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, { // 80 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, { // 81 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 82 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 83 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 256, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 84 + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 1, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 85 + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, { // 86 + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, { // 87 + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, { // 88 + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 89 + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + },{ // 90 + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .keylen = 512, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 91 + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 1, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 92 + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, { // 93 + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, { // 94 + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, { // 95 + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 96 + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + },{ // 97 + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .keylen = 512, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, { // 98 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 1, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + },{ // 99 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, { // 100 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, { // 101 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, { // 102 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 103 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, { // 104 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .keylen = 512, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + } + +}; + +static struct RSA_GENERATED_TEST_VECTOR rsa_generated_tv[] = { + { // tv[0] + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 1, + }, { //tv[1] + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 53, + }, { //tv[2] + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 1, + }, { //tv[3] + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 53, + }, { //tv[4] + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = { 0x03, 0x00, 0x01 }, + .inputlen = 1, + }, { //tv[5] + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = { 0x03, 0x00, 0x01 }, + .inputlen = 53, + }, { //tv[6] + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 1, + }, { //tv[7] + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 85, + }, { //tv[8] + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 1, + }, { //tv[9] + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 85, + }, { //tv[10] + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .inputlen = 1, + }, { //tv[11] + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .inputlen = 85, + }, { //tv[12] + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 1, + }, { //tv[13] + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 117, + }, { //tv[14] + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 1, + }, { //tv[15] + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 117, + }, { //tv[16] + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .inputlen = 1, + }, { //tv[17] + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .inputlen = 117, + }, { //tv[18] + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 1, + }, { //tv[19] + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 245, + }, { //tv[20] + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 1, + }, { //tv[21] + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 245, + }, { //tv[22] + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .inputlen = 1, + }, { //tv[23] + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .inputlen = 245, + }, { //tv[24] + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 1, + }, { //tv[25] + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 501, + }, { //tv[26] + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 1, + }, { //tv[27] + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 501, + }, { //tv[28] + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .inputlen = 1, + }, { //tv[29] + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .inputlen = 501, + }, + + +}; + +static struct RSA_GENERATED_TEST_VECTOR rsa_x509_generated_tv[] = { + { // tv[0] + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 1, + }, { // tv[1] + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 64, + }, { // tv[2] + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 1, + }, { // tv[3] + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 64, + }, { // tv[4] + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .inputlen = 1, + }, { // tv[5] + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .inputlen = 64, + }, { // tv[6] + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 1, + }, { // tv[7] + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 96, + }, { // tv[8] + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 1, + }, { // tv[9] + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 96, + }, { // tv[10] + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .inputlen = 1, + }, { // tv[11] + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .inputlen = 96, + }, { // tv[12] + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 1 + }, { // tv[13] + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 128, + }, { // tv[14] + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 1, + }, { // tv[15] + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 128, + }, { // tv[16] + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .inputlen = 1 + }, { // tv[17] + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .inputlen = 128, + }, { // tv[18] + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 1 + }, { // tv[19] + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 256, + }, { // tv[20] + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 1, + }, { // tv[21] + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 256, + }, { // tv[22] + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .inputlen = 1 + }, { // tv[23] + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .inputlen = 256, + }, { // tv[24] + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 1 + }, { // tv[25] + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = { 0x03 }, + .inputlen = 512, + }, { // tv[26] + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 1, + }, { // tv[27] + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = { 0x00, 0x11 }, + .inputlen = 512, + }, { // tv[28] + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .inputlen = 1 + }, { // tv[29] + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = { 0x01, 0x00, 0x01 }, + .inputlen = 512, + } +}; + +struct GENERATED_TEST_SUITE_INFO { + const char *name; + unsigned int tvcount; + struct RSA_GENERATED_TEST_VECTOR *tv; + CK_MECHANISM mech; +}; + +#define NUM_OF_GENERATED_KEYWRAP_TESTSUITES 2 +struct GENERATED_TEST_SUITE_INFO generated_keywrap_test_suites[] = { + { + .name = \"RSA PKCS\", + .tvcount = 105, + .tv = rsa_keywrap_generated_tv, + .mech = {CKM_RSA_PKCS, 0, 0}, + }, { + .name = \"RSA X.509\", + .tvcount = 105, + .tv = rsa_keywrap_generated_tv, + .mech = {CKM_RSA_X_509, 0, 0}, + } +}; + + +#define NUM_OF_GENERATED_SIGVER_TESTSUITES 5 +struct GENERATED_TEST_SUITE_INFO generated_sigver_test_suites[] = { + { + .name = \"RSA PKCS\", + .tvcount = 30, + .tv = rsa_generated_tv, + .mech = {CKM_RSA_PKCS, 0, 0}, + }, { + .name = \"RSA SHA1 PKCS\", + .tvcount = 30, + .tv = rsa_generated_tv, + .mech = {CKM_SHA1_RSA_PKCS, 0, 0}, + }, { + .name = \"RSA MD2 PKCS\", + .tvcount = 30, + .tv = rsa_generated_tv, + .mech = {CKM_MD2_RSA_PKCS, 0, 0}, + }, { + .name = \"RSA MD5 PKCS\", + .tvcount = 30, + .tv = rsa_generated_tv, + .mech = {CKM_MD5_RSA_PKCS, 0 , 0}, + }, { + .name = \"RSA X.509\", + .tvcount = 30, + .tv = rsa_x509_generated_tv, + .mech = {CKM_RSA_X_509, 0 , 0}, + } +}; + +#define NUM_OF_GENERATED_CRYPTO_TESTSUITES 2 +struct GENERATED_TEST_SUITE_INFO generated_crypto_test_suites[] = { + { + .name = \"RSA PKCS\", + .tvcount = 30, + .tv = rsa_generated_tv, + .mech = {CKM_RSA_PKCS, 0, 0}, + }, { + .name = \"RSA X.509\", + .tvcount = 30, + .tv = rsa_x509_generated_tv, + .mech = {CKM_RSA_X_509, 0, 0}, + } +}; + +struct RSA_PUBLISHED_TEST_VECTOR { + CK_BYTE mod[MAX_MODULUS_SIZE]; // n + CK_ULONG mod_len; + CK_BYTE prime1[MAX_PRIME_SIZE]; // p + CK_ULONG prime1_len; + CK_BYTE prime2[MAX_PRIME_SIZE]; // q + CK_ULONG prime2_len; + CK_BYTE exp1[MAX_EXPONENT_SIZE]; // d % (p-1) + CK_ULONG exp1_len; + CK_BYTE exp2[MAX_EXPONENT_SIZE]; // d % (q-1) + CK_ULONG exp2_len; + CK_BYTE coef[MAX_COEFFICIENT_SIZE]; // (q^-1) % p + CK_ULONG coef_len; + CK_BYTE pub_exp[MAX_EXPONENT_SIZE]; // e + CK_ULONG pubexp_len; + CK_BYTE priv_exp[MAX_EXPONENT_SIZE]; // d + CK_ULONG privexp_len; + CK_BYTE msg[MAX_MESSAGE_SIZE]; + CK_ULONG msg_len; + CK_BYTE sig[MAX_SIGNATURE_SIZE]; + CK_ULONG sig_len; +};\n"; + +# vars + +@mod; +@pubexp; +@privexp; +@prime1; +@prime2; +@exp1; +@exp2; +@coef; +@msg; +@sig; + +$modlen = 0; +$pubexplen = 0; +$privexplen = 0; +$prime1len = 0; +$prime2len = 0; +$exp1len = 0; +$exp2len = 0; +$coeflen = 0; +$msglen = 0; +$siglen = 0; + +# open test vector file +# parse contents +# print results +open ($file, $in_file); +print $defheader; +print $begin_struct; +my $subcount; +while (<$file>) { + # parse key pair + if ($_ =~ $key){ + parse_keys(); + $subcount = 0; + } + # parse message + if ($_ =~ $msghead){ + #print "\n"; + parse_msg(); + } + # parse signature and print struct element + if ($_ =~ $sighead){ + #print "\n"; + parse_sig(); + if ($subcount < $sub_max){ + print_ele(); + $count++; + } + if ($count > $max_tv){ + last; + } + #$count++; + $subcount++; + } +} +print $end_struct; +print "\n"; + +$footer = "struct PUBLISHED_TEST_SUITE_INFO { + const char *name; + unsigned int tvcount; + struct RSA_PUBLISHED_TEST_VECTOR *tv; + CK_MECHANISM mech; + unsigned int result; +}; + +#define NUM_OF_PUBLISHED_TESTSUITES 1 +struct PUBLISHED_TEST_SUITE_INFO published_test_suites[] = { + { + .name = \"RSA SHA-1 PKCS v1.5\", + .tvcount = $count, + .tv = rsa_sha1_pkcs_sigver_published_tv, + .mech = {CKM_SHA1_RSA_PKCS, 0, 0}, + } + + +};"; + +print $footer; +close ($file); + +sub parse_keys(){ + while (<$file>){ + print "\n"; + # skip # ----- + if ($_ =~ m/^# -/){ + next; + } + + # skip " " + elsif (length($_) == 1 || length($_) == 2 || (!$_)){ + next; + } + + # parse modulus + elsif ($_ =~ $modulus){ + parse_mod(); + next; + } + + # parse public exponent + elsif ($_ =~ $publicexponent){ + parse_pubexp(); + next; + } + + # parse private exponent + elsif ($_ =~ $privateexponent){ + parse_privexp(); + next; + } + + # parse prime1 + elsif ($_ =~ $prime1_){ + parse_prime1(); + next; + } + + # parse prime2 + elsif ($_ =~ $prime2_){ + parse_prime2(); + next; + } + + # parse exponent1 + elsif ($_ =~ $exponent1){ + parse_exp1(); + next; + } + + # parse exponent2 + elsif ($_ =~ $exponent2){ + parse_exp2(); + next; + } + + # parse coefficient + elsif ($_ =~ $coefficient){ + parse_coef(); + last; + } + } +} + +# parse modulus +sub parse_mod(){ + @mod = (); + while (<$file>){ + if ($_ =~ m{\S+}){ + for (my $n = 0; ($n + 2) < length($_); $n+=3) { + $string = "0x".substr($_, $n, 2); + push(@mod, $string); + } + } + else { + $modlen = @mod; + last; + } + } +} + +# parse public exponent +sub parse_pubexp(){ + @pubexp = (); + while (<$file>){ + if ($_ =~ m{\S+}){ + for (my $n = 0; ($n + 2) < length($_); $n+=3) { + $string = "0x".substr($_, $n, 2); + push(@pubexp, $string); + } + } + else { + $pubexplen = @pubexp; + last; + } + } +} + +# parse private exponent +sub parse_privexp(){ + @privexp = (); + while (<$file>){ + if ($_ =~ m{\S+}){ + for (my $n = 0; ($n + 2) < length($_); $n+=3) { + $string = "0x".substr($_, $n, 2); + push(@privexp, $string); + } + } + else { + $privexplen = @privexp; + last; + } + } +} + +# parse prime 1 +sub parse_prime1(){ + @prime1 = (); + while (<$file>){ + if ($_ =~ m{\S+}){ + for (my $n = 0; ($n + 2) < length($_); $n+=3) { + $string = "0x".substr($_, $n, 2); + push(@prime1, $string); + } + } + else { + $prime1len = @prime1; + last; + } + } +} + +# parse prime 2 +sub parse_prime2(){ + @prime2 = (); + while (<$file>){ + if ($_ =~ m{\S+}){ + for (my $n = 0; ($n + 2) < length($_); $n+=3) { + $string = "0x".substr($_, $n, 2); + push(@prime2, $string); + } + } + else { + $prime2len = @prime2; + last; + } + } +} + +# parse exponent 1 +sub parse_exp1(){ + @exp1 = (); + while (<$file>){ + if ($_ =~ m{\S+}){ + for (my $n = 0; ($n + 2) < length($_); $n+=3) { + $string = "0x".substr($_, $n, 2); + push(@exp1, $string); + } + } + else { + $exp1len = @exp1; + last; + } + } +} + +# parse exponent 2 +sub parse_exp2(){ + @exp2 = (); + while (<$file>){ + if ($_ =~ m{\S+}){ + for (my $n = 0; ($n + 2) < length($_); $n+=3) { + $string = "0x".substr($_, $n, 2); + push(@exp2, $string); + } + } + else { + $exp2len = @exp2; + last; + } + } +} + +# parse coefficient +sub parse_coef(){ + @coef = (); + while (<$file>){ + if ($_ =~ m{\S+}){ + for (my $n = 0; ($n + 2) < length($_); $n+=3) { + $string = "0x".substr($_, $n, 2); + push(@coef, $string); + } + } + else { + $coeflen = @coef; + last; + } + } +} + +# parse message +sub parse_msg(){ + @msg = (); + while (<$file>){ + if ($_ =~ m{\S+}){ + for (my $n = 0; ($n + 2) < length($_); $n+=3) { + $string = "0x".substr($_, $n, 2); + push(@msg, $string); + } + } + else { + $msglen = @msg; + last; + } + } +} + +# parse signature +sub parse_sig(){ + @sig = (); + while (<$file>){ + if ($_ =~ m{\S+}){ + for (my $n = 0; ($n + 2) < length($_); $n+=3) { + $string = "0x".substr($_, $n, 2); + push(@sig, $string); + } + } + else { + $siglen = @sig; + last; + } + } +} + +# prints test vector +sub print_ele(){ + print $begin_ele; + print "\t/\/\ $count\n"; # new + print_mod(); + print_pubexp(); + print_privexp(); + print_prime1(); + print_prime2(); + print_exp1(); + print_exp2(); + print_coef(); + print_msg(); + print_sig(); + print $end_ele; +} + +# prints modulus +sub print_mod(){ + print $begin_mod; + print "\t { "; + for (my $n = 0; $n < $modlen; $n++){ + print $mod[$n]; + if ($n + 1 < $modlen){ + print ","; + } + if (($n + 1 < $modlen) && !(($n + 1) % 8)){ + print "\n\t\t\t\t"; + } + } + print " },\n"; + print $begin_modlen; + print $modlen; + print ",\n"; +} + +# prints public exponent +sub print_pubexp(){ + print $begin_pubexp; + print " { "; + for (my $n = 0; $n < $pubexplen; $n++){ + print $pubexp[$n]; + if ($n + 1 < $pubexplen){ + print ","; + } + } + print " },\n"; + print $begin_pubexplen; + print $pubexplen; + print ",\n"; +} + +# prints private exponent +sub print_privexp(){ + print $begin_privexp; + print " { "; + for (my $n = 0; $n < $privexplen; $n++){ + print $privexp[$n]; + if ($n + 1 < $privexplen){ + print ","; + } + if (($n + 1 < $privexplen) && !(($n + 1) % 8)){ + print "\n\t\t\t\t"; + } + + } + print " },\n"; + print $begin_privexplen; + print $privexplen; + print ",\n"; +} + +# prints prime 1 +sub print_prime1(){ + print $begin_prime1; + print " { "; + for (my $n = 0; $n < $prime1len; $n++){ + print $prime1[$n]; + if ($n + 1 < $prime1len){ + print ","; + } + if (($n + 1 < $prime1len) && !(($n + 1) % 8)){ + print "\n\t\t\t\t"; + } + + } + print " },\n"; + print $begin_prime1len; + print $prime1len; + print ",\n"; +} + +# prints prime 2 +sub print_prime2(){ + print $begin_prime2; + print " { "; + for (my $n = 0; $n < $prime2len; $n++){ + print $prime2[$n]; + if ($n + 1 < $prime2len){ + print ","; + } + if (($n + 1 < $prime2len) && !(($n + 1) % 8)){ + print "\n\t\t\t\t"; + } + + } + print " },\n"; + print $begin_prime2len; + print $prime2len; + print ",\n"; +} + +# prints exponent 1 +sub print_exp1(){ + print $begin_exp1; + print " { "; + for (my $n = 0; $n < $exp1len; $n++){ + print $exp1[$n]; + if ($n + 1 < $exp1len){ + print ","; + } + if (($n + 1 < $exp1len) && !(($n + 1) % 8)){ + print "\n\t\t\t\t"; + } + + } + print " },\n"; + print $begin_exp1len; + print $exp1len; + print ",\n"; +} + +# prints exponent 2 +sub print_exp2(){ + print $begin_exp2; + print " { "; + for (my $n = 0; $n < $exp2len; $n++){ + print $exp2[$n]; + if ($n + 1 < $exp2len){ + print ","; + } + if (($n + 1 < $exp2len) && !(($n + 1) % 8)){ + print "\n\t\t\t\t"; + } + + } + print " },\n"; + print $begin_exp2len; + print $exp2len; + print ",\n"; +} + +# prints coefficient +sub print_coef(){ + print $begin_coef; + print " { "; + for (my $n = 0; $n < $coeflen; $n++){ + print $coef[$n]; + if ($n + 1 < $coeflen){ + print ","; + } + if (($n + 1 < $coeflen) && !(($n + 1) % 8)){ + print "\n\t\t\t\t"; + } + + } + print " },\n"; + print $begin_coeflen; + print $coeflen; + print ",\n"; +} + +# prints message +sub print_msg(){ + print $begin_msg; + print " { "; + for (my $n = 0; $n < $msglen; $n++){ + print $msg[$n]; + if ($n + 1 < $msglen){ + print ","; + } + if (($n + 1 < $msglen) && !(($n + 1) % 8)){ + print "\n\t\t\t\t"; + } + + } + print " },\n"; + print $begin_msglen; + print $msglen; + print ",\n"; +} + +# prints signature +sub print_sig(){ + print $begin_sig; + print " { "; + for (my $n = 0; $n < $siglen; $n++){ + print $sig[$n]; + if ($n + 1 < $siglen){ + print ","; + } + if (($n + 1 < $siglen) && !(($n + 1) % 8)){ + print "\n\t\t\t\t"; + } + + } + print " },\n"; + print $begin_siglen; + print $siglen; + print ",\n"; +} diff --git a/misc/test_mech_list.c b/misc/test_mech_list.c new file mode 100644 index 0000000..d5070ed --- /dev/null +++ b/misc/test_mech_list.c @@ -0,0 +1,34 @@ +/* + * 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 + */ + +/** + * This is something like what you can expect openCryptoki to do when + * it requests a mechanism list from your library. + */ + +#include +#include "mech_types.h" + +extern void generate_pkcs11_mech_list(struct mech_list *head); + +int main(int argc, char *argv[]) +{ + struct mech_list head; + struct mech_list *item; + generate_pkcs11_mech_list(&head); + item = head.next; + while (item) { + struct mech_list *next; + next = item->next; + printf("Mechanism type: [%.8x]\n", item->element.mech_type); + free(item); + item = next; + } +} diff --git a/misc/tmpfiles.conf.in b/misc/tmpfiles.conf.in new file mode 100644 index 0000000..faac1aa --- /dev/null +++ b/misc/tmpfiles.conf.in @@ -0,0 +1,2 @@ +# path mode uid gid age +D @lockdir@ 0770 root pkcs11 - diff --git a/opencryptoki.map b/opencryptoki.map new file mode 100644 index 0000000..d182817 --- /dev/null +++ b/opencryptoki.map @@ -0,0 +1,72 @@ +OPENCRYPTOKI_3.10 { + global: + C_CancelFunction; + C_CloseAllSessions; + C_CloseSession; + C_CopyObject; + C_CreateObject; + C_Decrypt; + C_DecryptDigestUpdate; + C_DecryptFinal; + C_DecryptInit; + C_DecryptUpdate; + C_DecryptVerifyUpdate; + C_DeriveKey; + C_DestroyObject; + C_Digest; + C_DigestEncryptUpdate; + C_DigestFinal; + C_DigestInit; + C_DigestKey; + C_DigestUpdate; + C_Encrypt; + C_EncryptFinal; + C_EncryptInit; + C_EncryptUpdate; + C_Finalize; + C_FindObjects; + C_FindObjectsFinal; + C_FindObjectsInit; + C_GenerateKey; + C_GenerateKeyPair; + C_GenerateRandom; + C_GetAttributeValue; + C_GetFunctionList; + C_GetFunctionStatus; + C_GetInfo; + C_GetMechanismInfo; + C_GetMechanismList; + C_GetObjectSize; + C_GetOperationState; + C_GetSessionInfo; + C_GetSlotInfo; + C_GetSlotList; + C_GetTokenInfo; + C_InitPIN; + C_InitToken; + C_Initialize; + C_Login; + C_Logout; + C_OpenSession; + C_SeedRandom; + C_SetAttributeValue; + C_SetOperationState; + C_SetPIN; + C_Sign; + C_SignEncryptUpdate; + C_SignFinal; + C_SignInit; + C_SignRecover; + C_SignRecoverInit; + C_SignUpdate; + C_UnwrapKey; + C_Verify; + C_VerifyFinal; + C_VerifyInit; + C_VerifyRecover; + C_VerifyRecoverInit; + C_VerifyUpdate; + C_WaitForSlotEvent; + C_WrapKey; + local: *; +}; diff --git a/opencryptoki_tok.map b/opencryptoki_tok.map new file mode 100644 index 0000000..2713f74 --- /dev/null +++ b/opencryptoki_tok.map @@ -0,0 +1,69 @@ +OPENCRYPTOKI_TOK_3.10 { + global: + SC_CancelFunction; + SC_CloseAllSessions; + SC_CloseSession; + SC_CopyObject; + SC_CreateObject; + SC_Decrypt; + SC_DecryptDigestUpdate; + SC_DecryptFinal; + SC_DecryptInit; + SC_DecryptUpdate; + SC_DecryptVerifyUpdate; + SC_DeriveKey; + SC_DestroyObject; + SC_Digest; + SC_DigestEncryptUpdate; + SC_DigestFinal; + SC_DigestInit; + SC_DigestKey; + SC_DigestUpdate; + SC_Encrypt; + SC_EncryptFinal; + SC_EncryptInit; + SC_EncryptUpdate; + SC_Finalize; + SC_FindObjects; + SC_FindObjectsFinal; + SC_FindObjectsInit; + SC_GenerateKey; + SC_GenerateKeyPair; + SC_GenerateRandom; + SC_GetAttributeValue; + SC_GetFunctionStatus; + SC_GetMechanismInfo; + SC_GetMechanismList; + SC_GetObjectSize; + SC_GetOperationState; + SC_GetSessionInfo; + SC_GetTokenInfo; + SC_InitPIN; + SC_InitToken; + SC_Login; + SC_Logout; + SC_OpenSession; + SC_SeedRandom; + SC_SetAttributeValue; + SC_SetFunctionList; + SC_SetOperationState; + SC_SetPIN; + SC_Sign; + SC_SignEncryptUpdate; + SC_SignFinal; + SC_SignInit; + SC_SignRecover; + SC_SignRecoverInit; + SC_SignUpdate; + SC_UnwrapKey; + SC_Verify; + SC_VerifyFinal; + SC_VerifyInit; + SC_VerifyRecover; + SC_VerifyRecoverInit; + SC_VerifyUpdate; + SC_WaitForSlotEvent; + SC_WrapKey; + ST_Initialize; + local: *; +}; diff --git a/rpm/opencryptoki.spec b/rpm/opencryptoki.spec new file mode 100644 index 0000000..fa4b989 --- /dev/null +++ b/rpm/opencryptoki.spec @@ -0,0 +1,343 @@ +%global _hardened_build 1 + +Name: opencryptoki +Summary: Implementation of the PKCS#11 (Cryptoki) specification v2.20 +Version: 3.14.0 +Release: 1%{?dist} +License: CPL +Group: System Environment/Base +URL: https://github.com/opencryptoki/opencryptoki +Source: https://github.com/%{name}/%{name}/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz + +Requires(pre): coreutils +BuildRequires: openssl-devel >= 1.0.2 +BuildRequires: trousers-devel +BuildRequires: openldap-devel +BuildRequires: autoconf automake libtool +BuildRequires: bison flex +BuildRequires: systemd +BuildRequires: libitm-devel +%ifarch s390 s390x +BuildRequires: libica-devel >= 3.3 +%endif +Requires(pre): %{name}-libs%{?_isa} = %{version}-%{release} +Requires: %{name}-libs%{?_isa} = %{version}-%{release} +Requires: %{name}(token) +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd + + +%description +Opencryptoki implements the PKCS#11 specification v2.20 for a set of +cryptographic hardware, such as IBM 4764 and 4765 crypto cards, and the +Trusted Platform Module (TPM) chip. Opencryptoki also brings a software +token implementation that can be used without any cryptographic +hardware. +This package contains the Slot Daemon (pkcsslotd) and general utilities. + + +%package libs +Group: System Environment/Libraries +Summary: The run-time libraries for opencryptoki package +Requires(pre): shadow-utils + +%description libs +Opencryptoki implements the PKCS#11 specification v2.20 for a set of +cryptographic hardware, such as IBM 4764 and 4765 crypto cards, and the +Trusted Platform Module (TPM) chip. Opencryptoki also brings a software +token implementation that can be used without any cryptographic +hardware. +This package contains the PKCS#11 library implementation, and requires +at least one token implementation (packaged separately) to be fully +functional. + + +%package devel +Group: Development/Libraries +Summary: Development files for openCryptoki +Requires: %{name}-libs%{?_isa} = %{version}-%{release} + +%description devel +This package contains the development header files for building +opencryptoki and PKCS#11 based applications + + +%package swtok +Group: System Environment/Libraries +Summary: The software token implementation for opencryptoki +Requires(pre): %{name}-libs%{?_isa} = %{version}-%{release} +Requires: %{name}-libs%{?_isa} = %{version}-%{release} +Provides: %{name}(token) + +%description swtok +Opencryptoki implements the PKCS#11 specification v2.20 for a set of +cryptographic hardware, such as IBM 4764 and 4765 crypto cards, and the +Trusted Platform Module (TPM) chip. Opencryptoki also brings a software +token implementation that can be used without any cryptographic +hardware. +This package brings the software token implementation to use opencryptoki +without any specific cryptographic hardware. + + +%package tpmtok +Group: System Environment/Libraries +Summary: Trusted Platform Module (TPM) device support for opencryptoki +Requires(pre): %{name}-libs%{?_isa} = %{version}-%{release} +Requires: %{name}-libs%{?_isa} = %{version}-%{release} +Provides: %{name}(token) + +%description tpmtok +Opencryptoki implements the PKCS#11 specification v2.20 for a set of +cryptographic hardware, such as IBM 4764 and 4765 crypto cards, and the +Trusted Platform Module (TPM) chip. Opencryptoki also brings a software +token implementation that can be used without any cryptographic +hardware. +This package brings the necessary libraries and files to support +Trusted Platform Module (TPM) devices in the opencryptoki stack. + + +%package icsftok +Group: System Environment/Libraries +Summary: ICSF token support for opencryptoki +Requires(pre): %{name}-libs%{?_isa} = %{version}-%{release} +Requires: %{name}-libs%{?_isa} = %{version}-%{release} +Provides: %{name}(token) + +%description icsftok +Opencryptoki implements the PKCS#11 specification v2.20 for a set of +cryptographic hardware, such as IBM 4764 and 4765 crypto cards, and the +Trusted Platform Module (TPM) chip. Opencryptoki also brings a software +token implementation that can be used without any cryptographic +hardware. +This package brings the necessary libraries and files to support +ICSF token in the opencryptoki stack. + + +%ifarch s390 s390x +%package icatok +Group: System Environment/Libraries +Summary: ICA cryptographic devices (clear-key) support for opencryptoki +Requires(pre): %{name}-libs%{?_isa} = %{version}-%{release} +Requires: %{name}-libs%{?_isa} = %{version}-%{release} +Provides: %{name}(token) + +%description icatok +Opencryptoki implements the PKCS#11 specification v2.20 for a set of +cryptographic hardware, such as IBM 4764 and 4765 crypto cards, and the +Trusted Platform Module (TPM) chip. Opencryptoki also brings a software +token implementation that can be used without any cryptographic +hardware. +This package brings the necessary libraries and files to support ICA +devices in the opencryptoki stack. ICA is an interface to IBM +cryptographic hardware such as IBM 4764 or 4765 that uses the +"accelerator" or "clear-key" path. + +%package ccatok +Group: System Environment/Libraries +Summary: CCA cryptographic devices (secure-key) support for opencryptoki +Requires(pre): %{name}-libs%{?_isa} = %{version}-%{release} +Requires: %{name}-libs%{?_isa} = %{version}-%{release} +Provides: %{name}(token) + +%description ccatok +Opencryptoki implements the PKCS#11 specification v2.20 for a set of +cryptographic hardware, such as IBM 4764 and 4765 crypto cards, and the +Trusted Platform Module (TPM) chip. Opencryptoki also brings a software +token implementation that can be used without any cryptographic +hardware. +This package brings the necessary libraries and files to support CCA +devices in the opencryptoki stack. CCA is an interface to IBM +cryptographic hardware such as IBM 4764 or 4765 that uses the +"co-processor" or "secure-key" path. + +%package ep11tok +Group: System Environment/Libraries +Summary: EP11 cryptographic devices (secure-key) support for opencryptoki +Requires(pre): %{name}-libs%{?_isa} = %{version}-%{release} +Requires: %{name}-libs%{?_isa} = %{version}-%{release} +Provides: %{name}(token) + +%description ep11tok +Opencryptoki implements the PKCS#11 specification v2.20 for a set of +cryptographic hardware, such as IBM 4764 and 4765 crypto cards, and the +Trusted Platform Module (TPM) chip. Opencryptoki also brings a software +token implementation that can be used without any cryptographic +hardware. +This package brings the necessary libraries and files to support EP11 +tokens in the opencryptoki stack. The EP11 token is a token that uses +the IBM Crypto Express adapters (starting with Crypto Express 4S adapters) +configured with Enterprise PKCS#11 (EP11) firmware. +%endif + + +%prep +%setup -q -n %{name}-%{version} + +%build +./bootstrap.sh + +%configure --with-systemd=%{_unitdir} \ +%ifarch s390 s390x + --enable-icatok --enable-ccatok --enable-ep11tok --enable-pkcsep11_migrate +%else + --disable-icatok --disable-ccatok --disable-ep11tok --disable-pkcsep11_migrate --disable-pkcscca_migrate +%endif + +make %{?_smp_mflags} CHGRP=/bin/true + +%install +make install DESTDIR=$RPM_BUILD_ROOT CHGRP=/bin/true + +# Remove unwanted cruft +rm -f $RPM_BUILD_ROOT/%{_libdir}/%{name}/*.la +rm -f $RPM_BUILD_ROOT/%{_libdir}/%{name}/stdll/*.la + +%post libs -p /sbin/ldconfig +%post swtok -p /sbin/ldconfig +%post tpmtok -p /sbin/ldconfig +%post icsftok -p /sbin/ldconfig +%ifarch s390 s390x +%post icatok -p /sbin/ldconfig +%post ccatok -p /sbin/ldconfig +%post ep11tok -p /sbin/ldconfig +%endif + +%postun libs -p /sbin/ldconfig +%postun swtok -p /sbin/ldconfig +%postun tpmtok -p /sbin/ldconfig +%postun icsftok -p /sbin/ldconfig +%ifarch s390 s390x +%postun icatok -p /sbin/ldconfig +%postun ccatok -p /sbin/ldconfig +%postun ep11tok -p /sbin/ldconfig +%endif + +%pre libs +# Create pkcs11 group +getent group pkcs11 >/dev/null || groupadd -r pkcs11 +exit 0 + +%post +%systemd_post pkcsslotd.service + +%preun +%systemd_preun pkcsslotd.service + +%postun +%systemd_postun_with_restart pkcsslotd.service + + +%files +%doc ChangeLog FAQ README.md +%doc doc/opencryptoki-howto.md +%doc doc/README.token_data +%dir %{_sysconfdir}/%{name} +%config(noreplace) %{_sysconfdir}/%{name}/%{name}.conf +%{_prefix}/lib/tmpfiles.d/%{name}.conf +%{_unitdir}/pkcsslotd.service +%{_sbindir}/pkcsconf +%{_sbindir}/pkcsslotd +%{_mandir}/man1/pkcsconf.1* +%{_mandir}/man5/%{name}.conf.5* +%{_mandir}/man7/%{name}.7* +%{_mandir}/man8/pkcsslotd.8* +%{_libdir}/opencryptoki/methods +%{_libdir}/pkcs11/methods +%dir %attr(770,root,pkcs11) %{_sharedstatedir}/%{name} +%dir %attr(770,root,pkcs11) %{_localstatedir}/lock/%{name} +%dir %attr(770,root,pkcs11) %{_localstatedir}/lock/%{name}/* + +%files libs +%license LICENSE +%{_sysconfdir}/ld.so.conf.d/* +# Unversioned .so symlinks usually belong to -devel packages, but opencryptoki +# needs them in the main package, because: +# documentation suggests that programs should dlopen "PKCS11_API.so". +%dir %{_libdir}/opencryptoki +%{_libdir}/opencryptoki/libopencryptoki.* +%{_libdir}/opencryptoki/PKCS11_API.so +%dir %{_libdir}/opencryptoki/stdll +%dir %{_libdir}/pkcs11 +%{_libdir}/pkcs11/libopencryptoki.so +%{_libdir}/pkcs11/PKCS11_API.so +%{_libdir}/pkcs11/stdll +%dir %attr(770,root,pkcs11) %{_localstatedir}/log/opencryptoki + + +%files devel +%{_includedir}/%{name}/ + +%files swtok +%{_libdir}/opencryptoki/stdll/libpkcs11_sw.* +%{_libdir}/opencryptoki/stdll/PKCS11_SW.so +%dir %attr(770,root,pkcs11) %{_sharedstatedir}/%{name}/swtok/ +%dir %attr(770,root,pkcs11) %{_sharedstatedir}/%{name}/swtok/TOK_OBJ/ + +%files tpmtok +%doc doc/README.tpm_stdll +%{_libdir}/opencryptoki/stdll/libpkcs11_tpm.* +%{_libdir}/opencryptoki/stdll/PKCS11_TPM.so +%dir %attr(770,root,pkcs11) %{_sharedstatedir}/%{name}/tpm/ + +%files icsftok +%doc doc/README.icsf_stdll +%{_sbindir}/pkcsicsf +%{_mandir}/man1/pkcsicsf.1* +%{_libdir}/opencryptoki/stdll/libpkcs11_icsf.* +%{_libdir}/opencryptoki/stdll/PKCS11_ICSF.so +%dir %attr(770,root,pkcs11) %{_sharedstatedir}/%{name}/icsf/ + +%ifarch s390 s390x +%files icatok +%{_libdir}/opencryptoki/stdll/libpkcs11_ica.* +%{_libdir}/opencryptoki/stdll/PKCS11_ICA.so +%dir %attr(770,root,pkcs11) %{_sharedstatedir}/%{name}/lite/ +%dir %attr(770,root,pkcs11) %{_sharedstatedir}/%{name}/lite/TOK_OBJ/ + +%files ccatok +%doc doc/README.cca_stdll +%{_sbindir}/pkcscca +%{_mandir}/man1/pkcscca.1* +%{_libdir}/opencryptoki/stdll/libpkcs11_cca.* +%{_libdir}/opencryptoki/stdll/PKCS11_CCA.so +%dir %attr(770,root,pkcs11) %{_sharedstatedir}/%{name}/ccatok/ +%dir %attr(770,root,pkcs11) %{_sharedstatedir}/%{name}/ccatok/TOK_OBJ/ + +%files ep11tok +%doc doc/README.ep11_stdll +%config(noreplace) %{_sysconfdir}/%{name}/ep11tok.conf +%config(noreplace) %{_sysconfdir}/%{name}/ep11cpfilter.conf +%{_sbindir}/pkcsep11_migrate +%{_sbindir}/pkcsep11_session +%{_mandir}/man1/pkcsep11_migrate.1.* +%{_mandir}/man1/pkcsep11_session.1.* +%{_libdir}/opencryptoki/stdll/libpkcs11_ep11.* +%{_libdir}/opencryptoki/stdll/PKCS11_EP11.so +%dir %attr(770,root,pkcs11) %{_sharedstatedir}/%{name}/ep11tok/ +%dir %attr(770,root,pkcs11) %{_sharedstatedir}/%{name}/ep11tok/TOK_OBJ/ +%endif + + +%changelog +* Fri Nov 15 2019 Patrick Steuer 3.12.0 +- Update build time requirements +* Thu Oct 26 2017 Eduardo Barretto 3.8.0 +- Update URL and source +- Remove unnecessary steps from spec file +* Tue Apr 25 2017 Eduardo Barretto 3.7.0 +- Update spec file according to Fedora 25 +- Add libitm as build dependency +- Added icsftok +- Added s390x ep11tok +* Thu Jul 29 2010 Klaus H Kiwi 2.3.2-1 +- Put STDLLs in separate packages +- General spec file cleanup +* Thu Aug 7 2006 Daniel H Jones +- spec file cleanup +* Tue Aug 1 2006 Daniel H Jones +- sw token not created for s390 +* Tue Jul 25 2006 Daniel H Jones +- fixed post section and /var/lib/opencryptoki perms +* Thu May 25 2006 Daniel H Jones 2.2.4-1 +- initial file created diff --git a/testcases/README b/testcases/README new file mode 100644 index 0000000..471939a --- /dev/null +++ b/testcases/README @@ -0,0 +1,40 @@ +openCryptoki Test Programs + +This directory contains programs designed to test the functionality of +openCryptoki and PKCS#11. The rely on STDLL's installed to the standard system +location. Many of the programs have command line options for passing the slot +number to use (default is slot 0) as well as other options. All programs expect +that the a slot has been intialized using pkcsconf. The expected user pin is +"01234567" and this can also be set using pkcsconf. The expected PINs can also +be changed by modifying DEFAULT_USER_PIN and DEFAULT_SO_PIN in +include/regress.h. + +For correct testcase execution, the token should be initialized before and +after running the testcases. + +crypto +------ +This directory contains testcases to test various crypto algorithms. + +login +----- +This directory contains testcases to test login functionality in pkcs11 +and opencryptoki. + +pkcs11 +------ +This directory contains tests that tests various api/functionality in +pkcs11 specification. + +misc_tests +---------- +This directory contains tests to test various functionality and operations +in opencryptoki. + +ock_test.sh +----------- +This driver runs the various testcases on various tokens. +TODO: Needs to be modified and tested for new testcase structure. + +For help, send mail to the openCryptoki mailing list at +opencryptoki-users@lists.sourceforge.net diff --git a/testcases/common/common.c b/testcases/common/common.c new file mode 100644 index 0000000..444dc61 --- /dev/null +++ b/testcases/common/common.c @@ -0,0 +1,1097 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2006-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 + */ + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" + +CK_FUNCTION_LIST *funcs; +CK_SLOT_ID SLOT_ID; + +CK_BBOOL skip_token_obj; +CK_BBOOL no_stop; +CK_BBOOL no_init; +CK_BBOOL securekey; + +CK_ULONG t_total = 0; // total test assertions +CK_ULONG t_ran = 0; // number of assertions ran +CK_ULONG t_passed = 0; // number of assertions passed +CK_ULONG t_failed = 0; // number of assertions failed +CK_ULONG t_skipped = 0; // number of assertions skipped +CK_ULONG t_errors = 0; // number of errors + +#define MAX_MODEL 4 + +#define DES_KEY_SIZE 8 +#define DES3_KEY_SIZE 24 + +static void *pkcs11lib = NULL; + +static void unload_pkcslib(void) +{ + if (pkcs11lib != NULL) { + dlclose(pkcs11lib); + } +} + +int mech_supported(CK_SLOT_ID slot_id, CK_ULONG mechanism) +{ + CK_MECHANISM_INFO mech_info; + int rc; + rc = funcs->C_GetMechanismInfo(slot_id, mechanism, &mech_info); + + return (rc == CKR_OK); +} + +int mech_supported_flags(CK_SLOT_ID slot_id, CK_ULONG mechanism, CK_FLAGS flags) +{ + CK_MECHANISM_INFO mech_info; + int rc; + + rc = funcs->C_GetMechanismInfo(slot_id, mechanism, &mech_info); + if (rc != CKR_OK) + return FALSE; + + if (mech_info.flags & flags) + return TRUE; + + return FALSE; +} + +/* + * Check if the specified key size is in the supported range of the mechanism. + * + * ATTENTION: It is mechanism dependent if the key size is in bits or bytes. + * The caller of this function must take care that the keylen parameter is + * specified in the appropriate unit. + */ +int check_supp_keysize(CK_SLOT_ID slot_id, CK_ULONG mechanism, CK_ULONG keylen) +{ + CK_MECHANISM_INFO mech_info; + int rc; + rc = funcs->C_GetMechanismInfo(slot_id, mechanism, &mech_info); + if (rc != CKR_OK) + return FALSE; + + return ((mech_info.ulMinKeySize <= keylen) + && (keylen <= mech_info.ulMaxKeySize)); +} + +/** Returns true if and only if slot supports + key wrapping with specified mechanism **/ +int wrap_supported(CK_SLOT_ID slot_id, CK_MECHANISM mech) +{ + CK_MECHANISM_INFO mech_info; + CK_RV rc; + // get mech info + rc = funcs->C_GetMechanismInfo(slot_id, mech.mechanism, &mech_info); + if (rc != CKR_OK) { + testcase_error("C_GetMechanismInfo(), rc=%s.", p11_get_ckr(rc)); + return -1; + } + rc = mech_info.flags & CKF_WRAP; + + return rc; +} + +/** Returns true if and only if slot supports + key unwrapping with specified mechanism **/ +int unwrap_supported(CK_SLOT_ID slot_id, CK_MECHANISM mech) +{ + CK_MECHANISM_INFO mech_info; + CK_RV rc; + // get mech info + rc = funcs->C_GetMechanismInfo(slot_id, mech.mechanism, &mech_info); + if (rc != CKR_OK) { + testcase_error("C_GetMechanismInfo(), rc=%s.", p11_get_ckr(rc)); + return -1; + } + rc = mech_info.flags & CKF_UNWRAP; + + return rc; +} + +/** Create an AES key handle with given value **/ +int create_AESKey(CK_SESSION_HANDLE session, + unsigned char key[], unsigned char key_len, + CK_OBJECT_HANDLE * h_key) +{ + CK_RV rc; + CK_BBOOL true = TRUE; + CK_BBOOL false = FALSE; + CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; + CK_KEY_TYPE keyType = CKK_AES; + CK_ATTRIBUTE keyTemplate[] = { + {CKA_CLASS, &keyClass, sizeof(keyClass)}, + {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, + {CKA_ENCRYPT, &true, sizeof(true)}, + {CKA_TOKEN, &false, sizeof(false)}, + {CKA_VALUE, key, key_len} + }; + + rc = funcs->C_CreateObject(session, keyTemplate, 5, h_key); + + return rc; +} + +/** Generate an AES key handle **/ +int generate_AESKey(CK_SESSION_HANDLE session, + CK_ULONG key_len, + CK_MECHANISM * mechkey, CK_OBJECT_HANDLE * h_key) +{ + CK_ATTRIBUTE key_gen_tmpl[] = { + {CKA_VALUE_LEN, &key_len, sizeof(CK_ULONG)} + }; + + CK_RV rc = funcs->C_GenerateKey(session, + mechkey, + key_gen_tmpl, + 1, + h_key); + + return rc; +} + +/** Create a DES key handle with given value **/ +int create_DESKey(CK_SESSION_HANDLE session, + unsigned char key[], unsigned char klen, + CK_OBJECT_HANDLE * h_key) +{ + CK_RV rc; + CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; + CK_KEY_TYPE keyType = CKK_DES; + CK_BYTE value[DES_KEY_SIZE]; + CK_BBOOL true = TRUE; + CK_BBOOL false = FALSE; + + CK_ATTRIBUTE keyTemplate[] = { + {CKA_CLASS, &keyClass, sizeof(keyClass)}, + {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, + {CKA_ENCRYPT, &true, sizeof(true)}, + {CKA_TOKEN, &false, sizeof(false)}, + {CKA_VALUE, value, klen} + }; + + memset(value, 0, sizeof(value)); + memcpy(value, key, klen); + rc = funcs->C_CreateObject(session, keyTemplate, 5, h_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Create DES2 key handle with given value **/ +int create_DES2Key(CK_SESSION_HANDLE session, + unsigned char key[], unsigned char klen, + CK_OBJECT_HANDLE * h_key) +{ + CK_RV rc; + CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; + CK_KEY_TYPE keyType = CKK_DES2; + CK_BYTE value[2 * DES_KEY_SIZE]; + CK_BBOOL true = TRUE; + CK_BBOOL false = FALSE; + CK_ATTRIBUTE keyTemplate[] = { + {CKA_CLASS, &keyClass, sizeof(keyClass)}, + {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, + {CKA_ENCRYPT, &true, sizeof(true)}, + {CKA_TOKEN, &false, sizeof(false)}, + {CKA_VALUE, value, klen} + }; + + memset(value, 0, sizeof(value)); + memcpy(value, key, klen); + rc = funcs->C_CreateObject(session, keyTemplate, 5, h_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Create DES3 key handle with given value **/ +int create_DES3Key(CK_SESSION_HANDLE session, + unsigned char key[], unsigned char klen, + CK_OBJECT_HANDLE * h_key) +{ + CK_RV rc; + CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; + CK_KEY_TYPE keyType = CKK_DES3; + CK_BYTE value[DES3_KEY_SIZE]; + CK_BBOOL true = TRUE; + CK_BBOOL false = FALSE; + CK_ATTRIBUTE keyTemplate[] = { + {CKA_CLASS, &keyClass, sizeof(keyClass)}, + {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, + {CKA_ENCRYPT, &true, sizeof(true)}, + {CKA_TOKEN, &false, sizeof(false)}, + {CKA_VALUE, value, klen} + }; + + memset(value, 0, sizeof(value)); + memcpy(value, key, klen); + rc = funcs->C_CreateObject(session, keyTemplate, 5, h_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Create Generic Secret key handle with given value **/ +int create_GenericSecretKey(CK_SESSION_HANDLE session, + CK_BYTE key[], + CK_ULONG key_len, CK_OBJECT_HANDLE * h_key) +{ + CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; + CK_KEY_TYPE key_type = CKK_GENERIC_SECRET; + CK_BBOOL false = FALSE; + CK_RV rc; + CK_ATTRIBUTE key_attribs[] = { + {CKA_CLASS, &key_class, sizeof(key_class)}, + {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, + {CKA_TOKEN, &false, sizeof(false)}, + {CKA_VALUE, key, key_len} + }; + + rc = funcs->C_CreateObject(session, key_attribs, 4, h_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Create an RSA private key using ctr + (chinese remainder theorem) values **/ +CK_RV create_RSAPrivateKey(CK_SESSION_HANDLE session, + CK_BYTE modulus[], + CK_BYTE publicExponent[], + CK_BYTE privateExponent[], + CK_BYTE prime1[], + CK_BYTE prime2[], + CK_BYTE exponent1[], + CK_BYTE exponent2[], + CK_BYTE coefficient[], + CK_ULONG modulus_len, + CK_ULONG publicExponent_len, + CK_ULONG privateExponent_len, + CK_ULONG prime1_len, + CK_ULONG prime2_len, + CK_ULONG exponent1_len, + CK_ULONG exponent2_len, + CK_ULONG coefficient_len, + CK_OBJECT_HANDLE * priv_key) +{ + + CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_RSA; + CK_UTF8CHAR label[] = "An RSA private key object"; + CK_BYTE subject[] = {0}; + CK_BYTE id[] = { 123 }; + CK_RV rc; + + CK_BBOOL true = TRUE; + CK_ATTRIBUTE template[] = { + {CKA_CLASS, &class, sizeof(class)}, + {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_LABEL, label, sizeof(label) - 1}, + {CKA_SUBJECT, subject, 0}, + {CKA_ID, id, sizeof(id)}, + {CKA_SENSITIVE, &true, sizeof(true)}, + {CKA_DECRYPT, &true, sizeof(true)}, + {CKA_SIGN, &true, sizeof(true)}, + {CKA_MODULUS, modulus, modulus_len}, + {CKA_PUBLIC_EXPONENT, publicExponent, publicExponent_len}, + {CKA_PRIVATE_EXPONENT, privateExponent, privateExponent_len}, + {CKA_PRIME_1, prime1, prime1_len}, + {CKA_PRIME_2, prime2, prime2_len}, + {CKA_EXPONENT_1, exponent1, exponent1_len}, + {CKA_EXPONENT_2, exponent2, exponent2_len}, + {CKA_COEFFICIENT, coefficient, coefficient_len} + }; + + // create key + rc = funcs->C_CreateObject(session, template, 17, priv_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Create an RSA public key **/ +CK_RV create_RSAPublicKey(CK_SESSION_HANDLE session, + CK_BYTE modulus[], + CK_BYTE publicExponent[], + CK_ULONG modulus_len, + CK_ULONG publicExponent_len, + CK_OBJECT_HANDLE * publ_key) +{ + + CK_RV rc; + CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; + CK_KEY_TYPE keyType = CKK_RSA; + CK_UTF8CHAR label[] = "An RSA public key object"; + CK_BBOOL true = TRUE; + CK_ATTRIBUTE template[] = { + {CKA_CLASS, &class, sizeof(class)}, + {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_LABEL, label, sizeof(label) - 1}, + {CKA_WRAP, &true, sizeof(true)}, + {CKA_ENCRYPT, &true, sizeof(true)}, + {CKA_MODULUS, modulus, modulus_len}, + {CKA_PUBLIC_EXPONENT, publicExponent, publicExponent_len} + }; + + // create key + rc = funcs->C_CreateObject(session, template, 8, publ_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Generate an RSA (PKCS) key pair **/ +CK_RV generate_RSA_PKCS_KeyPair(CK_SESSION_HANDLE session, + CK_ULONG modulusBits, + CK_BYTE publicExponent[], + CK_ULONG publicExponent_len, + CK_OBJECT_HANDLE * publ_key, + CK_OBJECT_HANDLE * priv_key) +{ + CK_RV rc; + CK_MECHANISM mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL, 0 }; + CK_BYTE subject[] = {0}; + CK_BYTE id[] = { 123 }; + CK_BBOOL true = TRUE; + CK_ATTRIBUTE publicKeyTemplate[] = { + {CKA_ENCRYPT, &true, sizeof(true)}, + {CKA_VERIFY, &true, sizeof(true)}, + {CKA_WRAP, &true, sizeof(true)}, + {CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)}, + {CKA_PUBLIC_EXPONENT, publicExponent, publicExponent_len} + }; + CK_ATTRIBUTE privateKeyTemplate[] = { + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_PRIVATE, &true, sizeof(true)}, + {CKA_SUBJECT, subject, 0}, + {CKA_ID, id, sizeof(id)}, + {CKA_SENSITIVE, &true, sizeof(true)}, + {CKA_DECRYPT, &true, sizeof(true)}, + {CKA_SIGN, &true, sizeof(true)}, + {CKA_UNWRAP, &true, sizeof(true)}, + }; + + // generate keys + rc = funcs->C_GenerateKeyPair(session, + &mech, + publicKeyTemplate, + 5, privateKeyTemplate, 8, publ_key, priv_key); + + return rc; + // no error checking due to + // ICA Token + public exponent values + CKR_TEMPLATE_INCONSISTENT + // work around + // see rsa_func.c +} + +/** Create an EC private key using private value 'd' + and ec parameter values (alg id of curve) **/ +CK_RV create_ECPrivateKey(CK_SESSION_HANDLE session, + CK_BYTE params[], + CK_ULONG params_len, + CK_BYTE privatekey[], + CK_ULONG privatekey_len, + CK_BYTE pubkey[], + CK_ULONG pubkey_len, CK_OBJECT_HANDLE * priv_key) +{ + + CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_EC; + CK_UTF8CHAR label[] = "An EC private key object"; + CK_BYTE subject[] = {0}; + CK_BYTE id[] = { 123 }; + CK_RV rc; + + CK_BBOOL true = TRUE; + CK_ATTRIBUTE template[] = { + {CKA_CLASS, &class, sizeof(class)}, + {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_PRIVATE, &true, sizeof(true)}, + {CKA_LABEL, label, sizeof(label)}, + {CKA_SUBJECT, subject, 0}, + {CKA_ID, id, sizeof(id)}, + {CKA_SENSITIVE, &true, sizeof(true)}, + {CKA_DECRYPT, &true, sizeof(true)}, + {CKA_SIGN, &true, sizeof(true)}, + {CKA_DERIVE, &true, sizeof(true)}, + {CKA_EC_PARAMS, params, params_len}, + {CKA_EC_POINT, pubkey, pubkey_len}, + {CKA_VALUE, privatekey, privatekey_len} + }; + + // create key + rc = funcs->C_CreateObject(session, template, + sizeof(template) / sizeof(CK_ATTRIBUTE), + priv_key); + return rc; +} + +/** Create an EC public key using ec params and point 'Q' **/ +CK_RV create_ECPublicKey(CK_SESSION_HANDLE session, + CK_BYTE params[], + CK_ULONG params_len, + CK_BYTE pointq[], + CK_ULONG pointq_len, CK_OBJECT_HANDLE * publ_key) +{ + CK_RV rc; + CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; + CK_KEY_TYPE keyType = CKK_EC; + CK_UTF8CHAR label[] = "An EC public key object"; + CK_BBOOL true = TRUE; + CK_ATTRIBUTE template[] = { + {CKA_CLASS, &class, sizeof(class)}, + {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_LABEL, label, sizeof(label)}, + {CKA_ENCRYPT, &true, sizeof(true)}, + {CKA_VERIFY, &true, sizeof(true)}, + {CKA_DERIVE, &true, sizeof(true)}, + {CKA_EC_PARAMS, params, params_len}, + {CKA_EC_POINT, pointq, pointq_len} + }; + + // create key + rc = funcs->C_CreateObject(session, template, + sizeof(template) / sizeof(CK_ATTRIBUTE), + publ_key); + return rc; +} + +/** Create an IBM Dilithium private key using private values **/ +CK_RV create_DilithiumPrivateKey(CK_SESSION_HANDLE session, + CK_BYTE rho[], CK_ULONG rho_len, + CK_BYTE seed[], CK_ULONG seed_len, + CK_BYTE tr[], CK_ULONG tr_len, + CK_BYTE s1[], CK_ULONG s1_len, + CK_BYTE s2[], CK_ULONG s2_len, + CK_BYTE t0[], CK_ULONG t0_len, + CK_BYTE t1[], CK_ULONG t1_len, + CK_OBJECT_HANDLE * priv_key) +{ + CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_IBM_PQC_DILITHIUM; + CK_UTF8CHAR label[] = "A Dilithium private key object"; + CK_BYTE subject[] = {0}; + CK_BYTE id[] = { 123 }; + CK_ULONG keyform = IBM_DILITHIUM_KEYFORM_ROUND2; + CK_RV rc; + + CK_BBOOL true = TRUE; + CK_ATTRIBUTE template[] = { + {CKA_CLASS, &class, sizeof(class)}, + {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_PRIVATE, &true, sizeof(true)}, + {CKA_LABEL, label, sizeof(label)}, + {CKA_SUBJECT, subject, 0}, + {CKA_ID, id, sizeof(id)}, + {CKA_SENSITIVE, &true, sizeof(true)}, + {CKA_SIGN, &true, sizeof(true)}, + {CKA_IBM_DILITHIUM_RHO, rho, rho_len}, + {CKA_IBM_DILITHIUM_SEED, seed, seed_len}, + {CKA_IBM_DILITHIUM_TR, tr, tr_len}, + {CKA_IBM_DILITHIUM_S1, s1, s1_len}, + {CKA_IBM_DILITHIUM_S2, s2, s2_len}, + {CKA_IBM_DILITHIUM_T0, t0, t0_len}, + {CKA_IBM_DILITHIUM_T1, t1, t1_len}, + {CKA_IBM_DILITHIUM_KEYFORM, &keyform, sizeof(keyform)}, + }; + + // create key + rc = funcs->C_CreateObject(session, template, + sizeof(template) / sizeof(CK_ATTRIBUTE), + priv_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Create an IBM Dilithium public key using (rho, t1) **/ +CK_RV create_DilithiumPublicKey(CK_SESSION_HANDLE session, + CK_BYTE rho[], CK_ULONG rho_len, + CK_BYTE t1[], CK_ULONG t1_len, + CK_OBJECT_HANDLE * publ_key) +{ + CK_RV rc; + CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; + CK_KEY_TYPE keyType = CKK_IBM_PQC_DILITHIUM; + CK_UTF8CHAR label[] = "A Dilithium public key object"; + CK_BBOOL true = TRUE; + CK_ULONG keyform = IBM_DILITHIUM_KEYFORM_ROUND2; + CK_ATTRIBUTE template[] = { + {CKA_CLASS, &class, sizeof(class)}, + {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_LABEL, label, sizeof(label)}, + {CKA_VERIFY, &true, sizeof(true)}, + {CKA_IBM_DILITHIUM_RHO, rho, rho_len}, + {CKA_IBM_DILITHIUM_T1, t1, t1_len}, + {CKA_IBM_DILITHIUM_KEYFORM, &keyform, sizeof(keyform)}, + }; + + // create key + rc = funcs->C_CreateObject(session, template, + sizeof(template) / sizeof(CK_ATTRIBUTE), + publ_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Create an DSA public key using the prime 'p', subprime 'q', base 'g' and private value 'y' **/ +CK_RV create_DSAPrivateKey(CK_SESSION_HANDLE session, + CK_BYTE prime[], + CK_ULONG prime_len, + CK_BYTE subprime[], + CK_ULONG subprime_len, + CK_BYTE base[], + CK_ULONG base_len, + CK_BYTE privatekey[], + CK_ULONG privatekey_len, CK_OBJECT_HANDLE * priv_key) +{ + + CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_DSA; + CK_UTF8CHAR label[] = "An DSA private key object"; + CK_BYTE subject[] = {0}; + CK_BYTE id[] = { 123 }; + CK_RV rc; + + CK_BBOOL true = TRUE; + CK_ATTRIBUTE template[] = { + {CKA_CLASS, &class, sizeof(class)}, + {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_LABEL, label, sizeof(label)}, + {CKA_SUBJECT, subject, 0}, + {CKA_ID, id, sizeof(id)}, + {CKA_SENSITIVE, &true, sizeof(true)}, + {CKA_DECRYPT, &true, sizeof(true)}, + {CKA_SIGN, &true, sizeof(true)}, + {CKA_PRIME, prime, prime_len}, + {CKA_SUBPRIME, subprime, subprime_len}, + {CKA_BASE, base, base_len}, + {CKA_VALUE, privatekey, privatekey_len} + }; + + // create key + rc = funcs->C_CreateObject(session, template, + sizeof(template) / sizeof(CK_ATTRIBUTE), + priv_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Create an DSA public key using the prime 'p', subprime 'q', base 'g' and public value 'x' **/ +CK_RV create_DSAPublicKey(CK_SESSION_HANDLE session, + CK_BYTE prime[], + CK_ULONG prime_len, + CK_BYTE subprime[], + CK_ULONG subprime_len, + CK_BYTE base[], + CK_ULONG base_len, + CK_BYTE publickey[], + CK_ULONG publickey_len, CK_OBJECT_HANDLE * publ_key) +{ + CK_RV rc; + CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; + CK_KEY_TYPE keyType = CKK_DSA; + CK_UTF8CHAR label[] = "An DSA public key object"; + CK_BBOOL true = TRUE; + CK_ATTRIBUTE template[] = { + {CKA_CLASS, &class, sizeof(class)}, + {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_LABEL, label, sizeof(label)}, + {CKA_ENCRYPT, &true, sizeof(true)}, + {CKA_VERIFY, &true, sizeof(true)}, + {CKA_PRIME, prime, prime_len}, + {CKA_SUBPRIME, subprime, subprime_len}, + {CKA_BASE, base, base_len}, + {CKA_VALUE, publickey, publickey_len} + }; + + // create key + rc = funcs->C_CreateObject(session, template, + sizeof(template) / sizeof(CK_ATTRIBUTE), + publ_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Create an DH public key using the prime 'p', base 'g' and private value 'y' **/ +CK_RV create_DHPrivateKey(CK_SESSION_HANDLE session, + CK_BYTE prime[], + CK_ULONG prime_len, + CK_BYTE base[], + CK_ULONG base_len, + CK_BYTE privatekey[], + CK_ULONG privatekey_len, CK_OBJECT_HANDLE * priv_key) +{ + + CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_DH; + CK_UTF8CHAR label[] = "An DH private key object"; + CK_BYTE subject[] = {0}; + CK_BYTE id[] = { 123 }; + CK_RV rc; + + CK_BBOOL true = TRUE; + CK_ATTRIBUTE template[] = { + {CKA_CLASS, &class, sizeof(class)}, + {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_LABEL, label, sizeof(label)}, + {CKA_SUBJECT, subject, 0}, + {CKA_ID, id, sizeof(id)}, + {CKA_SENSITIVE, &true, sizeof(true)}, + {CKA_DECRYPT, &true, sizeof(true)}, + {CKA_SIGN, &true, sizeof(true)}, + {CKA_DERIVE, &true, sizeof(true)}, + {CKA_PRIME, prime, prime_len}, + {CKA_BASE, base, base_len}, + {CKA_VALUE, privatekey, privatekey_len} + }; + + // create key + rc = funcs->C_CreateObject(session, template, + sizeof(template) / sizeof(CK_ATTRIBUTE), + priv_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/* Create an DH public key using the prime 'p', base 'g' and public value 'x' */ +CK_RV create_DHPublicKey(CK_SESSION_HANDLE session, + CK_BYTE prime[], + CK_ULONG prime_len, + CK_BYTE base[], + CK_ULONG base_len, + CK_BYTE publickey[], + CK_ULONG publickey_len, CK_OBJECT_HANDLE * publ_key) +{ + CK_RV rc; + CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; + CK_KEY_TYPE keyType = CKK_DH; + CK_UTF8CHAR label[] = "An DH public key object"; + CK_BBOOL true = TRUE; + CK_ATTRIBUTE template[] = { + {CKA_CLASS, &class, sizeof(class)}, + {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_LABEL, label, sizeof(label)}, + {CKA_ENCRYPT, &true, sizeof(true)}, + {CKA_VERIFY, &true, sizeof(true)}, + {CKA_PRIME, prime, prime_len}, + {CKA_BASE, base, base_len}, + {CKA_VALUE, publickey, publickey_len} + }; + + // create key + rc = funcs->C_CreateObject(session, template, + sizeof(template) / sizeof(CK_ATTRIBUTE), + publ_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/* Generate a secret key */ +CK_RV generate_SecretKey(CK_SESSION_HANDLE session, + CK_ULONG keylen, + CK_MECHANISM * mech, CK_OBJECT_HANDLE * secret_key) +{ + CK_RV rc; + CK_OBJECT_CLASS class = CKO_SECRET_KEY; + CK_ATTRIBUTE secret_tmpl[] = { + {CKA_CLASS, &class, sizeof(class)}, + {CKA_VALUE_LEN, &keylen, sizeof(keylen)} + }; + + rc = funcs->C_GenerateKey(session, mech, secret_tmpl, 2, secret_key); + if (rc != CKR_OK) { + testcase_fail("C_GenerateKey, rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +int keysize_supported(CK_SLOT_ID slot_id, CK_ULONG mechanism, CK_ULONG size) +{ + CK_MECHANISM_INFO mech_info; + CK_RV rc; + + rc = funcs->C_GetMechanismInfo(slot_id, mechanism, &mech_info); + if (size < mech_info.ulMinKeySize || size > mech_info.ulMaxKeySize) + return 0; + + return (rc == CKR_OK); +} + +/** Returns true if pubexp is valid for EP11 Tokens **/ +int is_valid_ep11_pubexp(CK_BYTE pubexp[], CK_ULONG pubexp_len) +{ + CK_ULONG i; + + /* everything > 0x10 valid */ + if (pubexp[0] > 0x10) { + return 1; + } else { + for (i = 1; i < pubexp_len + 1; i++) { + if (pubexp[i] != 0) + return 1; + } + } + + return 0; +} + +/** Returns true if slot_id is an ICA Token **/ +int is_ep11_token(CK_SLOT_ID slot_id) +{ + CK_RV rc; + CK_TOKEN_INFO tokinfo; + + rc = funcs->C_GetTokenInfo(slot_id, &tokinfo); + if (rc != CKR_OK) + return FALSE; + + return strstr((const char *) tokinfo.model, "EP11") != NULL; +} + +/** Returns true if pubexp is valid for CCA Tokens **/ +int is_valid_cca_pubexp(CK_BYTE pubexp[], CK_ULONG pubexp_len) +{ + CK_BYTE exp3[] = { 0x03 }; // 3 + CK_BYTE exp65537[] = { 0x01, 0x00, 0x01 }; // 65537 + + return (pubexp_len == 1 && (!memcmp(pubexp, exp3, 1))) + || (pubexp_len == 3 && (!memcmp(pubexp, exp65537, 3))); +} + +/** Returns true if slot_id is an ICSF token + ** ICSF token info is not necessarily hard-coded like the other tokens + ** so there is no single identifying attribute. So, instead just + ** use logical deduction.... + **/ +int is_icsf_token(CK_SLOT_ID slot_id) +{ + CK_RV rc; + CK_TOKEN_INFO tokinfo; + + rc = funcs->C_GetTokenInfo(slot_id, &tokinfo); + if (rc != CKR_OK) + return FALSE; + + if ((strstr((const char *) tokinfo.model, "ICA") == NULL) && + (strstr((const char *) tokinfo.model, "EP11") == NULL) && + (strstr((const char *) tokinfo.model, "CCA") == NULL) && + (strstr((const char *) tokinfo.model, "SoftTok") == NULL)) + return TRUE; + + return FALSE; +} + +/** Returns true if pubexp is valid for ICSF token **/ +int is_valid_icsf_pubexp(CK_BYTE pubexp[], CK_ULONG pubexp_len) +{ + CK_BYTE exp65537[] = { 0x01, 0x00, 0x01 }; // 65537 + + return (pubexp_len == 3 && (!memcmp(pubexp, exp65537, 3))); +} + +/** Returns true if slot_id is an ICA Token **/ +int is_ica_token(CK_SLOT_ID slot_id) +{ + CK_RV rc; + CK_TOKEN_INFO tokinfo; + + rc = funcs->C_GetTokenInfo(slot_id, &tokinfo); + if (rc != CKR_OK) + return FALSE; + + return strstr((const char *) tokinfo.model, "ICA") != NULL; +} + +/** Returns true if slot_id is a CCA Token **/ +int is_cca_token(CK_SLOT_ID slot_id) +{ + CK_RV rc; + CK_TOKEN_INFO tokinfo; + + rc = funcs->C_GetTokenInfo(slot_id, &tokinfo); + if (rc != CKR_OK) + return FALSE; + + return strstr((const char *) tokinfo.model, "CCA") != NULL; +} + +/** Returns true if slot_id is a SoftTok Token **/ +int is_soft_token(CK_SLOT_ID slot_id) +{ + CK_RV rc; + CK_TOKEN_INFO tokinfo; + + rc = funcs->C_GetTokenInfo(slot_id, &tokinfo); + if (rc != CKR_OK) + return FALSE; + + return strstr((const char *) tokinfo.model, "SoftTok") != NULL; +} + +/** Returns true if slot_id is a TPM Token **/ +int is_tpm_token(CK_SLOT_ID slot_id) +{ + CK_RV rc; + CK_TOKEN_INFO tokinfo; + + rc = funcs->C_GetTokenInfo(slot_id, &tokinfo); + if (rc != CKR_OK) + return FALSE; + + return strstr((const char *) tokinfo.model, "TPM") != NULL; +} + +/** Returns true if pubexp is valid for CCA Tokens **/ +int is_valid_tpm_pubexp(CK_BYTE pubexp[], CK_ULONG pubexp_len) +{ + CK_BYTE exp65537[] = { 0x01, 0x00, 0x01 }; // 65537 + + return (pubexp_len == 3 && (!memcmp(pubexp, exp65537, 3))); +} + +int is_valid_tpm_modbits(CK_ULONG modbits) +{ + switch (modbits) { + case 512: + case 1024: + case 2048: + return 1; + default: + return 0; + } +} + +int get_so_pin(CK_BYTE * dest) +{ + char *val; + + val = getenv(PKCS11_SO_PIN_ENV_VAR); + if (val == NULL) { + fprintf(stderr, "The environment variable %s must be set " + "before this testcase is run.\n", PKCS11_SO_PIN_ENV_VAR); + return -1; + } + + if ((strlen(val) + 1) > PKCS11_MAX_PIN_LEN) { + fprintf(stderr, "The environment variable %s must hold a " + "value less than %d chars in length.\n", + PKCS11_SO_PIN_ENV_VAR, (int) PKCS11_MAX_PIN_LEN); + return -1; + } + + memcpy(dest, val, strlen(val) + 1); + + return 0; +} + +int get_user_pin(CK_BYTE * dest) +{ + char *val; + + val = getenv(PKCS11_USER_PIN_ENV_VAR); + if (val == NULL) { + fprintf(stderr, "The environment variable %s must be set " + "before this testcase is run.\n", PKCS11_USER_PIN_ENV_VAR); + return -1; + } + + if ((strlen(val) + 1) > PKCS11_MAX_PIN_LEN) { + fprintf(stderr, "The environment variable %s must hold a " + "value less than %d chars in length.\n", + PKCS11_SO_PIN_ENV_VAR, (int) PKCS11_MAX_PIN_LEN); + return -1; + } + + memcpy(dest, val, strlen(val) + 1); + + return 0; +} + + + +void process_time(SYSTEMTIME t1, SYSTEMTIME t2) +{ + long ms = t2.millitm - t1.millitm; + long s = t2.time - t1.time; + + while (ms < 0) { + ms += 1000; + s--; + } + + ms += (s * 1000); + + printf("Time: %u msec\n", (unsigned int) ms); +} + + + +// +// +void print_hex(CK_BYTE * buf, CK_ULONG len) +{ + CK_ULONG i, j; + + i = 0; + + while (i < len) { + for (j = 0; (j < 16) && (i < len); j++, i++) + fprintf(stderr, "%02x ", buf[i]); + fprintf(stderr, "\n"); + } + fprintf(stderr, "\n"); +} + +void usage(char *fct) +{ + printf("usage: %s [-securekey] [-noskip] [-noinit] [-h] -slot \n\n", + fct); + + return; +} + + +int do_ParseArgs(int argc, char **argv) +{ + int i; + char *endp; + + skip_token_obj = TRUE; + no_stop = FALSE; + no_init = FALSE; + securekey = FALSE; + SLOT_ID = 1000; + + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { + usage(argv[0]); + return 0; + } else if (strcmp(argv[i], "-noskip") == 0) { + skip_token_obj = FALSE; + } else if (strcmp(argv[i], "-slot") == 0) { + if (argc <= i + 1) { + printf("No slot number specified\n"); + usage(argv[0]); + return -1; + } + SLOT_ID = strtol(argv[i + 1], &endp, 10); + if (*endp != '\0') { + printf("Invalid slot number specified: %s\n", argv[i + 1]); + usage(argv[0]); + return -1; + } + i++; + } else if (strcmp(argv[i], "-securekey") == 0) { + securekey = TRUE; + } else if (strcmp(argv[i], "-noinit") == 0) { + no_init = TRUE; + } else if (strcmp(argv[i], "-nostop") == 0) { + no_stop = TRUE; + } else { + printf("Invalid argument passed as option: %s\n", argv[i]); + usage(argv[0]); + return -1; + } + } + + // error if slot has not been identified. + if (SLOT_ID == 1000) { + printf("Please specify the slot to be tested.\n"); + usage(argv[0]); + return -1; + } + + return 1; +} + +// +// +int do_GetFunctionList(void) +{ + CK_RV rc; + CK_RV(*pfoo) (); + char *e; + char *f = "libopencryptoki.so"; + + e = getenv("PKCSLIB"); + if (e == NULL) { + e = f; + // return FALSE; + } + pkcs11lib = dlopen(e, RTLD_NOW); + if (pkcs11lib == NULL) { + return FALSE; + } + + *(void **)(&pfoo) = dlsym(pkcs11lib, "C_GetFunctionList"); + if (pfoo == NULL) { + dlclose(pkcs11lib); + return FALSE; + } + rc = pfoo(&funcs); + + if (rc != CKR_OK) { + testcase_error("C_GetFunctionList rc=%s", p11_get_ckr(rc)); + dlclose(pkcs11lib); + return FALSE; + } + + atexit(unload_pkcslib); + return TRUE; +} diff --git a/testcases/common/common.mk b/testcases/common/common.mk new file mode 100644 index 0000000..0f05f2b --- /dev/null +++ b/testcases/common/common.mk @@ -0,0 +1,6 @@ +noinst_LTLIBRARIES += testcases/common/libcommon.la + +testcases_common_libcommon_la_LIBADD = -lc -ldl -lpthread +testcases_common_libcommon_la_CFLAGS = -c ${testcases_inc} +testcases_common_libcommon_la_SOURCES = \ + usr/lib/common/p11util.c testcases/common/common.c diff --git a/testcases/crypto/README b/testcases/crypto/README new file mode 100644 index 0000000..b57bc8a --- /dev/null +++ b/testcases/crypto/README @@ -0,0 +1,47 @@ +Notes: + +aes_tests + Tests aes cbc/ecb/ctr modes using published test vectors and + generated test data. + + ICSF token - secret keys cannot wrap secret keys. + These testcase will fail in ICSF token. + +des_tests + Tests des ecb/cbc modes using published test vectors and generated + test data. + + ICSF token - secret keys cannot wrap secret keys. + These testcase will fail in ICSF token. + +des3_tests + Tests des3 ecb/cbc modes using published test vectors and generated + test data. + Tests des3 cbc mode with padding only using generated test data. + + ICSF token - secret keys cannot wrap secret keys. + These testcase will fail in ICSF token. + +dh_tests + Tests key generation and key derivation. + +digest_tests + Tests message digest, multipart message digest, and signature + verification using published test vectors for: + SHA1, SHA256, SHA384, SHA512, MD2, MD5, RIPEMD-160, RIPEMD-128 + HMAC SHA1, HMAC SHA256, HMAC SHA512, HMAC MD5 + +dsa_tests + TODO - To be tested. + +ec_tests + Tests regular curves. + +rsa_tests + Tests RSA using published test vectors and generated test data. + + ICSF token - only supports public exponents 0x03 and 0x010001. + Testcases with other exponents will fail. + +ssl3_tests + Tests key generation and key derivation. diff --git a/testcases/crypto/aes.h b/testcases/crypto/aes.h new file mode 100644 index 0000000..cdd365c --- /dev/null +++ b/testcases/crypto/aes.h @@ -0,0 +1,1835 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2011-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 + */ + +#include "pkcs11types.h" + +#ifndef _AES_H_ +#define _AES_H_ +#endif +#if !defined(TRUE) +#define TRUE 1 +#endif + +#if !defined(FALSE) +#define FALSE 0 +#endif + +#define MAX_KEY_SIZE 64 +#define MAX_TEXT_SIZE 4096 +#define MAX_IV_SIZE 64 +#define MAX_COUNTER_SIZE 16 +#define MAX_AAD_SIZE 512 +#define MAX_TAG_SIZE 16 +#define AES_BLOCK_SIZE 16 +#define AES_COUNTER_VALUE "0123456789012345" +#define AES_IV_VALUE "1234567890123456" +#define AES_KEY_LEN 32 + +#define AES_IV_SIZE 16 +#define AES_COUNTER_SIZE 16 +#define MAX_CHUNKS 8 + + +struct aes_test_vector { + unsigned char key[MAX_KEY_SIZE]; + unsigned char klen; + unsigned char plaintext[MAX_TEXT_SIZE]; + unsigned char plen; + unsigned char ciphertext[MAX_TEXT_SIZE]; + unsigned char clen; + unsigned char iv[MAX_IV_SIZE]; // aes cbc mode + unsigned char ivlen; // aes cbc mode + unsigned char counter[MAX_COUNTER_SIZE]; // aes ctr mode + unsigned char counterlen; // aes ctr mode + unsigned int counterbits; // aes ctr mode + unsigned char aad[MAX_AAD_SIZE]; // aes gcm mode + unsigned int aadlen; // aes gcm mode + unsigned int tag[MAX_TAG_SIZE]; // aes gcm mode + unsigned int taglen; // aes gcm mode + int chunks_plain[MAX_CHUNKS]; + int num_chunks_plain; + int chunks_ciph[MAX_CHUNKS]; + int num_chunks_ciph; +}; + +struct published_test_suite_info { + const char *name; + unsigned int tvcount; + struct aes_test_vector *tv; + unsigned int size; + CK_MECHANISM mech; +}; + +struct generated_test_suite_info { + const char *name; + CK_MECHANISM mech; + unsigned int size; +}; + +char aes_iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f +}; + +struct CK_AES_CTR_PARAMS aesctr = { + .ulCounterBits = AES_COUNTER_SIZE, + .cb = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}, +}; + +struct CK_GCM_PARAMS aesgcm = { + .ulIvLen = AES_BLOCK_SIZE, + .ulAADLen = 0, + .ulTagBits = 16, +}; + +struct CK_MECHANISM aes_keygen = { + .mechanism = CKM_AES_KEY_GEN, + .ulParameterLen = 0, + .pParameter = NULL, +}; + +struct cmac_test_vector { + unsigned char key[MAX_KEY_SIZE]; + unsigned char klen; + unsigned char msg[MAX_TEXT_SIZE]; + unsigned char mlen; + unsigned char mac[MAX_KEY_SIZE]; + unsigned char tlen; + int chunks_msg[MAX_CHUNKS]; + int num_chunks_message; +}; + +struct published_cmac_test_suite_info { + const char *name; + unsigned int tvcount; + struct cmac_test_vector *tv; + CK_MECHANISM mech; +}; + +/** NIST Special Publication 800-38A + http://www.csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf +**/ +static struct aes_test_vector aes_ecb_tv[] = { + { // #0 + .key = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}, + .klen = 16, + .plaintext = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}, + .plen = 64, + .ciphertext = {0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60, + 0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97, + 0xf5, 0xd3, 0xd5, 0x85, 0x03, 0xb9, 0x69, 0x9d, + 0xe7, 0x85, 0x89, 0x5a, 0x96, 0xfd, 0xba, 0xaf, + 0x43, 0xb1, 0xcd, 0x7f, 0x59, 0x8e, 0xce, 0x23, + 0x88, 0x1b, 0x00, 0xe3, 0xed, 0x03, 0x06, 0x88, + 0x7b, 0x0c, 0x78, 0x5e, 0x27, 0xe8, 0xad, 0x3f, + 0x82, 0x23, 0x20, 0x71, 0x04, 0x72, 0x5d, 0xd4}, + .clen = 64, + }, { // #1 + .key = {0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, + 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, + 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b}, + .klen = 24, + .plaintext = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}, + .plen = 64, + .num_chunks_plain = 4, + .chunks_plain = {16, 16, 16, 16}, + .ciphertext = {0xbd, 0x33, 0x4f, 0x1d, 0x6e, 0x45, 0xf2, 0x5f, + 0xf7, 0x12, 0xa2, 0x14, 0x57, 0x1f, 0xa5, 0xcc, + 0x97, 0x41, 0x04, 0x84, 0x6d, 0x0a, 0xd3, 0xad, + 0x77, 0x34, 0xec, 0xb3, 0xec, 0xee, 0x4e, 0xef, + 0xef, 0x7a, 0xfd, 0x22, 0x70, 0xe2, 0xe6, 0x0a, + 0xdc, 0xe0, 0xba, 0x2f, 0xac, 0xe6, 0x44, 0x4e, + 0x9a, 0x4b, 0x41, 0xba, 0x73, 0x8d, 0x6c, 0x72, + 0xfb, 0x16, 0x69, 0x16, 0x03, 0xc1, 0x8e, 0x0e}, + .clen = 64, + .num_chunks_ciph = 4, + .chunks_ciph = {16, 16, 16, 16}, + }, { // #2 + .key = {0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, + 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, + 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4}, + .klen = 32, + .plaintext = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}, + .plen = 64, + .num_chunks_plain = 5, + .chunks_plain = {25, 0, 8, -1, 31}, + .ciphertext = {0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c, + 0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8, + 0x59, 0x1c, 0xcb, 0x10, 0xd4, 0x10, 0xed, 0x26, + 0xdc, 0x5b, 0xa7, 0x4a, 0x31, 0x36, 0x28, 0x70, + 0xb6, 0xed, 0x21, 0xb9, 0x9c, 0xa6, 0xf4, 0xf9, + 0xf1, 0x53, 0xe7, 0xb1, 0xbe, 0xaf, 0xed, 0x1d, + 0x23, 0x30, 0x4b, 0x7a, 0x39, 0xf9, 0xf3, 0xff, + 0x06, 0x7d, 0x8d, 0x8f, 0x9e, 0x24, 0xec, 0xc7}, + .clen = 64, + .num_chunks_ciph = 5, + .chunks_ciph = {25, 0, 8, -1, 31}, + }, +}; + +/** NIST Special Publication 800-38A + http://www.csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf +**/ +static struct aes_test_vector aes_cbc_tv[] = { + { // #0 + .key = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}, + .klen = 16, + .plaintext = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}, + .plen = 64, + .ciphertext = {0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, + 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d, + 0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, + 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2, + 0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, + 0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16, + 0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, + 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7}, + .clen = 64, + .iv = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, + .ivlen = 16, + }, { // #1 + .key = {0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, + 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, + 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b}, + .klen = 24, + .plaintext = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}, + .plen = 64, + .num_chunks_plain = 4, + .chunks_plain = {16, 16, 16, 16}, + .ciphertext = {0x4f, 0x02, 0x1d, 0xb2, 0x43, 0xbc, 0x63, 0x3d, + 0x71, 0x78, 0x18, 0x3a, 0x9f, 0xa0, 0x71, 0xe8, + 0xb4, 0xd9, 0xad, 0xa9, 0xad, 0x7d, 0xed, 0xf4, + 0xe5, 0xe7, 0x38, 0x76, 0x3f, 0x69, 0x14, 0x5a, + 0x57, 0x1b, 0x24, 0x20, 0x12, 0xfb, 0x7a, 0xe0, + 0x7f, 0xa9, 0xba, 0xac, 0x3d, 0xf1, 0x02, 0xe0, + 0x08, 0xb0, 0xe2, 0x79, 0x88, 0x59, 0x88, 0x81, + 0xd9, 0x20, 0xa9, 0xe6, 0x4f, 0x56, 0x15, 0xcd}, + .clen = 64, + .iv = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, + .ivlen = 16, + .num_chunks_ciph = 4, + .chunks_ciph = {16, 16, 16, 16}, + }, { // #2 + .key = {0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, + 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, + 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4}, + .klen = 32, + .plaintext = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}, + .plen = 64, + .num_chunks_plain = 5, + .chunks_plain = {25, 0, 8, -1, 31}, + .ciphertext = {0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, + 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6, + 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, + 0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d, + 0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, + 0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61, + 0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, + 0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b}, + .clen = 64, + .iv = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, + .ivlen = 16, + .num_chunks_ciph = 5, + .chunks_ciph = {25, 0, 8, -1, 31}, + }, +}; + +/** NIST Special Publication 800-38A + http://www.csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf +**/ +static struct aes_test_vector aes_ctr_tv[] = { + { // #0 + .key = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}, + .klen = 16, + .counter = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}, + .counterlen = 16, + .counterbits = 128, + .plaintext = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}, + .plen = 64, + .ciphertext = {0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, + 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce, + 0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff, + 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff, + 0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e, + 0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab, + 0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1, + 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee}, + .clen = 64, + }, { // #1 + .key = {0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, + 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, + 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b}, + .klen = 24, + .counter = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}, + .counterlen = 16, + .counterbits = 128, + .plaintext = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}, + .plen = 64, + .num_chunks_plain = 4, + .chunks_plain = {16, 16, 16, 16}, + .ciphertext = {0x1a, 0xbc, 0x93, 0x24, 0x17, 0x52, 0x1c, 0xa2, + 0x4f, 0x2b, 0x04, 0x59, 0xfe, 0x7e, 0x6e, 0x0b, + 0x09, 0x03, 0x39, 0xec, 0x0a, 0xa6, 0xfa, 0xef, + 0xd5, 0xcc, 0xc2, 0xc6, 0xf4, 0xce, 0x8e, 0x94, + 0x1e, 0x36, 0xb2, 0x6b, 0xd1, 0xeb, 0xc6, 0x70, + 0xd1, 0xbd, 0x1d, 0x66, 0x56, 0x20, 0xab, 0xf7, + 0x4f, 0x78, 0xa7, 0xf6, 0xd2, 0x98, 0x09, 0x58, + 0x5a, 0x97, 0xda, 0xec, 0x58, 0xc6, 0xb0, 0x50}, + .clen = 64, + .num_chunks_ciph = 4, + .chunks_ciph = {16, 16, 16, 16}, + }, { // #2 + .key = {0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, + 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, + 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4}, + .klen = 32, + .counter = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}, + .counterlen = 16, + .counterbits = 128, + .plaintext = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}, + .plen = 64, + .num_chunks_plain = 5, + .chunks_plain = {25, 0, 8, -1, 31}, + .ciphertext = {0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89, 0xa5, + 0xb7, 0xa7, 0xf5, 0x04, 0xbb, 0xf3, 0xd2, 0x28, + 0xf4, 0x43, 0xe3, 0xca, 0x4d, 0x62, 0xb5, 0x9a, + 0xca, 0x84, 0xe9, 0x90, 0xca, 0xca, 0xf5, 0xc5, + 0x2b, 0x09, 0x30, 0xda, 0xa2, 0x3d, 0xe9, 0x4c, + 0xe8, 0x70, 0x17, 0xba, 0x2d, 0x84, 0x98, 0x8d, + 0xdf, 0xc9, 0xc5, 0x8d, 0xb6, 0x7a, 0xad, 0xa6, + 0x13, 0xc2, 0xdd, 0x08, 0x45, 0x79, 0x41, 0xa6}, + .clen = 64, + .num_chunks_ciph = 5, + .chunks_ciph = {25, 0, 8, -1, 31}, + }, +}; + +static struct aes_test_vector aes_gcm_tv[] = { + { /* #0 test with chunks */ + .key = {0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08}, + .klen = 16, + .iv = {0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88,}, + .ivlen = 12, + .aad = {0}, + .aadlen = 0, + .tag = {0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, + 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4}, + .taglen = 128, + .plaintext = {0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55}, + .plen = 64, + .num_chunks_plain = 5, + .chunks_plain = {20, 5, 7, 1, 31}, + .ciphertext = {0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85, + 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, + 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4}, + .clen = 80, + .num_chunks_ciph = 7, + .chunks_ciph = {20, 5, 7, 1, 31, 10, 6}, + }, { + /* #1 - NIST - + * [Keylen = 128] + * [IVlen = 96] + * [PTlen = 0] + * [AADlen = 0] + * [Taglen = 128] + */ + .key = {0x11, 0x75, 0x4c, 0xd7, 0x2a, 0xec, 0x30, 0x9b, + 0xf5, 0x2f, 0x76, 0x87, 0x21, 0x2e, 0x89, 0x57}, + .klen = 16, + .iv = {0x3c, 0x81, 0x9d, 0x9a, 0x9b, 0xed, 0x08, 0x76, + 0x15, 0x03, 0x0b, 0x65}, + .ivlen = 12, + .aad = {0}, + .aadlen = 0, + .tag = {0x25, 0x03, 0x27, 0xc6, 0x74, 0xaa, 0xf4, 0x77, + 0xae, 0xf2, 0x67, 0x57, 0x48, 0xcf, 0x69, 0x71}, + .taglen = 128, + .plaintext = {0}, + .plen = 0, + .ciphertext = {0x25, 0x03, 0x27, 0xc6, 0x74, 0xaa, 0xf4, 0x77, + 0xae, 0xf2, 0x67, 0x57, 0x48, 0xcf, 0x69, 0x71}, + .clen = 16, + }, { + /* #2 - NIST - + * [Keylen = 128] + * [IVlen = 96] + * [PTlen = 128] + * [AADlen = 0] + * [Taglen = 128] + */ + .key = {0x99, 0x71, 0x07, 0x10, 0x59, 0xab, 0xc0, 0x09, + 0xe4, 0xf2, 0xbd, 0x69, 0x86, 0x9d, 0xb3, 0x38}, + .klen = 16, + .iv = {0x07, 0xa9, 0xa9, 0x5e, 0xa3, 0x82, 0x1e, 0x9c, + 0x13, 0xc6, 0x32, 0x51}, + .ivlen = 12, + .aad = {0}, + .aadlen = 0, + .tag = {0x78, 0x70, 0xd9, 0x11, 0x7f, 0x54, 0x81, 0x1a, + 0x34, 0x69, 0x70, 0xf1, 0xde, 0x09, 0x0c, 0x41}, + .taglen = 128, + .plaintext = {0xf5, 0x4b, 0xc3, 0x50, 0x1f, 0xed, 0x4f, 0x6f, + 0x6d, 0xfb, 0x5e, 0xa8, 0x01, 0x06, 0xdf, 0x0b, + 0xd8, 0x36, 0xe6, 0x82, 0x62, 0x25, 0xb7, 0x5c, + 0x02, 0x22, 0xf6, 0xe8, 0x59, 0xb3, 0x59, 0x83}, + .plen = 32, + .ciphertext = {0x05, 0x56, 0xc1, 0x59, 0xf8, 0x4e, 0xf3, 0x6c, + 0xb1, 0x60, 0x2b, 0x45, 0x26, 0xb1, 0x20, 0x09, + 0xc7, 0x75, 0x61, 0x1b, 0xff, 0xb6, 0x4d, 0xc0, + 0xd9, 0xca, 0x92, 0x97, 0xcd, 0x2c, 0x6a, 0x01, + 0x78, 0x70, 0xd9, 0x11, 0x7f, 0x54, 0x81, 0x1a, + 0x34, 0x69, 0x70, 0xf1, 0xde, 0x09, 0x0c, 0x41}, + .clen = 48, + }, { + /* #3 - NIST - + * [Keylen = 128] + * [IVlen = 96] + * [PTlen = 104] + * [AADlen = 0] + * [Taglen = 128] + */ + .key = {0xfe, 0x9b, 0xb4, 0x7d, 0xeb, 0x3a, 0x61, 0xe4, + 0x23, 0xc2, 0x23, 0x18, 0x41, 0xcf, 0xd1, 0xfb}, + .klen = 16, + .iv = {0x4d, 0x32, 0x8e, 0xb7, 0x76, 0xf5, 0x00, 0xa2, + 0xf7, 0xfb, 0x47, 0xaa}, + .ivlen = 12, + .aad = {0}, + .aadlen = 0, + .tag = {0x43, 0xfd, 0x47, 0x27, 0xfe, 0x5c, 0xdb, 0x4b, + 0x5b, 0x42, 0x81, 0x8d, 0xea, 0x7e, 0xf8, 0xc9}, + .taglen = 128, + .plaintext = {0xf1, 0xcc, 0x38, 0x18, 0xe4, 0x21, 0x87, 0x6b, + 0xb6, 0xb8, 0xbb, 0xd6, 0xc9}, + .plen = 13, + .ciphertext = {0xb8, 0x8c, 0x5c, 0x19, 0x77, 0xb3, 0x5b, 0x51, + 0x7b, 0x0a, 0xea, 0xe9, 0x67, 0x43, 0xfd, 0x47, + 0x27, 0xfe, 0x5c, 0xdb, 0x4b, 0x5b, 0x42, 0x81, + 0x8d, 0xea, 0x7e, 0xf8, 0xc9}, + .clen = 29, + }, { + /* #4 - NIST - + * [Keylen = 128] + * [IVlen = 96] + * [PTlen = 128] + * [AADlen = 0] + * [Taglen = 96] + */ + .key = {0xf0, 0x0f, 0xdd, 0x01, 0x8c, 0x02, 0xe0, 0x35, + 0x76, 0x00, 0x8b, 0x51, 0x6e, 0xa9, 0x71, 0xad}, + .klen = 16, + .iv = {0x3b, 0x3e, 0x27, 0x6f, 0x9e, 0x98, 0xb1, 0xec, + 0xb7, 0xce, 0x6d, 0x28}, + .ivlen = 12, + .aad = {0}, + .aadlen = 0, + .tag = {0xcb, 0xa0, 0x6b, 0xb4, 0xf6, 0xe0, 0x97, 0x19, + 0x92, 0x50, 0xb0, 0xd1}, + .taglen = 96, + .plaintext = {0x28, 0x53, 0xe6, 0x6b, 0x7b, 0x1b, 0x3e, 0x1f, + 0xa3, 0xd1, 0xf3, 0x72, 0x79, 0xac, 0x82, 0xbe}, + .plen = 16, + .ciphertext = {0x55, 0xd2, 0xda, 0x7a, 0x3f, 0xb7, 0x73, 0xb8, + 0xa0, 0x73, 0xdb, 0x49, 0x9e, 0x24, 0xbf, 0x62, + 0xcb, 0xa0, 0x6b, 0xb4, 0xf6, 0xe0, 0x97, 0x19, + 0x92, 0x50, 0xb0, 0xd1}, + .clen = 28, + }, { + /* #5 - NIST - + * [Keylen = 128] + * [IVlen = 96] + * [PTlen = 128] + * [AADlen = 128] + * [Taglen = 128] + */ + .key = {0xc9, 0x39, 0xcc, 0x13, 0x39, 0x7c, 0x1d, 0x37, + 0xde, 0x6a, 0xe0, 0xe1, 0xcb, 0x7c, 0x42, 0x3c}, + .klen = 16, + .iv = {0xb3, 0xd8, 0xcc, 0x01, 0x7c, 0xbb, 0x89, 0xb3, + 0x9e, 0x0f, 0x67, 0xe2}, + .ivlen = 12, + .aad = {0x24, 0x82, 0x56, 0x02, 0xbd, 0x12, 0xa9, 0x84, + 0xe0, 0x09, 0x2d, 0x3e, 0x44, 0x8e, 0xda, 0x5f}, + .aadlen = 16, + .tag = {0x00, 0x32, 0xa1, 0xdc, 0x85, 0xf1, 0xc9, 0x78, + 0x69, 0x25, 0xa2, 0xe7, 0x1d, 0x82, 0x72, 0xdd}, + .taglen = 128, + .plaintext = {0xc3, 0xb3, 0xc4, 0x1f, 0x11, 0x3a, 0x31, 0xb7, + 0x3d, 0x9a, 0x5c, 0xd4, 0x32, 0x10, 0x30, 0x69}, + .plen = 16, + .ciphertext = {0x93, 0xfe, 0x7d, 0x9e, 0x9b, 0xfd, 0x10, 0x34, + 0x8a, 0x56, 0x06, 0xe5, 0xca, 0xfa, 0x73, 0x54, + 0x00, 0x32, 0xa1, 0xdc, 0x85, 0xf1, 0xc9, 0x78, + 0x69, 0x25, 0xa2, 0xe7, 0x1d, 0x82, 0x72, 0xdd}, + .clen = 32, + }, { + /* #6 - NIST - + * [Keylen = 128] + * [IVlen = 96] + * [PTlen = 128] + * [AADlen = 128] + * [Taglen = 96] + */ + .key = {0x56, 0x2a, 0xe8, 0xaa, 0xdb, 0x8d, 0x23, 0xe0, + 0xf2, 0x71, 0xa9, 0x9a, 0x7d, 0x1b, 0xd4, 0xd1}, + .klen = 16, + .iv = {0xf7, 0xa5, 0xe2, 0x39, 0x94, 0x13, 0xb8, 0x9b, + 0x6a, 0xd3, 0x1a, 0xff}, + .ivlen = 12, + .aad = {0x2b, 0x96, 0x80, 0xb8, 0x86, 0xb3, 0xef, 0xb7, + 0xc6, 0x35, 0x4b, 0x38, 0xc6, 0x3b, 0x53, 0x73}, + .aadlen = 16, + .tag = {0xcb, 0xf2, 0x01, 0x51, 0x84, 0xff, 0xfb, 0x82, + 0xf2, 0x65, 0x1c, 0x36}, + .taglen = 96, + .plaintext = {0xbb, 0xdc, 0x35, 0x04, 0xd8, 0x03, 0x68, 0x2a, + 0xa0, 0x8a, 0x77, 0x3c, 0xde, 0x5f, 0x23, 0x1a}, + .plen = 16, + .ciphertext = {0xe2, 0xb7, 0xe5, 0xed, 0x5f, 0xf2, 0x7f, 0xc8, + 0x66, 0x41, 0x48, 0xf5, 0xa6, 0x28, 0xa4, 0x6d, + 0xcb, 0xf2, 0x01, 0x51, 0x84, 0xff, 0xfb, 0x82, + 0xf2, 0x65, 0x1c, 0x36}, + .clen = 28, + }, { + /* #7 - NIST - + * [Keylen = 128] + * [IVlen = 96] + * [PTlen = 408] + * [AADlen = 160] + * [Taglen = 32] + */ + .key = {0xe6, 0x49, 0x03, 0xa7, 0x7d, 0x2c, 0x8f, 0x54, + 0xe5, 0x74, 0x13, 0x54, 0x89, 0x5f, 0x9f, 0x25}, + .klen = 16, + .iv = {0x75, 0xbf, 0xc0, 0xf3, 0xc6, 0xac, 0x07, 0x1a, + 0xf0, 0x43, 0x43, 0x18}, + .ivlen = 12, + .aad = {0x41, 0x6b, 0x40, 0xf1, 0x4b, 0xdb, 0x9f, 0x0a, + 0xce, 0xf9, 0x96, 0xc9, 0x63, 0xd2, 0x3b, 0xcf, + 0x10, 0xb7, 0x25, 0x18}, + .aadlen = 20, + .tag = {0x5c, 0x52, 0x6f, 0x9d}, + .taglen = 32, + .plaintext = {0x19, 0x56, 0x1f, 0x57, 0xd5, 0x7d, 0x9a, 0x96, + 0x1b, 0xbc, 0x6a, 0xc5, 0x63, 0x45, 0x56, 0xd0, + 0x05, 0xfa, 0x60, 0x10, 0xd9, 0x0b, 0xd2, 0x18, + 0xc6, 0x27, 0x75, 0x37, 0xa4, 0x3f, 0x8d, 0x3f, + 0xa8, 0xf2, 0x9a, 0x16, 0xe4, 0xcc, 0x49, 0x5b, + 0x49, 0xb8, 0xaf, 0x19, 0x5d, 0x91, 0x7c, 0xb7, + 0x60, 0xc3, 0x4f}, + .plen = 51, + .ciphertext = {0x89, 0x8a, 0xbb, 0x3d, 0x70, 0x69, 0xc0, 0x59, + 0x19, 0x04, 0x6f, 0xe4, 0x8c, 0xa9, 0xa4, 0x43, + 0xa5, 0xd2, 0xbd, 0x2d, 0x28, 0x50, 0x3f, 0xd0, + 0xa2, 0x71, 0x6b, 0x2e, 0xf5, 0xa1, 0x75, 0xf7, + 0x48, 0x68, 0xf7, 0x91, 0x7f, 0x55, 0x42, 0x14, + 0x4b, 0x67, 0x04, 0xdf, 0x8a, 0x42, 0xcc, 0x11, + 0xc9, 0x65, 0xc3, 0x5c, 0x52, 0x6f, 0x9d}, + .clen = 55, + }, { + /* #8 - NIST - + * [Keylen = 192] + * [IVlen = 96] + * [PTlen = 128] + * [AADlen = 128] + * [Taglen = 128] + */ + .key = {0x6f, 0x44, 0xf5, 0x2c, 0x2f, 0x62, 0xda, 0xe4, + 0xe8, 0x68, 0x4b, 0xd2, 0xbc, 0x7d, 0x16, 0xee, + 0x7c, 0x55, 0x73, 0x30, 0x30, 0x5a, 0x79, 0x0d}, + .klen = 24, + .iv = {0x9a, 0xe3, 0x58, 0x25, 0xd7, 0xc7, 0xed, 0xc9, + 0xa3, 0x9a, 0x07, 0x32}, + .ivlen = 12, + .aad = {0x1b, 0x42, 0x36, 0xb8, 0x46, 0xfc, 0x2a, 0x0f, + 0x78, 0x28, 0x81, 0xba, 0x48, 0xa0, 0x67, 0xe9}, + .aadlen = 16, + .tag = {0x1c, 0x19, 0x80, 0x86, 0x45, 0x0a, 0xe1, 0x83, + 0x4d, 0xd6, 0xc2, 0x63, 0x67, 0x96, 0xbc, 0xe2}, + .taglen = 128, + .plaintext = {0x37, 0x22, 0x2d, 0x30, 0x89, 0x5e, 0xb9, 0x58, + 0x84, 0xbb, 0xbb, 0xae, 0xe4, 0xd9, 0xca, 0xe1}, + .plen = 16, + .ciphertext = {0xa5, 0x4b, 0x5d, 0xa3, 0x3f, 0xc1, 0x19, 0x6a, + 0x8e, 0xf3, 0x1a, 0x53, 0x21, 0xbf, 0xca, 0xeb, + 0x1c, 0x19, 0x80, 0x86, 0x45, 0x0a, 0xe1, 0x83, + 0x4d, 0xd6, 0xc2, 0x63, 0x67, 0x96, 0xbc, 0xe2}, + .clen = 32, + }, { + /* #9 - NIST - + * [Keylen = 256] + * [IVlen = 96] + * [PTlen = 128] + * [AADlen = 128] + * [Taglen = 128] + */ + .key = {0x92, 0xe1, 0x1d, 0xcd, 0xaa, 0x86, 0x6f, 0x5c, + 0xe7, 0x90, 0xfd, 0x24, 0x50, 0x1f, 0x92, 0x50, + 0x9a, 0xac, 0xf4, 0xcb, 0x8b, 0x13, 0x39, 0xd5, + 0x0c, 0x9c, 0x12, 0x40, 0x93, 0x5d, 0xd0, 0x8b}, + .klen = 32, + .iv = {0xac, 0x93, 0xa1, 0xa6, 0x14, 0x52, 0x99, 0xbd, + 0xe9, 0x02, 0xf2, 0x1a}, + .ivlen = 12, + .aad = {0x1e, 0x08, 0x89, 0x01, 0x6f, 0x67, 0x60, 0x1c, + 0x8e, 0xbe, 0xa4, 0x94, 0x3b, 0xc2, 0x3a, 0xd6}, + .aadlen = 16, + .tag = {0xec, 0xa5, 0xaa, 0x77, 0xd5, 0x1d, 0x4a, 0x0a, + 0x14, 0xd9, 0xc5, 0x1e, 0x1d, 0xa4, 0x74, 0xab}, + .taglen = 128, + .plaintext = {0x2d, 0x71, 0xbc, 0xfa, 0x91, 0x4e, 0x4a, 0xc0, + 0x45, 0xb2, 0xaa, 0x60, 0x95, 0x5f, 0xad, 0x24}, + .plen = 16, + .ciphertext = {0x89, 0x95, 0xae, 0x2e, 0x6d, 0xf3, 0xdb, 0xf9, + 0x6f, 0xac, 0x7b, 0x71, 0x37, 0xba, 0xe6, 0x7f, + 0xec, 0xa5, 0xaa, 0x77, 0xd5, 0x1d, 0x4a, 0x0a, + 0x14, 0xd9, 0xc5, 0x1e, 0x1d, 0xa4, 0x74, 0xab}, + .clen = 32, + }, +}; + +/** NIST Special Publication 800-38A + http://www.csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf +**/ +static struct aes_test_vector aes_cfb8_tv[] = { + { + .key = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}, + .klen = 16, + .plaintext = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d}, + .plen = 18, + .ciphertext = {0x3b, 0x79, 0x42, 0x4c, 0x9c, 0x0d, 0xd4, 0x36, + 0xba, 0xce, 0x9e, 0x0e, 0xd4, 0x58, 0x6a, 0x4f, + 0x32, 0xb9}, + .clen = 18, + .iv = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, + .ivlen = 16, + }, { + .key = {0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, + 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, + 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b}, + .klen = 24, + .plaintext = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d}, + .plen = 18, + .num_chunks_plain = 2, + .chunks_plain = {8, 10}, + .ciphertext = {0xcd, 0xa2, 0x52, 0x1e, 0xf0, 0xa9, 0x05, 0xca, + 0x44, 0xcd, 0x05, 0x7c, 0xbf, 0x0d, 0x47, 0xa0, + 0x67, 0x8a}, + .clen = 18, + .iv = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, + .ivlen = 16, + .num_chunks_ciph = 2, + .chunks_ciph = {8, 10}, + }, { + .key = {0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, + 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, + 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4}, + .klen = 32, + .plaintext = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d}, + .plen = 18, + .num_chunks_plain = 5, + .chunks_plain = {5, 0, 9, -1, 4}, + .ciphertext = {0xdc, 0x1f, 0x1a, 0x85, 0x20, 0xa6, 0x4d, 0xb5, + 0x5f, 0xcc, 0x8a, 0xc5, 0x54, 0x84, 0x4e, 0x88, + 0x97, 0x00}, + .clen = 18, + .iv = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, + .ivlen = 16, + .num_chunks_ciph = 5, + .chunks_ciph = {5, 0, 9, -1, 4}, + } +}; + +/** NIST Special Publication 800-38A + http://www.csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf +**/ +static struct aes_test_vector aes_cfb128_tv[] = { + { // #0 + .key = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}, + .klen = 16, + .plaintext = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}, + .plen = 64, + .ciphertext = {0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, + 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a, + 0xc8, 0xa6, 0x45, 0x37, 0xa0, 0xb3, 0xa9, 0x3f, + 0xcd, 0xe3, 0xcd, 0xad, 0x9f, 0x1c, 0xe5, 0x8b, + 0x26, 0x75, 0x1f, 0x67, 0xa3, 0xcb, 0xb1, 0x40, + 0xb1, 0x80, 0x8c, 0xf1, 0x87, 0xa4, 0xf4, 0xdf, + 0xc0, 0x4b, 0x05, 0x35, 0x7c, 0x5d, 0x1c, 0x0e, + 0xea, 0xc4, 0xc6, 0x6f, 0x9f, 0xf7, 0xf2, 0xe6}, + .clen = 64, + .iv = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, + .ivlen = 16, + }, { // #2 + .key = {0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, + 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, + 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b}, + .klen = 24, + .plaintext = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}, + .plen = 64, + .num_chunks_plain = 4, + .chunks_plain = {16, 16, 16, 16}, + .ciphertext = {0xcd, 0xc8, 0x0d, 0x6f, 0xdd, 0xf1, 0x8c, 0xab, + 0x34, 0xc2, 0x59, 0x09, 0xc9, 0x9a, 0x41, 0x74, + 0x67, 0xce, 0x7f, 0x7f, 0x81, 0x17, 0x36, 0x21, + 0x96, 0x1a, 0x2b, 0x70, 0x17, 0x1d, 0x3d, 0x7a, + 0x2e, 0x1e, 0x8a, 0x1d, 0xd5, 0x9b, 0x88, 0xb1, + 0xc8, 0xe6, 0x0f, 0xed, 0x1e, 0xfa, 0xc4, 0xc9, + 0xc0, 0x5f, 0x9f, 0x9c, 0xa9, 0x83, 0x4f, 0xa0, + 0x42, 0xae, 0x8f, 0xba, 0x58, 0x4b, 0x09, 0xff}, + .clen = 64, + .iv = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, + .ivlen = 16, + .num_chunks_ciph = 4, + .chunks_ciph = {16, 16, 16, 16}, + }, { // #3 + .key = {0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, + 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, + 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4}, + .klen = 32, + .plaintext = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}, + .plen = 64, + .num_chunks_plain = 5, + .chunks_plain = {25, 0, 8, -1, 31}, + .ciphertext = {0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, + 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60, + 0x39, 0xff, 0xed, 0x14, 0x3b, 0x28, 0xb1, 0xc8, + 0x32, 0x11, 0x3c, 0x63, 0x31, 0xe5, 0x40, 0x7b, + 0xdf, 0x10, 0x13, 0x24, 0x15, 0xe5, 0x4b, 0x92, + 0xa1, 0x3e, 0xd0, 0xa8, 0x26, 0x7a, 0xe2, 0xf9, + 0x75, 0xa3, 0x85, 0x74, 0x1a, 0xb9, 0xce, 0xf8, + 0x20, 0x31, 0x62, 0x3d, 0x55, 0xb1, 0xe4, 0x71}, + .clen = 64, + .iv = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, + .ivlen = 16, + .num_chunks_ciph = 5, + .chunks_ciph = {25, 0, 8, -1, 31}, + } +}; + +/** NIST Special Publication 800-38A + http://www.csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf +**/ +static struct aes_test_vector aes_ofb_tv[] = { + { // #0 + .key = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}, + .klen = 16, + .plaintext = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}, + .plen = 64, + .ciphertext = {0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, + 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a, + 0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03, + 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25, + 0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6, + 0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc, + 0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78, + 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e}, + .clen = 64, + .iv = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, + .ivlen = 16, + }, { // #1 + .key = {0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, + 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, + 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b}, + .klen = 24, + .plaintext = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}, + .plen = 64, + .num_chunks_plain = 4, + .chunks_plain = {16, 16, 16, 16}, + .ciphertext = {0xcd, 0xc8, 0x0d, 0x6f, 0xdd, 0xf1, 0x8c, 0xab, + 0x34, 0xc2, 0x59, 0x09, 0xc9, 0x9a, 0x41, 0x74, + 0xfc, 0xc2, 0x8b, 0x8d, 0x4c, 0x63, 0x83, 0x7c, + 0x09, 0xe8, 0x17, 0x00, 0xc1, 0x10, 0x04, 0x01, + 0x8d, 0x9a, 0x9a, 0xea, 0xc0, 0xf6, 0x59, 0x6f, + 0x55, 0x9c, 0x6d, 0x4d, 0xaf, 0x59, 0xa5, 0xf2, + 0x6d, 0x9f, 0x20, 0x08, 0x57, 0xca, 0x6c, 0x3e, + 0x9c, 0xac, 0x52, 0x4b, 0xd9, 0xac, 0xc9, 0x2a}, + .clen = 64, + .iv = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, + .ivlen = 16, + .num_chunks_ciph = 4, + .chunks_ciph = {16, 16, 16, 16}, + }, { // #2 + .key = {0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, + 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, + 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4}, + .klen = 32, + .plaintext = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}, + .plen = 64, + .num_chunks_plain = 5, + .chunks_plain = {25, 0, 8, -1, 31}, + .ciphertext = {0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, + 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60, + 0x4f, 0xeb, 0xdc, 0x67, 0x40, 0xd2, 0x0b, 0x3a, + 0xc8, 0x8f, 0x6a, 0xd8, 0x2a, 0x4f, 0xb0, 0x8d, + 0x71, 0xab, 0x47, 0xa0, 0x86, 0xe8, 0x6e, 0xed, + 0xf3, 0x9d, 0x1c, 0x5b, 0xba, 0x97, 0xc4, 0x08, + 0x01, 0x26, 0x14, 0x1d, 0x67, 0xf3, 0x7b, 0xe8, + 0x53, 0x8f, 0x5a, 0x8b, 0xe7, 0x40, 0xe4, 0x84}, + .clen = 64, + .iv = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, + .ivlen = 16, + .num_chunks_ciph = 5, + .chunks_ciph = {25, 0, 8, -1, 31}, + } +}; + +/** + * NIST Special Publication 800-38B + * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/ + * CAVP-TESTING-BLOCK-CIPHER-MODES#CMAC + **/ +static struct cmac_test_vector aes128_cmac_tv[] = { + { // 0 (0) + .key = { 0xe4,0xb7,0x64,0x5b,0x2f,0x7d,0x63,0xb4,0x67, + 0x4c,0xd0,0x19,0x70,0xc9,0xd1,0xec }, + .klen = 16, + .msg = { 0x00 }, + .mlen = 0, + .mac = { 0xf2,0x66,0xa1,0x87 }, + .tlen = 4, + }, { // 1 (1) + .key = { 0x8e,0xec,0xa0,0xd1,0x46,0xfd,0x09,0xff,0xbb, + 0xe0,0xd4,0x7e,0xdc,0xdd,0xfc,0xec }, + .klen = 16, + .msg = { 0x00 }, + .mlen = 0, + .mac = { 0xc3,0x64,0x2c,0xe5 }, + .tlen = 4, + .chunks_msg = { 0, 0 }, + .num_chunks_message = 2, + }, { // 2 (16) + .key = { 0xe3,0x80,0x79,0x8d,0x05,0x75,0xd1,0x26,0x9c, + 0xc8,0xca,0xa2,0x31,0x35,0x44,0x37 }, + .klen = 16, + .msg = { 0x66,0xea,0xe0,0xea,0xbd,0x62,0x4a,0x7e,0xcc, + 0x11,0xe9,0xdb,0x46,0x2e,0x2b,0x86 }, + .mlen = 16, + .mac = { 0x9f,0x19,0x06,0x5a }, + .tlen = 4, + }, { // 3 (17) + .key = { 0xe1,0xdc,0x72,0x4d,0x56,0x21,0xfd,0xde,0x4a, + 0x8c,0x27,0x60,0x05,0xd6,0x15,0x75 }, + .klen = 16, + .msg = { 0x87,0x98,0x55,0xff,0x51,0x96,0x86,0x2c,0xc7, + 0x7e,0x32,0x3f,0x8c,0x76,0xb5,0xb0 }, + .mlen = 16, + .mac = { 0xd1,0xc2,0xa7,0x0e }, + .tlen = 4, + .chunks_msg = { 8, 8 }, + .num_chunks_message = 2, + }, { // 4 (18) + .key = { 0x56,0x10,0x52,0xad,0xe5,0x55,0xee,0xda,0x9c, + 0xb3,0x8b,0x1c,0xca,0x8d,0x11,0x8c }, + .klen = 16, + .msg = { 0x79,0xfc,0x4d,0x3a,0x8a,0x47,0x38,0x5d,0xb7, + 0x3e,0x19,0xa5,0x57,0x2a,0x27,0x41 }, + .mlen = 16, + .mac = { 0x1e,0xc9,0x24,0xeb }, + .tlen = 4, + .chunks_msg = { 5, 5, 6 }, + .num_chunks_message = 3, + }, { // 5 (24) + .key = { 0x67,0x08,0xc9,0x88,0x7b,0x84,0x70,0x84,0xf1, + 0x23,0xd3,0xdd,0x9c,0x3a,0x81,0x36 }, + .klen = 16, + .msg = { 0xa8,0xde,0x55,0x17,0x0c,0x6d,0xc0,0xd8,0x0d, + 0xe3,0x2f,0x50,0x8b,0xf4,0x9b,0x70 }, + .mlen = 16, + .mac = { 0xcf,0xef,0x9b,0x78,0x39,0x84,0x1f,0xdb,0xcc, + 0xbb,0x6c,0x2c,0xf2,0x38,0xf7 }, + .tlen = 15, + }, { // 6 (25) + .key = { 0xe3,0x9c,0x6f,0xf1,0xad,0x22,0x79,0x3d,0xc5, + 0x25,0xd3,0x4e,0x7d,0x7e,0x7d,0x6d }, + .klen = 16, + .msg = { 0xf2,0x38,0x77,0xb7,0x74,0x71,0xc8,0x0d,0xd5, + 0x65,0xec,0xe7,0xb2,0xca,0x0b,0xdd }, + .mlen = 16, + .mac = { 0x1a,0x5c,0x33,0xd5,0x4e,0x6d,0xe6,0xd9,0xfa, + 0x61,0xcb,0x96,0x36,0x05,0x3f }, + .tlen = 15, + .chunks_msg = { 8, 8 }, + .num_chunks_message = 2, + }, { // 7 (26) + .key = { 0x5f,0xca,0xd3,0x8a,0xe7,0x78,0x39,0x49,0x12, + 0xf8,0xf1,0xb8,0x41,0x3c,0xf7,0x73 }, + .klen = 16, + .msg = { 0x07,0x18,0x55,0x02,0xbf,0x6d,0x27,0x5c,0x84, + 0xe3,0xac,0x4f,0x5f,0x77,0xc3,0xd4 }, + .mlen = 16, + .mac = { 0xfd,0x44,0xfb,0xc0,0xdd,0x97,0x19,0xe8,0xb5, + 0x69,0xff,0x10,0x42,0x1d,0xf4 }, + .tlen = 15, + .chunks_msg = { 5, 5, 6 }, + .num_chunks_message = 3, + }, { // 8 (32) + .key = { 0x77,0xa7,0x7f,0xaf,0x29,0x0c,0x1f,0xa3,0x0c, + 0x68,0x3d,0xf1,0x6b,0xa7,0xa7,0x7b }, + .klen = 16, + .msg = { 0x02,0x06,0x83,0xe1,0xf0,0x39,0x2f,0x4c,0xac, + 0x54,0x31,0x8b,0x60,0x29,0x25,0x9e,0x9c,0x55, + 0x3d,0xbc,0x4b,0x6a,0xd9,0x98,0xe6,0x4d,0x58, + 0xe4,0xe7,0xdc,0x2e,0x13 }, + .mlen = 32, + .mac = { 0xfb,0xfe,0xa4,0x1b }, + .tlen = 4, + }, { // 9 (33) + .key = { 0x65,0x33,0x78,0x0f,0xc3,0x28,0xa8,0x8d,0x60, + 0x52,0x68,0xd6,0x2f,0x29,0x5d,0xc6 }, + .klen = 16, + .msg = { 0x02,0x74,0x9f,0x4f,0x9a,0xd8,0x2f,0xa7,0xba, + 0x41,0xd9,0x35,0xa6,0xf1,0xaa,0x63,0x76,0xb3, + 0x0b,0x87,0x75,0xb6,0x44,0x5a,0xc8,0x9b,0x3e, + 0xac,0x50,0xcd,0x8d,0x56 }, + .mlen = 32, + .mac = { 0x0b,0xfa,0x13,0x4a }, + .tlen = 4, + .chunks_msg = { 16, 16 }, + .num_chunks_message = 2, + }, { // 10 (34) + .key = { 0x49,0x2d,0xac,0xdc,0xb4,0xa3,0x5f,0xc4,0x38, + 0xa6,0xea,0xa3,0x5e,0x26,0xd2,0xf6 }, + .klen = 16, + .msg = { 0x99,0x2c,0x3e,0x56,0x13,0xff,0x42,0x0f,0xd9, + 0x1b,0xe8,0x78,0xd0,0xe1,0xd6,0x2e,0x71,0xf5, + 0xf1,0x10,0x6f,0x50,0x23,0xf3,0x99,0x91,0x5c, + 0x98,0x03,0x94,0xd6,0xdb }, + .mlen = 32, + .mac = { 0xb0,0x58,0x1e,0xd0 }, + .tlen = 4, + .chunks_msg = { 10, 10, 12 }, + .num_chunks_message = 3, + }, { // 11 (40) + .key = { 0x53,0x4c,0x6f,0x8f,0x88,0xbc,0x35,0x3f,0xae, + 0xe5,0x26,0x64,0x99,0x5d,0x54,0x57 }, + .klen = 16, + .msg = { 0x49,0x81,0xc5,0x1f,0xcc,0x09,0x35,0xf6,0x19, + 0xec,0x6b,0xf8,0x62,0x68,0x3b,0x00,0x25,0xcc, + 0x48,0x72,0x48,0x39,0xbc,0x1e,0x67,0xaa,0x3c, + 0x68,0x6d,0x32,0x1b,0xa6 }, + .mlen = 32, + .mac = { 0x63,0x77,0xc6,0xcf,0xe8,0xdd,0x60,0x5e,0xf0, + 0xa6,0x2a,0x84,0x5a,0xb3,0xf7 }, + .tlen = 15, + }, { // 12 (41) + .key = { 0xa1,0x7c,0x96,0xfa,0xa6,0x4c,0xca,0xb2,0xc4, + 0x5d,0x93,0xa0,0x63,0x89,0x36,0x81 }, + .klen = 16, + .msg = { 0xf2,0x68,0xc7,0xd4,0xdf,0x15,0x9e,0xf4,0xd2, + 0x84,0xbe,0x92,0x42,0x9b,0x80,0x72,0x6e,0xf1, + 0x34,0x73,0x4e,0xeb,0xb9,0xcc,0xc9,0x25,0x4c, + 0x96,0x28,0x13,0x9e,0x8b }, + .mlen = 32, + .mac = { 0xb7,0x3d,0xfe,0x7c,0x49,0x1b,0x2d,0x69,0x2e, + 0x17,0x04,0x81,0x97,0x1e,0x4e }, + .tlen = 15, + .chunks_msg = { 16, 16 }, + .num_chunks_message = 2, + }, { // 13 (42) + .key = { 0xc5,0x58,0x1d,0x40,0xb3,0x31,0xe2,0x40,0x03, + 0x90,0x1b,0xd6,0xbf,0x24,0x4a,0xca }, + .klen = 16, + .msg = { 0x5d,0x44,0xba,0xc1,0xa3,0x88,0xeb,0x81,0xb0, + 0xc3,0x57,0x1f,0x6d,0x05,0x66,0xb6,0x9b,0xde, + 0xf5,0xff,0x21,0x66,0x4b,0x73,0xa4,0x80,0x4e, + 0xb0,0x59,0x60,0xf6,0x1e }, + .mlen = 32, + .mac = { 0xa1,0x44,0x7d,0x0b,0x0b,0x02,0x83,0x24,0x9e, + 0x76,0x6f,0x83,0x8d,0xb9,0xf4 }, + .tlen = 15, + .chunks_msg = { 10, 10, 12 }, + .num_chunks_message = 3, + }, { // 14 (48) + .key = { 0x49,0x9d,0xb5,0xa3,0xec,0xc8,0x3d,0x34,0xfd, + 0x88,0x5f,0xde,0x06,0x93,0x10,0x97 }, + .klen = 16, + .msg = { 0xf2,0x78,0x35,0x40,0xc9,0xe1,0x70,0x6e,0xe3, + 0xe7,0xa4,0x3e,0x71,0x83,0x39,0x87,0xbb,0x72, + 0x44,0x1c,0x1e,0x2e,0xab,0x58,0x50,0x1c,0x8b, + 0xfa,0xec,0x07,0xd6,0x33,0x2a }, + .mlen = 33, + .mac = { 0x8e,0x96,0x49,0xdb }, + .tlen = 4, + }, { // 15 (49) + .key = { 0xa5,0x86,0xd9,0x2b,0xc5,0xf9,0x46,0xce,0x58, + 0x08,0x03,0x22,0x04,0x50,0x83,0xd6 }, + .klen = 16, + .msg = { 0x12,0x95,0xc5,0xbd,0x2d,0x07,0x6b,0x18,0x72, + 0x77,0xa0,0x2d,0x57,0x91,0x2d,0x2e,0x9e,0x27, + 0x71,0x90,0x31,0x82,0x60,0x03,0x51,0xf6,0xcc, + 0xa7,0xef,0xb9,0xe4,0x7d,0x5a }, + .mlen = 33, + .mac = { 0x6e,0x55,0x44,0x64 }, + .tlen = 4, + .chunks_msg = { 16, 17 }, + .num_chunks_message = 2, + }, { // 16 (50) + .key = { 0x52,0x57,0x3c,0x65,0x50,0x88,0x69,0xdb,0x32, + 0x59,0xcf,0x5e,0xcb,0x62,0x75,0x65 }, + .klen = 16, + .msg = { 0xb1,0x1a,0x4c,0x21,0x55,0xd3,0x79,0xd1,0xdf, + 0xa3,0xfc,0xb4,0x32,0xf6,0x5c,0xc5,0xac,0xc4, + 0x87,0xca,0x4b,0x1d,0x17,0x87,0x14,0x06,0xd3, + 0x31,0xb5,0x83,0x79,0x25,0x69 }, + .mlen = 33, + .mac = { 0x2e,0x8b,0x88,0x44 }, + .tlen = 4, + .chunks_msg = { 11, 10, 12 }, + .num_chunks_message = 3, + }, { // 17 (56) + .key = { 0xa0,0xc3,0x34,0xff,0x35,0x01,0xc9,0x9a,0x9d, + 0x5f,0x26,0x60,0xf4,0xa2,0xcc,0x5f }, + .klen = 16, + .msg = { 0xb4,0x69,0x3a,0x2a,0xa1,0x1c,0xf9,0xa5,0x44, + 0x2f,0x08,0xdf,0xa7,0x18,0x59,0x0f,0xef,0xf8, + 0xd3,0x8f,0xdf,0x15,0xf8,0xee,0x9d,0x8a,0xc5, + 0x41,0xb9,0x3d,0xd9,0xb9,0x6b }, + .mlen = 33, + .mac = { 0x6d,0x4b,0xf5,0x0d,0x3a,0x13,0xa2,0x6d,0x9d, + 0xc7,0x56,0x6d,0xee,0x12,0x23 }, + .tlen = 15, + }, { // 18 (57) + .key = { 0xd2,0x65,0x33,0xa7,0x60,0xe7,0x6d,0xfa,0xa4, + 0xa7,0xc9,0x52,0x9d,0xf8,0x60,0x31 }, + .klen = 16, + .msg = { 0x80,0xf3,0xea,0x04,0xe4,0x2d,0x4c,0xef,0x33, + 0x4c,0x04,0xc7,0xea,0xae,0x86,0x83,0x2f,0xaf, + 0x52,0xf2,0xaa,0x28,0x6b,0x5a,0x96,0x36,0x0b, + 0x60,0x18,0x3d,0x95,0x27,0xcf }, + .mlen = 33, + .mac = { 0xec,0xee,0x84,0xf8,0x19,0x24,0xee,0x3c,0x20, + 0x82,0x9e,0x3d,0x97,0xeb,0xf9 }, + .tlen = 15, + .chunks_msg = { 16, 17 }, + .num_chunks_message = 2, + }, { // 19 (58) + .key = { 0xc2,0xca,0x6a,0xce,0x8b,0x8b,0x19,0x31,0x4c, + 0xc1,0x43,0x90,0xe2,0x2c,0xbc,0x37 }, + .klen = 16, + .msg = { 0x8a,0x78,0x2e,0x7b,0x7c,0x2e,0xa7,0x7f,0x63, + 0xdd,0xaa,0x85,0x63,0xed,0x90,0xd3,0xb5,0x7c, + 0x8c,0x22,0x42,0xa6,0xdd,0x00,0x71,0x04,0x48, + 0x73,0x3d,0x72,0xc6,0xdf,0x8a }, + .mlen = 33, + .mac = { 0x77,0x1a,0x53,0xea,0x36,0x49,0x73,0xcc,0x5c, + 0x01,0x77,0xdb,0x25,0x0a,0xc7 }, + .tlen = 15, + .chunks_msg = { 11, 10, 12 }, + .num_chunks_message = 3, + }, { // 20 (64) + .key = { 0x8c,0x9e,0xab,0xe8,0x71,0xc6,0xe9,0x51,0x11, + 0x94,0xb4,0x8e,0xbf,0x9e,0x9b,0x03 }, + .klen = 16, + .msg = { 0x05,0x49,0xea,0xec,0xa4,0xf3,0x97,0x24,0x7f, + 0x1d,0x25,0x96,0x12,0xe6,0x86,0x7e,0x7d,0x78, + 0x8c,0x71,0xd0,0x3c,0x51,0x36,0x86,0x4a,0xd6, + 0xd8,0x4f,0x24,0xea,0xf9,0x13,0xa3,0x4e,0x69, + 0x33 }, + .mlen = 37, + .mac = { 0x0c,0x1e,0x97,0xd0 }, + .tlen = 4, + }, { // 21 (72) + .key = { 0x69,0x90,0xdb,0x6a,0x5c,0xd8,0xdc,0x14,0x94, + 0xcd,0x63,0x92,0x21,0x51,0x92,0x0c }, + .klen = 16, + .msg = { 0x8c,0xed,0xde,0xbd,0x38,0xf0,0x04,0x06,0x74, + 0x3a,0x67,0x56,0x56,0x5c,0xe7,0x62,0xd3,0x46, + 0x44,0x35,0xd5,0x0b,0xd6,0x1b,0x8d,0xe5,0x7f, + 0xbe,0x0b,0x79,0xdf,0x8f,0x0c,0x5c,0xc6,0x67, + 0x13 }, + .mlen = 37, + .mac = { 0xe5,0x2c,0xd4,0xfa,0x3c,0xf7,0x2b,0x2f,0x06, + 0xee,0xce,0x11,0x22,0x42,0xe6 }, + .tlen = 15, + } +}; + +/** + * NIST Special Publication 800-38B + * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/ + * CAVP-TESTING-BLOCK-CIPHER-MODES#CMAC + **/ +static struct cmac_test_vector aes192_cmac_tv[] = { + { // 0 (0) + .key = { 0xaf,0x18,0x9e,0xb9,0x93,0xee,0xd7,0x22,0x5b, + 0xd3,0xb6,0x1a,0xf2,0xd3,0xa9,0xa8,0x54,0xc8, + 0xb0,0x1b,0xa3,0x22,0x11,0xf1 }, + .klen = 24, + .msg = { 0x00 }, + .mlen = 0, + .mac = { 0x77,0x1b,0x8f,0x67,0x3b,0x2d,0xaf,0x2f,0xf0, + 0x54 }, + .tlen = 10, + }, { // 1 (1) + .key = { 0x33,0xf0,0x1a,0xa9,0x48,0x38,0xf1,0x5b,0xcd, + 0x13,0x5e,0x58,0x4b,0x78,0xce,0x67,0x3f,0x83, + 0x3e,0xa5,0x1a,0x6b,0x59,0x1f }, + .klen = 24, + .msg = { 0x00 }, + .mlen = 0, + .mac = { 0x8f,0xee,0x17,0x9b,0x1e,0x67,0x87,0x07,0xde, + 0x7f }, + .tlen = 10, + .chunks_msg = { 0, 0 }, + .num_chunks_message = 2, + }, { // 2 (8) + .key = { 0x91,0xa8,0xa9,0x47,0x3c,0xe4,0x8a,0x2e,0x2d, + 0x59,0x88,0x54,0x98,0xc6,0x7e,0xfc,0x42,0x24, + 0x8e,0x8f,0x7e,0xce,0xb6,0xe4 }, + .klen = 24, + .msg = { 0x00 }, + .mlen = 0, + .mac = { 0x7c,0x4d,0x12,0xc6,0x08,0x76,0x39,0xec,0x7c, + 0x68,0xb6,0x64 }, + .tlen = 12, + }, { // 3 (16) + .key = { 0x33,0x64,0x16,0x9e,0xe0,0x77,0xca,0xfb,0x9b, + 0x15,0xcb,0xab,0xaf,0xa4,0xf3,0xf1,0xea,0x13, + 0x8b,0xbc,0x09,0x75,0x64,0x70 }, + .klen = 24, + .msg = { 0x00 }, + .mlen = 0, + .mac = { 0x57,0xaa,0xb6,0x46,0x10,0x5c,0x5e,0x5b,0x80, + 0x21,0x4b,0x87,0xff,0xfa,0x38,0x47 }, + .tlen = 16, + }, { // 4 (24) + .key = { 0xb1,0x90,0x41,0x30,0x8b,0x76,0x71,0x38,0xee, + 0x19,0x60,0x22,0x48,0x03,0x01,0x68,0x3d,0x14, + 0x41,0x93,0x3e,0xc8,0x3a,0xa3 }, + .klen = 24, + .msg = { 0x86,0x61,0x70,0x12,0xaf,0x7d,0x94,0x78,0x41, + 0xba,0x40,0x8d,0xf5,0xff,0x8b,0x9a,0x44,0xf2, + 0x59,0x85,0xcc,0xc5,0xdc,0x44,0xf5,0x52,0x5a, + 0x97,0xd4,0x6b,0x30,0xf7 }, + .mlen = 32, + .mac = { 0x8e,0xfc,0x4d,0x25,0xb6,0x92,0xc3,0x4d,0xdb, + 0xbc }, + .tlen = 10, + }, { // 5 (25) + .key = { 0x7f,0xea,0x56,0x3a,0x86,0x65,0x71,0x82,0x24, + 0x72,0xda,0xde,0x8a,0x0b,0xec,0x4b,0x98,0x20, + 0x2d,0x47,0xa3,0x44,0x31,0x29 }, + .klen = 24, + .msg = { 0xa2,0x06,0xa1,0xeb,0x70,0xa9,0xd2,0x4b,0xb5, + 0xe7,0x2f,0x31,0x4e,0x7d,0x91,0xde,0x07,0x4f, + 0x59,0x05,0x56,0x53,0xbd,0xd2,0x4a,0xab,0x5f, + 0x2b,0xbe,0x11,0x24,0x36 }, + .mlen = 32, + .mac = { 0x3b,0xfe,0x96,0xf0,0x5e,0x9c,0xf9,0x6a,0x98, + 0xbd }, + .tlen = 10, + .chunks_msg = { 16, 16 }, + .num_chunks_message = 2, + }, { // 6 (26) + .key = { 0x3f,0x29,0xd9,0xb2,0xdb,0xf5,0xd3,0xe5,0x1f, + 0xcf,0x96,0xe8,0x6e,0x1d,0x40,0x75,0x66,0x92, + 0x02,0x09,0x66,0xa8,0xc5,0xf1 }, + .klen = 24, + .msg = { 0x5e,0x51,0x36,0xff,0x2c,0x39,0xc2,0xcb,0xb8, + 0x07,0x46,0xb3,0xdf,0x2e,0x39,0xe2,0x74,0x4c, + 0x8f,0x11,0x9a,0x02,0x38,0xfb,0x70,0x02,0xe9, + 0x11,0xf4,0x69,0x1e,0x6e }, + .mlen = 32, + .mac = { 0x0a,0x89,0x1a,0x79,0x9a,0x35,0x6e,0xc6,0x24, + 0x1c }, + .tlen = 10, + .chunks_msg = { 10, 10, 12 }, + .num_chunks_message = 3, + }, { // 7 (32) + .key = { 0x09,0x89,0x1e,0xd1,0x4f,0x44,0x88,0x06,0x9c, + 0xd6,0xa5,0x74,0x40,0x61,0xe0,0x6f,0x8f,0xf8, + 0xd1,0xbc,0x87,0xb1,0x04,0x48 }, + .klen = 24, + .msg = { 0x3c,0x3d,0x7f,0x18,0xa0,0xbd,0x3b,0x6f,0x36, + 0x6c,0x1b,0x49,0x7c,0x60,0x2e,0x88,0x9c,0xac, + 0x88,0xfe,0xed,0xd7,0xe6,0x83,0xbd,0x8d,0x95, + 0x45,0x4e,0x95,0x8f,0x60 }, + .mlen = 32, + .mac = { 0xa7,0x37,0xae,0x84,0x6c,0x1f,0xec,0xea,0x1c, + 0xf7,0x7a,0x17 }, + .tlen = 12, + }, { // 8 (33) + .key = { 0xa9,0x2e,0x82,0x0d,0x4a,0xa8,0x3a,0xb3,0x2b, + 0xc9,0xce,0x53,0x7a,0x95,0x82,0x30,0x38,0x96, + 0x06,0x48,0x40,0xd2,0x9e,0xe4 }, + .klen = 24, + .msg = { 0x6f,0x6c,0x7c,0xe5,0xd1,0xc7,0x25,0xf7,0xb0, + 0x28,0x47,0x03,0x73,0x6a,0x1d,0xe9,0xca,0x8f, + 0x75,0xcf,0x91,0x10,0xb4,0x15,0xf7,0x70,0x19, + 0x8b,0xdf,0x17,0x46,0xe2 }, + .mlen = 32, + .mac = { 0x08,0x70,0x06,0xce,0xa6,0x4c,0x26,0x5c,0xb2, + 0x33,0x1a,0x93 }, + .tlen = 12, + .chunks_msg = { 17, 15 }, + .num_chunks_message = 2, + }, { // 9 (34) + .key = { 0x33,0x14,0xe9,0xaf,0x7c,0xe9,0x91,0x7f,0xf7, + 0xf9,0x22,0xc8,0x67,0x06,0x27,0x7a,0x4e,0x98, + 0xd2,0x8e,0x11,0x97,0x41,0x3b }, + .klen = 24, + .msg = { 0xca,0x2b,0x30,0xd7,0x2d,0xf5,0x32,0xef,0xce, + 0x9c,0xde,0x44,0xff,0xb9,0xbb,0x56,0x11,0xe7, + 0x46,0xba,0x1a,0x76,0xdc,0x6a,0xf4,0x64,0xd9, + 0x5f,0x89,0x88,0x02,0x62 }, + .mlen = 32, + .mac = { 0xa1,0xf0,0xe1,0xa5,0xd2,0x31,0x60,0xf0,0x52, + 0xb3,0xaa,0x83 }, + .tlen = 12, + .chunks_msg = { 10, 11, 11 }, + .num_chunks_message = 3, + }, { // 10 (40) + .key = { 0x20,0x51,0xaf,0x34,0x76,0x2e,0xbe,0x55,0x6f, + 0x72,0xa5,0xc6,0xed,0xc7,0x77,0x1e,0xb9,0x24, + 0x5f,0xad,0x76,0xf0,0x34,0xbe }, + .klen = 24, + .msg = { 0xae,0x8e,0x93,0xc9,0xc9,0x91,0xcf,0x89,0x6a, + 0x49,0x1a,0x89,0x07,0xdf,0x4e,0x4b,0xe5,0x18, + 0x6a,0xe4,0x96,0xcd,0x34,0x0d,0xc1,0x9b,0x23, + 0x78,0x21,0xdb,0x7b,0x60 }, + .mlen = 32, + .mac = { 0x74,0xf7,0x46,0x08,0xc0,0x4f,0x0f,0x4e,0x47, + 0xfa,0x64,0x04,0x33,0xb6,0xe6,0xfb }, + .tlen = 16, + }, { // 11 (41) + .key = { 0x45,0x13,0xf5,0x5f,0x24,0x3b,0x70,0x54,0x4f, + 0xd9,0x7f,0xaf,0xe6,0x5a,0x68,0xed,0x82,0xc4, + 0xac,0xdc,0xc9,0xf7,0x39,0xff }, + .klen = 24, + .msg = { 0xbb,0x52,0x5c,0xbd,0x4c,0xfe,0x78,0x4d,0x33, + 0xc4,0xfa,0x8b,0x6e,0x75,0x00,0x6e,0x25,0x69, + 0x11,0xb0,0x3e,0xc4,0x54,0x2f,0x2c,0xf8,0xff, + 0x94,0x07,0x8b,0x13,0x32 }, + .mlen = 32, + .mac = { 0x52,0xd2,0x39,0x39,0xe5,0x98,0xa7,0xe5,0x54, + 0xd3,0x60,0x4d,0xdd,0xf7,0x90,0xb5 }, + .tlen = 16, + .chunks_msg = { 16, 16 }, + .num_chunks_message = 2, + }, { // 12 (42) + .key = { 0xcd,0x98,0x06,0x78,0x5d,0xb2,0x97,0x69,0xde, + 0x6f,0xdf,0x52,0x23,0xe4,0xf2,0x08,0x78,0xbf, + 0x13,0xcf,0xe3,0x7d,0x1c,0x2a }, + .klen = 24, + .msg = { 0xdf,0xdd,0xb7,0x19,0xd0,0x03,0x98,0xbf,0x48, + 0xa6,0xce,0xfd,0x27,0x73,0x63,0x89,0xe6,0x54, + 0xa9,0x3b,0x85,0x95,0xcd,0x5a,0xc4,0x46,0xaf, + 0x19,0x96,0xe0,0xf1,0x61 }, + .mlen = 32, + .mac = { 0x09,0xc4,0xd3,0x37,0xdb,0x14,0x6f,0x92,0x0d, + 0x93,0x7e,0xd2,0x83,0xcc,0x69,0x44 }, + .tlen = 16, + .chunks_msg = { 10, 10, 12 }, + .num_chunks_message = 3, + }, { // 13 (48) + .key = { 0x2c,0xc8,0x39,0x87,0x6d,0x39,0x89,0xf3,0x57, + 0x31,0xbe,0x37,0x1f,0x60,0xde,0x14,0x0e,0x3c, + 0x91,0x62,0x31,0xec,0x78,0x0e }, + .klen = 24, + .msg = { 0x2e,0xae,0xf8,0x6b,0x0f,0x60,0x23,0x64,0xf8, + 0x65,0x10,0xea,0xbc,0x58,0xbc,0x9a,0xd1,0xe6, + 0xf0,0xa6,0xf6,0xdf,0x0b,0x83,0x18,0x8c,0x01, + 0xe1,0x77,0x44,0xa4,0xe0,0x05,0x3a,0x22,0x81, + 0x0e,0x99,0xcf,0x5a,0x1e,0xd3,0x25,0x8f,0x20, + 0x35,0x09,0xfd }, + .mlen = 48, + .mac = { 0x80,0x6a,0x7c,0x69,0xee,0xbc,0x60,0x41,0xe6, + 0xf9 }, + .tlen = 10, + }, { // 14 (49) + .key = { 0x45,0x02,0x8d,0xd9,0x9d,0x0c,0x7f,0x13,0xfd, + 0x00,0xa2,0xe8,0x05,0x92,0x2e,0xbf,0x4f,0x83, + 0x30,0x80,0xf5,0x14,0x2f,0xa7 }, + .klen = 24, + .msg = { 0xf8,0x22,0x92,0x64,0xbd,0xb7,0x65,0x7c,0x05, + 0x6e,0xd4,0xaf,0x2a,0x07,0x33,0x55,0x33,0x3d, + 0xe2,0x9b,0xa7,0x48,0xc4,0x28,0xa4,0xa6,0xf2, + 0x01,0x2b,0x1b,0xb1,0xaa,0xbe,0xf7,0xa2,0x8f, + 0x2d,0x97,0x39,0xa2,0xad,0x2e,0x70,0x44,0x2a, + 0xc6,0xbd,0x69 }, + .mlen = 48, + .mac = { 0x42,0x88,0xca,0x11,0xa1,0x7f,0x43,0x64,0x12, + 0x5f }, + .tlen = 10, + .chunks_msg = { 32, 16 }, + .num_chunks_message = 2, + }, { // 15 (50) + .key = { 0x7e,0xff,0xb0,0xee,0x6e,0xaf,0x5d,0xf3,0x7e, + 0x69,0xae,0xbe,0x27,0x92,0x0c,0x62,0x40,0x74, + 0x1e,0x39,0xce,0xcf,0x40,0x84 }, + .klen = 24, + .msg = { 0x37,0x3b,0x1b,0x64,0xbb,0x55,0x16,0xd9,0x6e, + 0x40,0x86,0x31,0xac,0xf8,0x49,0x66,0xd2,0x76, + 0x46,0x53,0xa2,0x80,0xf3,0x23,0xe9,0xc5,0x1b, + 0x0a,0x5e,0x29,0xde,0x33,0xce,0x5e,0xf9,0xf9, + 0x76,0xb4,0x47,0x59,0xb1,0x32,0x88,0xa7,0xd3, + 0xe5,0x62,0x81 }, + .mlen = 48, + .mac = { 0x2e,0x2f,0x77,0x79,0x69,0x8b,0x53,0x06,0xe5, + 0x67 }, + .tlen = 10, + .chunks_msg = { 16, 16, 16 }, + .num_chunks_message = 3, + }, { // 16 (140) + .key = { 0xa1,0x2a,0x70,0xeb,0xca,0xad,0x31,0x0f,0x65, + 0x02,0xfe,0x82,0xc3,0x08,0xcf,0xa8,0xc1,0xf6, + 0x8b,0x1f,0x9c,0xe5,0x7b,0x5a }, + .klen = 24, + .msg = { 0xe1,0x9a,0xc0,0x8a,0xeb,0x3c,0xd7,0x8e,0x40, + 0x54,0x8d,0xb4,0x3c,0x5a,0xca,0x50,0xad,0x78, + 0x60,0xfe,0x92,0x3e,0xef,0xf0,0x23,0x97,0x06, + 0x86,0x11,0xfc,0x8a,0x1f,0x0e,0xe7,0x5c,0x30, + 0x90,0x8b,0x36,0x93,0xd2,0xc2,0xd6,0x21,0x1c, + 0x47,0x5f,0x82,0x45,0x25,0xfc,0x44,0x76,0x6f, + 0xc6,0x2b,0x30,0x32,0xe8,0xc8 }, + .mlen = 60, + .mac = { 0x86,0xc4,0x41,0x50,0xfe,0xd8,0x4d,0x2e,0x18, + 0x97,0x66,0x61,0x27,0xe3,0xb5,0x6e }, + .tlen = 16, + }, { // 17 (141) + .key = { 0x62,0xb8,0x26,0x3d,0xc0,0x15,0xef,0x87,0x3c, + 0xd1,0x62,0x72,0xe4,0xda,0x89,0x79,0x9b,0x91, + 0x0f,0x2b,0x04,0x20,0x44,0x20 }, + .klen = 24, + .msg = { 0x8b,0x4d,0x85,0xd9,0x95,0x26,0x50,0xae,0xb2, + 0x39,0x1f,0x70,0x1f,0x1d,0x34,0x2b,0x45,0xe4, + 0x6f,0x0a,0x33,0xb6,0x67,0x1d,0x4c,0xb8,0xb9, + 0x59,0x3d,0x32,0xa0,0xe1,0x33,0xf2,0xc6,0x84, + 0x4a,0xeb,0x5a,0x86,0x48,0x22,0x63,0xa3,0x8b, + 0xcb,0x54,0x51,0x40,0xae,0xe0,0x46,0xd6,0xd0, + 0x0f,0x3a,0xb2,0x50,0x92,0xee }, + .mlen = 60, + .mac = { 0xca,0x55,0x8a,0x0b,0xea,0x31,0xff,0x12,0x99, + 0xee,0xb9,0x4b,0xc0,0x6c,0xda,0x38 }, + .tlen = 16, + .chunks_msg = { 30, 30 }, + .num_chunks_message = 2, + }, { // 18 (142) + .key = { 0x3d,0xa1,0xc7,0xcf,0xfa,0xa1,0x67,0x55,0x7b, + 0x25,0x06,0x34,0xe8,0x05,0x2f,0xa0,0x30,0xc6, + 0x62,0xe8,0xfb,0xbe,0xab,0xb3 }, + .klen = 24, + .msg = { 0xd1,0xde,0x1b,0xe5,0xf7,0xa4,0x61,0x91,0xbb, + 0x3d,0x24,0xd8,0x6f,0xc3,0xea,0xbd,0x5b,0x6f, + 0xd6,0x65,0x5f,0xb0,0x6f,0xcb,0xda,0x7a,0xa4, + 0xb5,0xca,0xe1,0x0c,0xe7,0x34,0xe6,0x72,0x96, + 0xc6,0x91,0x90,0x1f,0xbb,0x40,0x1b,0xf9,0xff, + 0x3e,0x00,0xe8,0x93,0x97,0xee,0x74,0x34,0x2b, + 0x14,0x9a,0x37,0x02,0x2c,0xc1 }, + .mlen = 60, + .mac = { 0xa9,0x22,0x6f,0x20,0xdb,0x94,0x7f,0x83,0x5e, + 0x85,0x75,0x42,0x1c,0x05,0xa2,0x41 }, + .tlen = 16, + .chunks_msg = { 20, 20, 20 }, + .num_chunks_message = 3, + }, { // 19 (143) + .key = { 0x01,0x2d,0x3f,0x35,0xfe,0x16,0x2a,0xc6,0x99, + 0x9a,0xd8,0x4d,0x90,0x57,0xff,0xfb,0x5c,0xac, + 0x15,0xbc,0x4e,0x78,0x09,0x17 }, + .klen = 24, + .msg = { 0x94,0x0c,0xec,0x23,0xe8,0x87,0x56,0x9a,0xa8, + 0x1d,0x54,0x99,0x02,0x50,0x37,0xbe,0x68,0xdb, + 0x9a,0xc7,0xf2,0x8b,0xe8,0x06,0xfd,0x50,0x1e, + 0x10,0x19,0x94,0xd2,0xb6,0x22,0xcb,0x75,0x36, + 0xac,0x4c,0xd5,0xb2,0xa4,0x5f,0xe5,0xe0,0x35, + 0x97,0xc1,0x04,0xe9,0x62,0xed,0x1b,0x11,0xde, + 0xdd,0x59,0x66,0xee,0xbb,0xd6 }, + .mlen = 60, + .mac = { 0xd1,0xf9,0x0c,0x9f,0x65,0x29,0xdb,0x7c,0x7b, + 0xfa,0x8e,0x79,0x24,0x80,0x59,0x25 }, + .tlen = 16, + .chunks_msg = { 12, 6, 6, 6, 6, 6, 6, 12 }, + .num_chunks_message = 8, + } +}; + +/** + * NIST Special Publication 800-38B + * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/ + * CAVP-TESTING-BLOCK-CIPHER-MODES#CMAC + **/ +static struct cmac_test_vector aes256_cmac_tv[] = { + { // 0 (0) + .key = { 0x95,0xd8,0xaf,0xb8,0xa4,0xb7,0x24,0x5c,0xe7, + 0x9f,0x9f,0x9c,0x5d,0xdd,0x40,0xde,0x61,0xb3, + 0x59,0x05,0xdc,0xb6,0x38,0xf2,0xb8,0x75,0x40, + 0x4a,0x98,0x5b,0x3f,0x7a }, + .klen = 32, + .msg = { 0x00 }, + .mlen = 0, + .mac = { 0x68,0xad,0xfc,0x9b,0x59 }, + .tlen = 5, + }, { // 1 (1) + .key = { 0x96,0xa0,0x85,0xfe,0x88,0xbc,0x98,0xc7,0x63, + 0xc1,0x06,0x4d,0xa4,0xc9,0xc8,0xb4,0xaa,0x4a, + 0xd4,0x2a,0xba,0xff,0x40,0x7a,0x46,0x26,0xab, + 0xde,0x6f,0xec,0xd9,0x15 }, + .klen = 32, + .msg = { 0x00 }, + .mlen = 0, + .mac = { 0xd8,0xdc,0x67,0x26,0xd8 }, + .tlen = 5, + .chunks_msg = { 0, 0 }, + .num_chunks_message = 2, + }, { // 2 (8) + .key = { 0xf0,0xa3,0xe4,0xc2,0x37,0xd8,0x67,0x18,0xd8, + 0x4c,0x43,0x18,0x5e,0x70,0xf9,0xce,0xf0,0xdc, + 0x92,0xb3,0x78,0xe3,0xe0,0xdb,0x04,0x6b,0x06, + 0x71,0x6c,0xfb,0x3b,0x61 }, + .klen = 32, + .msg = { 0x00 }, + .mlen = 0, + .mac = { 0x38,0xba,0x46,0x60,0x2f,0x34,0x11,0xa5,0x8b, + 0x2e }, + .tlen = 10, + }, { // 3 (16) + .key = { 0x91,0x6c,0xd8,0x11,0x9a,0x4d,0x7e,0x82,0x5e, + 0x01,0xa8,0x6f,0x93,0xb0,0xee,0xe4,0xa4,0x6d, + 0x29,0x21,0x61,0x15,0xcc,0x9e,0xf6,0x7a,0x78, + 0x4c,0x19,0xc1,0xca,0x1e }, + .klen = 32, + .msg = { 0x33,0x10,0xfc,0x5b,0xc9,0x10,0xf4,0xc9,0xb9, + 0xcf,0x49,0x57,0xac,0x63,0x8a,0xe7 }, + .mlen = 16, + .mac = { 0x03,0xf0,0x45,0xf8,0x86 }, + .tlen = 5, + }, { // 4 (17) + .key = { 0x00,0x9f,0x47,0xf1,0x80,0xe0,0x85,0x77,0x6b, + 0xe6,0x64,0x4a,0xea,0xc0,0x07,0x0b,0xe6,0x4c, + 0x28,0x9f,0x84,0xa7,0xba,0x3d,0xec,0xe7,0xcd, + 0xc5,0x4f,0x0d,0xb3,0x54 }, + .klen = 32, + .msg = { 0x41,0xb9,0x85,0x38,0xc7,0x52,0x79,0x5d,0x9d, + 0x48,0x70,0x2b,0x56,0xf3,0x34,0xd9 }, + .mlen = 16, + .mac = { 0xb9,0x61,0xae,0xec,0x5d }, + .tlen = 5, + .chunks_msg = { 8, 8 }, + .num_chunks_message = 2, + }, { // 5 (18) + .key = { 0x7a,0xd4,0x91,0xec,0x57,0x18,0x7d,0x42,0x43, + 0xc3,0x66,0x03,0xce,0xfe,0x68,0x2c,0x0c,0x56, + 0x67,0x5c,0x31,0x04,0x48,0x39,0x5e,0x71,0x60, + 0x0f,0xbb,0xf9,0x2c,0xbb }, + .klen = 32, + .msg = { 0x0b,0xa2,0x1b,0x26,0x0e,0xe8,0x94,0x14,0x78, + 0x53,0xa1,0x43,0x28,0xce,0xcf,0x1d }, + .mlen = 16, + .mac = { 0x1d,0xd6,0xcd,0xc6,0xa7 }, + .tlen = 5, + .chunks_msg = { 5, 5, 6 }, + .num_chunks_message = 3, + }, { // 6 (24) + .key = { 0x3a,0x75,0xa9,0xd2,0xbd,0xb8,0xc8,0x04,0xba, + 0x4a,0xb4,0x98,0x35,0x73,0xa6,0xb2,0x53,0x16, + 0x0d,0xd9,0x0f,0x8e,0xdd,0xfb,0x2f,0xdc,0x2a, + 0xb1,0x76,0x04,0xf5,0xc5 }, + .klen = 32, + .msg = { 0x42,0xf3,0x5d,0x5a,0xa5,0x33,0xa7,0xa0,0xa5, + 0xf7,0x4e,0x14,0x4f,0x2a,0x5f,0x20 }, + .mlen = 16, + .mac = { 0xf1,0x53,0x2f,0x87,0x32,0xd9,0xf5,0x90,0x30, + 0x07 }, + .tlen = 10, + }, { // 7 (32) + .key = { 0xdc,0xba,0x2c,0xe0,0x16,0x33,0x93,0x7b,0x1c, + 0xda,0xb1,0x2b,0x2e,0x83,0x59,0x8a,0x49,0xc5, + 0x16,0x09,0xef,0xae,0x0f,0x40,0x26,0xb6,0x2d, + 0x82,0xc3,0xf2,0x80,0xb5 }, + .klen = 32, + .msg = { 0x9a,0xa3,0xe8,0xad,0x92,0x77,0x7d,0xfe,0xb1, + 0x21,0xa6,0x46,0xce,0x2e,0x91,0x8d,0x1e,0x12, + 0xb3,0x07,0x54,0xbc,0x09,0x47,0x0d,0x6d,0xa4, + 0xaf,0x6c,0xc9,0x64,0x2b,0x01,0x2f,0x04,0x1f, + 0xf0,0x46,0x56,0x9d,0x4f,0xd8,0xd0,0xdc,0xcf, + 0xe4,0x48,0xe5 }, + .mlen = 48, + .mac = { 0x81,0x62,0x82,0xfb,0x33 }, + .tlen = 5, + }, { // 8 (33) + .key = { 0x0b,0x12,0x2a,0xc8,0xf3,0x4e,0xd1,0xfe,0x08, + 0x2a,0x36,0x25,0xd1,0x57,0x56,0x14,0x54,0x16, + 0x7a,0xc1,0x45,0xa1,0x0b,0xbf,0x77,0xc6,0xa7, + 0x05,0x96,0xd5,0x74,0xf1 }, + .klen = 32, + .msg = { 0x49,0x8b,0x53,0xfd,0xec,0x87,0xed,0xcb,0xf0, + 0x70,0x97,0xdc,0xcd,0xe9,0x3a,0x08,0x4b,0xad, + 0x75,0x01,0xa2,0x24,0xe3,0x88,0xdf,0x34,0x9c, + 0xe1,0x89,0x59,0xfe,0x84,0x85,0xf8,0xad,0x15, + 0x37,0xf0,0xd8,0x96,0xea,0x73,0xbe,0xdc,0x72, + 0x14,0x71,0x3f }, + .mlen = 48, + .mac = { 0xf6,0x2c,0x46,0x32,0x9b }, + .tlen = 5, + .chunks_msg = { 24, 24 }, + .num_chunks_message = 2, + }, { // 9 (34) + .key = { 0x75,0x11,0xf3,0xa0,0x4e,0x0e,0xa0,0xe7,0xce, + 0xda,0x9e,0x06,0x66,0x6d,0x15,0x53,0xab,0x58, + 0x63,0x84,0x0b,0xa7,0x6d,0xb6,0xb8,0x0b,0x37, + 0xb5,0xe9,0x39,0xb3,0x77 }, + .klen = 32, + .msg = { 0x30,0x83,0x43,0x08,0x18,0x7b,0x8b,0xe1,0xbe, + 0x40,0x5d,0x4b,0x27,0x4d,0x97,0xb5,0xd8,0xab, + 0x71,0x90,0x50,0x64,0x18,0x5f,0xd7,0x3b,0x99, + 0x0d,0x76,0x9a,0x01,0x84,0x47,0xcc,0xc2,0x7b, + 0xef,0x6c,0x59,0x8f,0x68,0x1e,0x2e,0x96,0x04, + 0x7d,0xbc,0x30 }, + .mlen = 48, + .mac = { 0xc0,0x4f,0xf7,0x16,0x38 }, + .tlen = 5, + .chunks_msg = { 16, 16, 16 }, + .num_chunks_message = 3, + }, { // 10 (66) + .key = { 0xcf,0x3b,0x0e,0xbe,0xe6,0xb4,0xac,0x11,0xaa, + 0x76,0x78,0xb2,0xf5,0x45,0x3c,0x13,0x07,0xaf, + 0x5c,0xda,0x7c,0x34,0x67,0x2a,0x7b,0xaa,0xec, + 0x25,0x2f,0xe0,0x8f,0xaf }, + .klen = 32, + .msg = { 0xe4,0xbd,0x45,0xe3,0x1e,0x1d,0x3c,0xf9,0x27, + 0x60,0x96,0xc1,0x8d,0x2d,0x70 }, + .mlen = 15, + .mac = { 0x32,0x6b,0x02,0x39,0x04 }, + .tlen = 5, + }, { // 11 (67) + .key = { 0x47,0x97,0x20,0xcd,0xda,0xa5,0xe0,0x08,0xfa, + 0x19,0x4b,0xb8,0x59,0xec,0x3f,0xce,0x76,0xb2, + 0xd6,0x96,0xc2,0x29,0xa0,0xe7,0x02,0x12,0x2f, + 0x9d,0xf4,0x3f,0xd9,0x48 }, + .klen = 32, + .msg = { 0x3a,0x98,0x7e,0xb8,0x79,0x58,0x08,0x01,0x28, + 0xf0,0x8d,0xcd,0xf9,0x1e,0x63 }, + .mlen = 15, + .mac = { 0x1e,0xbe,0xca,0x94,0xae }, + .tlen = 5, + .chunks_msg = { 1, 14 }, + .num_chunks_message = 2, + }, { // 12 (93) + .key = { 0x23,0xe5,0x42,0x2e,0x8d,0x75,0x60,0xa9,0xe6, + 0x56,0x42,0xb5,0xe7,0x23,0xa4,0x75,0x36,0xc1, + 0x67,0x91,0xf3,0xa0,0xcf,0x91,0x8d,0x3d,0xee, + 0x8a,0xdb,0xec,0x60,0xfd }, + .klen = 32, + .msg = { 0xb9,0xee,0x14,0x00,0x18,0x6c,0x0c,0x07,0x74, + 0x40,0x1a,0x81,0x5b,0xcd,0xe3,0x0d,0x3b,0xe1, + 0xd4,0xf8,0x7f,0x42,0x64,0x6c,0xfb,0x8a,0x99, + 0xe4,0x8a,0x35,0xce,0xe3,0xf5,0xf9,0xb3,0xe6, + 0x17,0x56,0x95,0x97,0x3f,0x6d,0xe0,0x43,0xd6, + 0x15,0xe2,0x8e }, + .mlen = 48, + .mac = { 0x17,0x75,0x84,0x70,0x19,0xca,0x9b,0x88,0x68, + 0x3e }, + .tlen = 10, + .chunks_msg = { 8, 4, 4, 8, 4, 4, 8, 8 }, + .num_chunks_message = 8, + }, { // 13 (94) + .key = { 0x7c,0xfc,0x08,0x6d,0x10,0x65,0x9d,0x7c,0xb9, + 0x24,0x72,0x08,0x35,0x8d,0xd8,0x2c,0x03,0xb8, + 0xdb,0xd8,0x23,0x32,0x23,0x23,0x1d,0xf2,0x18, + 0xe2,0x44,0x8f,0x4a,0x79 }, + .klen = 32, + .msg = { 0xa3,0xaf,0x8f,0x99,0x70,0x3a,0x60,0x10,0x86, + 0xc2,0xa1,0xff,0xe5,0x5f,0xde,0x4c,0x2c,0x41, + 0x53,0xdb,0xff,0x8d,0x66,0x01,0xab,0x68,0x74, + 0x3c,0x0d,0x50,0xd0,0x21,0xb0,0xb3,0x09,0x95, + 0x35,0xba,0x6c,0x40,0xf8,0x66,0xca,0x3f,0xf0, + 0xdf,0x7c,0x19 }, + .mlen = 48, + .mac = { 0x9d,0x71,0x3a,0x19,0x44,0xb8,0xeb,0x64,0x95, + 0x84 }, + .tlen = 10, + .chunks_msg = { 7, 7, 7, 15, 12 }, + .num_chunks_message = 5, + } +}; + +#define NUM_OF_PUBLISHED_TESTSUITES 7 + +struct published_test_suite_info published_test_suites[] = { + { + .name = "AES_ECB", + .tvcount = 3, + .tv = aes_ecb_tv, + .size = AES_BLOCK_SIZE, + .mech = {CKM_AES_ECB, 0, 0}, + }, { + .name = "AES_CBC", + .tvcount = 3, + .tv = aes_cbc_tv, + .size = AES_BLOCK_SIZE, + .mech = {CKM_AES_CBC, &aes_iv, AES_IV_SIZE}, + }, { + .name = "AES_CTR", + .tvcount = 3, + .tv = aes_ctr_tv, + .size = AES_BLOCK_SIZE, + .mech = {CKM_AES_CTR, &aesctr, sizeof(aesctr)}, + }, { + .name = "AES_GCM", + .tvcount = 10, + .tv = aes_gcm_tv, + .size = AES_BLOCK_SIZE, + .mech = {CKM_AES_GCM, &aesgcm, sizeof(aesgcm)}, + }, { + .name = "AES_CFB8", + .tvcount = 3, + .tv = aes_cfb8_tv, + .size = 1, + .mech = {CKM_AES_CFB8, &aes_iv, AES_IV_SIZE}, + }, { + .name = "AES_CFB128", + .tvcount = 3, + .tv = aes_cfb128_tv, + .size = AES_BLOCK_SIZE, + .mech = {CKM_AES_CFB128, &aes_iv, AES_IV_SIZE}, + }, { + .name = "AES_OFB", + .tvcount = 3, + .tv = aes_ofb_tv, + .size = AES_BLOCK_SIZE, + .mech = {CKM_AES_OFB, &aes_iv, AES_IV_SIZE}, + } +}; + +#define NUM_OF_GENERATED_TESTSUITES 4 + +struct generated_test_suite_info generated_test_suites[] = { + { + .name = "AES_ECB", + .mech = {CKM_AES_ECB, 0, 0}, + }, { + .name = "AES_CBC", + .mech = {CKM_AES_CBC, &aes_iv, AES_IV_SIZE}, + }, { + .name = "AES_CBC_PAD", + .mech = {CKM_AES_CBC_PAD, &aes_iv, AES_IV_SIZE}, + }, { + .name = "AES_CTR", + .mech = {CKM_AES_CTR, &aesctr, sizeof(aesctr)}, + } +}; + +#define NUM_OF_GENERATED_ERR_TESTSUITES 2 + +struct generated_test_suite_info generated_err_test_suites[] = { + { + .name = "AES_ECB", + .mech = {CKM_AES_ECB, 0, 0}, + }, { + .name = "AES_CBC", + .mech = {CKM_AES_CBC, &aes_iv, AES_IV_SIZE}, + } +}; + +#define NUM_OF_PUBLISHED_CMAC_TESTSUITES 9 + +struct published_cmac_test_suite_info published_cmac_test_suites[] = { + { + .name = "AES_CMAC_GENERAL (128)", + .tvcount = 22, + .tv = aes128_cmac_tv, + .mech = {CKM_AES_CMAC_GENERAL, 0, 0}, + }, { + .name = "AES_CMAC_GENERAL (192)", + .tvcount = 20, + .tv = aes192_cmac_tv, + .mech = {CKM_AES_CMAC_GENERAL, 0, 0}, + }, { + .name = "AES_CMAC_GENERAL (256)", + .tvcount = 14, + .tv = aes256_cmac_tv, + .mech = {CKM_AES_CMAC_GENERAL, 0, 0}, + }, { + .name = "AES_CMAC (128)", + .tvcount = 22, + .tv = aes128_cmac_tv, + .mech = {CKM_AES_CMAC, 0, 0}, + }, { + .name = "AES_CMAC (192)", + .tvcount = 20, + .tv = aes192_cmac_tv, + .mech = {CKM_AES_CMAC, 0, 0}, + }, { + .name = "AES_CMAC (256)", + .tvcount = 14, + .tv = aes256_cmac_tv, + .mech = {CKM_AES_CMAC, 0, 0}, + }, { + .name = "IBM-CMAC (128)", + .tvcount = 22, + .tv = aes128_cmac_tv, + .mech = {CKM_IBM_CMAC, 0, 0}, + }, { + .name = "IBM-CMAC (192)", + .tvcount = 20, + .tv = aes192_cmac_tv, + .mech = {CKM_IBM_CMAC, 0, 0}, + }, { + .name = "IBM-CMAC (256)", + .tvcount = 14, + .tv = aes256_cmac_tv, + .mech = {CKM_IBM_CMAC, 0, 0}, + } +}; diff --git a/testcases/crypto/aes_func.c b/testcases/crypto/aes_func.c new file mode 100644 index 0000000..20b7d68 --- /dev/null +++ b/testcases/crypto/aes_func.c @@ -0,0 +1,2008 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2006-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 + */ + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "aes.h" +#include "common.c" +#include "mech_to_str.h" + +CK_ULONG key_lens[] = { 16, 24, 32 }; + +/* aes-ctr has 3encck+3decck+3encsk+3decsk+3keywrap+1RSA + * aes-ecb has 3encck+3decck+3encsk+3decsk+3keywrap+1RSA + * aec-cbc has 3encck+3decck+3encsk+3decsk+3keywrap+3encpad+3decpad+ + * 3keywrappad+2RSA + * Note: securekey and clearkey both have 3enc and 3dec, so number + * of assertions is the same whether using clearkey or securekey. + */ + +CK_RV do_EncryptDecryptAES(struct generated_test_suite_info *tsuite) +{ + int i; + CK_BYTE original[BIG_REQUEST]; + CK_BYTE crypt[BIG_REQUEST + AES_BLOCK_SIZE]; + CK_BYTE decrypt[BIG_REQUEST + AES_BLOCK_SIZE]; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG j; + CK_ULONG user_pin_len; + CK_ULONG orig_len, crypt_len, decrypt_len; + + CK_SESSION_HANDLE session; + CK_MECHANISM mechkey, mech; + CK_OBJECT_HANDLE h_key; + CK_FLAGS flags; + CK_RV rc = CKR_OK; + CK_SLOT_ID slot_id = SLOT_ID; + + testsuite_begin("%s Encryption/Decryption.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip tests if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(3, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + + /** iterate over test key sizes **/ + for (i = 0; i < 3; i++) { + + testcase_begin("%s Encryption/Decryption with key len=%ld.", + tsuite->name, key_lens[i]); + + /** generate key **/ + mechkey = aes_keygen; + rc = generate_AESKey(session, key_lens[i], &mechkey, &h_key); + + if (rc != CKR_OK) { + testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** clear buffers **/ + memset(original, 0, sizeof(original)); + memset(crypt, 0, sizeof(crypt)); + memset(decrypt, 0, sizeof(decrypt)); + + /** generate data **/ + orig_len = sizeof(original); + + for (j = 0; j < orig_len; j++) + original[j] = j % 255; + + /** set crypto mech **/ + mech = tsuite->mech; + + /** single encryption **/ + rc = funcs->C_EncryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + crypt_len = sizeof(crypt); + + rc = funcs->C_Encrypt(session, original, orig_len, crypt, &crypt_len); + + if (rc != CKR_OK) { + testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** single decryption **/ + rc = funcs->C_DecryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + decrypt_len = sizeof(decrypt); + + rc = funcs->C_Decrypt(session, crypt, crypt_len, decrypt, &decrypt_len); + + if (rc != CKR_OK) { + testcase_error("C_Decrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare actual results with expected results **/ + testcase_new_assertion(); + + if (decrypt_len != orig_len) { + testcase_fail("decrypted data length does not " + "match original data length.\nexpected " + "length=%ld, but found length=%ld\n", + orig_len, decrypt_len); + } else if (memcmp(decrypt, original, orig_len)) { + testcase_fail("decrypted data does not match " "original data"); + } else { + testcase_pass("%s Encryption/Decryption with " + "key length %ld passed.", tsuite->name, key_lens[i]); + } + + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + goto testcase_cleanup; + +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +CK_RV do_EncryptDecryptUpdateAES(struct generated_test_suite_info * tsuite) +{ + int i; + CK_BYTE original[BIG_REQUEST]; + CK_BYTE crypt[BIG_REQUEST + AES_BLOCK_SIZE]; + CK_BYTE decrypt[BIG_REQUEST + AES_BLOCK_SIZE]; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG j, k, tmp; + CK_ULONG user_pin_len; + CK_ULONG orig_len, crypt_len, decrypt_len; + + CK_SLOT_ID slot_id = SLOT_ID; + CK_SESSION_HANDLE session; + CK_MECHANISM mechkey, mech; + CK_OBJECT_HANDLE h_key; + CK_FLAGS flags; + CK_RV rc = CKR_OK; + + /** begin testsuite **/ + testsuite_begin("%s Multipart Encryption/Decryption.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip test if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testcase_skip("Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + /** iterate over key sizes **/ + for (i = 0; i < 3; i++) { + + testcase_begin("%s Multipart Encryption/Decryption with " + "key len=%ld.", tsuite->name, key_lens[i]); + + /** generate key **/ + mechkey = aes_keygen; + rc = generate_AESKey(session, key_lens[i], &mechkey, &h_key); + + if (rc != CKR_OK) { + testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** clear buffers **/ + memset(original, 0, sizeof(original)); + memset(crypt, 0, sizeof(crypt)); + memset(decrypt, 0, sizeof(decrypt)); + + /** generate data **/ + orig_len = sizeof(original); + + for (j = 0; j < orig_len; j++) + original[j] = j % 255; + + /** set crypto mech **/ + mech = tsuite->mech; + + /** multipart encryption **/ + rc = funcs->C_EncryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /* Encrypt in place except for CBC_PAD, since it + * pads and pkcs padding can make it unclear about what is + * output at what stage. (See pkcs11v2.20 Section 11.2) + */ + if (mech.mechanism != CKM_AES_CBC_PAD) { + + memcpy(crypt, original, orig_len); + crypt_len = orig_len; + k = 0; + while (k < orig_len) { + rc = funcs->C_EncryptUpdate(session, + &crypt[k], + AES_BLOCK_SIZE, + &crypt[k], &crypt_len); + if (rc != CKR_OK) { + testcase_error("C_EncryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + + k += crypt_len; // encrypted amount + crypt_len = orig_len - k; // space in out buf + + } + } else { + + j = k = 0; // j indexes source buffer + // k indexes destination buffer + crypt_len = sizeof(crypt); + + while (j < orig_len) { + tmp = crypt_len - k; // room left + rc = funcs->C_EncryptUpdate(session, + &original[j], + AES_BLOCK_SIZE, &crypt[k], &tmp); + if (rc != CKR_OK) { + testcase_error("C_EncryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + + k += tmp; + j += AES_BLOCK_SIZE; + } + + crypt_len = sizeof(crypt) - k; + } + + rc = funcs->C_EncryptFinal(session, &crypt[k], &crypt_len); + if (rc != CKR_OK) { + testcase_error("C_EncryptFinal rc=%s", p11_get_ckr(rc)); + goto error; + } + + crypt_len += k; + + /** multipart decryption **/ + rc = funcs->C_DecryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /* decrypt in place. skip for AES_CBC_PAD since it + * pads and pkcs padding can make it unclear about what is + * output at what stage. (See pkcs11v2.20 Section 11.2) + */ + if (mech.mechanism != CKM_AES_CBC_PAD) { + + memcpy(decrypt, crypt, crypt_len); + k = 0; + decrypt_len = crypt_len; + while (k < crypt_len) { + rc = funcs->C_DecryptUpdate(session, + &decrypt[k], + AES_BLOCK_SIZE, + &decrypt[k], &decrypt_len); + if (rc != CKR_OK) { + testcase_error("C_DecryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + + k += decrypt_len; // decrypted amount + decrypt_len = crypt_len - k; // space in out buf + } + } else { + + j = k = 0; // j indexes source buffer, + // k indexes destination buffer + decrypt_len = sizeof(decrypt); + while (j < crypt_len) { + tmp = decrypt_len - k; // room left in outbuf + rc = funcs->C_DecryptUpdate(session, + &crypt[j], + AES_BLOCK_SIZE, &decrypt[k], &tmp); + if (rc != CKR_OK) { + testcase_error("C_DecryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + k += tmp; + j += AES_BLOCK_SIZE; + } + + decrypt_len = sizeof(decrypt) - k; + } + + rc = funcs->C_DecryptFinal(session, &decrypt[k], &decrypt_len); + if (rc != CKR_OK) { + testcase_error("C_DecryptFinal rc=%s", p11_get_ckr(rc)); + goto error; + } + + decrypt_len += k; + + /** compare actual results with expected results **/ + testcase_new_assertion(); + + if (decrypt_len != orig_len) { + testcase_fail("decrypted multipart data length does not" + " match original data length.\nexpected " + "length=%ld, but found length=%ld\n", + orig_len, decrypt_len); + } else if (memcmp(decrypt, original, orig_len)) { + testcase_fail("decrypted multipart data does not match" + " original data"); + } else { + testcase_pass("%s Multipart Encryption/Decryption with" + " key length %ld passed.", tsuite->name, key_lens[i]); + } + + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + goto testcase_cleanup; + +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +CK_RV do_EncryptAES(struct published_test_suite_info * tsuite) +{ + unsigned int i; + CK_BYTE input[BIG_REQUEST]; // cleartext buffer + CK_BYTE output[BIG_REQUEST]; // encryption buffer + CK_BYTE expected[BIG_REQUEST]; // encrypted data + CK_ULONG input_len, output_len, expected_len; + CK_ULONG user_pin_len; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_OBJECT_HANDLE h_key; + CK_RV rc = CKR_OK; + CK_FLAGS flags; + CK_SLOT_ID slot_id = SLOT_ID; + CK_GCM_PARAMS *gcm_param; + + /** begin testsuite **/ + testsuite_begin("%s Encryption.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip test if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + for (i = 0; i < tsuite->tvcount; i++) { + + testcase_begin("%s Encryption with published test vector %d.", + tsuite->name, i); + + rc = CKR_OK; + + /** create key handle **/ + rc = create_AESKey(session, + tsuite->tv[i].key, tsuite->tv[i].klen, &h_key); + + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** get mech **/ + mech = tsuite->mech; + if (mech.mechanism == CKM_AES_GCM) { + gcm_param = ((CK_GCM_PARAMS *) mech.pParameter); + gcm_param->pIv = (CK_BYTE *) tsuite->tv[i].iv; + gcm_param->ulIvLen = tsuite->tv[i].ivlen; + gcm_param->pAAD = tsuite->tv[i].aad; + gcm_param->ulAADLen = tsuite->tv[i].aadlen; + gcm_param->ulTagBits = tsuite->tv[i].taglen; + } + + /** clear buffers **/ + memset(expected, 0, sizeof(expected)); + memset(input, 0, sizeof(input)); + memset(output, 0, sizeof(output)); + + /** get ciphertext (expected results) **/ + expected_len = tsuite->tv[i].clen; + memcpy(expected, tsuite->tv[i].ciphertext, expected_len); + + /** get plaintext **/ + input_len = tsuite->tv[i].plen; + memcpy(input, tsuite->tv[i].plaintext, input_len); + + /** single (in-place) encryption **/ + rc = funcs->C_EncryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + rc = funcs->C_Encrypt(session, input, input_len, NULL, &output_len); + if (rc != CKR_OK) { + testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + rc = funcs->C_Encrypt(session, input, input_len, output, &output_len); + + if (rc != CKR_OK) { + testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare actual results with expected results. **/ + testcase_new_assertion(); + + if (output_len != expected_len) { + testcase_fail("encrypted data length does not match " + "test vector's encrypted data length.\n\n" + "expected length=%ld, but found length=%ld\n", + expected_len, output_len); + } else if (memcmp(output, expected, expected_len)) { + testcase_fail("encrypted data does not match test " + "vector's encrypted data"); + } else { + testcase_pass("%s Encryption with test vector %d " + "passed.", tsuite->name, i); + } + + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + goto testcase_cleanup; + +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +CK_RV do_EncryptUpdateAES(struct published_test_suite_info * tsuite) +{ + unsigned int i; + CK_BYTE plaintext[BIG_REQUEST]; + CK_BYTE expected[BIG_REQUEST]; // encrypted data + CK_BYTE crypt[BIG_REQUEST]; + CK_ULONG expected_len, p_len, crypt_len, k; + CK_ULONG user_pin_len; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_OBJECT_HANDLE h_key; + CK_RV rc = CKR_OK; + CK_FLAGS flags; + CK_SLOT_ID slot_id = SLOT_ID; + CK_GCM_PARAMS *gcm_param; + + testsuite_begin("%s Multipart Encryption.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip test if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + for (i = 0; i < tsuite->tvcount; i++) { + + testcase_begin("%s Multipart Encryption with published test " + "vector %d.", tsuite->name, i); + + rc = CKR_OK; + + /** create key handle **/ + rc = create_AESKey(session, + tsuite->tv[i].key, tsuite->tv[i].klen, &h_key); + + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** get mech **/ + mech = tsuite->mech; + if (mech.mechanism == CKM_AES_GCM) { + gcm_param = ((CK_GCM_PARAMS *) mech.pParameter); + gcm_param->pIv = (CK_BYTE *) tsuite->tv[i].iv; + gcm_param->ulIvLen = tsuite->tv[i].ivlen; + gcm_param->pAAD = tsuite->tv[i].aad; + gcm_param->ulAADLen = tsuite->tv[i].aadlen; + gcm_param->ulTagBits = tsuite->tv[i].taglen; + } + + /** clear buffers **/ + memset(expected, 0, sizeof(expected)); + memset(plaintext, 0, sizeof(plaintext)); + memset(crypt, 0, sizeof(crypt)); + + /** get ciphertext (expected results) **/ + expected_len = tsuite->tv[i].clen; + memcpy(expected, tsuite->tv[i].ciphertext, expected_len); + + /** get plaintext **/ + p_len = tsuite->tv[i].plen; + memcpy(plaintext, tsuite->tv[i].plaintext, p_len); + + /** multipart encryption **/ + rc = funcs->C_EncryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /* for chunks, -1 is NULL, and 0 is empty string, + * and a value > 0 is amount of data from test vector's + * plaintext data. This way we test vary-sized chunks. + */ + if (tsuite->tv[i].num_chunks_plain) { + int j; + CK_ULONG outlen, len; + CK_BYTE *data_chunk = NULL; + + k = 0; + crypt_len = 0; + outlen = sizeof(crypt); + + for (j = 0; j < tsuite->tv[i].num_chunks_plain; j++) { + if (tsuite->tv[i].chunks_plain[j] == -1) { + len = 0; + data_chunk = NULL; + } else if (tsuite->tv[i].chunks_plain[j] == 0) { + len = 0; + data_chunk = (CK_BYTE *) ""; + } else { + len = tsuite->tv[i].chunks_plain[j]; + data_chunk = plaintext + k; + } + + rc = funcs->C_EncryptUpdate(session, data_chunk, + len, &crypt[crypt_len], &outlen); + if (rc != CKR_OK) { + testcase_error("C_EncryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + k += len; + crypt_len += outlen; + outlen = sizeof(crypt) - crypt_len; + } + } else { + crypt_len = sizeof(crypt); + rc = funcs->C_EncryptUpdate(session, plaintext, p_len, + crypt, &crypt_len); + if (rc != CKR_OK) { + testcase_error("C_EncryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + } + + k = sizeof(crypt) - crypt_len; + rc = funcs->C_EncryptFinal(session, &crypt[crypt_len], &k); + if (rc != CKR_OK) { + testcase_error("C_EncryptFinal rc=%s", p11_get_ckr(rc)); + goto error; + } + + crypt_len += k; + + /** compare encryption results with expected results. **/ + testcase_new_assertion(); + + if (crypt_len != expected_len) { + testcase_fail("encrypted multipart data length does " + "not match test vector's encrypted data length." + "\n\nexpected length=%ld, but found length=%ld" + "\n", expected_len, crypt_len); + } else if (memcmp(crypt, expected, expected_len)) { + testcase_fail("encrypted multipart data does not match" + " test vector's encrypted data.\n"); + } else { + testcase_pass("%s Multipart Encryption with test " + "vector %d passed.", tsuite->name, i); + } + + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + goto testcase_cleanup; + +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +CK_RV do_DecryptAES(struct published_test_suite_info * tsuite) +{ + unsigned int i; + CK_BYTE input[BIG_REQUEST]; // encrypted buffer + CK_BYTE output[BIG_REQUEST]; // decryption buffer + CK_BYTE expected[BIG_REQUEST]; // decrypted data + CK_ULONG input_len, output_len, expected_len; + CK_ULONG user_pin_len; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_OBJECT_HANDLE h_key; + CK_RV rc = CKR_OK; + CK_FLAGS flags; + CK_SLOT_ID slot_id = SLOT_ID; + CK_GCM_PARAMS *gcm_param; + + testsuite_begin("%s Decryption.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip test if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + for (i = 0; i < tsuite->tvcount; i++) { + + testcase_begin("%s Decryption with published test vector %d.", + tsuite->name, i); + + rc = CKR_OK; + + /** create key handle **/ + rc = create_AESKey(session, + tsuite->tv[i].key, tsuite->tv[i].klen, &h_key); + + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** get mech **/ + mech = tsuite->mech; + if (mech.mechanism == CKM_AES_GCM) { + gcm_param = ((CK_GCM_PARAMS *) mech.pParameter); + gcm_param->pIv = (CK_BYTE *) tsuite->tv[i].iv; + gcm_param->ulIvLen = tsuite->tv[i].ivlen; + gcm_param->pAAD = tsuite->tv[i].aad; + gcm_param->ulAADLen = tsuite->tv[i].aadlen; + gcm_param->ulTagBits = tsuite->tv[i].taglen; + } + + /** clear buffers **/ + memset(expected, 0, sizeof(expected)); + memset(input, 0, sizeof(input)); + memset(output, 0, sizeof(output)); + + /** get plaintext (expected results) **/ + expected_len = tsuite->tv[i].plen; + memcpy(expected, tsuite->tv[i].plaintext, expected_len); + + /** get ciphertext **/ + input_len = tsuite->tv[i].clen; + memcpy(input, tsuite->tv[i].ciphertext, input_len); + + /** single (in-place) decryption **/ + rc = funcs->C_DecryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + rc = funcs->C_Decrypt(session, input, input_len, NULL, &output_len); + if (rc != CKR_OK) { + testcase_error("C_Decrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + rc = funcs->C_Decrypt(session, input, input_len, output, &output_len); + if (rc != CKR_OK) { + testcase_error("C_Decrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare actual results with expected results. **/ + testcase_new_assertion(); + + if (output_len != expected_len) { + testcase_fail("decrypted data length does not match " + "test vector's decrypted data length.\n\n" + "expected length=%ld, but found length=%ld\n", + expected_len, output_len); + } else if (memcmp(output, expected, expected_len)) { + testcase_fail("decrypted data does not match test " + "vector's decrypted data"); + } else { + testcase_pass("%s Decryption with test vector %d " + "passed.", tsuite->name, i); + } + + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + goto testcase_cleanup; + +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + + return rc; +} + +CK_RV do_DecryptUpdateAES(struct published_test_suite_info * tsuite) +{ + unsigned int i; + CK_BYTE cipher[BIG_REQUEST]; + CK_BYTE expected[BIG_REQUEST]; // decrypted data + CK_BYTE plaintext[BIG_REQUEST]; + CK_ULONG cipher_len, expected_len, p_len, k; + CK_ULONG user_pin_len; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_OBJECT_HANDLE h_key; + CK_RV rc = CKR_OK; + CK_FLAGS flags; + CK_SLOT_ID slot_id = SLOT_ID; + CK_GCM_PARAMS *gcm_param; + + testsuite_begin("%s Multipart Decryption.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip tests if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + for (i = 0; i < tsuite->tvcount; i++) { + + testcase_begin("%s Multipart Decryption with published test " + "vector %d.", tsuite->name, i); + + /** create key handle **/ + rc = create_AESKey(session, + tsuite->tv[i].key, tsuite->tv[i].klen, &h_key); + + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** get mech **/ + mech = tsuite->mech; + if (mech.mechanism == CKM_AES_GCM) { + gcm_param = ((CK_GCM_PARAMS *) mech.pParameter); + gcm_param->pIv = (CK_BYTE *) tsuite->tv[i].iv; + gcm_param->ulIvLen = tsuite->tv[i].ivlen; + gcm_param->pAAD = tsuite->tv[i].aad; + gcm_param->ulAADLen = tsuite->tv[i].aadlen; + gcm_param->ulTagBits = tsuite->tv[i].taglen; + } + + /** clear buffers **/ + memset(expected, 0, sizeof(expected)); + memset(cipher, 0, sizeof(cipher)); + memset(plaintext, 0, sizeof(plaintext)); + + /** get plaintext (expected results) **/ + expected_len = tsuite->tv[i].plen; + memcpy(expected, tsuite->tv[i].plaintext, expected_len); + + p_len = sizeof(plaintext); + cipher_len = tsuite->tv[i].clen; + memcpy(cipher, tsuite->tv[i].ciphertext, cipher_len); + + /** multipart (in-place) decryption **/ + rc = funcs->C_DecryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /* for chunks, -1 is NULL, and 0 is empty string, + * and a value > 0 is amount of data from test vector's + * plaintext data. This way we test vary-sized chunks. + */ + if (tsuite->tv[i].num_chunks_ciph) { + int j; + CK_ULONG outlen, len; + CK_BYTE *data_chunk = NULL; + + k = 0; + p_len = 0; + outlen = sizeof(plaintext); + for (j = 0; j < tsuite->tv[i].num_chunks_ciph; j++) { + if (tsuite->tv[i].chunks_ciph[j] == -1) { + len = 0; + data_chunk = NULL; + } else if (tsuite->tv[i].chunks_ciph[j] == 0) { + len = 0; + data_chunk = (CK_BYTE *) ""; + } else { + len = tsuite->tv[i].chunks_ciph[j]; + data_chunk = cipher + k; + } + + rc = funcs->C_DecryptUpdate(session, data_chunk, + len, &plaintext[p_len], &outlen); + if (rc != CKR_OK) { + testcase_error("C_DecryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + k += len; + p_len += outlen; + outlen = sizeof(plaintext) - p_len; + } + } else { + p_len = sizeof(plaintext); + rc = funcs->C_DecryptUpdate(session, cipher, cipher_len, + plaintext, &p_len); + if (rc != CKR_OK) { + testcase_error("C_DecryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + } + + k = sizeof(plaintext) - p_len; + rc = funcs->C_DecryptFinal(session, &plaintext[p_len], &k); + if (rc != CKR_OK) { + testcase_error("C_DecryptFinal rc=%s", p11_get_ckr(rc)); + goto error; + } + p_len += k; /* add possible last part to overall length */ + + /** compare decryption results with expected results. **/ + testcase_new_assertion(); + + if (p_len != expected_len) { + testcase_fail("decrypted multipart data length does " + "not match test vector's decrypted data " + "length.\n\nexpected length=%ld, but found " + "length=%ld\n", expected_len, p_len); + } else if (memcmp(plaintext, expected, expected_len)) { + testcase_fail("decrypted multipart data does not match" + " test vector's decrypted data.\n"); + } else { + testcase_pass("%s Multipart Decryption with test " + "vector %d passed.", tsuite->name, i); + } + + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + goto testcase_cleanup; +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + + return rc; +} + +CK_RV do_WrapUnwrapAES(struct generated_test_suite_info * tsuite) +{ + unsigned int i, j; + CK_BYTE original[BIG_REQUEST + AES_BLOCK_SIZE]; + CK_BYTE crypt[BIG_REQUEST + AES_BLOCK_SIZE]; + CK_BYTE decrypt[BIG_REQUEST + AES_BLOCK_SIZE]; + CK_BYTE_PTR wrapped_data = NULL; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_SESSION_HANDLE session; + CK_MECHANISM mechkey, mech; + CK_OBJECT_HANDLE h_key = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE w_key = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE uw_key = CK_INVALID_HANDLE; + CK_ULONG wrapped_data_len = 0; + CK_ULONG user_pin_len; + CK_ULONG orig_len, crypt_len, decrypt_len; + CK_ULONG tmpl_count = 2; /* Use only the first 2 attrs, except for CCA */ + CK_ULONG key_size; + CK_FLAGS flags; + CK_RV rc = CKR_OK; + CK_SLOT_ID slot_id = SLOT_ID; + CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; + CK_KEY_TYPE key_type = CKK_AES; + CK_ATTRIBUTE template[] = { + {CKA_CLASS, &key_class, sizeof(key_class)}, + {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, + {CKA_VALUE_LEN, &key_size, sizeof(key_size)} /* For CCA only */ + }; + + testsuite_begin("%s Wrap/Unwrap.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip test if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(3, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + if (!wrap_supported(slot_id, tsuite->mech)) { + testsuite_skip(3, "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + /* key sizes must be a multiple of AES block size in order to be passed + in as data. Recall AES expects data in multiple of AES block size. + */ + for (i = 0; i < 3; i++) { + + if (key_lens[i] % AES_BLOCK_SIZE != 0) + continue; + + testcase_begin("%s Wrap/Unwrap key test with keylength=%ld.", + tsuite->name, key_lens[i]); + + /** set mechanisms **/ + mech = tsuite->mech; + mechkey = aes_keygen; + + /** set key_size **/ + key_size = key_lens[i]; + + /** clear buffers **/ + memset(original, 0, sizeof(original)); + memset(crypt, 0, sizeof(crypt)); + memset(decrypt, 0, sizeof(decrypt)); + + /** generate crypto key **/ + rc = generate_AESKey(session, key_lens[i], &mechkey, &h_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** generate wrapping key **/ + rc = generate_AESKey(session, key_lens[i], &mechkey, &w_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** generate data **/ + orig_len = BIG_REQUEST; + crypt_len = BIG_REQUEST + AES_BLOCK_SIZE; + decrypt_len = BIG_REQUEST + AES_BLOCK_SIZE; + for (j = 0; j < orig_len; j++) { + original[j] = j % 255; + } + + /** initiate the encrypt **/ + rc = funcs->C_EncryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** continue with encrypt **/ + rc = funcs->C_Encrypt(session, original, orig_len, crypt, &crypt_len); + + if (rc != CKR_OK) { + testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** wrap key **/ + rc = funcs->C_WrapKey(session, + &mech, w_key, h_key, NULL, &wrapped_data_len); + + if (rc != CKR_OK) { + testcase_error("C_WrapKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + wrapped_data = malloc(wrapped_data_len); + if (wrapped_data == NULL) { + testcase_error("malloc failed"); + goto error; + } + memset(wrapped_data, 0, wrapped_data_len); + rc = funcs->C_WrapKey(session, &mech, w_key, h_key, wrapped_data, + &wrapped_data_len); + if (rc != CKR_OK) { + testcase_error("C_WrapKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + if (is_cca_token(slot_id)) { + /* + * CCA requires the CKA_VALUE_LEN attribute in the unwrap template, + * although the PKCS#11 standard states that it can not be specified + * for unwrap. + */ + tmpl_count = 3; + } + + /** unwrap key **/ + rc = funcs->C_UnwrapKey(session, + &mech, + w_key, + wrapped_data, + wrapped_data_len, + template, tmpl_count, &uw_key); + + if (rc != CKR_OK) { + testcase_error("C_UnwrapKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + if (wrapped_data) { + free(wrapped_data); + wrapped_data = NULL; + } + + /** initiate decryption (with unwrapped key) **/ + rc = funcs->C_DecryptInit(session, &mech, uw_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do decryption (with the unwrapped key) **/ + rc = funcs->C_Decrypt(session, crypt, crypt_len, decrypt, &decrypt_len); + + if (rc != CKR_OK) { + testcase_error("C_Decrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare actual results with expected results **/ + testcase_new_assertion(); + + if (decrypt_len != orig_len) { + testcase_fail("Decrypted length doesn't match the " + "original plaintext length."); + rc = CKR_GENERAL_ERROR; + } else if (memcmp(decrypt, original, orig_len)) { + testcase_fail("Decrypted data does not match original " + "plaintext data."); + rc = CKR_GENERAL_ERROR; + } else { + testcase_pass("%s Wrap/UnWrap test with key length " + "%u passed.", tsuite->name, + (unsigned int) key_lens[i]); + } + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + } + h_key = CK_INVALID_HANDLE; + + rc = funcs->C_DestroyObject(session, w_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + } + w_key = CK_INVALID_HANDLE; + + rc = funcs->C_DestroyObject(session, uw_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + } + uw_key = CK_INVALID_HANDLE; + } + goto testcase_cleanup; +error: + if (wrapped_data) + free(wrapped_data); + + 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)); + } + } + + if (w_key != CK_INVALID_HANDLE) { + rc = funcs->C_DestroyObject(session, w_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + } + } + + if (uw_key != CK_INVALID_HANDLE) { + rc = funcs->C_DestroyObject(session, uw_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + } + } + goto testcase_cleanup; + +testcase_cleanup: + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +CK_RV do_WrapUnwrapRSA(struct generated_test_suite_info * tsuite) +{ + unsigned int i; + CK_BYTE original[BIG_REQUEST]; + CK_BYTE decipher[BIG_REQUEST + AES_BLOCK_SIZE]; + CK_BYTE cipher[BIG_REQUEST + AES_BLOCK_SIZE]; + CK_BYTE wrapped_data[BIG_REQUEST + AES_BLOCK_SIZE]; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_BYTE pub_exp[] = { 0x01, 0x00, 0x01 }; + CK_MECHANISM mech, mech2; + CK_MECHANISM_INFO mech_info; + CK_OBJECT_HANDLE publ_key, priv_key, w_key, uw_key; + CK_ULONG orig_len, cipher_len, decipher_len; + CK_ULONG bits = 1024; + CK_ULONG wrapped_data_len; + CK_ULONG user_pin_len; + CK_ULONG key_size; + CK_RV rc = CKR_OK; + CK_FLAGS flags; + CK_SESSION_HANDLE session; + CK_OBJECT_CLASS keyclass = CKO_PRIVATE_KEY; + CK_KEY_TYPE keytype = CKK_RSA; + CK_SLOT_ID slot_id = SLOT_ID; + + CK_ATTRIBUTE pub_tmpl[] = { + {CKA_MODULUS_BITS, &bits, sizeof(bits)} + , + {CKA_PUBLIC_EXPONENT, &pub_exp, sizeof(pub_exp)} + }; + CK_ATTRIBUTE uw_tmpl[] = { + {CKA_CLASS, &keyclass, sizeof(keyclass)} + , + {CKA_KEY_TYPE, &keytype, sizeof(keytype)} + }; + CK_ATTRIBUTE key_gen_tmpl[] = { + {CKA_VALUE_LEN, &key_size, sizeof(CK_ULONG)} + }; + + testsuite_begin("%s wrap/unwrap of RSA key.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip AES_EBC/AES_CBC (only supported for symmetric keys) **/ + if ((tsuite->mech.mechanism == CKM_AES_ECB) || + (tsuite->mech.mechanism == CKM_AES_CBC)) { + testcase_skip + ("Mechanism %s (%u) not supported to wrap/unwrap asymmetric Keys", + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + /** skip test if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(3, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + if (!mech_supported(slot_id, CKM_RSA_PKCS)) { + testsuite_skip(3, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(CKM_RSA_PKCS), + (unsigned int) CKM_RSA_PKCS); + goto testcase_cleanup; + } + + for (i = 0; i < 3; i++) { + + testcase_begin("%s wrap/unwrap of RSA key for key length=%ld.", + tsuite->name, key_lens[i]); + + key_size = key_lens[i]; + + /** first mechanism generate AES wrapping key **/ + mech.mechanism = CKM_AES_KEY_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + /** mechanism to generate an RSA key pair to be wrapped **/ + mech2.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; + mech2.ulParameterLen = 0; + mech2.pParameter = NULL; + + /** generate an RSA key pair. **/ + rc = funcs->C_GenerateKeyPair(session, + &mech2, + pub_tmpl, + 2, NULL, 0, &publ_key, &priv_key); + + if (rc != CKR_OK) { + testcase_error("C_GenerateKeyPair rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** generate the wrapping key **/ + rc = funcs->C_GenerateKey(session, &mech, key_gen_tmpl, 1, &w_key); + + if (rc != CKR_OK) { + testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** set the mech for AES crypto **/ + mech = tsuite->mech; + + /** wrap the key **/ + wrapped_data_len = sizeof(wrapped_data); + + /** get mech info **/ + rc = funcs->C_GetMechanismInfo(slot_id, mech.mechanism, &mech_info); + + if (rc != CKR_OK) { + testcase_error("C_GetMechanismInfo rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** key is wrappable **/ + if (mech_info.flags & CKF_WRAP) { + /** wrap key **/ + rc = funcs->C_WrapKey(session, + &mech, + w_key, + priv_key, wrapped_data, &wrapped_data_len); + + if (rc != CKR_OK) { + testcase_error("C_WrapKey rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** unwrap key **/ + rc = funcs->C_UnwrapKey(session, + &mech, + w_key, + wrapped_data, + wrapped_data_len, uw_tmpl, 2, &uw_key); + + if (rc != CKR_OK) { + testcase_error("C_UnWrapKey rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** generate data **/ + orig_len = 30; + for (i = 0; i < orig_len; i++) + original[i] = i % 255; + + /** set mech2 for RSA crypto **/ + mech2.mechanism = CKM_RSA_PKCS; + mech2.ulParameterLen = 0; + mech2.pParameter = NULL; + + /** initialize RSA encryption (with public key) **/ + rc = funcs->C_EncryptInit(session, &mech2, publ_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + cipher_len = sizeof(cipher); // set cipher buffer size + + /** do RSA encryption (with public key) **/ + rc = funcs->C_Encrypt(session, + original, orig_len, cipher, &cipher_len); + + if (rc != CKR_OK) { + testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** initialize RSA decryption + (with unwrapped private key) **/ + rc = funcs->C_DecryptInit(session, &mech2, uw_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + decipher_len = sizeof(decipher); + + /** do RSA decryption (with unwrapped private key) **/ + rc = funcs->C_Decrypt(session, + cipher, cipher_len, decipher, &decipher_len); + + if (rc != CKR_OK) { + testcase_error("C_Decrypt rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** compare actual results with expected results **/ + testcase_new_assertion(); + if (orig_len != decipher_len) { + testcase_fail("lengths don't match: " + "%ld vs %ld\n", orig_len, decipher_len); + rc = CKR_GENERAL_ERROR; + } else if (memcmp(original, decipher, orig_len)) { + testcase_fail("deciphered data does not match" + " original data"); + rc = CKR_GENERAL_ERROR; + } else { + testcase_pass("%s passed wrap/unwrap RSA key " + "test.", tsuite->name); + } + + + } else { /** key is not wrappable **/ + testcase_new_assertion(); + + /** try to wrap key **/ + rc = funcs->C_WrapKey(session, + &mech, + w_key, + priv_key, wrapped_data, &wrapped_data_len); + if (rc != CKR_MECHANISM_INVALID && rc != CKR_KEY_NOT_WRAPPABLE) { + testcase_fail("Expected CKR_MECHANISM_INVALID or " + "CKR_KEY_NOT_WRAPPABLE, but got %s", + p11_get_ckr(rc)); + } else { + testcase_pass("%s passed wrap/unwrap RSA key " + "test.", tsuite->name); + } + } + } + +testcase_cleanup: + testcase_close_session(); + + return rc; +} + +CK_RV do_WrapRSA_Err(struct generated_test_suite_info * tsuite) +{ + unsigned int i; + CK_BYTE wrapped_data[BIG_REQUEST + AES_BLOCK_SIZE]; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_BYTE pub_exp[] = { 0x01, 0x00, 0x01 }; + CK_MECHANISM mech, mech2; + CK_MECHANISM_INFO mech_info; + CK_OBJECT_HANDLE publ_key, priv_key, w_key; + CK_ULONG bits = 1024; + CK_ULONG wrapped_data_len, user_pin_len, key_size; + CK_RV rc = CKR_OK; + CK_FLAGS flags; + CK_SESSION_HANDLE session; + CK_SLOT_ID slot_id = SLOT_ID; + + CK_ATTRIBUTE pub_tmpl[] = { + {CKA_MODULUS_BITS, &bits, sizeof(bits)} + , + {CKA_PUBLIC_EXPONENT, &pub_exp, sizeof(pub_exp)} + }; + CK_ATTRIBUTE key_gen_tmpl[] = { + {CKA_VALUE_LEN, &key_size, sizeof(CK_ULONG)} + }; + + testsuite_begin("%s wrap/unwrap of RSA key.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip test if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(3, "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + for (i = 0; i < 3; i++) { + + testcase_begin("%s wrap/unwrap of RSA key for key length=%ld.", + tsuite->name, key_lens[i]); + + key_size = key_lens[i]; + + /** first mechanism generate AES wrapping key **/ + mech.mechanism = CKM_AES_KEY_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + /** mechanism to generate an RSA key pair to be wrapped **/ + mech2.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; + mech2.ulParameterLen = 0; + mech2.pParameter = NULL; + + /** generate an RSA key pair. **/ + rc = funcs->C_GenerateKeyPair(session, &mech2, pub_tmpl, 2, NULL, + 0, &publ_key, &priv_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKeyPair rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** generate the wrapping key **/ + rc = funcs->C_GenerateKey(session, &mech, key_gen_tmpl, 1, &w_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** set the mech for AES crypto **/ + mech = tsuite->mech; + + /** wrap the key **/ + wrapped_data_len = sizeof(wrapped_data); + + /** get mech info **/ + rc = funcs->C_GetMechanismInfo(slot_id, mech.mechanism, &mech_info); + + if (rc != CKR_OK) { + testcase_error("C_GetMechanismInfo rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** key is wrappable **/ + if (mech_info.flags & CKF_WRAP) { + + testcase_new_assertion(); + + /** wrap key **/ + rc = funcs->C_WrapKey(session, &mech, w_key, priv_key, + wrapped_data, &wrapped_data_len); + + /* Expect dedicated error code here, since it's not allowed + * to unwrap non secret keys with AES_ECB/AES_CBC */ + if (rc != CKR_KEY_NOT_WRAPPABLE) { + testcase_error("Expected C_WrapKey rc=%s, but returned rc=%s", + p11_get_ckr(CKR_KEY_NOT_WRAPPABLE), + p11_get_ckr(rc)); + goto testcase_cleanup; + } else { + testcase_pass("%s passed wrap RSA key test.", tsuite->name); + } + } else { + /** key is not wrappable **/ + testcase_new_assertion(); + + /** try to wrap key **/ + rc = funcs->C_WrapKey(session, &mech, w_key, priv_key, + wrapped_data, &wrapped_data_len); + if (rc != CKR_MECHANISM_INVALID && rc != CKR_KEY_NOT_WRAPPABLE) + testcase_fail("Expected CKR_MECHANISM_INVALID or " + "CKR_KEY_NOT_WRAPPABLE, but got %s", + p11_get_ckr(rc)); + else + testcase_pass("%s passed wrap/unwrap RSA key test.", + tsuite->name); + } + } + +testcase_cleanup: + testcase_close_session(); + + return rc; +} + + + +CK_RV do_UnwrapRSA_Err(struct generated_test_suite_info * tsuite) +{ + unsigned int i; + CK_BYTE wrapped_data[BIG_REQUEST + AES_BLOCK_SIZE] = {0}; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN] = {0}; + CK_BYTE pub_exp[] = { 0x01, 0x00, 0x01 }; + CK_MECHANISM mech, mech1, mech2; + CK_MECHANISM_INFO mech_info; + CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, + priv_key = CK_INVALID_HANDLE, w_key = CK_INVALID_HANDLE, + uw_key = CK_INVALID_HANDLE; + CK_ULONG bits = 1024; + CK_ULONG wrapped_data_len = 0, user_pin_len = 0, key_size = 0; + CK_RV rc = CKR_OK; + CK_FLAGS flags = 0; + CK_SESSION_HANDLE session = CK_INVALID_HANDLE; + CK_OBJECT_CLASS keyclass = CKO_PRIVATE_KEY; + CK_KEY_TYPE keytype = CKK_RSA; + CK_SLOT_ID slot_id = SLOT_ID; + + memset(&mech, 0, sizeof(mech)); + memset(&mech1, 0, sizeof(mech1)); + memset(&mech2, 0, sizeof(mech2)); + memset(&mech_info, 0, sizeof(mech_info)); + + CK_ATTRIBUTE pub_tmpl[] = { + {CKA_MODULUS_BITS, &bits, sizeof(bits)} + , + {CKA_PUBLIC_EXPONENT, &pub_exp, sizeof(pub_exp)} + }; + CK_ATTRIBUTE uw_tmpl[] = { + {CKA_CLASS, &keyclass, sizeof(keyclass)} + , + {CKA_KEY_TYPE, &keytype, sizeof(keytype)} + }; + CK_ATTRIBUTE key_gen_tmpl[] = { + {CKA_VALUE_LEN, &key_size, sizeof(CK_ULONG)} + }; + + testsuite_begin("%s wrap/unwrap of RSA key.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip test if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(3, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + for (i = 0; i < 3; i++) { + + testcase_begin("%s wrap/unwrap of RSA key for key length=%ld.", + tsuite->name, key_lens[i]); + + key_size = key_lens[i]; + + /** first mechanism generate AES wrapping key **/ + mech.mechanism = CKM_AES_KEY_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + /** mechanism to generate an RSA key pair to be wrapped **/ + mech2.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; + mech2.ulParameterLen = 0; + mech2.pParameter = NULL; + + /** generate an RSA key pair. **/ + rc = funcs->C_GenerateKeyPair(session, &mech2, pub_tmpl, 2, NULL, + 0, &publ_key, &priv_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKeyPair rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** generate the wrapping key **/ + rc = funcs->C_GenerateKey(session, &mech, key_gen_tmpl, 1, &w_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** set the mech for AES crypto **/ + mech = tsuite->mech; + + /** wrap the key **/ + wrapped_data_len = sizeof(wrapped_data); + + /** get mech info **/ + rc = funcs->C_GetMechanismInfo(slot_id, mech.mechanism, &mech_info); + if (rc != CKR_OK) { + testcase_error("C_GetMechanismInfo rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** key is wrappable **/ + if (mech_info.flags & CKF_UNWRAP) { + + /** mechanism for wrapping the key **/ + mech1.mechanism = CKM_AES_CBC_PAD; + mech1.ulParameterLen = AES_IV_SIZE; + mech1.pParameter = &aes_iv; + + /** wrap key **/ + rc = funcs->C_WrapKey(session, &mech1, w_key, priv_key, + wrapped_data, &wrapped_data_len); + if (rc != CKR_OK) { + testcase_error("C_WrapKey rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + testcase_new_assertion(); + + /** unwrap key **/ + rc = funcs->C_UnwrapKey(session, &mech, w_key, wrapped_data, + wrapped_data_len, uw_tmpl, 2, &uw_key); + /* Expect dedicated error code here, since it's not allowed + * to unwrap non secret keys with AES_ECB/AES_CBC */ + if (rc != CKR_ARGUMENTS_BAD) { + testcase_error("Expected C_UnWrapKey rc=%s, but returned rc=%s", + p11_get_ckr(CKR_ARGUMENTS_BAD), p11_get_ckr(rc)); + goto testcase_cleanup; + } + testcase_pass("%s passed unwrap RSA key test.", tsuite->name); + } else { + /** key is not wrappable **/ + testcase_new_assertion(); + + /** try to wrap key **/ + rc = funcs->C_WrapKey(session, &mech, w_key, priv_key, + wrapped_data, &wrapped_data_len); + if (rc != CKR_MECHANISM_INVALID && rc != CKR_KEY_NOT_WRAPPABLE) { + testcase_fail("Expected CKR_MECHANISM_INVALID or " + "CKR_KEY_NOT_WRAPPABLE, but got %s", + p11_get_ckr(rc)); + } else { + testcase_pass("%s passed unwrap RSA key test.", tsuite->name); + } + } + } + +testcase_cleanup: + testcase_close_session(); + + return rc; +} + +CK_RV do_SignVerifyCMAC(struct published_cmac_test_suite_info *tsuite) +{ + unsigned int i; + int k; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_OBJECT_HANDLE h_key; + 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_MAC_GENERAL_PARAMS mac_param; + CK_ULONG ofs; + CK_BYTE actual[MAX_KEY_SIZE]; + CK_ULONG actual_len; + + testsuite_begin("%s Sign/Verify CMAC.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip tests if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(3, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + + for (i = 0; i < tsuite->tvcount; i++) { + testcase_begin("%s Sign/Verify CMAC with published test vector %d.", + tsuite->name, i); + + /** create key handle **/ + rc = create_AESKey(session, + tsuite->tv[i].key, tsuite->tv[i].klen, &h_key); + + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** get mech **/ + mech = tsuite->mech; + if (mech.mechanism == CKM_AES_CMAC_GENERAL) { + mac_param = tsuite->tv[i].tlen; + mech.pParameter = &mac_param; + mech.ulParameterLen = sizeof(mac_param); + } + + /** initialize signing **/ + rc = funcs->C_SignInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + actual_len = sizeof(actual); + memset(actual, 0, sizeof(actual)); + + if (tsuite->tv[i].num_chunks_message > 0) { + ofs = 0; + for (k = 0; k < tsuite->tv[i].num_chunks_message; k++) { + rc = funcs->C_SignUpdate(session, tsuite->tv[i].msg + ofs, + tsuite->tv[i].chunks_msg[k]); + if (rc != CKR_OK) { + testcase_error("C_SignUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + ofs += tsuite->tv[i].chunks_msg[k]; + } + + rc = funcs->C_SignFinal(session, actual, &actual_len); + if (rc != CKR_OK) { + testcase_error("C_SignFinal rc=%s", p11_get_ckr(rc)); + goto error; + } + } else { + rc = funcs->C_Sign(session, tsuite->tv[i].msg,tsuite->tv[i].mlen, + actual, &actual_len); + if (rc != CKR_OK) { + testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); + goto error; + } + } + + /** initilaize verification **/ + rc = funcs->C_VerifyInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do verification **/ + if (tsuite->tv[i].num_chunks_message > 0) { + ofs = 0; + for (k = 0; k < tsuite->tv[i].num_chunks_message; k++) { + rc = funcs->C_VerifyUpdate(session, tsuite->tv[i].msg + ofs, + tsuite->tv[i].chunks_msg[k]); + if (rc != CKR_OK) { + testcase_error("C_VerifyUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + ofs += tsuite->tv[i].chunks_msg[k]; + } + + rc = funcs->C_VerifyFinal(session, actual, actual_len); + if (rc != CKR_OK) { + testcase_error("C_VerifyFinal rc=%s", p11_get_ckr(rc)); + goto error; + } + } else { + rc = funcs->C_Verify(session, tsuite->tv[i].msg,tsuite->tv[i].mlen, + actual, actual_len); + if (rc != CKR_OK) { + testcase_error("C_Verify rc=%s", p11_get_ckr(rc)); + goto error; + } + } + + /** compare sign/verify results with expected results **/ + testcase_new_assertion(); + + if (mech.mechanism == CKM_AES_CMAC_GENERAL && + actual_len != tsuite->tv[i].tlen) { + testcase_fail("signature length does not match test vector's " + "signature length\nexpected length=%d, found " + "length=%ld", tsuite->tv[i].tlen, actual_len); + } else if (mech.mechanism != CKM_AES_CMAC_GENERAL && + actual_len != AES_BLOCK_SIZE) { + testcase_fail("signature length does not match test vector's " + "signature length\nexpected length=%d, found " + "length=%ld", AES_BLOCK_SIZE, actual_len); + } else if (memcmp(actual, tsuite->tv[i].mac, tsuite->tv[i].tlen)) { + testcase_fail("signature does not match test vector's signature"); + } else { + testcase_pass("%s Sign/Verify CMAC with test vector %d " + "passed.", tsuite->name, i); + } + + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + goto testcase_cleanup; + +error: + 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 aes_funcs() +{ + unsigned int i; + CK_RV rv = CKR_OK; + + for (i = 0; i < NUM_OF_PUBLISHED_TESTSUITES; i++) { + rv = do_EncryptAES(&published_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + + rv = do_DecryptAES(&published_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + + rv = do_EncryptUpdateAES(&published_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + + rv = do_DecryptUpdateAES(&published_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + + } + + for (i = 0; i < NUM_OF_GENERATED_TESTSUITES; i++) { + rv = do_EncryptDecryptAES(&generated_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + + rv = do_EncryptDecryptUpdateAES(&generated_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + + rv = do_WrapUnwrapAES(&generated_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + + rv = do_WrapUnwrapRSA(&generated_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + } + + /***** Error scenarios *****/ + for (i = 0; i < NUM_OF_GENERATED_ERR_TESTSUITES; i++) { + rv = do_WrapRSA_Err(&generated_err_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + + rv = do_UnwrapRSA_Err(&generated_err_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + } + + /* CMAC test cases */ + for (i = 0; i < NUM_OF_PUBLISHED_CMAC_TESTSUITES; i++) { + rv = do_SignVerifyCMAC(&published_cmac_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + } + + return rv; +} + +int main(int argc, char **argv) +{ + int rc; + CK_C_INITIALIZE_ARGS cinit_args; + CK_RV rv = 0; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: nostop: %d\n", no_stop); + + rc = do_GetFunctionList(); + if (!rc) { + testcase_error("do_getFunctionList(), rc=%s", p11_get_ckr(rc)); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + // SAB Add calls to ALL functions before the C_Initialize gets hit + + funcs->C_Initialize(&cinit_args); + + { + CK_SESSION_HANDLE hsess = 0; + + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + } + + testcase_setup(0); //TODO + rv = aes_funcs(); + testcase_print_result(); + + funcs->C_Finalize(NULL); + + /* make sure we return non-zero if rv is non-zero */ + return ((rv == 0) || (rv % 256) ? (int)rv : -1); +} diff --git a/testcases/crypto/crypto.mk b/testcases/crypto/crypto.mk new file mode 100644 index 0000000..230cd17 --- /dev/null +++ b/testcases/crypto/crypto.mk @@ -0,0 +1,56 @@ +noinst_PROGRAMS += \ + testcases/crypto/aes_tests testcases/crypto/des_tests \ + testcases/crypto/des3_tests testcases/crypto/digest_tests \ + testcases/crypto/dsa_tests testcases/crypto/rsa_tests \ + testcases/crypto/dh_tests testcases/crypto/ssl3_tests \ + testcases/crypto/ec_tests testcases/crypto/rsaupdate_tests \ + testcases/crypto/dilithium_tests +noinst_HEADERS += \ + testcases/crypto/aes.h testcases/crypto/des.h \ + testcases/crypto/des3.h testcases/crypto/digest.h \ + testcases/crypto/ec.h testcases/crypto/rsa.h + +testcases_crypto_aes_tests_CFLAGS = ${testcases_inc} +testcases_crypto_aes_tests_LDADD = testcases/common/libcommon.la +testcases_crypto_aes_tests_SOURCES = \ + usr/lib/common/p11util.c testcases/crypto/aes_func.c + +testcases_crypto_des3_tests_CFLAGS = ${testcases_inc} +testcases_crypto_des3_tests_LDADD = testcases/common/libcommon.la +testcases_crypto_des3_tests_SOURCES = testcases/crypto/des3_func.c + +testcases_crypto_des_tests_CFLAGS = ${testcases_inc} +testcases_crypto_des_tests_LDADD = testcases/common/libcommon.la +testcases_crypto_des_tests_SOURCES = testcases/crypto/des_func.c + +testcases_crypto_dh_tests_CFLAGS = ${testcases_inc} +testcases_crypto_dh_tests_LDADD = testcases/common/libcommon.la +testcases_crypto_dh_tests_SOURCES = testcases/crypto/dh_func.c + +testcases_crypto_digest_tests_CFLAGS = ${testcases_inc} +testcases_crypto_digest_tests_LDADD = testcases/common/libcommon.la +testcases_crypto_digest_tests_SOURCES = testcases/crypto/digest_func.c + +testcases_crypto_dsa_tests_CFLAGS = ${testcases_inc} +testcases_crypto_dsa_tests_LDADD = testcases/common/libcommon.la +testcases_crypto_dsa_tests_SOURCES = testcases/crypto/dsa_func.c + +testcases_crypto_rsa_tests_CFLAGS = ${testcases_inc} +testcases_crypto_rsa_tests_LDADD = testcases/common/libcommon.la +testcases_crypto_rsa_tests_SOURCES = testcases/crypto/rsa_func.c + +testcases_crypto_ssl3_tests_CFLAGS = ${testcases_inc} +testcases_crypto_ssl3_tests_LDADD = testcases/common/libcommon.la +testcases_crypto_ssl3_tests_SOURCES = testcases/crypto/ssl3_func.c + +testcases_crypto_ec_tests_CFLAGS = ${testcases_inc} +testcases_crypto_ec_tests_LDADD = testcases/common/libcommon.la +testcases_crypto_ec_tests_SOURCES = testcases/crypto/ec_func.c + +testcases_crypto_dilithium_tests_CFLAGS = ${testcases_inc} +testcases_crypto_dilithium_tests_LDADD = testcases/common/libcommon.la +testcases_crypto_dilithium_tests_SOURCES = testcases/crypto/dilithium_func.c + +testcases_crypto_rsaupdate_tests_CFLAGS = ${testcases_inc} +testcases_crypto_rsaupdate_tests_LDADD = testcases/common/libcommon.la +testcases_crypto_rsaupdate_tests_SOURCES = testcases/crypto/rsaupdate_func.c diff --git a/testcases/crypto/des.h b/testcases/crypto/des.h new file mode 100644 index 0000000..164ad91 --- /dev/null +++ b/testcases/crypto/des.h @@ -0,0 +1,160 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2011-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 + */ + +#include "pkcs11types.h" + +#define DES_KEY_SIZE 8 +#define DES_IV_SIZE 8 +#define MAX_TEXT_SIZE 8 +#define DES_BLOCK_SIZE 8 +#define MAX_CHUNKS 8 + +unsigned char des_cbc_iv[] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef}; + +struct CK_MECHANISM des_keygen = { + .mechanism = CKM_DES_KEY_GEN, + .ulParameterLen = 0, + .pParameter = NULL, +}; + +struct des_test_vector { + unsigned char key[DES_KEY_SIZE]; + unsigned char klen; + unsigned char iv[DES_IV_SIZE]; + unsigned char ivlen; + unsigned char plaintext[MAX_TEXT_SIZE]; + unsigned char plen; + unsigned char ciphertext[MAX_TEXT_SIZE]; + unsigned char clen; + int chunks[MAX_CHUNKS]; + int num_chunks; +}; + +struct published_test_suite_info { + const char *name; + unsigned int tvcount; + struct des_test_vector *tv; + unsigned long mechanism; +}; + +struct generated_test_suite_info { + const char *name; + CK_MECHANISM mech; +}; + +/** FIPS PUB 81 - DES MODES OF OPERATION + http://www.itl.nist.gov/fipspubs/fip81.htm + Table B1 - AN EXAMPLE OF THE ELECTRONIC CODEBOOK (ECB) MODE +**/ +static struct des_test_vector des_ecb_tv[] = { + { // 1 + .key = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, + .klen = 8, + .iv = {0}, + .ivlen = 0, + .plaintext = {0x4e, 0x6f, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74}, + .plen = 8, + .ciphertext = {0x3f, 0xa4, 0x0e, 0x8a, 0x98, 0x4d, 0x48, 0x15}, + .clen = 8 + }, { // 2 + .key = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, + .klen = 8, + .iv = {0}, + .ivlen = 0, + .plaintext = {0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20}, + .plen = 8, + .ciphertext = {0x6a, 0x27, 0x17, 0x87, 0xab, 0x88, 0x83, 0xf9}, + .clen = 8, + .num_chunks = 3, + .chunks = {3, 0, 5}, + }, { // 3 + .key = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, + .klen = 8, + .iv = {0}, + .ivlen = 0, + .plaintext = {0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20}, + .plen = 8, + .ciphertext = {0x89, 0x3d, 0x51, 0xec, 0x4b, 0x56, 0x3b, 0x53}, + .clen = 8, + .num_chunks = 3, + .chunks = {4, -1, 4}, + }, +}; + +/** NIST Special Publication 800-17 + http://csrc.nist.gov/publications/nistpubs/800-17/800-17.pdf + Appendix B - Variable Key Known Answer Test +**/ +static struct des_test_vector des_cbc_tv[] = { + { // round 0 + .key = {0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, + .klen = 8, + .iv = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + .ivlen = 8, + .plaintext = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + .plen = 8, + .ciphertext = {0x95, 0xA8, 0xD7, 0x28, 0x13, 0xDA, 0xA9, 0x4D}, + .clen = 8, + }, { // round 1 + .key = {0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, + .klen = 8, + .iv = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + .ivlen = 8, + .plaintext = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + .plen = 8, + .ciphertext = {0x0E, 0xEC, 0x14, 0x87, 0xDD, 0x8C, 0x26, 0xD5}, + .clen = 8, + .num_chunks = 3, + .chunks = {3, 0, 5}, + }, { // round 2 + .key = {0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, + .klen = 8, + .iv = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + .ivlen = 8, + .plaintext = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + .plen = 8, + .ciphertext = {0x7A, 0xD1, 0x6F, 0xFB, 0x79, 0xC4, 0x59, 0x26}, + .clen = 8, + .num_chunks = 3, + .chunks = {4, -1, 4}, + }, +}; + + +#define NUM_OF_PUBLISHED_TESTSUITES 2 + +struct published_test_suite_info published_test_suites[] = { + { + .name = "DES_ECB", + .tvcount = 3, + .tv = des_ecb_tv, + .mechanism = CKM_DES_ECB, + }, { + .name = "DES_CBC", + .tvcount = 3, + .tv = des_cbc_tv, + .mechanism = CKM_DES_CBC, + } +}; + +#define NUM_OF_GENERATED_TESTSUITES 3 + +static struct generated_test_suite_info generated_test_suites[] = { + { + .name = "DES_ECB", + .mech = {CKM_DES_ECB, 0, 0}, + }, { + .name = "DES_CBC", + .mech = {CKM_DES_CBC, &des_cbc_iv, DES_IV_SIZE}, + }, { + .name = "DES_CBC_PAD", + .mech = {CKM_DES_CBC_PAD, &des_cbc_iv, DES_IV_SIZE}, + } +}; diff --git a/testcases/crypto/des3.h b/testcases/crypto/des3.h new file mode 100644 index 0000000..b5213cb --- /dev/null +++ b/testcases/crypto/des3.h @@ -0,0 +1,1413 @@ +/* + * 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 + */ + +#ifndef _DES3_H_ +#define _DES3_H_ +#endif + +#include "pkcs11types.h" + +#define MAX_KEY_SIZE 64 +#define MAX_TEXT_SIZE 128 +#define MAX_IV_SIZE 64 +#define DES3_BLOCK_SIZE 8 +#define DES3_KEY_SIZE 24 +#define DES3_IV_SIZE 8 +#define MAX_CHUNKS 8 + +struct des3_test_vector { + unsigned char key[MAX_KEY_SIZE]; + unsigned char klen; + unsigned char iv[MAX_IV_SIZE]; + unsigned char ivlen; + unsigned char plaintext[MAX_TEXT_SIZE]; + unsigned char plen; + unsigned char ciphertext[MAX_TEXT_SIZE]; + unsigned char clen; + int chunks[MAX_CHUNKS]; + int num_chunks; +}; + +struct published_test_suite_info { + const char *name; + unsigned int tvcount; + struct des3_test_vector *tv; + unsigned int size; + unsigned long mechanism; +}; + +struct generated_test_suite_info { + const char *name; + CK_MECHANISM mech; +}; + +struct CK_MECHANISM des3_keygen = { + .mechanism = CKM_DES3_KEY_GEN, + .ulParameterLen = 0, + .pParameter = NULL, +}; + +struct cmac_test_vector { + unsigned char key[MAX_KEY_SIZE]; + unsigned char klen; + unsigned char msg[MAX_TEXT_SIZE]; + unsigned char mlen; + unsigned char mac[MAX_KEY_SIZE]; + unsigned char tlen; + int chunks_msg[MAX_CHUNKS]; + int num_chunks_message; +}; + +struct published_cmac_test_suite_info { + const char *name; + unsigned int tvcount; + struct cmac_test_vector *tv; + CK_MECHANISM mech; + CK_KEY_TYPE key_type; +}; + +unsigned char des3_cbc_iv[] = {0x67, 0x9f, 0xdb, 0xee, 0x16, 0x6c, 0x2e, 0x0a}; + +/** http://csrc.nist.gov/groups/STM/cavp/documents/des/tdesmmt.zip + TECBMMT1.rsp +**/ +static struct des3_test_vector des3_ecb_tv[] = { + { // #0 + .key = {0xe9, 0x7c, 0x83, 0x13, 0xba, 0x26, 0x5d, 0x43, 0x25, + 0x4c, 0xbf, 0x9e, 0x8f, 0x7c, 0x2a, 0xa8, 0xa7, 0x54, + 0xd6, 0x5e, 0x8a, 0xe9, 0x97, 0xe3}, + .klen = 24, + .iv = {0}, + .ivlen = 0, + .plaintext = {0x46, 0x56, 0xed, 0x81, 0xa8, 0xbc, 0x58, 0xa9}, + .plen = 8, + .ciphertext = {0x42, 0x6a, 0x0a, 0xc2, 0x65, 0x86, 0xbf, 0x6c}, + .clen = 8, + }, { // #1 + .key = {0x86, 0x6d, 0x38, 0x94, 0xb3, 0x67, 0x0e, 0xfe, 0x37, + 0x54, 0xa2, 0xe5, 0x0e, 0x76, 0x7f, 0xcd, 0x34, 0x51, + 0xfb, 0x68, 0x89, 0xda, 0xfe, 0xb5}, + .klen = 24, + .iv = {0}, + .ivlen = 0, + .plaintext = {0x50, 0xea, 0xab, 0x2a, 0x14, 0x14, 0x07, 0xc4, 0x7d, + 0x71, 0x6b, 0x70, 0x36, 0x50, 0xf3, 0xa8}, + .plen = 16, + .ciphertext = {0xb7, 0x84, 0xaf, 0xf1, 0x1d, 0x71, 0x5d, 0x60, 0x18, + 0x5d, 0x11, 0x1a, 0x29, 0x10, 0xeb, 0xca}, + .clen = 16, + }, { // #2 + .key = {0x02, 0x20, 0x04, 0x83, 0xba, 0x6d, 0xf7, 0x67, 0x5d, + 0xea, 0x40, 0x73, 0xb0, 0x2a, 0x1c, 0x5b, 0x85, 0x02, + 0x54, 0x23, 0xe5, 0xc4, 0xa4, 0xb5}, + .klen = 24, + .iv = {0}, + .ivlen = 0, + .plaintext = {0x30, 0x0c, 0xe0, 0x17, 0x8d, 0x4d, 0x54, 0x56, 0x40, + 0x24, 0x3b, 0x9d, 0xb8, 0x18, 0x90, 0x4a, 0xe9, 0x17, + 0x19, 0x5d, 0xe7, 0xbb, 0x9a, 0xda}, + .plen = 24, + .ciphertext = {0x8f, 0x83, 0x4b, 0x37, 0xf7, 0x40, 0x4e, 0x5e, 0xdb, + 0x32, 0xd1, 0x0b, 0x17, 0x5c, 0x28, 0xac, 0x6d, 0x94, + 0x3b, 0x19, 0xc2, 0x59, 0x83, 0x49}, + .clen = 24, + .num_chunks = 3, + .chunks = {8, 8, 8}, + }, { // #3 + .key = {0x2c, 0x29, 0x20, 0x2c, 0x10, 0x79, 0x79, 0x85, 0xef, + 0xc2, 0x52, 0xb3, 0xda, 0x37, 0x8a, 0x89, 0xe9, 0xa7, + 0xf8, 0x8c, 0x98, 0xc7, 0x3b, 0x1c}, + .klen = 24, + .iv = {0}, + .ivlen = 0, + .plaintext = {0x40, 0x58, 0x77, 0x1b, 0x9c, 0x80, 0x8e, 0x69, 0x35, + 0x65, 0x0f, 0x97, 0xdb, 0x27, 0xe9, 0xe6, 0x96, 0x41, + 0xfc, 0xc5, 0xe7, 0xbc, 0x7f, 0xa5, 0x51, 0xa2, 0x9f, + 0x09, 0x18, 0xb6, 0x69, 0xdc}, + .plen = 32, + .ciphertext = {0x94, 0x38, 0xd7, 0xb8, 0xb2, 0x05, 0x7a, 0x62, 0x4a, + 0x40, 0x71, 0xde, 0x46, 0xc9, 0x86, 0xa3, 0x39, 0x3d, + 0xa8, 0x68, 0xa2, 0x96, 0x47, 0x04, 0x14, 0x18, 0xcb, + 0x94, 0x6a, 0x51, 0xd3, 0x68}, + .clen = 32, + .num_chunks = 2, + .chunks = {16, 16}, + }, { // #4 + .key = {0xc4, 0x02, 0x97, 0x20, 0x20, 0xec, 0x0e, 0x4a, 0x64, + 0x83, 0x3d, 0xfd, 0x5b, 0x1a, 0x43, 0xbf, 0x20, 0xf7, + 0x3b, 0xc7, 0x0b, 0xbf, 0x8f, 0x08}, + .klen = 24, + .iv = {0}, + .ivlen = 0, + .plaintext = {0x35, 0x1c, 0xc5, 0xe4, 0xa8, 0xa8, 0xb0, 0xb0, 0xdb, + 0x89, 0xde, 0xef, 0xfc, 0xc4, 0x91, 0xee, 0xfa, 0x1f, + 0xc4, 0xcb, 0x45, 0xd8, 0x0e, 0xcf, 0xd5, 0x96, 0xc8, + 0xfd, 0x6d, 0xa0, 0x72, 0xeb, 0x21, 0x4d, 0x53, 0xd1, + 0x16, 0xbc, 0x60, 0xe0}, + .plen = 40, + .ciphertext = {0xc8, 0x50, 0xf2, 0xb1, 0xe1, 0xd3, 0x76, 0xb3, 0xbd, + 0x08, 0x66, 0xd0, 0xfd, 0x23, 0x51, 0x5c, 0x4c, 0x95, + 0x60, 0xe9, 0x3d, 0x5e, 0x74, 0xe7, 0x4e, 0xb2, 0xd3, + 0xd9, 0x04, 0xc7, 0xf2, 0x90, 0xee, 0xc9, 0x53, 0x9d, + 0xf3, 0xd8, 0xc7, 0x8a}, + .clen = 40, + .num_chunks = 3, + .chunks = {20, -1, 20}, + }, { // #5 + .key = {0x68, 0x26, 0xf8, 0x91, 0x07, 0x9d, 0xda, 0x4c, 0x0e, + 0x57, 0xd0, 0x58, 0x13, 0x62, 0x9d, 0x61, 0x97, 0x89, + 0xbc, 0x68, 0x4a, 0xe9, 0x6d, 0x32}, + .klen = 24, + .iv = {0}, + .ivlen = 0, + .plaintext = {0xf5, 0xee, 0x26, 0x02, 0x16, 0x50, 0xef, 0x21, 0x8f, + 0xa4, 0xf4, 0x4a, 0xa5, 0xeb, 0xc5, 0x22, 0x7d, 0x86, + 0xd3, 0xa5, 0x30, 0xf5, 0x24, 0x0d, 0x21, 0xe5, 0x4b, + 0xf6, 0x8f, 0x6a, 0x98, 0xbf, 0x66, 0x89, 0x8c, 0x33, + 0x5b, 0xf9, 0x8f, 0x69, 0x37, 0x2a, 0xe5, 0xe8, 0x73, + 0x87, 0xdf, 0x0f}, + .plen = 48, + .ciphertext = {0xa8, 0x19, 0xe2, 0xbc, 0x81, 0x0d, 0xd1, 0xc6, 0xed, + 0x4e, 0x7e, 0x07, 0x6c, 0x5a, 0x05, 0xc3, 0xce, 0xb6, + 0xdb, 0x5e, 0x21, 0x74, 0xc2, 0x86, 0x3d, 0x05, 0x24, + 0x93, 0xca, 0x24, 0x80, 0x3d, 0xce, 0x58, 0x8b, 0x4b, + 0x92, 0x8b, 0x36, 0x4d, 0xe7, 0x58, 0x8e, 0xb6, 0x62, + 0xb5, 0x8c, 0xa6}, + .clen = 48, + .num_chunks = 4, + .chunks = {28, 13, 0, 7}, + }, { // #6 + .key = {0x94, 0xec, 0x51, 0xd0, 0x80, 0x4a, 0x15, 0x31, 0x68, + 0x5e, 0x1c, 0x6b, 0x9b, 0xab, 0xc7, 0x08, 0x02, 0x89, + 0x40, 0x6e, 0x51, 0x19, 0x61, 0xda}, + .klen = 24, + .iv = {0}, + .ivlen = 0, + .plaintext = {0x4e, 0xc4, 0x2e, 0xbd, 0x1e, 0x7d, 0xc5, 0xf2, 0xcf, + 0xba, 0x60, 0x67, 0xda, 0x9f, 0xe7, 0x77, 0xfb, 0x84, + 0x9d, 0x67, 0x37, 0xed, 0x48, 0xf6, 0x1e, 0xbc, 0x91, + 0x35, 0x4e, 0xa5, 0xad, 0x99, 0x38, 0xe3, 0x3d, 0x4f, + 0x27, 0x29, 0x73, 0xcf, 0x7e, 0xdc, 0x77, 0xb4, 0x40, + 0x7f, 0x09, 0xcb, 0xd6, 0x6f, 0x67, 0x6a, 0x0d, 0xd0, + 0x71, 0x03}, + .plen = 56, + .ciphertext = {0xdd, 0x61, 0x15, 0x22, 0x7a, 0x40, 0x90, 0x7c, 0x83, + 0x5a, 0x98, 0xeb, 0x22, 0x78, 0x6d, 0xd6, 0x77, 0x19, + 0x09, 0xd0, 0x9c, 0x4d, 0x9e, 0x3a, 0xe6, 0x99, 0xcd, + 0xbd, 0x11, 0x0a, 0x82, 0xe1, 0xca, 0xc4, 0xd3, 0x2f, + 0xc3, 0x5a, 0x5b, 0x3d, 0xb5, 0xba, 0x1a, 0xc1, 0x88, + 0xcc, 0x63, 0x39, 0xc6, 0x63, 0x34, 0xde, 0xde, 0xca, + 0x7e, 0x4e}, + .clen = 56, + }, { // #7 + .key = {0x04, 0xe3, 0xf4, 0x67, 0x02, 0x91, 0x32, 0x13, 0xb0, + 0x07, 0x76, 0xbf, 0x52, 0xc7, 0x8a, 0xcb, 0xfd, 0xab, + 0xa1, 0xf8, 0xb6, 0xd6, 0x58, 0x57}, + .klen = 24, + .iv = {0}, + .ivlen = 0, + .plaintext = {0x9e, 0xc9, 0xa6, 0x9f, 0xf3, 0x69, 0x22, 0x5b, 0x75, + 0x03, 0x38, 0xaa, 0x11, 0xdb, 0xee, 0x12, 0x7f, 0xda, + 0x57, 0xe4, 0x24, 0xe1, 0xa1, 0x26, 0x36, 0x5d, 0x56, + 0xd1, 0x21, 0x1c, 0xdb, 0x3d, 0x29, 0x5f, 0x3d, 0xd9, + 0x51, 0x30, 0x2c, 0x1f, 0x7c, 0xf5, 0x48, 0xc7, 0xd3, + 0x46, 0x9c, 0x3b, 0x66, 0xfc, 0x68, 0x4c, 0x16, 0x8a, + 0x24, 0x23, 0xb2, 0x91, 0xc1, 0x7a, 0x60, 0xae, 0x32, + 0x0c}, + .plen = 64, + .ciphertext = {0x85, 0x88, 0xa7, 0x92, 0x64, 0x0c, 0x21, 0x5b, 0xcb, + 0x3b, 0x93, 0x89, 0x7e, 0xd8, 0xc5, 0x49, 0x63, 0x36, + 0xca, 0xc5, 0xa4, 0xbd, 0x39, 0x3e, 0x9d, 0x35, 0x67, + 0xf8, 0x70, 0x45, 0xb3, 0xa1, 0x4c, 0x4b, 0xfd, 0x3e, + 0x2c, 0x3b, 0x5e, 0x6e, 0xe1, 0x5c, 0xfb, 0xba, 0xd3, + 0x92, 0xef, 0x92, 0x95, 0x31, 0x21, 0x8f, 0x4e, 0x9a, + 0x85, 0x81, 0xf0, 0xb5, 0xc0, 0x92, 0xfd, 0x64, 0x3c, + 0xe2}, + .clen = 64, + }, { // #8 + .key = {0xb6, 0xb0, 0xda, 0xc8, 0xa8, 0x38, 0x61, 0x10, 0x32, + 0x75, 0xd0, 0x4f, 0x46, 0x7a, 0x40, 0xb3, 0x92, 0x4c, + 0x3d, 0xc4, 0x0d, 0xbf, 0x7c, 0x79}, + .klen = 24, + .iv = {0}, + .ivlen = 0, + .plaintext = {0x8f, 0x6e, 0x5d, 0x5d, 0xa6, 0xdc, 0x3a, 0x8e, 0xf8, + 0x7b, 0xe3, 0x47, 0xf5, 0x46, 0x72, 0x05, 0xbb, 0x3c, + 0x00, 0x4e, 0x42, 0xbe, 0x76, 0x3a, 0xd6, 0x38, 0xa0, + 0x32, 0xcb, 0x03, 0x83, 0xf8, 0x6c, 0x8a, 0xf1, 0xe7, + 0x34, 0xac, 0x5a, 0x7d, 0x41, 0x62, 0xe5, 0x16, 0x05, + 0xa2, 0xbf, 0xfa, 0x3f, 0x83, 0xb3, 0x9a, 0x29, 0xa1, + 0xfc, 0x17, 0xf3, 0xc3, 0x57, 0x04, 0x71, 0xbb, 0x5c, + 0x6d, 0x11, 0x8e, 0x0d, 0x18, 0x0f, 0xd5, 0xb0, 0x0a}, + .plen = 72, + .ciphertext = {0x7b, 0xe0, 0x1e, 0x90, 0x9b, 0x9d, 0x8d, 0x33, 0xd4, + 0xba, 0x8d, 0x24, 0xee, 0x9a, 0xc2, 0x78, 0x89, 0x8d, + 0xca, 0xb3, 0xaf, 0xaf, 0x4c, 0xde, 0xf7, 0x3c, 0x53, + 0x9c, 0x99, 0x6b, 0x97, 0xa9, 0x68, 0x77, 0x9d, 0x27, + 0x30, 0xac, 0x7d, 0x0c, 0xbf, 0x68, 0x20, 0xee, 0x3d, + 0xc2, 0x6c, 0xa7, 0x15, 0x8c, 0xeb, 0x37, 0xa0, 0xb4, + 0x95, 0x65, 0x16, 0xe0, 0xd9, 0x61, 0x8c, 0xce, 0xff, + 0xa5, 0xfe, 0x83, 0x6c, 0xd5, 0x53, 0xa1, 0x77, 0x8c}, + .clen = 72, + }, { // #9 + .key = {0xa8, 0xd9, 0xfb, 0xec, 0xb9, 0x64, 0x67, 0xbc, 0xbf, + 0xdf, 0x57, 0xa1, 0x1c, 0x49, 0xc7, 0x7f, 0x0d, 0x3e, + 0xce, 0x23, 0xcd, 0xd0, 0xf1, 0x79}, + .klen = 24, + .iv = {0}, + .ivlen = 0, + .plaintext = {0x89, 0xd6, 0x67, 0xba, 0x5e, 0x88, 0xf5, 0x63, 0xad, + 0x02, 0x9a, 0x7f, 0x78, 0x87, 0x97, 0x1d, 0x20, 0x44, + 0x7b, 0x5c, 0xdb, 0xec, 0x3d, 0x2e, 0x62, 0xa0, 0x88, + 0x5c, 0xea, 0x11, 0x56, 0xca, 0x56, 0xe8, 0xc0, 0xfd, + 0xab, 0x66, 0x14, 0xda, 0xc4, 0x47, 0x29, 0xb0, 0x47, + 0xed, 0xef, 0x79, 0xd7, 0xba, 0x4a, 0x5d, 0x8b, 0xbe, + 0x21, 0x78, 0x9f, 0x92, 0xb2, 0xdd, 0x6a, 0x83, 0x28, + 0xdb, 0x90, 0xf3, 0x6f, 0x7f, 0x79, 0xfd, 0x47, 0x59, + 0x02, 0x58, 0x97, 0x83, 0x72, 0x7e, 0x04, 0xe0}, + .plen = 80, + .ciphertext = {0xc3, 0x69, 0x6e, 0x20, 0xf3, 0x35, 0xb3, 0xf7, 0x62, + 0x9b, 0xe3, 0x38, 0xd8, 0x70, 0xd2, 0x79, 0x5b, 0x30, + 0x75, 0xe9, 0xb8, 0x85, 0x2c, 0x3a, 0xae, 0xa0, 0x76, + 0x97, 0x7f, 0x62, 0xa9, 0xaf, 0xfd, 0x8e, 0x75, 0x68, + 0x83, 0x1f, 0x1b, 0x99, 0x40, 0x4e, 0x9a, 0xd4, 0xd5, + 0x26, 0x84, 0x21, 0x7e, 0xe2, 0x7d, 0xb9, 0x85, 0x10, + 0xc0, 0x99, 0x4f, 0x53, 0xa2, 0x63, 0xd1, 0x0e, 0xba, + 0x9b, 0xa2, 0x96, 0xd0, 0x90, 0x9a, 0x51, 0x75, 0xa9, + 0xa7, 0x63, 0x74, 0x41, 0xfd, 0x42, 0x00, 0xcc}, + .clen = 80, + } +}; + +/** http://csrc.nist.gov/groups/STM/cavp/documents/des/tdesmmt.zip + TCBCMMT3.rsp +**/ +static struct des3_test_vector des3_cbc_tv[] = { + { // #0 + .key = {0x46, 0x13, 0x3d, 0xcb, 0xf2, 0x32, 0xb5, 0x19, 0x64, + 0xe0, 0xd9, 0x5e, 0x83, 0x20, 0x8f, 0x15, 0x67, 0x32, + 0xbf, 0x75, 0xb6, 0x73, 0xab, 0xf1}, + .klen = 24, + .iv = {0x34, 0x81, 0x4c, 0x87, 0xf4, 0x7f, 0xd5, 0x9d}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0xde, 0x65, 0x5a, 0x0e, 0xa7, 0x71, 0x43, 0x6c}, + .plen = 8, + .ciphertext = {0x09, 0x23, 0x68, 0x40, 0x52, 0x96, 0x74, 0x4a}, + .clen = 8, + }, { // #1 + .key = {0x6d, 0x0d, 0x67, 0xda, 0x68, 0xab, 0x16, 0x6d, 0x1f, + 0x43, 0xc7, 0x20, 0x4c, 0x4c, 0x2a, 0xa4, 0xc8, 0x1a, + 0x52, 0x85, 0x15, 0xf1, 0xdf, 0xf2}, + .klen = 24, + .iv = {0x68, 0xe6, 0x3a, 0x07, 0xb2, 0x2e, 0x33, 0xeb}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x43, 0x46, 0xc4, 0xe8, 0x13, 0x80, 0x62, 0x6f, 0xa0, + 0xb2, 0x77, 0x6d, 0x30, 0xa4, 0xfc, 0x05}, + .plen = 16, + .ciphertext = {0x52, 0x74, 0xbe, 0x18, 0x3f, 0x5d, 0xfb, 0x6b, 0x01, + 0x8f, 0x22, 0xb3, 0x22, 0xf0, 0x39, 0x2d}, + .clen = 16, + }, { // #2 + .key = {0x13, 0x4c, 0xb3, 0xef, 0xe6, 0x2a, 0x4a, 0xd5, 0x52, + 0xcb, 0x85, 0xa1, 0x64, 0xfe, 0xe6, 0xb9, 0x64, 0xa1, + 0x26, 0x9b, 0x19, 0x3d, 0x68, 0xc4}, + .klen = 24, + .iv = {0x0f, 0xa3, 0x11, 0xf9, 0x9e, 0xc5, 0x7b, 0x86}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x1b, 0x73, 0x5b, 0x05, 0x57, 0x25, 0x5a, 0x0e, 0x6d, + 0x8d, 0x67, 0x58, 0x79, 0xe7, 0x20, 0x1c, 0xa3, 0x4c, + 0x87, 0x61, 0xa1, 0x29, 0xa9, 0x14}, + .plen = 24, + .ciphertext = {0x2f, 0x1a, 0xc7, 0xee, 0x14, 0x14, 0xaf, 0x15, 0x58, + 0x7c, 0xb2, 0xc5, 0x40, 0x40, 0x12, 0x94, 0x02, 0x8e, + 0x1e, 0x39, 0xd1, 0xcf, 0x2f, 0x67}, + .clen = 24, + .num_chunks = 3, + .chunks = {8, 8, 8}, + }, { // #3 + .key = {0x20, 0x23, 0x98, 0xb6, 0x15, 0x49, 0x68, 0xc1, 0x68, + 0x20, 0x13, 0x29, 0x91, 0x0e, 0x61, 0x2f, 0x29, 0x61, + 0x89, 0xd3, 0x20, 0x67, 0x01, 0x20}, + .klen = 24, + .iv = {0x51, 0x42, 0x73, 0xc9, 0x38, 0x06, 0xfd, 0xe6}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x9a, 0x5e, 0xc9, 0x13, 0x87, 0x62, 0x99, 0x49, 0x2d, + 0xda, 0x39, 0x98, 0xf8, 0x8e, 0x1c, 0x31, 0xa7, 0x54, + 0x93, 0xb3, 0xad, 0xe1, 0x4e, 0x9e, 0xd7, 0xde, 0x1f, + 0x0a, 0x30, 0x3f, 0x02, 0x99}, + .plen = 32, + .ciphertext = {0x9b, 0xc0, 0x22, 0x47, 0xff, 0x5c, 0xef, 0xde, 0x9a, + 0x03, 0x07, 0xf9, 0x48, 0xf9, 0x43, 0x7e, 0xf2, 0xa2, + 0x98, 0xcd, 0xd6, 0x95, 0x42, 0x23, 0x6c, 0xba, 0x47, + 0xe8, 0xc9, 0x54, 0xe8, 0x19}, + .clen = 32, + .num_chunks = 2, + .chunks = {16, 16}, + }, { // #4 + .key = {0x19, 0x94, 0x76, 0xc2, 0x43, 0x02, 0xb6, 0xab, 0x0b, + 0x98, 0xd5, 0xa8, 0x07, 0x07, 0x9e, 0x43, 0x37, 0xe6, + 0x8f, 0x5e, 0xc7, 0x75, 0x61, 0xab}, + .klen = 24, + .iv = {0x6e, 0x06, 0x87, 0x59, 0x55, 0xb8, 0x7f, 0x87}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x42, 0x0f, 0xdf, 0xfb, 0x70, 0x67, 0x70, 0xba, 0x1a, + 0xee, 0x85, 0xbb, 0x99, 0x2e, 0xd2, 0xef, 0xe7, 0xc4, + 0xcb, 0x10, 0xa7, 0x5c, 0xc0, 0x35, 0x65, 0xdd, 0x4d, + 0xa4, 0x1e, 0xe1, 0xf1, 0xe7, 0x03, 0x68, 0xfd, 0x22, + 0x7a, 0xcd, 0xb0, 0xa3}, + .plen = 40, + .ciphertext = {0xf3, 0x90, 0xd5, 0xaf, 0xc5, 0x96, 0x9d, 0x63, 0xd9, + 0xc0, 0xa9, 0x5e, 0x1f, 0x1c, 0x29, 0x0d, 0x0b, 0xd2, + 0x95, 0x10, 0xe8, 0xe9, 0x82, 0x50, 0x2f, 0xaa, 0x7e, + 0xd6, 0x16, 0xcf, 0xe8, 0x73, 0xaf, 0x88, 0xb2, 0x7a, + 0x7b, 0x62, 0xcb, 0x21}, + .clen = 40, + .num_chunks = 0, + .chunks = {20, -1, 20}, + }, { // #5 + .key = {0x32, 0x3b, 0xf2, 0x4f, 0xe0, 0xad, 0x70, 0x94, 0x3e, + 0x70, 0xbf, 0x1c, 0x5d, 0xf4, 0xd5, 0x31, 0xdc, 0x0d, + 0x92, 0x6e, 0x83, 0x80, 0x4c, 0x4a}, + .klen = 24, + .iv = {0x29, 0x85, 0x58, 0xd9, 0x55, 0x17, 0xa0, 0x45}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x26, 0xe4, 0x4a, 0xa7, 0x8f, 0xcc, 0x69, 0x06, 0x87, + 0xe7, 0x4c, 0xfd, 0xfc, 0xbd, 0x6e, 0xf3, 0x46, 0x96, + 0x01, 0x1e, 0x5a, 0xe1, 0xcb, 0xfe, 0x40, 0xd6, 0x33, + 0x2b, 0xc7, 0x5b, 0x9c, 0x51, 0x77, 0x24, 0xf1, 0x79, + 0xc7, 0x1f, 0x81, 0x8a, 0x90, 0x0f, 0x0e, 0x0f, 0xc2, + 0x76, 0x20, 0x3a}, + .plen = 48, + .ciphertext = {0xd0, 0x9b, 0x95, 0x68, 0x87, 0x77, 0x69, 0x78, 0x0f, + 0xda, 0x99, 0x11, 0xc2, 0x9b, 0x30, 0x3b, 0x27, 0xe1, + 0x5b, 0x5f, 0x29, 0xb2, 0xdd, 0xf8, 0x9c, 0x3b, 0x7e, + 0xdc, 0xc0, 0x4d, 0xee, 0x78, 0xb7, 0x51, 0xd4, 0x59, + 0xa5, 0x0d, 0xf3, 0xae, 0x57, 0xbf, 0xfd, 0x4b, 0x4c, + 0xa4, 0x1f, 0xc4}, + .clen = 48, + .num_chunks = 4, + .chunks = {28, 13, 0, 7}, + }, { // #6 + .key = {0xf7, 0xa4, 0x94, 0xc2, 0x73, 0x26, 0x73, 0x4a, 0x10, + 0x45, 0x25, 0x04, 0x10, 0x52, 0x10, 0x3e, 0xf2, 0x68, + 0x0e, 0x3b, 0xd3, 0x5e, 0xa1, 0x58}, + .klen = 24, + .iv = {0xa5, 0xfe, 0x08, 0xd9, 0x04, 0x5b, 0xbf, 0x88}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0xf9, 0x11, 0x72, 0x49, 0x04, 0x7f, 0xb9, 0xfe, 0x88, + 0x4c, 0x89, 0x26, 0x7e, 0x5a, 0xc9, 0x63, 0x14, 0xf2, + 0x33, 0xd2, 0x01, 0xc1, 0x4d, 0x33, 0x15, 0x20, 0x9a, + 0x4a, 0x14, 0x99, 0x11, 0x84, 0xc4, 0xa6, 0xce, 0xde, + 0x45, 0xbb, 0x08, 0x03, 0xa1, 0x87, 0x43, 0xb4, 0xa4, + 0x78, 0xc6, 0x6d, 0xee, 0x7d, 0x50, 0x46, 0x46, 0x0f, + 0x07, 0x17}, + .plen = 56, + .ciphertext = {0xc8, 0x9f, 0xf7, 0xbc, 0xc5, 0x55, 0x89, 0x52, 0xe8, + 0x61, 0x4a, 0x7b, 0xfc, 0xf8, 0xa1, 0xb0, 0x17, 0xf0, + 0x40, 0xef, 0x95, 0x4f, 0x65, 0x52, 0x69, 0x6a, 0xe5, + 0x3b, 0x70, 0xe6, 0xf9, 0x53, 0xba, 0x6d, 0x9d, 0x0e, + 0xfe, 0x38, 0x1c, 0x2b, 0xdd, 0x54, 0xd9, 0x11, 0xad, + 0x6e, 0xac, 0x5b, 0x0c, 0xe2, 0x84, 0x53, 0x41, 0xae, + 0x34, 0x58}, + .clen = 56, + }, { // #7 + .key = {0xd3, 0x31, 0x89, 0x58, 0xc7, 0x8c, 0xfd, 0x98, 0xc7, + 0xae, 0x31, 0x2a, 0x2c, 0x08, 0xbc, 0xfe, 0xfd, 0x10, + 0x26, 0x97, 0x29, 0x01, 0x3d, 0xe5}, + .klen = 24, + .iv = {0x01, 0xb6, 0xdd, 0x4a, 0x4c, 0x96, 0x34, 0x9a}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x83, 0x57, 0x73, 0x46, 0x84, 0x1a, 0x1b, 0xbf, 0x08, + 0xfb, 0x6d, 0x2b, 0xe3, 0x51, 0xf3, 0x39, 0x14, 0xef, + 0xc8, 0xef, 0x9a, 0xa7, 0x05, 0x4b, 0x89, 0x0d, 0x7c, + 0x2b, 0x5c, 0x7d, 0xa9, 0x6a, 0x8d, 0x60, 0xe5, 0x4c, + 0x63, 0xaa, 0xdd, 0x1c, 0x0c, 0xa7, 0x43, 0x13, 0xeb, + 0xf8, 0xc3, 0x7c, 0x33, 0xd9, 0x39, 0x16, 0xb5, 0xa5, + 0x21, 0xba, 0xf6, 0x9b, 0x4e, 0x3d, 0x85, 0xe2, 0xe0, + 0x98}, + .plen = 64, + .ciphertext = {0x8b, 0xe3, 0x0c, 0xa7, 0x45, 0xa0, 0x6e, 0x2f, 0x67, + 0xc3, 0xec, 0x2e, 0xd1, 0x8e, 0x87, 0x20, 0x28, 0x44, + 0x85, 0x97, 0x21, 0x8b, 0x00, 0x77, 0x46, 0xd9, 0x54, + 0xda, 0x0b, 0xa6, 0xb3, 0xdb, 0x20, 0xf9, 0xa2, 0x8d, + 0x7f, 0xae, 0xa3, 0x2e, 0xe3, 0xf1, 0x31, 0x03, 0xdc, + 0x80, 0x18, 0xe8, 0xf9, 0x7d, 0xc2, 0xc3, 0x48, 0xd2, + 0x96, 0x6c, 0x9e, 0x2b, 0x87, 0xb0, 0xf3, 0x18, 0xe0, + 0x26}, + .clen = 64, + }, { // #8 + .key = {0xa4, 0xe5, 0x0d, 0x8a, 0x1f, 0x64, 0xf4, 0xd9, 0xf4, + 0x1a, 0x8a, 0xd0, 0xa8, 0xc8, 0x68, 0xb3, 0x4a, 0xc8, + 0x61, 0xdc, 0x4c, 0x38, 0xfd, 0x89}, + .klen = 24, + .iv = {0xf2, 0x10, 0x47, 0xa0, 0x8a, 0x1b, 0xed, 0x96}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0xfa, 0x7c, 0x94, 0xa2, 0xeb, 0x67, 0xdb, 0xf0, 0xce, + 0x8e, 0x30, 0xd5, 0xb9, 0x44, 0xe9, 0x58, 0x5f, 0xfe, + 0xf8, 0xb9, 0xd8, 0x07, 0xca, 0xbd, 0xa0, 0x75, 0x6f, + 0x46, 0xe1, 0x5b, 0xfa, 0x26, 0xf5, 0x40, 0x2b, 0x35, + 0x26, 0xd0, 0x4b, 0xa2, 0xb9, 0xd2, 0x58, 0x86, 0x2c, + 0x5a, 0x62, 0xbf, 0xbb, 0x40, 0x35, 0xfb, 0x29, 0xd0, + 0x38, 0x13, 0xbc, 0xc3, 0x95, 0x9b, 0x8a, 0x6f, 0x9a, + 0xb7, 0xf3, 0x3a, 0x60, 0x2f, 0x6f, 0x54, 0xaa, 0xc6}, + .plen = 72, + .ciphertext = {0xe4, 0x02, 0x5b, 0x1f, 0x5b, 0xcd, 0xe6, 0xea, 0xe6, + 0xc7, 0xbb, 0xfd, 0x48, 0x51, 0x25, 0x8a, 0xf6, 0xd0, + 0x97, 0x79, 0x1a, 0x02, 0xd8, 0xdf, 0x54, 0x83, 0xa8, + 0xcb, 0xcf, 0xea, 0xaf, 0x52, 0xdd, 0xdb, 0x61, 0xbf, + 0x1d, 0xdc, 0x52, 0xb9, 0xcb, 0x6d, 0xf9, 0x47, 0xcb, + 0x04, 0x92, 0x48, 0x90, 0x36, 0x21, 0x25, 0x43, 0xfa, + 0xb8, 0x26, 0x94, 0x44, 0x9c, 0x8d, 0x3d, 0x32, 0x3d, + 0xce, 0x01, 0x6e, 0x26, 0x48, 0xac, 0x6f, 0x65, 0x3e}, + .clen = 72, + }, { // #9 + .key = {0x08, 0x76, 0x3d, 0xa8, 0x62, 0xad, 0x16, 0xef, 0x58, + 0x15, 0x40, 0x8f, 0x5d, 0x3b, 0x70, 0x54, 0x15, 0xab, + 0x15, 0x43, 0xa4, 0x2c, 0x3e, 0xfb}, + .klen = 24, + .iv = {0x06, 0x34, 0xd6, 0x9e, 0xaf, 0xf3, 0xae, 0x17}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x10, 0x9a, 0x3d, 0x3d, 0x74, 0x5d, 0x65, 0xb3, 0x8e, + 0xdb, 0xc7, 0x3d, 0x1d, 0xe8, 0xb2, 0x80, 0x7f, 0x78, + 0x20, 0x22, 0x1a, 0x6c, 0x39, 0x37, 0xfa, 0xab, 0x19, + 0xfc, 0xbb, 0x75, 0xd3, 0xc8, 0xaa, 0xf4, 0xb6, 0x3f, + 0x27, 0x14, 0xcf, 0xc9, 0x4e, 0x95, 0xae, 0x43, 0xd6, + 0x5f, 0x6d, 0xf4, 0x38, 0x15, 0xef, 0xc2, 0x14, 0xec, + 0x66, 0xa5, 0xd1, 0xbe, 0x18, 0x5d, 0x85, 0x5a, 0x62, + 0x60, 0x14, 0x1f, 0xfd, 0x17, 0x9b, 0xc9, 0x80, 0x49, + 0x0f, 0x8a, 0x26, 0xd8, 0x21, 0x5d, 0xd2, 0xab}, + .plen = 80, + .ciphertext = {0xe9, 0x51, 0x3e, 0x88, 0x92, 0xa0, 0x90, 0x85, 0xbe, + 0xe2, 0x9c, 0x35, 0x80, 0x14, 0xaf, 0xd6, 0x0d, 0x75, + 0x78, 0xd2, 0x1e, 0x00, 0xa3, 0x1e, 0x5d, 0x61, 0xb9, + 0x65, 0xc1, 0x87, 0x78, 0xeb, 0xe1, 0x84, 0x69, 0x17, + 0x07, 0x94, 0xe5, 0xdd, 0xf2, 0x4a, 0xa7, 0x77, 0xc8, + 0xab, 0x0a, 0x2c, 0x62, 0x47, 0x41, 0x09, 0xe6, 0x17, + 0x97, 0x8b, 0xcc, 0x5c, 0xe3, 0x45, 0x6d, 0xdd, 0x96, + 0x22, 0x83, 0x34, 0x20, 0x44, 0x3c, 0x2a, 0x26, 0xb1, + 0xb6, 0xe2, 0x0a, 0x05, 0xc1, 0x89, 0xda, 0x6c}, + .clen = 80, + } +}; + +/** http://csrc.nist.gov/groups/STM/cavp/documents/des/tdesmmt.zip + TCFB8MMT3.rsp +**/ +static struct des3_test_vector des3_cfb8_tv[] = { + { // #0 + .key = {0x94, 0x73, 0xba, 0x2c, 0x29, 0xa8, 0x7f, 0xec, 0x4f, + 0x38, 0x29, 0xb3, 0xb6, 0xbc, 0x9e, 0x92, 0x43, 0x4c, + 0xab, 0x51, 0x89, 0x0e, 0xda, 0x8c}, + .klen = 24, + .iv = {0x34, 0x20, 0xb1, 0x32, 0x81, 0xd3, 0x0b, 0x06}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0xcd}, + .plen = 1, + .ciphertext = {0x22}, + .clen = 1, + }, { // #1 + .key = {0xb6, 0x92, 0xea, 0x4a, 0x62, 0x29, 0x9b, 0x32, 0xd9, + 0x04, 0x51, 0x38, 0x8a, 0x25, 0x8f, 0xce, 0x3b, 0x3b, + 0x1c, 0xfd, 0x34, 0xbc, 0x7f, 0x5d}, + .klen = 24, + .iv = {0x54, 0xc0, 0xb1, 0xef, 0xef, 0xf2, 0x53, 0xa2}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x32, 0xee}, + .plen = 2, + .ciphertext = {0x7c, 0x92}, + .clen = 2, + }, { // #2 + .key = {0x40, 0x49, 0x02, 0xc8, 0x51, 0x19, 0xda, 0xb6, 0x1f, + 0xb5, 0xce, 0xd6, 0xf4, 0x6b, 0x45, 0xf8, 0xe5, 0xe0, + 0x61, 0x34, 0xa8, 0xb5, 0xc1, 0xb9}, + .klen = 24, + .iv = {0xa3, 0xd6, 0x97, 0x32, 0xf9, 0x4f, 0xff, 0xc7}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x14, 0xc4, 0x5c}, + .plen = 3, + .ciphertext = {0x35, 0x8d, 0x66}, + .clen = 3, + }, { // #3 + .key = {0xc4, 0xd3, 0x45, 0xfd, 0xdc, 0x9d, 0xf7, 0x02, 0x3b, + 0x04, 0xe6, 0x76, 0x52, 0x8a, 0x2f, 0x57, 0xe0, 0x51, + 0xba, 0x86, 0x6b, 0x98, 0x7a, 0xba}, + .klen = 24, + .iv = {0xd7, 0x6f, 0xbd, 0x43, 0x4d, 0x8b, 0x2e, 0xd9}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x1d, 0x1e, 0x42, 0xcd}, + .plen = 4, + .ciphertext = {0x44, 0xde, 0xee, 0xe3}, + .clen = 4, + }, { // #4 + .key = {0xf1, 0xc4, 0x07, 0xf8, 0x25, 0x0b, 0xcd, 0x10, 0xda, + 0x91, 0x4f, 0x62, 0x6b, 0xf7, 0x15, 0x54, 0x8c, 0x31, + 0xd6, 0xe0, 0xba, 0x70, 0xec, 0x5b}, + .klen = 24, + .iv = {0x0f, 0x9d, 0x30, 0x71, 0xaf, 0x25, 0xa1, 0x42}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0xa4, 0x3e, 0xcd, 0x3d, 0x06}, + .plen = 5, + .ciphertext = {0x6a, 0x6d, 0xa4, 0x8c, 0x70}, + .clen = 5, + }, { // #5 + .key = {0x26, 0x7c, 0xcb, 0xea, 0xa4, 0x91, 0x25, 0x51, 0x2c, + 0x7f, 0x2c, 0x9e, 0x8a, 0xf8, 0x4a, 0xe6, 0x3b, 0x9b, + 0xb9, 0x57, 0x83, 0x16, 0x8a, 0x52}, + .klen = 24, + .iv = {0x03, 0xf6, 0x56, 0xfb, 0x72, 0xc9, 0xbf, 0x5d}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0xab, 0x15, 0x81, 0x70, 0x7d, 0x7d}, + .plen = 6, + .ciphertext = {0x16, 0x88, 0x1e, 0x43, 0xfc, 0x0c}, + .clen = 6, + }, { // #6 + .key = {0x5e, 0xfe, 0x5d, 0x40, 0x80, 0x2f, 0x4f, 0x25, 0xad, + 0xc2, 0x62, 0x4c, 0xdc, 0x29, 0x80, 0x45, 0x2c, 0x0b, + 0x38, 0x91, 0x52, 0x57, 0x52, 0x80}, + .klen = 24, + .iv = {0x00, 0x16, 0x7d, 0x7f, 0x48, 0x30, 0x9f, 0x0a}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x02, 0x4e, 0x62, 0x6c, 0xea, 0x49, 0x91}, + .plen = 7, + .ciphertext = {0x2b, 0x23, 0x9e, 0x41, 0xd9, 0x60, 0x69}, + .clen = 7, + }, { // #7 + .key = {0xcb, 0x79, 0xb6, 0xdf, 0xad, 0xa1, 0x13, 0x79, 0xb6, + 0x51, 0x32, 0xa7, 0x70, 0x54, 0xd3, 0x08, 0x13, 0xb9, + 0xda, 0x29, 0x54, 0x02, 0x0e, 0x9e}, + .klen = 24, + .iv = {0x2c, 0x5f, 0x51, 0xcd, 0x90, 0x0f, 0xe7, 0x53}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x58, 0x76, 0xdb, 0xe3, 0xd1, 0xe6, 0x3b, 0xec}, + .plen = 8, + .ciphertext = {0x73, 0xc1, 0x54, 0x52, 0x4f, 0x4d, 0x57, 0x29}, + .clen = 8, + }, { // #8 + .key = {0x04, 0xdf, 0x08, 0x19, 0x29, 0x64, 0xd6, 0xbc, 0xc8, + 0x4c, 0x97, 0xda, 0x94, 0x0b, 0x32, 0xc8, 0x80, 0xdf, + 0xd0, 0xce, 0x8c, 0x91, 0x80, 0xa8}, + .klen = 24, + .iv = {0xcf, 0x7e, 0x0c, 0xc1, 0xf2, 0x23, 0x34, 0x3e}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x1d, 0xe8, 0x12, 0x27, 0x9b, 0xd5, 0x57, 0x6e, 0xc2}, + .plen = 9, + .ciphertext = {0x34, 0xd1, 0x06, 0x7d, 0x1a, 0x92, 0xa8, 0xda, 0x19}, + .clen = 9, + .num_chunks = 3, + .chunks = {4, -1, 5}, + }, { // #9 + .key = {0xe3, 0x34, 0x7a, 0x6b, 0x0b, 0xc1, 0x15, 0x2c, 0x64, + 0x2a, 0x25, 0xcb, 0xd3, 0xbc, 0x31, 0xab, 0xfb, 0xa1, + 0x62, 0xa8, 0x1f, 0x19, 0x7c, 0x15}, + .klen = 24, + .iv = {0xb7, 0x40, 0xcc, 0x21, 0xe9, 0x25, 0xe3, 0xc8}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0xdb, 0xe9, 0x15, 0xfc, 0xb3, 0x3b, 0xca, 0x18, 0xef, + 0x14}, + .plen = 10, + .ciphertext = {0xf4, 0x80, 0x1a, 0x8d, 0x03, 0x9d, 0xb4, 0xca, 0x8f, + 0xf6}, + .clen = 10, + .num_chunks = 3, + .chunks = {5, 0, 5}, + } +}; + + +/** http://csrc.nist.gov/groups/STM/cavp/documents/des/tdesmmt.zip + TCFB64MMT3.rsp +**/ +static struct des3_test_vector des3_cfb64_tv[] = { + { // #0 + .key = {0xe0, 0xd5, 0x25, 0xe9, 0xec, 0xa2, 0x26, 0xd5, 0x58, + 0x4a, 0x70, 0x2f, 0xdc, 0xd3, 0xdf, 0x23, 0x80, 0x58, + 0xad, 0x4c, 0x15, 0x70, 0x34, 0x8f}, + .klen = 24, + .iv = {0x8b, 0xf6, 0xfe, 0xbf, 0xde, 0x90, 0xbd, 0x17}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x26, 0x85, 0xa3, 0x86, 0x57, 0xe8, 0xdb, 0xfe}, + .plen = 8, + .ciphertext = {0xe9, 0xfb, 0xc0, 0x28, 0x10, 0x53, 0x54, 0xed}, + .clen = 8, + }, { // #1 + .key = {0x02, 0xf1, 0xb5, 0x64, 0x51, 0xc8, 0x20, 0x7f, 0xce, + 0x70, 0x92, 0x8f, 0x1f, 0xcd, 0xe0, 0xb3, 0x6d, 0xcd, + 0xa8, 0x58, 0xef, 0xe9, 0xb0, 0x6b}, + .klen = 24, + .iv = {0xee, 0x34, 0x61, 0x53, 0xc0, 0x9d, 0xc8, 0x73}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0xa7, 0x2f, 0x0d, 0x3f, 0xb8, 0xd4, 0xd8, 0xf7, 0x84, + 0xce, 0x12, 0x0f, 0x2b, 0x4b, 0x85, 0x38}, + .plen = 16, + .ciphertext = {0x3b, 0x6b, 0x32, 0x36, 0x5d, 0xac, 0xe6, 0xc9, 0x9b, + 0x76, 0x74, 0xfb, 0xbe, 0xa1, 0x7a, 0x9b}, + .clen = 16, + }, { // #2 + .key = {0x76, 0xdc, 0xf7, 0xba, 0x76, 0x9b, 0xd3, 0x32, 0x34, + 0x02, 0xc2, 0xae, 0x61, 0x15, 0x02, 0xc8, 0xd5, 0xc2, + 0x26, 0x15, 0xef, 0xb0, 0xe0, 0x9e}, + .klen = 24, + .iv = {0x5b, 0x48, 0x33, 0x4d, 0x9f, 0x3a, 0x67, 0xda}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0xb4, 0xd0, 0x02, 0x4c, 0x7f, 0xa1, 0x40, 0xbe, 0xde, + 0xa2, 0x19, 0xdc, 0xce, 0x36, 0x7a, 0xa9, 0xd6, 0x10, + 0x53, 0x27, 0x82, 0xdf, 0xa8, 0x19}, + .plen = 24, + .ciphertext = {0x26, 0xa9, 0x83, 0x6c, 0xfa, 0xc9, 0x6d, 0xfa, 0x2e, + 0x45, 0x55, 0x48, 0xd2, 0x6c, 0x09, 0xea, 0x93, 0xe5, + 0x3b, 0xff, 0x52, 0x37, 0x5c, 0xf0}, + .clen = 24, + .num_chunks = 3, + .chunks = {12, 0, 12}, + }, { // #3 + .key = {0x4f, 0x5d, 0xad, 0xfe, 0x34, 0x43, 0x80, 0x3d, 0x07, + 0xdc, 0xcb, 0x2c, 0x37, 0x73, 0xdc, 0xb5, 0xc4, 0xc2, + 0xd6, 0x97, 0xcd, 0x7f, 0x67, 0xe9}, + .klen = 24, + .iv = {0x9a, 0x6d, 0x3d, 0x65, 0xd3, 0xca, 0x4d, 0xfb}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x1c, 0x1f, 0x3c, 0xe7, 0x92, 0x7d, 0x25, 0x62, 0xc0, + 0x53, 0xc6, 0x5d, 0x73, 0x8a, 0x6e, 0xbc, 0x92, 0xbf, + 0x59, 0x9c, 0x52, 0xa4, 0x82, 0xdb, 0xa8, 0xa3, 0xb8, + 0xda, 0x04, 0xc5, 0xf4, 0x81}, + .plen = 32, + .ciphertext = {0xb6, 0x88, 0xdd, 0x16, 0x5b, 0x56, 0x12, 0x8c, 0x8f, + 0x14, 0xcc, 0xd5, 0x99, 0x12, 0x63, 0x1f, 0x13, 0x0f, + 0x0d, 0x95, 0x67, 0x7c, 0xae, 0xc3, 0x60, 0xd4, 0x96, + 0x58, 0x99, 0x2e, 0x09, 0xec}, + .clen = 32, + .num_chunks = 4, + .chunks = {8, 8, 8, 8}, + }, { // #4 + .key = {0x02, 0xc1, 0x64, 0x46, 0xe5, 0x25, 0x4c, 0x97, 0x45, + 0xf1, 0xab, 0xab, 0xd6, 0xc7, 0xcd, 0x9d, 0xf8, 0xcd, + 0x0d, 0x4a, 0x04, 0x20, 0xd3, 0xe5}, + .klen = 24, + .iv = {0x61, 0x54, 0x2a, 0xc6, 0x07, 0xbb, 0x26, 0x7e}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0xf9, 0x07, 0xdd, 0x85, 0x81, 0x65, 0x1f, 0xef, 0xf3, + 0x3d, 0x54, 0x5d, 0xc4, 0xb9, 0x4a, 0x74, 0xd3, 0xd1, + 0x71, 0xf5, 0xaa, 0x77, 0x3d, 0x95, 0x01, 0x12, 0xcc, + 0x09, 0x84, 0x2e, 0xc9, 0x60, 0xd7, 0x72, 0x90, 0x95, + 0xd6, 0xd2, 0x93, 0x65}, + .plen = 40, + .ciphertext = {0x45, 0x3f, 0xe0, 0x1c, 0x94, 0xf0, 0xd0, 0x28, 0xac, + 0xb8, 0xd8, 0x3d, 0x66, 0xca, 0xc3, 0x73, 0x4e, 0xb8, + 0x43, 0xab, 0x4b, 0x6c, 0xbd, 0x6c, 0x0c, 0xbf, 0x1a, + 0x1e, 0x8e, 0x55, 0x4c, 0x88, 0x13, 0xfa, 0x42, 0x93, + 0xa9, 0x3c, 0x6f, 0x8c}, + .clen = 40, + .num_chunks = 3, + .chunks = {20, -1, 20}, + }, { // #5 + .key = {0x70, 0x75, 0x57, 0x15, 0x23, 0xd9, 0x02, 0xc8, 0x9b, + 0x0d, 0xa2, 0x0b, 0x85, 0x70, 0x43, 0x04, 0x70, 0xe5, + 0x61, 0xda, 0x58, 0xfe, 0xe0, 0x38}, + .klen = 24, + .iv = {0x86, 0xd8, 0xa5, 0xa0, 0x76, 0xce, 0xae, 0x0a}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x18, 0x39, 0xc8, 0xb6, 0xcd, 0xd4, 0x07, 0x0a, 0xdc, + 0xc4, 0x24, 0x2c, 0x48, 0x4e, 0x5e, 0x31, 0x5d, 0xdb, + 0x8f, 0x5c, 0xe9, 0x56, 0x01, 0x9c, 0xa9, 0xd6, 0x82, + 0x55, 0x02, 0x7d, 0xbb, 0x63, 0xf1, 0xa0, 0xbd, 0x5d, + 0x45, 0x27, 0xdd, 0x16, 0x0c, 0x37, 0xc2, 0x6a, 0x4b, + 0x0f, 0xbc, 0x37}, + .plen = 48, + .ciphertext = {0x4f, 0xe9, 0x7b, 0xab, 0x6c, 0x9d, 0xdd, 0xf7, 0xf6, + 0x7d, 0xa8, 0xf2, 0xc1, 0x67, 0x3c, 0x17, 0xbf, 0x35, + 0xd7, 0x4d, 0x8c, 0xf4, 0xa1, 0xb1, 0x6a, 0xc1, 0xb2, + 0x74, 0xf7, 0x12, 0x40, 0xea, 0xef, 0x79, 0x31, 0x81, + 0x8b, 0xa7, 0x45, 0x3a, 0x09, 0xa7, 0x4e, 0x3a, 0x1c, + 0xb0, 0xc4, 0x81}, + .clen = 48, + }, { // #6 + .key = {0x79, 0x5b, 0x80, 0x98, 0xe5, 0xb3, 0xe5, 0x67, 0xd9, + 0xa8, 0x9d, 0x4a, 0x8c, 0x08, 0x3e, 0x54, 0x0e, 0xf7, + 0x31, 0x16, 0x62, 0x6d, 0xb0, 0x32}, + .klen = 24, + .iv = {0xe1, 0x92, 0x73, 0x25, 0x82, 0xbf, 0x00, 0x85}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x02, 0xbc, 0x7e, 0xda, 0x94, 0xe8, 0x91, 0x19, 0xa9, + 0x6e, 0xf5, 0x50, 0x1d, 0x05, 0x91, 0x96, 0x3a, 0x27, + 0x0a, 0xcf, 0xe3, 0x72, 0x95, 0x2d, 0x11, 0x4e, 0x09, + 0xf6, 0x84, 0xd0, 0x39, 0x87, 0xb2, 0xde, 0x80, 0x99, + 0x04, 0x94, 0x9d, 0xc3, 0x41, 0xe7, 0xc1, 0x40, 0x4a, + 0x88, 0xe7, 0xf3, 0x09, 0x0b, 0x64, 0xa8, 0xa4, 0x49, + 0xbf, 0x9d}, + .plen = 56, + .ciphertext = {0xdd, 0x87, 0x24, 0xcd, 0xd9, 0x53, 0xf6, 0x95, 0x10, + 0x9c, 0xaa, 0x06, 0x8d, 0xd7, 0x1a, 0xa6, 0x58, 0xe7, + 0x5e, 0x79, 0x64, 0xc2, 0xc6, 0x02, 0x1c, 0x77, 0x1d, + 0x53, 0x59, 0x05, 0x60, 0xc0, 0x0c, 0x88, 0xcc, 0xc6, + 0xee, 0x14, 0x8e, 0x28, 0x72, 0xa1, 0x33, 0x70, 0x37, + 0xe2, 0x79, 0xea, 0xe0, 0x27, 0x60, 0xac, 0x0f, 0xe4, + 0x83, 0x96}, + .clen = 56, + .num_chunks = 4, + .chunks = {16, 16, 16, 8}, + }, { // #7 + .key = {0x7c, 0x7c, 0xc7, 0xfe, 0x4a, 0xf2, 0x0e, 0x6b, 0x38, + 0xa8, 0x79, 0x5d, 0xab, 0xfd, 0xba, 0x1f, 0xbc, 0x5d, + 0x25, 0x45, 0x2a, 0x94, 0x32, 0x34}, + .klen = 24, + .iv = {0x84, 0x32, 0xa5, 0x46, 0x2a, 0x16, 0xbc, 0xfb}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x58, 0x8a, 0x36, 0x9d, 0x93, 0xdd, 0x68, 0xbd, 0x51, + 0x8f, 0xd3, 0x41, 0xba, 0xb4, 0x83, 0x10, 0xea, 0x89, + 0x14, 0x6a, 0xf4, 0x65, 0xd3, 0x79, 0x27, 0xec, 0x20, + 0x29, 0x90, 0x86, 0x17, 0x3a, 0xbf, 0x10, 0x6f, 0x94, + 0xce, 0xd1, 0xa1, 0xda, 0xa0, 0xaf, 0x4d, 0x41, 0x67, + 0xa2, 0xda, 0xa3, 0x69, 0x6a, 0x5e, 0xcf, 0x03, 0x7d, + 0xbd, 0x24, 0xee, 0x44, 0x14, 0x5e, 0xc1, 0x86, 0x58, + 0xaf}, + .plen = 64, + .ciphertext = {0x2b, 0xfb, 0x5c, 0x7b, 0x2d, 0x9f, 0xbe, 0x4a, 0x51, + 0x4a, 0x2d, 0x14, 0x0c, 0xaf, 0x8c, 0x46, 0x46, 0xfd, + 0x13, 0xd9, 0xc2, 0x51, 0xc1, 0x07, 0x3d, 0x07, 0xf8, + 0x95, 0xea, 0x99, 0xec, 0x90, 0xf4, 0x5a, 0xbb, 0xd4, + 0x0b, 0xf4, 0x0f, 0xc7, 0x85, 0xaa, 0x9f, 0x9f, 0xf5, + 0xb9, 0x25, 0xcd, 0x29, 0xdb, 0x70, 0xe5, 0x14, 0x9c, + 0x16, 0x28, 0x79, 0xde, 0xd9, 0x45, 0xa7, 0x78, 0x09, + 0xc8}, + .clen = 64, + .num_chunks = 4, + .chunks = {32, 0, -1, 32}, + }, { // #8 + .key = {0x8c, 0x37, 0xbc, 0x49, 0x32, 0x01, 0x64, 0x79, 0xf1, + 0x97, 0xb0, 0xf7, 0x57, 0xcb, 0x16, 0xf1, 0x46, 0x54, + 0xfb, 0x49, 0x92, 0x46, 0xda, 0xba}, + .klen = 24, + .iv = {0xfd, 0xee, 0x51, 0xb0, 0x6b, 0x61, 0xfc, 0xe8}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0xc1, 0x55, 0x07, 0xd7, 0x25, 0xaf, 0xa1, 0x47, 0x55, + 0xda, 0x2c, 0xc3, 0xcd, 0xf5, 0x9a, 0x83, 0xad, 0x28, + 0xbd, 0x20, 0x05, 0xdd, 0xaf, 0x5e, 0x50, 0x2c, 0x71, + 0x48, 0x3e, 0x96, 0xd2, 0x83, 0xb7, 0xf7, 0x92, 0xdc, + 0x1c, 0xb6, 0xc8, 0x23, 0xd0, 0x3f, 0x81, 0x3c, 0xf7, + 0xb3, 0xaa, 0x73, 0x7d, 0xdd, 0x30, 0x10, 0x5a, 0x69, + 0x65, 0x2b, 0x15, 0x50, 0xa6, 0xc2, 0x87, 0x97, 0x3b, + 0x09, 0xe2, 0x39, 0x7e, 0x01, 0xf2, 0x62, 0x3f, 0x4c}, + .plen = 72, + .ciphertext = {0xe5, 0x6f, 0x5d, 0x07, 0x80, 0x60, 0x61, 0xcd, 0xa9, + 0xcc, 0x7a, 0x83, 0x09, 0x64, 0xc1, 0x64, 0x7e, 0x92, + 0x02, 0x3d, 0xb2, 0xb6, 0x8d, 0xd8, 0x4a, 0xa5, 0x48, + 0xf4, 0x86, 0xcc, 0xc7, 0x79, 0xd2, 0x7d, 0xfa, 0xef, + 0x17, 0x1c, 0x52, 0xc6, 0x32, 0x1f, 0x9f, 0x47, 0x73, + 0x0d, 0x2a, 0x8e, 0x10, 0x9b, 0x67, 0xad, 0x57, 0x59, + 0xd5, 0x62, 0x44, 0x06, 0x67, 0x69, 0xe4, 0x3c, 0x6c, + 0x11, 0xe9, 0x05, 0xa7, 0x37, 0x2a, 0x81, 0x45, 0x6b}, + .clen = 72, + .num_chunks = 5, + .chunks = {5, 20, -1, 17, 30}, + }, { // #9 + .key = {0x4f, 0x52, 0x26, 0x01, 0x9d, 0xb3, 0x6b, 0x40, 0x46, + 0x43, 0x92, 0xc8, 0xe5, 0xc4, 0x2a, 0xd9, 0x5e, 0x20, + 0x32, 0x26, 0x3d, 0xce, 0x8f, 0x20}, + .klen = 24, + .iv = {0xee, 0x24, 0xf2, 0xe7, 0xd6, 0xd1, 0xf6, 0xf9}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x6a, 0x9a, 0xaf, 0xb3, 0x4b, 0x4d, 0xd8, 0xad, 0x40, + 0x07, 0x21, 0xb5, 0xc2, 0xee, 0x62, 0x50, 0x15, 0xc8, + 0x9a, 0x92, 0xcb, 0x6d, 0x92, 0x35, 0x8b, 0x7c, 0xbd, + 0xe8, 0x10, 0x4e, 0x63, 0xe9, 0x74, 0x28, 0xfe, 0xd6, + 0xaf, 0xb5, 0xe5, 0xc1, 0x5b, 0xb3, 0x27, 0x82, 0xba, + 0xec, 0xba, 0x51, 0xf9, 0x68, 0xd5, 0x94, 0xb6, 0xe1, + 0x9a, 0xf5, 0xc1, 0x77, 0xf8, 0xb8, 0x1f, 0xa5, 0xd0, + 0x4b, 0x55, 0x74, 0x56, 0x1f, 0xe3, 0xee, 0xbb, 0xb7, + 0x0e, 0xd6, 0x09, 0xff, 0xe2, 0x96, 0x4e, 0xde}, + .plen = 80, + .ciphertext = {0x34, 0x9d, 0xdf, 0x37, 0xbf, 0xa1, 0x25, 0x30, 0x4f, + 0x91, 0x03, 0x5a, 0xa0, 0x2b, 0x5f, 0xd5, 0xc4, 0x9c, + 0x6f, 0xd2, 0x44, 0x37, 0x9c, 0x43, 0xcf, 0x7e, 0xbe, + 0xca, 0xd4, 0x89, 0xe3, 0x8a, 0xed, 0xeb, 0x74, 0x90, + 0xa7, 0x7b, 0xb1, 0x77, 0x7d, 0x62, 0x8f, 0x01, 0x8c, + 0x86, 0x22, 0x2e, 0xbf, 0x4d, 0x12, 0x48, 0x3f, 0x97, + 0x9d, 0xdf, 0x13, 0x6f, 0x35, 0x15, 0x1c, 0x56, 0x5c, + 0x54, 0xf8, 0x6f, 0x24, 0x59, 0xad, 0xc7, 0xb1, 0x66, + 0x80, 0x66, 0xe6, 0x9f, 0xc2, 0x66, 0x17, 0x01}, + .clen = 80, + .num_chunks = 2, + .chunks = {40, 40}, + } +}; + + +/** http://csrc.nist.gov/groups/STM/cavp/documents/des/tdesmmt.zip + TOFBMMT3.rsp +**/ +static struct des3_test_vector des3_ofb64_tv[] = { + { // #0 + .key = {0xe9, 0x61, 0x54, 0xa2, 0xa8, 0x75, 0x5b, 0xfd, 0x2c, + 0x51, 0xd6, 0xa1, 0x97, 0x67, 0xd5, 0x26, 0x43, 0x5d, + 0x19, 0xb6, 0x98, 0x2c, 0x6d, 0xa7}, + .klen = 24, + .iv = {0xd9, 0xb4, 0x23, 0x43, 0x4c, 0xea, 0x15, 0xf3}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x31, 0x93, 0xf8, 0xd9, 0xf6, 0x90, 0x61, 0xbf}, + .plen = 8, + .ciphertext = {0x0a, 0x7b, 0x1d, 0xa0, 0x7c, 0x99, 0xa3, 0xdd}, + .clen = 8, + }, { // #1 + .key = {0x83, 0x86, 0xc4, 0x64, 0xef, 0xbf, 0xf1, 0xa7, 0x1c, + 0xa8, 0x4c, 0xbf, 0xbf, 0x76, 0x0e, 0x32, 0x2a, 0x07, + 0x8a, 0x2f, 0x6d, 0x1f, 0xf2, 0x31}, + .klen = 24, + .iv = {0x15, 0xed, 0xcd, 0xe1, 0xbd, 0x53, 0xc4, 0xc5}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x32, 0x7d, 0xa4, 0x0b, 0x70, 0xe3, 0x56, 0x86, 0x8d, + 0x22, 0x15, 0x1c, 0x96, 0xe7, 0x65, 0x8e}, + .plen = 16, + .ciphertext = {0xda, 0x19, 0x0d, 0x06, 0xdb, 0x62, 0x69, 0xef, 0xa0, + 0x6a, 0xe7, 0x2a, 0x79, 0xb9, 0x86, 0xb1}, + .clen = 16, + }, { // #2 + .key = {0xb9, 0x20, 0x9e, 0xbc, 0x8c, 0xce, 0x62, 0x40, 0x16, + 0xf1, 0x7a, 0x43, 0xa2, 0x8a, 0x25, 0x15, 0x1a, 0xab, + 0x8c, 0xab, 0xb0, 0x6b, 0x08, 0x3b}, + .klen = 24, + .iv = {0x2c, 0x95, 0x82, 0x73, 0xea, 0x54, 0x96, 0x7f}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x5e, 0x26, 0x18, 0x8f, 0xb4, 0x5d, 0x09, 0x3f, 0x60, + 0x67, 0xff, 0x5c, 0x4c, 0x14, 0xe0, 0x43, 0x35, 0xc2, + 0xdd, 0x74, 0x67, 0x19, 0x53, 0xe9}, + .plen = 24, + .ciphertext = {0x49, 0x2a, 0x36, 0xf8, 0x13, 0xd1, 0x99, 0xd3, 0x11, + 0x21, 0xe5, 0x37, 0x9a, 0xf9, 0xa8, 0x20, 0x51, 0x90, + 0xf4, 0x38, 0xbb, 0x18, 0x03, 0x06}, + .clen = 24, + .num_chunks = 3, + .chunks = {12, 0, 12}, + }, { // #3 + .key = {0xbf, 0x13, 0x92, 0x07, 0x86, 0x6b, 0xb6, 0x5d, 0xe9, + 0x76, 0xa8, 0x70, 0x2f, 0x23, 0x64, 0x34, 0xb3, 0xdc, + 0xc8, 0x37, 0x08, 0x23, 0x52, 0xc2}, + .klen = 24, + .iv = {0x4c, 0xd5, 0xe1, 0xf5, 0x82, 0x2b, 0x32, 0x4c}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0xaa, 0xed, 0x11, 0xce, 0x4c, 0x1e, 0x77, 0xee, 0x37, + 0xbc, 0xbc, 0x01, 0x98, 0x14, 0x88, 0x60, 0x6d, 0xf7, + 0xf8, 0x06, 0xde, 0xbe, 0x93, 0xaa, 0xd1, 0x8a, 0x80, + 0x2b, 0xb9, 0xd1, 0xf6, 0x31}, + .plen = 32, + .ciphertext = {0x84, 0xab, 0xa2, 0x7a, 0xf1, 0x2f, 0x6c, 0xf9, 0x6e, + 0x1d, 0xc8, 0x85, 0xb2, 0x79, 0xda, 0xb0, 0xba, 0x88, + 0x7c, 0x96, 0xb3, 0xbb, 0x0d, 0x29, 0x0d, 0x54, 0x0f, + 0xa8, 0x96, 0x6a, 0x6e, 0x2d}, + .clen = 32, + .num_chunks = 4, + .chunks = {8, 8, 8, 8}, + }, { // #4 + .key = {0x89, 0xb0, 0x9e, 0x9b, 0x8c, 0x73, 0x37, 0x79, 0xe5, + 0xcd, 0x01, 0x94, 0x83, 0x20, 0xb3, 0xb0, 0x75, 0xc4, + 0x3e, 0x3d, 0xe6, 0x32, 0xe3, 0xc4}, + .klen = 24, + .iv = {0x37, 0x61, 0x25, 0x03, 0x1f, 0x18, 0xf6, 0xf0}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x88, 0x2c, 0x7a, 0x11, 0x39, 0xa5, 0xa8, 0xfd, 0x56, + 0xf1, 0x1d, 0xd0, 0x86, 0xa7, 0x65, 0xf7, 0x52, 0xc1, + 0xe5, 0x54, 0xe3, 0x4d, 0xbe, 0x92, 0x0d, 0x65, 0xf4, + 0xb6, 0x8d, 0x60, 0xd0, 0xf7, 0x8f, 0x4a, 0x82, 0xd0, + 0x74, 0x92, 0x0b, 0x53}, + .plen = 40, + .ciphertext = {0xe8, 0xd9, 0x04, 0x39, 0xe3, 0x06, 0xc3, 0xe3, 0xe9, + 0x46, 0x00, 0x39, 0xfd, 0x21, 0x4f, 0x00, 0xf7, 0xef, + 0xfc, 0x0b, 0x59, 0xb6, 0x01, 0x93, 0xe6, 0x1c, 0x6e, + 0x28, 0xa9, 0xf4, 0xfb, 0xd3, 0x39, 0x25, 0x23, 0x1e, + 0x48, 0x8a, 0x52, 0xd2}, + .clen = 40, + .num_chunks = 3, + .chunks = {20, -1, 20}, + }, { // #5 + .key = {0xa4, 0x40, 0xba, 0x91, 0xba, 0xe5, 0x62, 0x19, 0x1f, + 0x97, 0xdf, 0x58, 0xae, 0x58, 0x7c, 0x19, 0x89, 0x75, + 0xd3, 0x45, 0x73, 0xcb, 0xcb, 0xa4}, + .klen = 24, + .iv = {0x0b, 0x39, 0x33, 0x67, 0x57, 0x11, 0xb1, 0x15}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x80, 0xee, 0x89, 0xf4, 0x2d, 0x88, 0x11, 0x9b, 0xbc, + 0x87, 0x4f, 0x70, 0xd3, 0xc7, 0x3e, 0xd2, 0x5d, 0x59, + 0x3f, 0xf1, 0xdc, 0x83, 0x0b, 0xee, 0x00, 0x07, 0xec, + 0x3e, 0x78, 0xa8, 0x2d, 0x50, 0x08, 0xeb, 0xce, 0x6f, + 0xdc, 0x1b, 0x7d, 0xe9, 0x1c, 0x8f, 0xc2, 0x71, 0xc0, + 0x30, 0x7a, 0xc2}, + .plen = 48, + .ciphertext = {0xbb, 0x2b, 0x2f, 0xb1, 0x88, 0xba, 0x69, 0xda, 0x7c, + 0xc5, 0x2b, 0x01, 0x60, 0x7d, 0x3d, 0x15, 0x42, 0x24, + 0x9d, 0x0b, 0x11, 0xec, 0x27, 0xcc, 0x6c, 0x6f, 0xc7, + 0x3f, 0x0f, 0x28, 0x23, 0xe0, 0xae, 0xea, 0xc4, 0x8e, + 0x30, 0xc6, 0x66, 0x74, 0x02, 0x02, 0xfe, 0x93, 0x70, + 0xa5, 0x19, 0x0d}, + .clen = 48, + }, { // #6 + .key = {0x64, 0x13, 0x20, 0x94, 0x8a, 0x29, 0x85, 0xc2, 0xec, + 0xec, 0x0d, 0xfb, 0x34, 0xb9, 0x04, 0x45, 0x75, 0xfb, + 0x2a, 0x0b, 0x10, 0x3b, 0x75, 0x51}, + .klen = 24, + .iv = {0x9a, 0xc0, 0x63, 0x68, 0xfa, 0x0e, 0x64, 0xe0}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0xea, 0x00, 0xb3, 0x66, 0xd3, 0x2d, 0xae, 0x2d, 0x9c, + 0xba, 0x94, 0x15, 0x54, 0x84, 0x9c, 0x0f, 0x76, 0x2e, + 0xac, 0xf3, 0xc9, 0x73, 0x64, 0x75, 0x85, 0xba, 0x5e, + 0x56, 0xb7, 0xeb, 0xb4, 0xd7, 0xe6, 0x82, 0xc3, 0x73, + 0xf7, 0xe2, 0x2f, 0xcd, 0x4e, 0xeb, 0x28, 0xe8, 0x36, + 0xce, 0xeb, 0x96, 0x83, 0x20, 0x8b, 0x33, 0x76, 0x2e, + 0xf1, 0x92}, + .plen = 56, + .ciphertext = {0xb3, 0x19, 0x40, 0xc4, 0xdd, 0x1d, 0x84, 0xfd, 0x6f, + 0xda, 0x95, 0x3c, 0x11, 0x7f, 0x1f, 0x20, 0xe5, 0x80, + 0xc2, 0xd1, 0x8f, 0x4e, 0xfe, 0x39, 0xfc, 0x15, 0xe4, + 0xc5, 0x5a, 0xee, 0x88, 0x6a, 0x65, 0x15, 0x5b, 0x4b, + 0x43, 0x4a, 0xb7, 0x29, 0xeb, 0x25, 0xd8, 0x9c, 0x69, + 0xb4, 0xd5, 0xc9, 0x3a, 0x66, 0x25, 0xf8, 0x80, 0x32, + 0xae, 0xe3}, + .clen = 56, + .num_chunks = 4, + .chunks = {16, 16, 16, 8}, + }, { // #7 + .key = {0x2c, 0xfb, 0xbc, 0x62, 0x5b, 0xad, 0x3e, 0x54, 0xe6, + 0x01, 0xf2, 0x52, 0xc4, 0x20, 0xa8, 0x34, 0x13, 0xe9, + 0x2a, 0x46, 0xc1, 0xa7, 0xe5, 0x86}, + .klen = 24, + .iv = {0xba, 0xda, 0x00, 0xb1, 0x23, 0x6c, 0x22, 0xfa}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x70, 0xa8, 0x94, 0x85, 0x40, 0x56, 0x75, 0x66, 0x54, + 0x36, 0xb9, 0x27, 0xad, 0x9b, 0x7e, 0x3d, 0x7c, 0x3e, + 0xa8, 0xcf, 0xda, 0x25, 0x30, 0xbd, 0xb9, 0xc9, 0xbe, + 0xe2, 0x1b, 0x77, 0x7b, 0x96, 0x82, 0xf7, 0x20, 0x77, + 0xa7, 0x6c, 0x54, 0x6a, 0x6e, 0x7b, 0x34, 0xdc, 0x1a, + 0xaf, 0x33, 0x4e, 0xbd, 0x1c, 0x24, 0x10, 0xf3, 0x43, + 0x95, 0x4c, 0xd0, 0x36, 0x5f, 0x47, 0x17, 0xfd, 0x7b, + 0xe4}, + .plen = 64, + .ciphertext = {0x51, 0xde, 0x0e, 0x2f, 0xee, 0x09, 0xc6, 0x0d, 0xa1, + 0x97, 0x13, 0xa6, 0xcd, 0x1b, 0x82, 0x1f, 0xb2, 0xa2, + 0x3f, 0xd7, 0xb4, 0x80, 0x76, 0xd2, 0xe0, 0x9d, 0xd7, + 0x5f, 0x69, 0x2a, 0x29, 0x5f, 0x1c, 0xda, 0x91, 0xe2, + 0x3e, 0x83, 0x52, 0x26, 0x6e, 0x1e, 0x7c, 0x85, 0x38, + 0x61, 0xe8, 0xf4, 0x0c, 0xf3, 0x72, 0x56, 0x0c, 0x94, + 0x92, 0x4e, 0xd9, 0xfd, 0x5e, 0xdc, 0x49, 0x7b, 0xf5, + 0xeb}, + .clen = 64, + .num_chunks = 4, + .chunks = {32, 0, -1, 32}, + }, { // #8 + .key = {0xb3, 0xae, 0x76, 0x13, 0xc4, 0xd0, 0x3b, 0x7a, 0x23, + 0x58, 0x8a, 0x6e, 0x7c, 0x9b, 0x1f, 0xe5, 0x6e, 0x43, + 0x58, 0x8f, 0xf7, 0x4f, 0x8a, 0x32}, + .klen = 24, + .iv = {0x89, 0x62, 0x65, 0xe4, 0x3e, 0x5a, 0x7b, 0xea}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0x01, 0xa7, 0x68, 0xf8, 0x00, 0x2e, 0x80, 0xe8, 0xc7, + 0x5b, 0xbc, 0x2d, 0x48, 0x1d, 0xdb, 0xdc, 0x5b, 0xc6, + 0x7d, 0x61, 0xc9, 0xc7, 0xdb, 0x66, 0xa3, 0xbb, 0xb4, + 0xf7, 0xd9, 0xa8, 0x8b, 0xe3, 0x07, 0x81, 0x0f, 0x65, + 0x92, 0xef, 0xdb, 0x03, 0xf4, 0x50, 0x5f, 0xb7, 0x54, + 0x01, 0x1e, 0x4d, 0x5a, 0xd8, 0x1b, 0x0c, 0x41, 0xf5, + 0x8d, 0x98, 0x2e, 0xbb, 0xda, 0x17, 0xc0, 0x19, 0xc3, + 0x93, 0xe8, 0x0e, 0xdc, 0x9f, 0xfb, 0x6c, 0x40, 0x3e}, + .plen = 72, + .ciphertext = {0x92, 0xfb, 0xd9, 0x0d, 0xc8, 0x61, 0x5a, 0xef, 0x01, + 0x6a, 0x1a, 0x43, 0x3f, 0xd8, 0xc5, 0x6a, 0xfa, 0x8d, + 0x25, 0x68, 0x25, 0xae, 0x50, 0xad, 0x85, 0x59, 0xff, + 0x5d, 0xcc, 0xfc, 0xe4, 0x2e, 0x56, 0xc3, 0xef, 0x8d, + 0x7e, 0xbf, 0x6a, 0x75, 0x97, 0xfd, 0x0e, 0x95, 0x3b, + 0x0c, 0x00, 0xa0, 0x22, 0xbc, 0xaa, 0xd9, 0x2c, 0xbc, + 0x17, 0x2c, 0xc7, 0x9e, 0xf5, 0xf9, 0x41, 0xb6, 0xe0, + 0x7e, 0xc7, 0xe1, 0xc2, 0x71, 0x6a, 0x93, 0x9a, 0x7d}, + .clen = 72, + .num_chunks = 5, + .chunks = {5, 20, -1, 17, 30}, + }, { // #9 + .key = {0x13, 0xf1, 0x0b, 0xc8, 0xd5, 0x98, 0x7c, 0x6d, 0x97, + 0x0d, 0xe6, 0xd6, 0x01, 0x52, 0xdc, 0xe6, 0xda, 0x3b, + 0x3b, 0x04, 0xb5, 0x2c, 0x20, 0x5d}, + .klen = 24, + .iv = {0x9d, 0x99, 0x5c, 0x62, 0x11, 0xb4, 0xec, 0x4d}, + .ivlen = DES3_IV_SIZE, + .plaintext = {0xb6, 0x94, 0xeb, 0x44, 0x89, 0x7b, 0x59, 0xd3, 0x97, + 0x65, 0x9d, 0x3b, 0x00, 0x81, 0x80, 0x35, 0x6f, 0x64, + 0x8a, 0x34, 0x54, 0x46, 0x6a, 0x3e, 0x74, 0x6f, 0x99, + 0xfb, 0xa4, 0xec, 0x3b, 0x0c, 0xd1, 0x86, 0x46, 0x9d, + 0x44, 0xf5, 0xe5, 0x3e, 0x24, 0x50, 0x1f, 0xee, 0x3d, + 0xc8, 0xb4, 0x79, 0xff, 0x96, 0x47, 0x05, 0xca, 0x32, + 0xc2, 0xe7, 0x69, 0xc6, 0xf7, 0xbb, 0xdc, 0xe2, 0x83, + 0xb3, 0x5a, 0x71, 0xf8, 0x2f, 0x96, 0xec, 0x3b, 0x8e, + 0x42, 0xcd, 0x2a, 0x44, 0xd1, 0x47, 0x82, 0x2d}, + .plen = 80, + .ciphertext = {0xa5, 0xf7, 0xee, 0xe8, 0x26, 0xee, 0x1e, 0x8b, 0xcb, + 0x77, 0xd2, 0xef, 0x6f, 0xfb, 0x56, 0xc9, 0xa3, 0xa5, + 0x43, 0xc4, 0xfd, 0x89, 0xa0, 0x6b, 0x4f, 0x26, 0x5b, + 0xda, 0xab, 0x1c, 0x2c, 0x03, 0xb6, 0x6c, 0x51, 0x43, + 0x9a, 0xd4, 0x14, 0xf5, 0x2a, 0x4f, 0xcb, 0xac, 0xea, + 0x83, 0x3a, 0x33, 0xd1, 0x61, 0x0f, 0x80, 0xf9, 0x33, + 0xab, 0x90, 0x0e, 0xc0, 0x47, 0x33, 0x4f, 0xd3, 0x3f, + 0xaf, 0xc5, 0xc2, 0x59, 0x17, 0x40, 0x9f, 0x01, 0xe0, + 0x47, 0xbb, 0x83, 0x28, 0x35, 0x2f, 0x7c, 0x45}, + .clen = 80, + .num_chunks = 2, + .chunks = {40, 40}, + } +}; + +/** + * NIST Special Publication 800-38B + * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/ + * CAVP-TESTING-BLOCK-CIPHER-MODES#CMAC + **/ +static struct cmac_test_vector des2_cmac_tv[] = { + { // 0 (0) + .key = { 0xdc,0x04,0x73,0x68,0x02,0x32,0x52,0xd9,0x0e, + 0xbc,0xcd,0xc2,0x16,0x61,0xe3,0xab }, + .klen = 16, + .msg = { 0x00 }, + .mlen = 0, + .mac = { 0x72,0x61,0x9d,0xc7,0xda }, + .tlen = 5, + }, { // 1 (1) + .key = { 0x76,0xfd,0x92,0x07,0x04,0x29,0xd3,0x3d,0x29, + 0x02,0x9b,0x46,0x1a,0x8a,0x2f,0x57 }, + .klen = 16, + .msg = { 0x00 }, + .mlen = 0, + .mac = { 0x63,0x92,0x98,0x77,0xf1 }, + .tlen = 5, + .chunks_msg = { 0, 0 }, + .num_chunks_message = 2, + }, { // 2 (8) + .key = { 0x3d,0x4c,0xf2,0x64,0x13,0x76,0xae,0xc2,0x13, + 0xa8,0x26,0x5d,0x52,0x9b,0x7a,0x20 }, + .klen = 16, + .msg = { 0x00 }, + .mlen = 0, + .mac = { 0xcd,0xd2,0xe2,0xc8,0x49,0x31,0xc1 }, + .tlen = 7, + }, { // 3 (16) + .key = { 0xd3,0x94,0x8a,0xa4,0x52,0x7a,0xe5,0xba,0x1a, + 0x54,0x32,0xe9,0x08,0x54,0x10,0xdc }, + .klen = 16, + .msg = { 0x39,0x2e,0x55,0x79,0x30,0xd3,0x04,0xd5 }, + .mlen = 8, + .mac = { 0x0c,0x01,0x23,0x3c,0x9a }, + .tlen = 5, + }, { // 4 (17) + .key = { 0xe6,0x2f,0x08,0xd0,0x26,0x04,0xfd,0xcb,0x2c, + 0x16,0x6d,0x62,0x0e,0x10,0xe5,0x07 }, + .klen = 16, + .msg = { 0x95,0x84,0x8f,0x94,0x05,0x62,0xae,0x51 }, + .mlen = 8, + .mac = { 0x87,0x6d,0x6a,0x38,0x69 }, + .tlen = 5, + .chunks_msg = { 4, 4 }, + .num_chunks_message = 2, + }, { // 5 (32) + .key = { 0x5d,0xb9,0xb0,0xd6,0xb5,0xd9,0x25,0x46,0x86, + 0x1c,0xbf,0x5b,0xf8,0xf2,0xf1,0xe6 }, + .klen = 16, + .msg = { 0xeb,0x00,0x22,0x4e,0x03,0x65,0x2e,0xb1,0x84, + 0x2a,0x47,0x73,0x54,0xae,0x19,0x1f }, + .mlen = 16, + .mac = { 0x61,0x75,0xa0,0xf3,0x6f }, + .tlen = 5, + }, { // 6 (33) + .key = { 0x51,0x1c,0x68,0x25,0xfb,0x97,0xda,0x70,0x70, + 0xb5,0xd5,0x19,0x0b,0xec,0x49,0x9e }, + .klen = 16, + .msg = { 0x25,0xd8,0x7c,0x44,0x02,0xf3,0x4e,0xa5,0x9b, + 0x38,0x98,0xbe,0xaa,0x40,0x1e,0x96 }, + .mlen = 16, + .mac = { 0x18,0x76,0xc6,0xa2,0x72 }, + .tlen = 5, + .chunks_msg = { 5, 5, 6 }, + .num_chunks_message = 3, + }, { // 7 (40) + .key = { 0xb9,0x02,0x6e,0xba,0xda,0x62,0x38,0xd9,0x20, + 0x7f,0x07,0x3e,0x1c,0x1c,0xb6,0xd5 }, + .klen = 16, + .msg = { 0x23,0x32,0x82,0xca,0x3e,0x2a,0xfc,0x6f,0x4c, + 0x47,0x13,0x26,0x75,0x1e,0xd2,0x5a }, + .mlen = 16, + .mac = { 0xfe,0x6a,0xc1,0xbf,0x3a,0x15,0x89 }, + .tlen = 7, + }, { // 8 (48) + .key = { 0xc2,0x75,0x57,0x76,0xb0,0x6e,0x67,0x97,0x26, + 0x1a,0xef,0x15,0xa1,0x38,0x38,0x8f }, + .klen = 16, + .msg = { 0x30,0x94,0xb1,0x6e,0x28,0x99,0x1c }, + .mlen = 7, + .mac = { 0x15,0xa3,0x7f,0x1a,0x7b }, + .tlen = 5, + }, { // 9 (49) + .key = { 0xf8,0xf1,0x49,0x2c,0xb5,0xae,0x70,0xcd,0x5e, + 0x97,0x94,0x19,0xc8,0xfb,0xc7,0xad }, + .klen = 16, + .msg = { 0x53,0x53,0x4f,0x17,0x77,0x5c,0x0e }, + .mlen = 7, + .mac = { 0x2c,0x2a,0x55,0x32,0x96 }, + .tlen = 5, + .chunks_msg = { 3, 4 }, + .num_chunks_message = 2, + }, { // 10 (64) + .key = { 0x04,0x13,0xb3,0x67,0xc2,0xbf,0x49,0x1f,0x5e, + 0xea,0xb5,0x40,0x43,0xfe,0x7f,0x16 }, + .klen = 16, + .msg = { 0x70,0xb2,0xdb,0xfe,0x6d,0x89,0x2a,0xd8,0xd0, + 0xd0,0x48,0xec,0x8a,0x04,0xc9 }, + .mlen = 15, + .mac = { 0xd5,0x25,0xaa,0x36,0x43 }, + .tlen = 5, + } +}; + +/** + * NIST Special Publication 800-38B + * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/ + * CAVP-TESTING-BLOCK-CIPHER-MODES#CMAC + **/ +static struct cmac_test_vector des3_cmac_tv[] = { + { // 0 (0) + .key = { 0xc4,0x79,0xf8,0x13,0xad,0x1a,0x45,0xd5,0xdc, + 0x43,0x45,0x9d,0xa4,0xc8,0x5e,0x85,0x1c,0xda, + 0x51,0x8a,0xf8,0x86,0xbf,0x1f }, + .klen = 24, + .msg = { 0x00 }, + .mlen = 0, + .mac = { 0xfe,0xa0,0x1c,0x84,0xa7 }, + .tlen = 5, + }, { // 1 (1) + .key = { 0x73,0x13,0x31,0x86,0x67,0x54,0x58,0x8f,0xd3, + 0x32,0xef,0x51,0xe0,0xce,0x19,0x25,0xd5,0x86, + 0xcb,0xa7,0x04,0x40,0xf4,0x4f }, + .klen = 24, + .msg = { 0x00 }, + .mlen = 0, + .mac = { 0x16,0x4b,0xdb,0x85,0x82 }, + .tlen = 5, + .chunks_msg = { 0, 0 }, + .num_chunks_message = 2, + }, { // 2 (8) + .key = { 0xf8,0x7c,0x4c,0x3d,0xf7,0x1f,0xd9,0x8c,0xe5, + 0x32,0xf4,0x1f,0xfe,0x31,0x58,0x20,0x51,0x4f, + 0xad,0x7c,0x7a,0xae,0x2f,0x46 }, + .klen = 24, + .msg = { 0x00 }, + .mlen = 0, + .mac = { 0x19,0xfb,0xd3,0xdc,0x15,0x4b,0xc1,0x39 }, + .tlen = 8, + }, { // 3 (16) + .key = { 0xd9,0x61,0xb6,0xd5,0x57,0xae,0xba,0x4a,0x0e, + 0xc1,0xbf,0xf2,0x79,0x7a,0xdf,0xda,0x04,0x70, + 0x61,0x68,0x83,0x92,0x76,0xfe }, + .klen = 24, + .msg = { 0xd7,0x68,0x97,0x5c,0x45,0x4f,0x93,0x90,0x6c, + 0xd3,0x5e,0x6a,0x6d,0x5f,0x44,0x53 }, + .mlen = 16, + .mac = { 0x96,0x72,0x52,0xe4,0xf3 }, + .tlen = 5, + }, { // 4 (17) + .key = { 0xdf,0x10,0xfb,0x6b,0x76,0x6e,0xab,0x34,0xd5, + 0xcb,0x75,0x79,0x58,0x2f,0xb6,0xa8,0x02,0x5e, + 0x45,0x9b,0xb3,0x8f,0x43,0x37 }, + .klen = 24, + .msg = { 0x35,0x07,0x23,0xc4,0xf1,0x67,0x7f,0x7b,0xac, + 0xdb,0x78,0xd1,0x2a,0x22,0xa1,0x9b }, + .mlen = 16, + .mac = { 0xb4,0xd9,0x1d,0x08,0xe4 }, + .tlen = 5, + .chunks_msg = { 5, 5, 6 }, + .num_chunks_message = 3, + }, { // 5 (24) + .key = { 0x01,0xc1,0x25,0xc2,0x79,0xcb,0xe9,0x0d,0xdf, + 0xc2,0xc1,0xb0,0x4c,0xa8,0xae,0x49,0x16,0x16, + 0xad,0x64,0x43,0x3d,0x83,0x4a }, + .klen = 24, + .msg = { 0x0a,0x25,0x8b,0x67,0x19,0xe2,0xe0,0x07,0x9b, + 0x78,0x0a,0x08,0x63,0xff,0x11,0x5b }, + .mlen = 16, + .mac = { 0xa7,0xbc,0xbe,0x72,0x0a,0xc2,0xa7,0xe5 }, + .tlen = 8, + }, { // 6 (32) + .key = { 0xe6,0xe0,0xd5,0xfd,0x61,0xda,0xe3,0x15,0x5b, + 0x32,0x98,0x0e,0x70,0xe6,0xd6,0x7f,0xd9,0x9d, + 0x8f,0xf4,0x34,0x8f,0xe9,0x8f }, + .klen = 24, + .msg = { 0xe4,0x3b,0xd4,0x9c,0x39,0x76,0xaf,0xa7,0x8a, + 0x71,0x38,0xdd,0xab,0xfa,0x13,0x2a,0x72,0xe7, + 0xd1,0xa4,0x22,0xb4,0x0a,0x58,0x2a,0x6d,0xac, + 0x4a,0x10,0xce,0x92,0xb7 }, + .mlen = 32, + .mac = { 0xd4,0x4f,0x71,0x0b,0x81 }, + .tlen = 5, + }, { // 7 (33) + .key = { 0x20,0x40,0x40,0xce,0x67,0x10,0x2c,0x3b,0x31, + 0x29,0x43,0x5d,0x8a,0x85,0x3d,0x91,0x6d,0x37, + 0x8a,0x2c,0x68,0x76,0x70,0xd3 }, + .klen = 24, + .msg = { 0x9b,0x75,0x8b,0xc9,0x3d,0x48,0x25,0x05,0xb1, + 0xb7,0xb6,0xf1,0x47,0x20,0x3a,0x72,0xe8,0x1b, + 0xf1,0x90,0x04,0xa5,0xfa,0xc1,0xcb,0x7e,0x23, + 0x6a,0xa0,0xcf,0x00,0xa3 }, + .mlen = 32, + .mac = { 0x49,0x00,0x1a,0x2a,0x10 }, + .tlen = 5, + .chunks_msg = { 10, 10, 10, 2 }, + .num_chunks_message = 4, + }, { // 8 (48) + .key = { 0xef,0x0d,0x5e,0x94,0xe5,0xc8,0x89,0x34,0xbf, + 0xcb,0xb5,0x80,0x67,0x08,0x97,0x4a,0x70,0xc1, + 0x4a,0x70,0x31,0x02,0x3d,0xb0 }, + .klen = 24, + .msg = { 0x8d,0x32,0x44,0xbd,0x36,0x4e,0xea,0x1f,0x53 }, + .mlen = 9, + .mac = { 0x65,0x52,0x7e,0xeb,0x1b }, + .tlen = 5, + }, { // 9 (49) + .key = { 0xdf,0xd6,0xd0,0xb0,0x58,0x75,0x1f,0xa1,0x7a, + 0x1f,0xd6,0x73,0x45,0x16,0x3d,0xa1,0x37,0xad, + 0x25,0x1f,0x3e,0x1f,0x70,0x8a }, + .klen = 24, + .msg = { 0x9a,0xa7,0xd5,0xfb,0x6b,0xa2,0xd8,0x55,0x75 }, + .mlen = 9, + .mac = { 0x5c,0x08,0x41,0x49,0x31 }, + .tlen = 5, + .chunks_msg = { 4, 5 }, + .num_chunks_message = 2, + }, { // 10 (56) + .key = { 0x9e,0x98,0xd0,0x2a,0xc8,0xda,0x0d,0xa8,0x38, + 0x20,0xda,0x43,0x83,0xce,0x6e,0xea,0x16,0x19, + 0xa4,0x7f,0xe0,0xa1,0xa1,0x13 }, + .klen = 24, + .msg = { 0xa1,0xb0,0xd3,0x65,0xea,0x1b,0xfb,0xf0,0x84 }, + .mlen = 9, + .mac = { 0x9c,0xf6,0xad,0x27,0xde,0xb8,0x4e,0xe7 }, + .tlen = 8, + }, { // 11 (64) + .key = { 0xea,0x5e,0xc8,0x6b,0x61,0x9d,0x7a,0x58,0xbf, + 0x7c,0x75,0xdf,0xdc,0xa7,0xb6,0x25,0x3d,0xf8, + 0xd5,0x40,0x73,0x23,0x38,0xb6 }, + .klen = 24, + .msg = { 0x4c,0xdb,0x3b,0x20,0xd6,0x33,0x8b,0x67,0x96, + 0x71,0x99,0x23,0xf4,0xeb,0xb8,0x6b,0x74 }, + .mlen = 17, + .mac = { 0x46,0xe2,0xd2,0xa7,0x8c }, + .tlen = 5, + }, { // 12 (65) + .key = { 0xa1,0xad,0xe6,0x13,0x37,0x43,0x5e,0x3b,0xd3, + 0xd6,0x43,0x49,0x45,0x4c,0xab,0xe5,0x62,0x45, + 0x25,0x62,0xc4,0x38,0x34,0xae }, + .klen = 24, + .msg = { 0x35,0x94,0x21,0xe9,0xf7,0x8c,0xc4,0xa3,0x1f, + 0x4f,0x01,0x99,0x77,0xd7,0xfd,0x29,0x78 }, + .mlen = 17, + .mac = { 0xff,0x99,0xe6,0xcc,0x7c }, + .tlen = 5, + .chunks_msg = { 7, 10 }, + .num_chunks_message = 2, + }, { // 13 (80) + .key = { 0x3e,0x7f,0xf2,0xe9,0x3e,0x01,0x26,0x58,0xbf, + 0x97,0x79,0x0e,0x49,0x8c,0x23,0xad,0xd3,0x52, + 0xcd,0x26,0xb3,0x64,0xbf,0x19 }, + .klen = 24, + .msg = { 0x75,0x55,0x98,0x98,0xf4,0xba,0x03,0xc5,0x5a, + 0xfc,0x25,0xea,0x91,0xaa,0x61,0xa9,0x3c,0x2f, + 0x82,0x70,0xa5,0xfa,0x51,0xb6,0xf6,0xdc,0x68, + 0x81,0xad,0xb1,0x41,0x2c }, + .mlen = 32, + .mac = { 0xe4,0x21,0xb4,0x30,0x74 }, + .tlen = 5, + } +}; + + +#define NUM_OF_PUBLISHED_TESTSUITES 5 + +struct published_test_suite_info published_test_suites[] = { + { + .name = "DES3_ECB", + .tvcount = 10, + .tv = des3_ecb_tv, + .size = DES3_BLOCK_SIZE, + .mechanism = CKM_DES3_ECB, + }, { + .name = "DES3_CBC", + .tvcount = 10, + .tv = des3_cbc_tv, + .size = DES3_BLOCK_SIZE, + .mechanism = CKM_DES3_CBC, + }, { + .name = "DES3_CFB8", + .tvcount = 10, + .tv = des3_cfb8_tv, + .size = 1, + .mechanism = CKM_DES_CFB8, + }, { + .name = "DES3_CFB64", + .tvcount = 10, + .tv = des3_cfb64_tv, + .size = DES3_BLOCK_SIZE, + .mechanism = CKM_DES_CFB64, + }, { + .name = "DES3_OFB64", + .tvcount = 10, + .tv = des3_ofb64_tv, + .size = DES3_BLOCK_SIZE, + .mechanism = CKM_DES_OFB64, + } +}; + +#define NUM_OF_GENERATED_TESTSUITES 3 + +static struct generated_test_suite_info generated_test_suites[] = { + { + .name = "DES3_ECB", + .mech = {CKM_DES3_ECB, 0, 0}, + }, { + .name = "DES3_CBC", + .mech = {CKM_DES3_CBC, &des3_cbc_iv, DES3_IV_SIZE}, + }, { + .name = "DES3_CBC_PAD", + .mech = {CKM_DES3_CBC_PAD, &des3_cbc_iv, DES3_IV_SIZE}, + } +}; + +#define NUM_OF_PUBLISHED_CMAC_TESTSUITES 5 + +struct published_cmac_test_suite_info published_cmac_test_suites[] = { + { + .name = "2DES_CMAC_GENERAL", + .tvcount = 11, + .tv = des2_cmac_tv, + .mech = {CKM_DES3_CMAC_GENERAL, 0, 0}, + .key_type = CKK_DES2, + }, { + .name = "3DES_CMAC_GENERAL", + .tvcount = 14, + .tv = des3_cmac_tv, + .mech = {CKM_DES3_CMAC_GENERAL, 0, 0}, + .key_type = CKK_DES3, + }, { + .name = "2DES_CMAC", + .tvcount = 11, + .tv = des2_cmac_tv, + .mech = {CKM_DES3_CMAC, 0, 0}, + .key_type = CKK_DES2, + }, { + .name = "3DES_CMAC", + .tvcount = 14, + .tv = des3_cmac_tv, + .mech = {CKM_DES3_CMAC, 0, 0}, + .key_type = CKK_DES3, + }, { + .name = "IBM-CMAC", + .tvcount = 14, + .tv = des3_cmac_tv, + .mech = {CKM_IBM_CMAC, 0, 0}, + .key_type = CKK_DES3, + } +}; diff --git a/testcases/crypto/des3_func.c b/testcases/crypto/des3_func.c new file mode 100644 index 0000000..7f564a7 --- /dev/null +++ b/testcases/crypto/des3_func.c @@ -0,0 +1,1376 @@ +/* + * 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 + */ + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "des3.h" +#include "common.c" +#include "mech_to_str.h" + +/** Tests triple DES encryption with published test vectors. **/ +CK_RV do_EncryptDES3(struct published_test_suite_info *tsuite) +{ + unsigned int i; // test vector index + CK_BYTE expected[BIG_REQUEST]; // encrypted data + CK_BYTE actual[BIG_REQUEST]; // encryption buffer + CK_ULONG expected_len, actual_len, original_len, k; + + CK_SLOT_ID slot_id = SLOT_ID; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_OBJECT_HANDLE h_key; + CK_RV rc; + CK_FLAGS flags; + + + /** begin testsuite **/ + testsuite_begin("%s Encryption.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip testsuite if the slot does not support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mechanism), + (unsigned int) tsuite->mechanism); + goto testcase_cleanup; + } + + /** iterate over test vectors **/ + for (i = 0; i < tsuite->tvcount; i++) { + + testcase_begin("%s Encryption with test vector %d", tsuite->name, i); + + rc = CKR_OK; // set rc + + /** clear buffers **/ + memset(expected, 0, sizeof(expected)); + memset(actual, 0, sizeof(actual)); + + /** get ciphertext (expected results) **/ + memcpy(expected, tsuite->tv[i].ciphertext, tsuite->tv[i].clen); + expected_len = tsuite->tv[i].clen; + + /** get plaintext **/ + memcpy(actual, tsuite->tv[i].plaintext, tsuite->tv[i].plen); + actual_len = original_len = k = tsuite->tv[i].plen; + + /** get mech **/ + mech.mechanism = tsuite->mechanism; + mech.ulParameterLen = tsuite->tv[i].ivlen; + mech.pParameter = tsuite->tv[i].iv; + + /** create key handle. **/ + rc = create_DES3Key(session, + tsuite->tv[i].key, tsuite->tv[i].klen, &h_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** initialize single (in-place) encryption **/ + rc = funcs->C_EncryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do single (in-place) encryption **/ + rc = funcs->C_Encrypt(session, actual, actual_len, actual, &actual_len); + if (rc != CKR_OK) { + testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare encryption results with expected results. **/ + rc = 0; + testcase_new_assertion(); + + if (actual_len != expected_len) { + testcase_fail("encrypted data length does not match " + "test vector's encrypted data length.\n" + "expected length=%ld, but found length=" "%ld\n", + expected_len, actual_len); + } else if (memcmp(actual, expected, expected_len)) { + testcase_fail("encrypted data does not match test " + "vector's encrypted data.\n"); + } else { + testcase_pass("%s Encryption with test vector " + "%d passed.", tsuite->name, i); + } + + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + goto testcase_cleanup; + +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Tests triple DES multipart encryption with published test vectors. **/ +CK_RV do_EncryptUpdateDES3(struct published_test_suite_info * tsuite) +{ + unsigned int i; // test vector index + CK_BYTE expected[BIG_REQUEST]; + CK_BYTE plaintext[BIG_REQUEST]; + CK_BYTE crypt[BIG_REQUEST]; + CK_ULONG expected_len, p_len, crypt_len, k; + + CK_SLOT_ID slot_id = SLOT_ID; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_OBJECT_HANDLE h_key; + CK_RV rc; + CK_FLAGS flags; + + /** begin testsuite **/ + testsuite_begin("%s Multipart Encryption.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip testuite if the slot does not support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mechanism), + (unsigned int) tsuite->mechanism); + goto testcase_cleanup; + } + + /** iterate over test vectors **/ + for (i = 0; i < tsuite->tvcount; i++) { + + /** begin testcase **/ + testcase_begin("%s Multipart Encryption with test vector %d.", + tsuite->name, i); + + rc = CKR_OK; // set rc + + + /** clear buffers **/ + memset(expected, 0, sizeof(expected)); + memset(crypt, 0, sizeof(crypt)); + memset(plaintext, 0, sizeof(plaintext)); + + /** get ciphertext (expected results) **/ + expected_len = tsuite->tv[i].clen; + memcpy(expected, tsuite->tv[i].ciphertext, expected_len); + + /** get plaintext **/ + p_len = k = tsuite->tv[i].plen; + memcpy(plaintext, tsuite->tv[i].plaintext, p_len); + + /** get mech **/ + mech.mechanism = tsuite->mechanism; + mech.ulParameterLen = tsuite->tv[i].ivlen; + mech.pParameter = tsuite->tv[i].iv; + + /** create key handle. **/ + rc = create_DES3Key(session, + tsuite->tv[i].key, tsuite->tv[i].klen, &h_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** initialize multipart (in-place) encryption **/ + rc = funcs->C_EncryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /* do multipart encryption + * for chunks, -1 is NULL, and 0 is empty string, + * and a value > 0 is amount of data from test vector's + * plaintext data. The is way we test input in various sizes. + */ + if (tsuite->tv[i].num_chunks) { + int j; + CK_ULONG outlen, len; + CK_BYTE *data_chunk = NULL; + + k = 0; + crypt_len = 0; + outlen = sizeof(crypt); + + for (j = 0; j < tsuite->tv[i].num_chunks; j++) { + if (tsuite->tv[i].chunks[j] == -1) { + len = 0; + data_chunk = NULL; + } else if (tsuite->tv[i].chunks[j] == 0) { + len = 0; + data_chunk = (CK_BYTE *) ""; + } else { + len = tsuite->tv[i].chunks[j]; + data_chunk = plaintext + k; + } + + rc = funcs->C_EncryptUpdate(session, data_chunk, + len, &crypt[crypt_len], &outlen); + if (rc != CKR_OK) { + testcase_error("C_EncryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + k += len; + crypt_len += outlen; + outlen = sizeof(crypt) - crypt_len; + } + } else { + crypt_len = sizeof(crypt); + rc = funcs->C_EncryptUpdate(session, plaintext, p_len, + crypt, &crypt_len); + if (rc != CKR_OK) { + testcase_error("C_EncryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + } + + k = sizeof(crypt) - crypt_len; + rc = funcs->C_EncryptFinal(session, &crypt[crypt_len], &k); + if (rc != CKR_OK) { + testcase_error("C_EncryptFinal rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare encryption results with expected results. **/ + testcase_new_assertion(); + + if (crypt_len != expected_len) { + testcase_fail("multipart encrypted data length does " + "not match test vector's encrypted data length.\n" + "expected length=%ld, but found length=%ld\n", + expected_len, crypt_len); + } else if (memcmp(crypt, expected, expected_len)) { + testcase_fail("multipart encrypted data does " + "not match test vector's encrypted data.\n"); + } else { + testcase_pass("%s Multipart Encryption with test vector" + " %d passed.", tsuite->name, i); + } + + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + goto testcase_cleanup; + +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Tests triple DES decryption with published test vectors. **/ +CK_RV do_DecryptDES3(struct published_test_suite_info * tsuite) +{ + unsigned int i; // test vector index + CK_BYTE expected[BIG_REQUEST]; // decrypted data + CK_BYTE actual[BIG_REQUEST]; // decryption buffer + CK_ULONG expected_len, actual_len; + + CK_SLOT_ID slot_id = SLOT_ID; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_OBJECT_HANDLE h_key; + CK_RV rc; + CK_FLAGS flags; + + /** begin testsuite **/ + testsuite_begin("%s Decryption.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + + /** skip test if the slot does not support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mechanism), + (unsigned int) tsuite->mechanism); + goto testcase_cleanup; + } + + /** iterate over test vectors **/ + for (i = 0; i < tsuite->tvcount; i++) { + + /** begin test **/ + testcase_begin("%s Decryption with test vector %d.", tsuite->name, i); + + rc = CKR_OK; // set rc + + /** clear buffers **/ + memset(expected, 0, sizeof(expected)); + memset(actual, 0, sizeof(actual)); + + /** get plaintext (expected result) **/ + expected_len = tsuite->tv[i].plen; + memcpy(expected, tsuite->tv[i].plaintext, expected_len); + + /** get ciphertext **/ + actual_len = tsuite->tv[i].clen; + memcpy(actual, tsuite->tv[i].ciphertext, actual_len); + + /** get mechanism **/ + mech.mechanism = tsuite->mechanism; + mech.ulParameterLen = tsuite->tv[i].ivlen; + mech.pParameter = tsuite->tv[i].iv; + + /** create key handle. **/ + rc = create_DES3Key(session, + tsuite->tv[i].key, tsuite->tv[i].klen, &h_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** initialize single (in-place) decryption **/ + rc = funcs->C_DecryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do single (in-place) decryption **/ + rc = funcs->C_Decrypt(session, actual, actual_len, actual, &actual_len); + if (rc != CKR_OK) { + testcase_error("C_Decrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare decryption results with expected results. **/ + testcase_new_assertion(); + + if (actual_len != expected_len) { + testcase_fail("decrypted data length does not match test " + "vector's decrypted data length.\nexpected length=" + "%ld, but found length=%ld\n", + expected_len, actual_len); + } else if (memcmp(actual, expected, expected_len)) { + testcase_fail("decrypted data does not match test " + "vector's decrypted data.\n"); + } else { + testcase_pass("%s Decryption with test vector %d " + "passed.", tsuite->name, i); + } + + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + goto testcase_cleanup; + +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Tests triple DES multipart decryption with published test vectors **/ +CK_RV do_DecryptUpdateDES3(struct published_test_suite_info * tsuite) +{ + unsigned int i; // test vector index + CK_BYTE expected[BIG_REQUEST]; + CK_BYTE cipher[BIG_REQUEST]; + CK_BYTE plaintext[BIG_REQUEST]; + CK_ULONG expected_len, p_len, cipher_len, k; + + CK_SLOT_ID slot_id = SLOT_ID; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_OBJECT_HANDLE h_key; + CK_RV rc; + CK_FLAGS flags; + + /** begin testsuite **/ + testsuite_begin("%s Decryption.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + + /** skip test if the slot does not support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mechanism), + (unsigned int) tsuite->mechanism); + goto testcase_cleanup; + } + + /** iterate over test vectors **/ + for (i = 0; i < tsuite->tvcount; i++) { + + /** begin test **/ + testcase_begin("%s Decryption with test vector %d.", tsuite->name, i); + + rc = CKR_OK; // set rc + + /** clear buffers **/ + memset(expected, 0, sizeof(expected)); + memset(cipher, 0, sizeof(cipher)); + memset(plaintext, 0, sizeof(plaintext)); + p_len = sizeof(plaintext); + + /** get plaintext (expected results) **/ + expected_len = tsuite->tv[i].plen; + memcpy(expected, tsuite->tv[i].plaintext, expected_len); + + /** get ciphertext **/ + cipher_len = k = tsuite->tv[i].clen; + memcpy(cipher, tsuite->tv[i].ciphertext, cipher_len); + + /** get mech **/ + mech.mechanism = tsuite->mechanism; + mech.ulParameterLen = tsuite->tv[i].ivlen; + mech.pParameter = tsuite->tv[i].iv; + + + /** create key handle. **/ + rc = create_DES3Key(session, + tsuite->tv[i].key, tsuite->tv[i].klen, &h_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** initialize multipart (in-place) decryption **/ + rc = funcs->C_DecryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /* do multipart encryption + * for chunks, -1 is NULL, and 0 is empty string, + * and a value > 0 is amount of data from test vector's + * plaintext data. The is way we test input in various sizes. + */ + if (tsuite->tv[i].num_chunks) { + int j; + CK_ULONG outlen, len; + CK_BYTE *data_chunk = NULL; + + k = 0; + p_len = 0; + outlen = sizeof(plaintext); + + for (j = 0; j < tsuite->tv[i].num_chunks; j++) { + if (tsuite->tv[i].chunks[j] == -1) { + len = 0; + data_chunk = NULL; + } else if (tsuite->tv[i].chunks[j] == 0) { + len = 0; + data_chunk = (CK_BYTE *) ""; + } else { + len = tsuite->tv[i].chunks[j]; + data_chunk = cipher + k; + } + rc = funcs->C_DecryptUpdate(session, data_chunk, + len, &plaintext[p_len], &outlen); + if (rc != CKR_OK) { + testcase_error("C_DecryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + k += len; + p_len += outlen; + outlen = sizeof(plaintext) - p_len; + } + } else { + p_len = sizeof(plaintext); + rc = funcs->C_DecryptUpdate(session, cipher, cipher_len, + plaintext, &p_len); + if (rc != CKR_OK) { + testcase_error("C_DecryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + } + + k = sizeof(plaintext) - p_len; + rc = funcs->C_DecryptFinal(session, &plaintext[p_len], &k); + if (rc != CKR_OK) { + testcase_error("C_DecryptFinal rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare decryption results with expected results. **/ + testcase_new_assertion(); + + if (p_len != expected_len) { + testcase_fail("decrypted multipart data length does " + "not match test vector's decrypted data " + "length.\nexpected length=%ld, but " + "found length=%ld\n", expected_len, p_len); + } else if (memcmp(plaintext, expected, expected_len)) { + testcase_fail("decrypted multipart data does not " + "match test vector's decrypted data.\n"); + } else { + testcase_pass("%s Multipart Decryption with test " + "vector %d passed.", tsuite->name, i); + } + + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + goto testcase_cleanup; + +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Tests triple DES encryption & decryption using generated keys **/ +CK_RV do_EncryptDecryptDES3(struct generated_test_suite_info * tsuite) +{ + unsigned int j; + CK_BYTE original[BIG_REQUEST]; + CK_BYTE crypt[BIG_REQUEST + DES3_BLOCK_SIZE]; + CK_BYTE decrypt[BIG_REQUEST + DES3_BLOCK_SIZE]; + CK_ULONG crypt_len, decrypt_len, original_len; + + CK_SLOT_ID slot_id = SLOT_ID; + CK_SESSION_HANDLE session; + CK_MECHANISM mech, mechkey; + CK_OBJECT_HANDLE h_key; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rc; + + /** begin test **/ + testcase_begin("%s Encryption/Decryption tests with key generation.", + tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip test if the slot does not support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testcase_skip("Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + /** clear buffers **/ + memset(original, 0, sizeof(original)); + memset(crypt, 0, sizeof(crypt)); + memset(decrypt, 0, sizeof(decrypt)); + + /** generate test data **/ + original_len = sizeof(original); + crypt_len = sizeof(crypt); + decrypt_len = sizeof(decrypt); + + for (j = 0; j < original_len; j++) + original[j] = j % 255; + + /** set mechanism for key gen **/ + mechkey = des3_keygen; + + /** generate key **/ + rc = funcs->C_GenerateKey(session, &mechkey, NULL, 0, &h_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** set mech for crypto **/ + mech = tsuite->mech; + + /** initialize single encryption **/ + rc = funcs->C_EncryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do single encryption **/ + rc = funcs->C_Encrypt(session, original, original_len, crypt, &crypt_len); + if (rc != CKR_OK) { + testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** initialize single decryption **/ + rc = funcs->C_DecryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do single decryption **/ + rc = funcs->C_Decrypt(session, crypt, crypt_len, decrypt, &decrypt_len); + if (rc != CKR_OK) { + testcase_error("C_Decrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare encryption/decryption results with expected results. **/ + testcase_new_assertion(); + + if (decrypt_len != original_len) { + testcase_fail("decrypted data length does not match original data " + "length.\nexpected length=%ld, but found length=%ld\n", + original_len, decrypt_len); + } else if (memcmp(decrypt, original, original_len)) { + testcase_fail("decrypted data does not match original data"); + } else { + testcase_pass("%s Encryption/Decryption test passed.", tsuite->name); + } + + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + } + + goto testcase_cleanup; + +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/* + * Tests triple DES multipart encryption & multipart + * decryption using generated keys. + */ +CK_RV do_EncryptDecryptUpdateDES3(struct generated_test_suite_info * tsuite) +{ + unsigned int i, j, k; + CK_BYTE original[BIG_REQUEST]; + CK_BYTE crypt[BIG_REQUEST + DES3_BLOCK_SIZE]; + CK_BYTE decrypt[BIG_REQUEST + DES3_BLOCK_SIZE]; + CK_ULONG crypt_len, decrypt_len, original_len, tmp; + + CK_SLOT_ID slot_id = SLOT_ID; + CK_SESSION_HANDLE session; + CK_MECHANISM mech, mechkey; + CK_OBJECT_HANDLE h_key; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rc; + + /** begin test **/ + testcase_begin("%s Multipart Encryption/Decryption tests with " + "key generation.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip test if the slot does not support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testcase_skip("Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + /** clear buffers **/ + memset(original, 0, sizeof(original)); + memset(crypt, 0, sizeof(crypt)); + memset(decrypt, 0, sizeof(decrypt)); + + /** generate test data **/ + original_len = sizeof(original); + crypt_len = sizeof(crypt); + decrypt_len = sizeof(decrypt); + + for (j = 0; j < original_len; j++) + original[j] = j % 255; + + /** set mechanism for key gen **/ + mechkey = des3_keygen; + + /** generate key **/ + rc = funcs->C_GenerateKey(session, &mechkey, NULL, 0, &h_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** set mech for crypto **/ + mech = tsuite->mech; + + /** initialize multipart encryption **/ + rc = funcs->C_EncryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /* do multipart (in-place) encryption for all mechs but CBC_PAD since + * it pads and pkcs padding can make it unclear about what is + * output at what stage. (See pkcs11v2.20 Section 11.2) + */ + if (mech.mechanism != CKM_DES3_CBC_PAD) { + memcpy(crypt, original, original_len); + k = 0; + + while (k < original_len) { + rc = funcs->C_EncryptUpdate(session, &crypt[k], + DES3_BLOCK_SIZE, &crypt[k], &crypt_len); + if (rc != CKR_OK) { + testcase_error("C_EncryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + k += crypt_len; // encrypted amount + crypt_len = sizeof(crypt) - k; // space in out buf + } + } else { + i = k = 0; // i indexes source buffer + // k indexes destination buffer + tmp = 0; + + while (i < original_len) { + + tmp = crypt_len - k; // room is left in mpcrypt + rc = funcs->C_EncryptUpdate(session, &original[i], + DES3_BLOCK_SIZE, &crypt[k], &tmp); + + if (rc != CKR_OK) { + testcase_error("C_EncryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + + k += tmp; + i += DES3_BLOCK_SIZE; + } + crypt_len -= k; + } + + rc = funcs->C_EncryptFinal(session, &crypt[k], &crypt_len); + if (rc != CKR_OK) { + testcase_error("C_EncryptFinal rc=%s", p11_get_ckr(rc)); + goto error; + } + + crypt_len += k; + + /** initialize multipart decryption **/ + rc = funcs->C_DecryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /* do multipart (in-place) encryption for all mechs but CBC_PAD since + * it pads and pkcs padding can make it unclear about what is + * output at what stage. (See pkcs11v2.20 Section 11.2) + */ + if (mech.mechanism != CKM_DES3_CBC_PAD) { + memcpy(decrypt, crypt, crypt_len); + decrypt_len = crypt_len; + k = 0; + + while (k < crypt_len) { + rc = funcs->C_DecryptUpdate(session, &decrypt[k], + DES3_BLOCK_SIZE, + &decrypt[k], &decrypt_len); + if (rc != CKR_OK) { + testcase_error("C_DecryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + k += decrypt_len; + decrypt_len = crypt_len - k; + } + } else { + + i = k = 0; + + while (i < crypt_len) { + + tmp = decrypt_len - k; // room left in mpdecrypt + + rc = funcs->C_DecryptUpdate(session, &crypt[i], + DES3_BLOCK_SIZE, &decrypt[k], &tmp); + + if (rc != CKR_OK) { + testcase_error("C_DecryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + + k += tmp; + i += DES3_BLOCK_SIZE; + } + + decrypt_len = sizeof(decrypt) - k; + } + + rc = funcs->C_DecryptFinal(session, &decrypt[k], &decrypt_len); + if (rc != CKR_OK) { + testcase_error("C_DecryptFinal rc=%s", p11_get_ckr(rc)); + goto error; + } + + decrypt_len += k; + + /* compare multipart encryption/decryption results with expected results */ + testcase_new_assertion(); + + if (decrypt_len != original_len) { + testcase_fail("decrypted multipart data length does not match " + "original data length.\nexpected length=%ld, but " + "found length=%ld\n", original_len, decrypt_len); + } else if (memcmp(decrypt, original, original_len)) { + testcase_fail("decrypted multipart data does not match " + "original data"); + } else { + testcase_pass("%s Multipart Encryption/Decryption test passed.", + tsuite->name); + } + +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/* + * Tests triple DES encryption & decryption using + * wrapped/unwrapped (generated) keys + */ +CK_RV do_WrapUnwrapDES3(struct generated_test_suite_info * tsuite) +{ + unsigned int j; + CK_BYTE expected[BIG_REQUEST + DES3_BLOCK_SIZE]; + CK_BYTE actual[BIG_REQUEST + DES3_BLOCK_SIZE]; + CK_ULONG expected_len, actual_len, cipher_len; + + CK_SLOT_ID slot_id = SLOT_ID; + CK_BYTE wrapped_data[BIG_REQUEST + DES3_BLOCK_SIZE]; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_SESSION_HANDLE session; + CK_MECHANISM mechkey, mech; + CK_OBJECT_HANDLE h_key; + CK_OBJECT_HANDLE w_key; + CK_OBJECT_HANDLE uw_key; + CK_ULONG wrapped_data_len; + CK_ULONG user_pin_len; + CK_ULONG key_size; + CK_ULONG tmpl_count = 2; /* Use only the first 2 attrs, except for CCA */ + CK_FLAGS flags; + CK_RV rc; + CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; + CK_KEY_TYPE key_type = CKK_DES3; + + CK_ATTRIBUTE template[] = { + {CKA_CLASS, &key_class, sizeof(key_class)}, + {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, + {CKA_VALUE_LEN, &key_size, sizeof(key_size)} /* For CCA only */ + }; + + CK_ATTRIBUTE key_gen_tmpl[] = { + {CKA_VALUE_LEN, &key_size, sizeof(CK_ULONG)} + }; + + /** begin test **/ + testcase_begin("%s Wrap/Unwrap key test.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip test if the slot does not support this mechanism **/ + if (!mech_supported(SLOT_ID, tsuite->mech.mechanism)) { + testcase_skip("Slot %u doesn't support %s (%u)", + (unsigned int) SLOT_ID, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + if (!wrap_supported(SLOT_ID, tsuite->mech)) { + testcase_skip("Slot %u doesn't support %s (%u)", + (unsigned int) SLOT_ID, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + /** clear buffers **/ + memset(actual, 0, sizeof(actual)); + memset(expected, 0, sizeof(expected)); + + /** generate data **/ + actual_len = expected_len = BIG_REQUEST; + cipher_len = BIG_REQUEST + DES3_BLOCK_SIZE; + + for (j = 0; j < actual_len; j++) { + actual[j] = j % 255; + expected[j] = j % 255; + } + + /** set crypto mech **/ + mech = tsuite->mech; + + /** set key gen mechanism **/ + mechkey = des3_keygen; + key_size = 24; + + /** generate a DES3 Key **/ + rc = funcs->C_GenerateKey(session, &mechkey, key_gen_tmpl, 1, &h_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** generate wrapping key **/ + rc = funcs->C_GenerateKey(session, &mechkey, key_gen_tmpl, 1, &w_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** initialize single encryption **/ + rc = funcs->C_EncryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do single encryption **/ + rc = funcs->C_Encrypt(session, actual, actual_len, actual, &cipher_len); + if (rc != CKR_OK) { + testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** wrap key **/ + wrapped_data_len = 3 * DES3_KEY_SIZE; + rc = funcs->C_WrapKey(session, + &mech, + w_key, + h_key, (CK_BYTE *) & wrapped_data, &wrapped_data_len); + + if (rc != CKR_OK) { + testcase_error("C_WrapKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + if (is_cca_token(slot_id)) { + /* + * CCA requires the CKA_VALUE_LEN attribute in the unwrap template, + * although the PKCS#11 standard states that it can not be specified + * for unwrap. + */ + tmpl_count = 3; + } + + /** unwrap key **/ + rc = funcs->C_UnwrapKey(session, + &mech, + w_key, + wrapped_data, + wrapped_data_len, template, tmpl_count, &uw_key); + if (rc != CKR_OK) { + testcase_error("C_UnwrapKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** initialize single decryption (with unwrapped key) **/ + rc = funcs->C_DecryptInit(session, &mech, uw_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do single decryption (with unwrapped key) **/ + rc = funcs->C_Decrypt(session, actual, cipher_len, actual, &actual_len); + if (rc != CKR_OK) { + testcase_error("C_Decrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare encrypted/decrypted data with original data **/ + testcase_new_assertion(); + + if (actual_len != expected_len) { + testcase_fail("decrypted data length does not match original data " + "length.\nexpected length=%ld, but found length=%ld\n", + expected_len, actual_len); + } else if (memcmp(actual, expected, actual_len)) { + testcase_fail("decrypted data does not match original data."); + } else { + testcase_pass("%s Wrap/UnWrap test passed.", tsuite->name); + } + + goto testcase_cleanup; + +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +CK_RV do_SignVerifyCMAC(struct published_cmac_test_suite_info *tsuite) +{ + unsigned int i; + int k; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_OBJECT_HANDLE h_key; + 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_MAC_GENERAL_PARAMS mac_param; + CK_ULONG ofs; + CK_BYTE actual[MAX_KEY_SIZE]; + CK_ULONG actual_len; + + testsuite_begin("%s Sign/Verify CMAC.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip tests if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(3, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + if (is_ica_token(slot_id) && tsuite->key_type == CKK_DES2) { + testsuite_skip(3, + "ICA token in slot %u doesn't support DES2 keys when " + "compiled in FIPS mode", (unsigned int) slot_id); + goto testcase_cleanup; + } + + for (i = 0; i < tsuite->tvcount; i++) { + testcase_begin("%s Sign/Verify CMAC with published test vector %d.", + tsuite->name, i); + + /** create key handle **/ + if (tsuite->key_type == CKK_DES2) + rc = create_DES2Key(session, + tsuite->tv[i].key, tsuite->tv[i].klen, &h_key); + else if (tsuite->key_type == CKK_DES3) + rc = create_DES3Key(session, + tsuite->tv[i].key, tsuite->tv[i].klen, &h_key); + else + rc = CKR_KEY_TYPE_INCONSISTENT; + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** get mech **/ + mech = tsuite->mech; + if (mech.mechanism == CKM_DES3_CMAC_GENERAL) { + mac_param = tsuite->tv[i].tlen; + mech.pParameter = &mac_param; + mech.ulParameterLen = sizeof(mac_param); + } + + /** initialize signing **/ + rc = funcs->C_SignInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + actual_len = sizeof(actual); + memset(actual, 0, sizeof(actual)); + + if (tsuite->tv[i].num_chunks_message > 0) { + ofs = 0; + for (k = 0; k < tsuite->tv[i].num_chunks_message; k++) { + rc = funcs->C_SignUpdate(session, tsuite->tv[i].msg + ofs, + tsuite->tv[i].chunks_msg[k]); + if (rc != CKR_OK) { + testcase_error("C_SignUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + ofs += tsuite->tv[i].chunks_msg[k]; + } + + rc = funcs->C_SignFinal(session, actual, &actual_len); + if (rc != CKR_OK) { + testcase_error("C_SignFinal rc=%s", p11_get_ckr(rc)); + goto error; + } + } else { + rc = funcs->C_Sign(session, tsuite->tv[i].msg,tsuite->tv[i].mlen, + actual, &actual_len); + if (rc != CKR_OK) { + testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); + goto error; + } + } + + /** initilaize verification **/ + rc = funcs->C_VerifyInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do verification **/ + if (tsuite->tv[i].num_chunks_message > 0) { + ofs = 0; + for (k = 0; k < tsuite->tv[i].num_chunks_message; k++) { + rc = funcs->C_VerifyUpdate(session, tsuite->tv[i].msg + ofs, + tsuite->tv[i].chunks_msg[k]); + if (rc != CKR_OK) { + testcase_error("C_VerifyUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + ofs += tsuite->tv[i].chunks_msg[k]; + } + + rc = funcs->C_VerifyFinal(session, actual, actual_len); + if (rc != CKR_OK) { + testcase_error("C_VerifyFinal rc=%s", p11_get_ckr(rc)); + goto error; + } + } else { + rc = funcs->C_Verify(session, tsuite->tv[i].msg,tsuite->tv[i].mlen, + actual, actual_len); + if (rc != CKR_OK) { + testcase_error("C_Verify rc=%s", p11_get_ckr(rc)); + goto error; + } + } + + /** compare sign/verify results with expected results **/ + testcase_new_assertion(); + + if (mech.mechanism == CKM_DES3_CMAC_GENERAL && + actual_len != tsuite->tv[i].tlen) { + testcase_fail("signature length does not match test vector's " + "signature length\nexpected length=%d, found " + "length=%ld", tsuite->tv[i].tlen, actual_len); + } else if (mech.mechanism != CKM_DES3_CMAC_GENERAL && + actual_len != DES3_BLOCK_SIZE) { + testcase_fail("signature length does not match test vector's " + "signature length\nexpected length=%d, found " + "length=%ld", DES3_BLOCK_SIZE, actual_len); + } else if (memcmp(actual, tsuite->tv[i].mac, tsuite->tv[i].tlen)) { + testcase_fail("signature does not match test vector's signature"); + } else { + testcase_pass("%s Sign/Verify CMAC with test vector %d " + "passed.", tsuite->name, i); + } + + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + goto testcase_cleanup; + +error: + 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() +{ + int i; + CK_RV rv; + + /** published (known answer) tests **/ + for (i = 0; i < NUM_OF_PUBLISHED_TESTSUITES; i++) { + rv = do_EncryptDES3(&published_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + + rv = do_DecryptDES3(&published_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + + rv = do_EncryptUpdateDES3(&published_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + + rv = do_DecryptUpdateDES3(&published_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + } + + /** generated key tests **/ + for (i = 0; i < NUM_OF_GENERATED_TESTSUITES; i++) { + rv = do_WrapUnwrapDES3(&generated_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + do_EncryptDecryptDES3(&generated_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + + do_EncryptDecryptUpdateDES3(&generated_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + } + + /* CMAC test cases */ + for (i = 0; i < NUM_OF_PUBLISHED_CMAC_TESTSUITES; i++) { + rv = do_SignVerifyCMAC(&published_cmac_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + } + + return rv; +} + +int main(int argc, char **argv) +{ + int rc; + CK_C_INITIALIZE_ARGS cinit_args; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) { + return rc; + } + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: no_stop: %d\n", no_stop); + + rc = do_GetFunctionList(); + if (!rc) { + testcase_error("do_GetFunctionList(), rc=%s", p11_get_ckr(rc)); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + funcs->C_Initialize(&cinit_args); + { + CK_SESSION_HANDLE hsess = 0; + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) { + return rc; + } + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) { + return rc; + } + } + + testcase_setup(0); //TODO + rc = des3_funcs(); + testcase_print_result(); + + funcs->C_Finalize(NULL); + + return rc; +} diff --git a/testcases/crypto/des_func.c b/testcases/crypto/des_func.c new file mode 100644 index 0000000..14216e3 --- /dev/null +++ b/testcases/crypto/des_func.c @@ -0,0 +1,1145 @@ +/* + * 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 + */ + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "des.h" +#include "common.c" +#include "mech_to_str.h" + +/** Tests DES encryption with published test vectors. **/ +CK_RV do_EncryptDES(struct published_test_suite_info *tsuite) +{ + unsigned int i; + CK_BYTE expected[BIG_REQUEST]; + CK_BYTE actual[BIG_REQUEST]; + CK_ULONG expected_len, actual_len; + + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_OBJECT_HANDLE h_key; + CK_RV rc; + CK_FLAGS flags; + CK_SLOT_ID slot_id = SLOT_ID; + + /** begin testsuite **/ + testsuite_begin("%s Encryption.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + + /** skip test if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mechanism), + (unsigned int) tsuite->mechanism); + goto testcase_cleanup; + } + + /** iterate over test vectors **/ + for (i = 0; i < tsuite->tvcount; i++) { + + /** begin testcase **/ + testcase_begin("%s Encryption with published test vector " + "%d.", tsuite->name, i); + + rc = CKR_OK; // set rc + + /** clear buffers **/ + memset(expected, 0, sizeof(expected)); + memset(actual, 0, sizeof(actual)); + + /** get ciphertext (expected results) **/ + expected_len = tsuite->tv[i].clen; + memcpy(expected, tsuite->tv[i].ciphertext, expected_len); + + /** get plaintext **/ + actual_len = tsuite->tv[i].plen; + memcpy(actual, tsuite->tv[i].plaintext, actual_len); + + /** get mech **/ + mech.mechanism = tsuite->mechanism; + mech.ulParameterLen = tsuite->tv[i].ivlen; + mech.pParameter = tsuite->tv[i].iv; + + /** create key handle. **/ + rc = create_DESKey(session, + tsuite->tv[i].key, tsuite->tv[i].klen, &h_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** initialize single encryption **/ + rc = funcs->C_EncryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do single (in-place) encryption **/ + rc = funcs->C_Encrypt(session, actual, actual_len, actual, &actual_len); + if (rc != CKR_OK) { + testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare encryption results with expected results. **/ + testcase_new_assertion(); + + if (actual_len != expected_len) { + testcase_fail("encrypted data length does not " + "match test vector's encrypted data " + "length.\n\nexpected length=%ld, but found" + " length=%ld\n", expected_len, actual_len); + } else if (memcmp(actual, expected, expected_len)) { + testcase_fail("encrypted data does not match test " + "vector's encrypted data"); + } else { + testcase_pass("%s Encryption with test vector %d " + "passed.", tsuite->name, i); + } + + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + } + + } + goto testcase_cleanup; + +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Tests DES multipart encryption with published test vectors. **/ +CK_RV do_EncryptUpdateDES(struct published_test_suite_info * tsuite) +{ + unsigned int i; + CK_BYTE expected[BIG_REQUEST]; + CK_BYTE plaintext[BIG_REQUEST]; + CK_BYTE crypt[BIG_REQUEST]; + CK_ULONG expected_len, p_len, crypt_len = 0, k; + + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_OBJECT_HANDLE h_key; + CK_RV rc; + CK_FLAGS flags; + CK_SLOT_ID slot_id = SLOT_ID; + + /** begin testsuite **/ + testsuite_begin("%s Multipart Encryption.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip test if slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mechanism), + (unsigned int) tsuite->mechanism); + goto testcase_cleanup; + } + + /** iterate over test vectors **/ + for (i = 0; i < tsuite->tvcount; i++) { + + /** begin test **/ + testcase_begin("%s Multipart Encryption with published " + "test vector %d.", tsuite->name, i); + + rc = CKR_OK; // set rc + + + /** clear buffers **/ + memset(expected, 0, sizeof(expected)); + memset(crypt, 0, sizeof(crypt)); + memset(plaintext, 0, sizeof(plaintext)); + + /** get ciphertext (expected results) **/ + expected_len = tsuite->tv[i].clen; + memcpy(expected, tsuite->tv[i].ciphertext, expected_len); + + /** get plaintext **/ + p_len = tsuite->tv[i].plen; + memcpy(plaintext, tsuite->tv[i].plaintext, p_len); + + /** get mech **/ + mech.mechanism = tsuite->mechanism; + mech.ulParameterLen = tsuite->tv[i].ivlen; + mech.pParameter = tsuite->tv[i].iv; + + /** create key handle **/ + rc = create_DESKey(session, + tsuite->tv[i].key, tsuite->tv[i].klen, &h_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** initialize multipart encryption **/ + rc = funcs->C_EncryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /* do multipart encryption + * for chunks, -1 is NULL, and 0 is empty string, + * and a value > 0 is amount of data from test vector's + * plaintext data. The is way we test input in various sizes. + */ + k = 0; + if (tsuite->tv[i].num_chunks) { + int j; + CK_ULONG outlen, len; + CK_BYTE *data_chunk = NULL; + + crypt_len = 0; + outlen = sizeof(crypt); + + for (j = 0; j < tsuite->tv[i].num_chunks; j++) { + if (tsuite->tv[i].chunks[j] == -1) { + len = 0; + data_chunk = NULL; + } else if (tsuite->tv[i].chunks[j] == 0) { + len = 0; + data_chunk = (CK_BYTE *) ""; + } else { + len = tsuite->tv[i].chunks[j]; + data_chunk = plaintext + k; + } + + rc = funcs->C_EncryptUpdate(session, data_chunk, + len, &crypt[crypt_len], &outlen); + if (rc != CKR_OK) { + testcase_error("C_EncryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + k += len; + crypt_len += outlen; + outlen = sizeof(crypt) - crypt_len; + } + } else { + crypt_len = sizeof(crypt); + rc = funcs->C_EncryptUpdate(session, plaintext, p_len, + crypt, &crypt_len); + if (rc != CKR_OK) { + testcase_error("C_EncryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + } + + /** finalize multipart encryption **/ + k = sizeof(crypt) - crypt_len; + rc = funcs->C_EncryptFinal(session, &crypt[p_len], &k); + if (rc != CKR_OK) { + testcase_error("C_EncryptFinal rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare encryption results with expected results. **/ + testcase_new_assertion(); + + if (crypt_len != expected_len) { + testcase_fail("encrypted multipart data length " + "does not match test vector's encrypted " + "data length.\n\nexpected length=%ld, " + "but found length=%ld\n", expected_len, crypt_len); + } else if (memcmp(crypt, expected, expected_len)) { + testcase_fail("encrypted multipart data does not " + "match test vector's encrypted data.\n"); + } else { + testcase_pass("%s Multipart Encryption with test " + "vector %d passed.", tsuite->name, i); + } + + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + goto testcase_cleanup; + +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Tests DES decryption with published test vectors. **/ +CK_RV do_DecryptDES(struct published_test_suite_info * tsuite) +{ + unsigned int i; + CK_BYTE expected[BIG_REQUEST]; + CK_BYTE actual[BIG_REQUEST]; + CK_ULONG expected_len, actual_len; + + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_OBJECT_HANDLE h_key; + CK_RV rc; + CK_FLAGS flags; + CK_SLOT_ID slot_id = SLOT_ID; + + /** begin testsuite **/ + testsuite_begin("%s Decryption.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + rc = CKR_OK; + + /** query the slot to see if the mech is supported. **/ + if (!mech_supported(slot_id, tsuite->mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mechanism), + (unsigned int) tsuite->mechanism); + goto testcase_cleanup; + } + + /** iterate over test vector **/ + for (i = 0; i < tsuite->tvcount; i++) { + + /** begin test **/ + testcase_begin("%s Decryption with published test vector " "%d.", + tsuite->name, i); + + rc = CKR_OK; + + /** create key handle. **/ + rc = create_DESKey(session, + tsuite->tv[i].key, tsuite->tv[i].klen, &h_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** get mech **/ + mech.mechanism = tsuite->mechanism; + mech.ulParameterLen = tsuite->tv[i].ivlen; + mech.pParameter = tsuite->tv[i].iv; + + /** clear buffers **/ + memset(expected, 0, sizeof(expected)); + memset(actual, 0, sizeof(actual)); + + /** get plaintext (expected results) **/ + expected_len = tsuite->tv[i].plen; + memcpy(expected, tsuite->tv[i].plaintext, expected_len); + + /** get ciphertext **/ + actual_len = tsuite->tv[i].clen; + memcpy(actual, tsuite->tv[i].ciphertext, actual_len); + + /** initialize single decryption **/ + rc = funcs->C_DecryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do single (in-place) decryption **/ + rc = funcs->C_Decrypt(session, actual, actual_len, actual, &actual_len); + if (rc != CKR_OK) { + testcase_error("C_Decrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare decryption results with expected results. **/ + testcase_new_assertion(); + + if (actual_len != expected_len) { + testcase_fail("decrypted data length does not " + "match test vector's decrypted data " + "length.\n\nexpected length=%ld, but found" + " length=%ld\n", expected_len, actual_len); + } else if (memcmp(actual, expected, expected_len)) { + testcase_fail("decrypted data does not match test " + "vector's decrypted data.\n"); + } else { + testcase_pass("%s Decryption with test vector %d " + "passed.", tsuite->name, i); + } + + } + + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + } + goto testcase_cleanup; + +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Tests DES multipart decryption with published test vectors. **/ +CK_RV do_DecryptUpdateDES(struct published_test_suite_info * tsuite) +{ + unsigned int i; + CK_BYTE expected[BIG_REQUEST]; + CK_BYTE cipher[BIG_REQUEST]; + CK_BYTE plaintext[BIG_REQUEST]; + CK_ULONG expected_len, p_len, cipher_len, k; + + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_OBJECT_HANDLE h_key; + CK_RV rc; + CK_FLAGS flags; + CK_SLOT_ID slot_id = SLOT_ID; + + /** begin testsuite **/ + testsuite_begin("%s Multipart Decryption.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + rc = CKR_OK; // set rc + + /** skip testsuite if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mechanism), + (unsigned int) tsuite->mechanism); + goto testcase_cleanup; + } + + /** iterate over test vectors **/ + for (i = 0; i < tsuite->tvcount; i++) { + + /** begin test **/ + testcase_begin("%s Multipart Decryption with published " + "test vector %d.", tsuite->name, i); + + rc = CKR_OK; // set rc + + /** clear buffers **/ + memset(expected, 0, sizeof(expected)); + memset(cipher, 0, sizeof(cipher)); + memset(plaintext, 0, sizeof(plaintext)); + + /** get plaintext (expected results) **/ + expected_len = tsuite->tv[i].plen; + memcpy(expected, tsuite->tv[i].plaintext, expected_len); + + /** get ciphertext **/ + cipher_len = tsuite->tv[i].clen; + memcpy(cipher, tsuite->tv[i].ciphertext, cipher_len); + + /** get mech **/ + mech.mechanism = tsuite->mechanism; + mech.ulParameterLen = tsuite->tv[i].ivlen; + mech.pParameter = tsuite->tv[i].iv; + + /** create key handle. **/ + rc = create_DESKey(session, + tsuite->tv[i].key, tsuite->tv[i].klen, &h_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** initialize multipart decryption **/ + rc = funcs->C_DecryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /* do multipart encryption + * for chunks, -1 is NULL, and 0 is empty string, + * and a value > 0 is amount of data from test vector's + * plaintext data. The is way we test input in various sizes. + */ + k = 0; + if (tsuite->tv[i].num_chunks) { + int j; + CK_ULONG outlen, len; + CK_BYTE *data_chunk = NULL; + + p_len = 0; + outlen = sizeof(plaintext); + for (j = 0; j < tsuite->tv[i].num_chunks; j++) { + if (tsuite->tv[i].chunks[j] == -1) { + len = 0; + data_chunk = NULL; + } else if (tsuite->tv[i].chunks[j] == 0) { + len = 0; + data_chunk = (CK_BYTE *) ""; + } else { + len = tsuite->tv[i].chunks[j]; + data_chunk = cipher + k; + } + + rc = funcs->C_DecryptUpdate(session, data_chunk, + len, &plaintext[p_len], &outlen); + if (rc != CKR_OK) { + testcase_error("C_DecryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + k += len; + p_len += outlen; + outlen = sizeof(plaintext) - p_len; + } + } else { + p_len = sizeof(plaintext); + rc = funcs->C_DecryptUpdate(session, cipher, cipher_len, + plaintext, &p_len); + if (rc != CKR_OK) { + testcase_error("C_DecryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + } + + /** finalize multipart decryption **/ + k = sizeof(plaintext) - p_len; + rc = funcs->C_DecryptFinal(session, &plaintext[k], &k); + if (rc != CKR_OK) { + testcase_error("C_DecryptFinal rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare decryption results with expected results. **/ + testcase_new_assertion(); + + if (p_len != expected_len) { + testcase_fail("decrypted multipart data length " + "does not match test vector's decrypted " + "data length.\n\nexpected length=%ld, but " + "found length=%ld\n", expected_len, p_len); + } else if (memcmp(plaintext, expected, expected_len)) { + testcase_fail("decrypted multipart data does not " + "match test vector's decrypted data.\n"); + } else { + testcase_pass("%s Multipart Decryption with test " + "vector %d passed.", tsuite->name, i); + } + + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + } + goto testcase_cleanup; + +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Tests DES encryption & decryption with generated (secure) keys. **/ +CK_RV do_EncryptDecryptDES(struct generated_test_suite_info * tsuite) +{ + unsigned int j; + CK_BYTE original[BIG_REQUEST]; + CK_BYTE crypt[BIG_REQUEST + DES_BLOCK_SIZE]; + CK_BYTE decrypt[BIG_REQUEST + DES_BLOCK_SIZE]; + CK_ULONG original_len, crypt_len, decrypt_len; + + CK_SESSION_HANDLE session; + CK_MECHANISM mech, mechkey; + CK_OBJECT_HANDLE h_key; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_SLOT_ID slot_id = SLOT_ID; + CK_RV rc; + + /** begin test **/ + testcase_begin("%s Encryption/Decryption with key generation " + "test.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip test if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testcase_skip("Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + /** clear buffers **/ + memset(original, 0, sizeof(original)); + memset(crypt, 0, sizeof(crypt)); + memset(decrypt, 0, sizeof(decrypt)); + + /** generate test data **/ + original_len = sizeof(original); + crypt_len = sizeof(crypt); + decrypt_len = sizeof(decrypt); + + for (j = 0; j < original_len; j++) + original[j] = j % 255; + + /** set mechanism for key generation **/ + mechkey = des_keygen; + + /** generate key **/ + rc = funcs->C_GenerateKey(session, &mechkey, NULL, 0, &h_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** set mech for crypto **/ + mech = tsuite->mech; + + /** initialize single encryption **/ + rc = funcs->C_EncryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do single encryption **/ + rc = funcs->C_Encrypt(session, original, original_len, crypt, &crypt_len); + if (rc != CKR_OK) { + testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** initialize single decryption **/ + rc = funcs->C_DecryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do single decryption **/ + rc = funcs->C_Decrypt(session, crypt, crypt_len, decrypt, &decrypt_len); + if (rc != CKR_OK) { + testcase_error("C_Decrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare encryption/decryption results with original data **/ + testcase_new_assertion(); + + if (decrypt_len != original_len) { + testcase_fail("decrypted data length does not match " + "original data length.\nexpected length=%ld, " + "but found length=%ld\n", original_len, decrypt_len); + } else if (memcmp(decrypt, original, original_len)) { + testcase_fail("decrypted data does not match original " "data"); + } else { + testcase_pass("%s Encryption/Decryption with key " + "generation test passed.", tsuite->name); + } + + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + } + goto testcase_cleanup; + +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Tests DES multipart encryption & decryption with generated keys. **/ +CK_RV do_EncryptDecryptUpdateDES(struct generated_test_suite_info * tsuite) +{ + unsigned int i, j, k; + CK_BYTE original[BIG_REQUEST]; + CK_BYTE crypt[BIG_REQUEST + DES_BLOCK_SIZE]; + CK_BYTE decrypt[BIG_REQUEST + DES_BLOCK_SIZE]; + CK_ULONG original_len, crypt_len, decrypt_len; + CK_ULONG tmp; + + CK_SESSION_HANDLE session; + CK_MECHANISM mech, mechkey; + CK_OBJECT_HANDLE h_key; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_SLOT_ID slot_id = SLOT_ID; + CK_RV rc; + + /** begin test **/ + testcase_begin("%s Multipart Encryption/Decryption with key " + "generation test.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip test if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testcase_skip("Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + /** clear buffers **/ + memset(original, 0, sizeof(original)); + memset(crypt, 0, sizeof(crypt)); + memset(decrypt, 0, sizeof(decrypt)); + + /** generate test data **/ + original_len = sizeof(original); + + for (j = 0; j < original_len; j++) + original[j] = j % 255; + + /** set mechanism for key gen **/ + mechkey = des_keygen; + + /** generate key **/ + rc = funcs->C_GenerateKey(session, &mechkey, NULL, 0, &h_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** set mech for crypto **/ + mech = tsuite->mech; + + /** initialize multipart encryption **/ + rc = funcs->C_EncryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit #1 rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do multipart encryption **/ + i = k = 0; // i indexes source buffer + // k indexes destination buffer + crypt_len = sizeof(crypt); + tmp = 0; + + while (i < original_len) { + tmp = crypt_len - k; // room left in mpcrypt + rc = funcs->C_EncryptUpdate(session, + &original[i], + DES_BLOCK_SIZE, &crypt[k], &tmp); + if (rc != CKR_OK) { + testcase_error("C_EncryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + k += tmp; + i += DES_BLOCK_SIZE; + } + + /** finalize multipart encryption **/ + crypt_len = sizeof(crypt) - k; + + rc = funcs->C_EncryptFinal(session, &crypt[k], &crypt_len); + if (rc != CKR_OK) { + testcase_error("C_EncryptFinal rc=%s", p11_get_ckr(rc)); + goto error; + } + + crypt_len += k; + + /** initialize multipart decryption **/ + rc = funcs->C_DecryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do multipart decryption **/ + i = k = 0; // i indexes source buffer + // k indexes destination buffer + decrypt_len = sizeof(decrypt); + + while (i < crypt_len) { + tmp = decrypt_len - k; // room left in mpdecrypt + rc = funcs->C_DecryptUpdate(session, + &crypt[i], + DES_BLOCK_SIZE, &decrypt[k], &tmp); + if (rc != CKR_OK) { + testcase_error("C_DecryptUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + k += tmp; + i += DES_BLOCK_SIZE; + } + + decrypt_len = sizeof(decrypt) - k; + + /** finalize multipart decryption **/ + rc = funcs->C_DecryptFinal(session, &decrypt[k], &decrypt_len); + if (rc != CKR_OK) { + testcase_error("C_DecryptFinal rc=%s", p11_get_ckr(rc)); + return rc; + } + + decrypt_len += k; + + /** compare encrypt/decrypt results with original data **/ + testcase_new_assertion(); + + if (decrypt_len != original_len) { + testcase_fail("decrypted multipart data length does not " + "match original data length.\nexpected length=%ld," + " but found length=%ld\n", original_len, decrypt_len); + } else if (memcmp(decrypt, original, original_len)) { + testcase_fail("decrypted data does not match original " "data"); + } else { + testcase_pass("%s Multipart Encryption/Decryption with key" + "generation test passed.", tsuite->name); + } + + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + } + + goto testcase_cleanup; + +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Tests DES encryption & decryption with wrapped/unwrapped keys. **/ +CK_RV do_WrapUnwrapDES(struct generated_test_suite_info * tsuite) +{ + unsigned int j; + CK_BYTE expected[BIG_REQUEST + DES_BLOCK_SIZE]; + CK_BYTE actual[BIG_REQUEST + DES_BLOCK_SIZE]; + CK_ULONG expected_len, actual_len, cipher_len; + + CK_BYTE wrapped_data[BIG_REQUEST + DES_BLOCK_SIZE]; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_SESSION_HANDLE session; + CK_MECHANISM mechkey, mech; + CK_OBJECT_HANDLE h_key; + CK_OBJECT_HANDLE w_key; + CK_OBJECT_HANDLE uw_key; + CK_ULONG wrapped_data_len; + CK_ULONG user_pin_len; + CK_ULONG tmpl_count = 2; + CK_FLAGS flags; + CK_RV rc; + CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; + CK_KEY_TYPE key_type = CKK_DES; + CK_SLOT_ID slot_id = SLOT_ID; + + CK_ATTRIBUTE template[] = { + {CKA_CLASS, &key_class, sizeof(key_class)} + , + {CKA_KEY_TYPE, &key_type, sizeof(key_type)} + }; + + /** begin test **/ + testcase_begin("%s Wrap/Unwrap key test.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /** skip test if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testcase_skip("Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + if (!wrap_supported(slot_id, tsuite->mech)) { + testcase_skip("Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + /** clear buffers **/ + memset(actual, 0, sizeof(actual)); + memset(expected, 0, sizeof(expected)); + + /** generate data **/ + actual_len = expected_len = BIG_REQUEST; + cipher_len = BIG_REQUEST + DES_BLOCK_SIZE; + for (j = 0; j < actual_len; j++) { + actual[j] = j % 255; + expected[j] = j % 255; + } + + /** set mechkey for key generation **/ + mechkey = des_keygen; + + /** generate a DES Key **/ + rc = funcs->C_GenerateKey(session, &mechkey, NULL, 0, &h_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** generate wrapping key **/ + rc = funcs->C_GenerateKey(session, &mechkey, NULL, 0, &w_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** set mech for crypto**/ + mech = tsuite->mech; + + /** initialize single encryption **/ + rc = funcs->C_EncryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do single encryption **/ + rc = funcs->C_Encrypt(session, actual, actual_len, actual, &cipher_len); + if (rc != CKR_OK) { + testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** wrap key **/ + wrapped_data_len = sizeof(wrapped_data); + rc = funcs->C_WrapKey(session, + &mech, + w_key, + h_key, (CK_BYTE *) & wrapped_data, &wrapped_data_len); + if (rc != CKR_OK) { + testcase_error("C_WrapKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** unwrap key **/ + rc = funcs->C_UnwrapKey(session, &mech, w_key, wrapped_data, + wrapped_data_len, template, tmpl_count, &uw_key); + if (rc != CKR_OK) { + testcase_error("C_UnwrapKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** decrypt data with unwrapped key **/ + rc = funcs->C_DecryptInit(session, &mech, uw_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + rc = funcs->C_Decrypt(session, actual, cipher_len, actual, &actual_len); + if (rc != CKR_OK) { + testcase_error("C_Decrypt rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare encrypted/decrypted data with original data **/ + testcase_new_assertion(); + + if (actual_len != expected_len) { + testcase_fail("expected length=%ld, but found length=%ld" + "\n", expected_len, actual_len); + rc = CKR_GENERAL_ERROR; + } else if (memcmp(actual, expected, actual_len)) { + testcase_fail("decrypted data does not match plaintext " "data."); + rc = CKR_GENERAL_ERROR; + } else { + testcase_pass("DES Wrap/UnWrap test for %s passed.", tsuite->name); + } + + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + } + goto testcase_cleanup; + +error: + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +CK_RV des_funcs() +{ + int i; + CK_RV rv; + + /** published (known answer) tests **/ + for (i = 0; i < NUM_OF_PUBLISHED_TESTSUITES; i++) { + rv = do_EncryptDES(&published_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + + rv = do_DecryptDES(&published_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + + rv = do_EncryptUpdateDES(&published_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + + rv = do_DecryptUpdateDES(&published_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + } + + /** generated tests **/ + for (i = 0; i < NUM_OF_GENERATED_TESTSUITES; i++) { + rv = do_WrapUnwrapDES(&generated_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + rv = do_EncryptDecryptDES(&generated_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + rv = do_EncryptDecryptUpdateDES(&generated_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + } + + return rv; +} + +int main(int argc, char **argv) +{ + int rc; + CK_C_INITIALIZE_ARGS cinit_args; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) { + return rc; + } + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: no_stop: %d\n", no_stop); + + rc = do_GetFunctionList(); + if (!rc) { + testcase_error("do_GetFunctionList(), rc=%s", p11_get_ckr(rc)); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + funcs->C_Initialize(&cinit_args); + { + CK_SESSION_HANDLE hsess = 0; + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) { + return rc; + } + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) { + return rc; + } + } + rc = 0; + testcase_setup(0); //TODO + rc = des_funcs(); + testcase_print_result(); + + funcs->C_Finalize(NULL); + + return rc; +} diff --git a/testcases/crypto/dh_func.c b/testcases/crypto/dh_func.c new file mode 100644 index 0000000..9214dd2 --- /dev/null +++ b/testcases/crypto/dh_func.c @@ -0,0 +1,616 @@ +/* + * 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 + */ + +/************************************************************************ +* * +* Copyright: Corrent Corporation (c) 2000-2003 * +* * +* Filename: dh_func.c * +* Created By: Kapil Sood * +* Created On: April 28, 2003 * +* Description: This is the file for testing Diffie-Hellman * +* key pair generation and shared key derivation * +* operations. * +* * +************************************************************************/ + +// File: dh_func.c +// + +#include + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "common.c" + + +// These values were obtained from openssl genkey. +// These values are in big-endian format. +// These are required for generating DH keys and secrets. + + +CK_BYTE DH_PUBL_PRIME[128] = { + 0xd5, 0xb1, 0xaa, 0x6a, 0x3b, 0x85, 0x50, 0xf0, 0xe2, + 0xea, 0x6b, 0xec, 0x26, 0x3b, 0xe0, 0xbf, 0x7a, 0x82, + 0x45, 0x1b, 0xa8, 0x0a, 0x54, 0x2e, 0x14, 0x2c, 0xc2, + 0x58, 0xb1, 0xf5, 0x59, 0xec, 0x7d, 0x16, 0x9e, 0x00, + 0x62, 0xb3, 0xa7, 0xdc, 0x38, 0x6f, 0x64, 0x40, 0xfc, + 0x0d, 0x3e, 0x0b, 0x66, 0x13, 0x5e, 0xa5, 0x84, 0x90, + 0x26, 0x62, 0xcf, 0x5a, 0x14, 0x72, 0x2d, 0x1b, 0x37, + 0x7e, 0x8a, 0x4b, 0xc0, 0xb7, 0xf2, 0x63, 0xd1, 0xaa, + 0x51, 0x92, 0x96, 0x18, 0xae, 0xb9, 0xfd, 0x5f, 0x9d, + 0x5d, 0xdf, 0x75, 0xa9, 0x80, 0x3d, 0xaa, 0xc2, 0x54, + 0x00, 0xcc, 0xc1, 0x9e, 0x31, 0x4d, 0x22, 0x31, 0x44, + 0xe9, 0x69, 0x34, 0xae, 0xcf, 0xcd, 0x6d, 0xf6, 0xe9, + 0x37, 0x20, 0xa4, 0xd3, 0x85, 0x24, 0xff, 0x9f, 0x39, + 0xeb, 0x78, 0xf2, 0xd1, 0xc3, 0xf9, 0x66, 0xab, 0xbd, + 0x2d, 0xd3 +}; + + +CK_BYTE DH_PUBL_BASE[128] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02 +}; + +CK_BYTE DH_PRIVATE_A[128] = { + 0x69, 0xd1, 0xfd, 0xaf, 0x5f, 0x00, 0x75, 0x0e, 0x85, + 0xfe, 0xc1, 0x8d, 0x5f, 0x0e, 0x86, 0x3f, 0xfa, 0xe0, + 0xef, 0x19, 0x8b, 0xfd, 0x90, 0xe5, 0x8e, 0xd7, 0xc6, + 0x5f, 0xd7, 0x37, 0x20, 0x15, 0xc6, 0x65, 0x6c, 0x9b, + 0xdd, 0xb7, 0x50, 0xda, 0x5e, 0xf0, 0xb9, 0x9f, 0x5d, + 0x9b, 0x06, 0xdf, 0x10, 0xf0, 0x60, 0x74, 0x8e, 0x71, + 0xb5, 0x4b, 0x6f, 0xdf, 0x0b, 0x86, 0x36, 0x54, 0x3d, + 0x95, 0x17, 0x38, 0x27, 0x6f, 0xb7, 0x32, 0x57, 0x2b, + 0x72, 0xc6, 0x9e, 0x81, 0x52, 0x8f, 0xcd, 0x43, 0x6f, + 0x9c, 0x6b, 0xee, 0x58, 0x00, 0x8c, 0xb5, 0xff, 0x94, + 0xfe, 0xbc, 0x2b, 0xd0, 0xab, 0x97, 0x90, 0x7c, 0x2c, + 0xbf, 0xf9, 0x19, 0xa8, 0x19, 0x82, 0xff, 0xf4, 0xc4, + 0xd0, 0x02, 0x01, 0xb7, 0xd5, 0x4b, 0x00, 0x6d, 0x69, + 0x1e, 0xfc, 0x7a, 0x9f, 0xc0, 0x3f, 0x38, 0x8b, 0xb3, + 0xc6, 0x89 +}; + +CK_BYTE DH_PUBLIC_A[128] = { + 0x89, 0x5b, 0xfe, 0x83, 0xdd, 0x18, 0x69, 0x47, 0x86, + 0x28, 0x17, 0x86, 0xba, 0x8f, 0x47, 0x27, 0x3c, 0xe6, + 0x0e, 0x21, 0xac, 0x4f, 0x7f, 0xc4, 0x25, 0xaa, 0x52, + 0x86, 0x26, 0x07, 0xc6, 0x2d, 0x2e, 0xbe, 0xfc, 0xb5, + 0x97, 0xa9, 0x73, 0x57, 0x20, 0x11, 0x77, 0x0a, 0xef, + 0x3e, 0x55, 0x56, 0x29, 0x2b, 0xc3, 0x7f, 0x87, 0x9d, + 0x0f, 0x08, 0xd4, 0x4c, 0x46, 0x7a, 0x37, 0xba, 0xb7, + 0x3d, 0x47, 0xce, 0x70, 0x94, 0x9c, 0xa6, 0x59, 0x61, + 0xf7, 0x98, 0x15, 0x33, 0x7e, 0x6a, 0x25, 0x66, 0x1f, + 0x18, 0x88, 0x5a, 0x02, 0xfa, 0x69, 0xa5, 0x8e, 0x1b, + 0x9e, 0x2f, 0xcb, 0x2b, 0x28, 0x56, 0x8d, 0xcd, 0x92, + 0xea, 0xf0, 0x9d, 0x37, 0x9b, 0xa3, 0x92, 0x5b, 0x9c, + 0x10, 0x02, 0x7d, 0x57, 0xe9, 0xd7, 0x8d, 0x6e, 0x13, + 0x5e, 0x34, 0x9e, 0x8c, 0x15, 0x4e, 0x0f, 0xe2, 0x28, + 0x70, 0x3d +}; + +CK_BYTE DH_PRIVATE_B[128] = { + 0x71, 0x07, 0xa2, 0x3c, 0x08, 0x08, 0x5c, 0x47, 0x6e, + 0x2d, 0x70, 0xf5, 0x8c, 0xb1, 0xc0, 0xc6, 0x2b, 0xdf, + 0xa7, 0x23, 0x68, 0xcf, 0x84, 0x34, 0x88, 0xb5, 0x0a, + 0x99, 0xc2, 0x7b, 0x08, 0x1f, 0xe8, 0x83, 0x8d, 0x27, + 0x76, 0x28, 0x7c, 0xb8, 0x72, 0xf1, 0x17, 0x99, 0x87, + 0xe3, 0xaa, 0x97, 0xa9, 0x0f, 0x92, 0xa1, 0xe3, 0x6f, + 0x6b, 0x53, 0xff, 0xd1, 0x25, 0x83, 0xb0, 0xca, 0x07, + 0x32, 0x48, 0x72, 0xf3, 0xe5, 0xb4, 0xaf, 0x82, 0x6b, + 0x90, 0x0d, 0x32, 0x46, 0x07, 0x1b, 0x4b, 0x97, 0x73, + 0xbb, 0x4d, 0x57, 0x4e, 0x38, 0x7d, 0x59, 0xd6, 0xd5, + 0xb1, 0xbd, 0x93, 0x85, 0x15, 0xa1, 0x14, 0x98, 0xb7, + 0xe6, 0x7f, 0x8a, 0xf1, 0xbd, 0x1a, 0x88, 0x4a, 0x1b, + 0xa8, 0x3f, 0xc9, 0x1f, 0x9a, 0xbe, 0x33, 0x27, 0x79, + 0xd6, 0xeb, 0x45, 0xda, 0xc9, 0x5f, 0x59, 0xe8, 0xeb, + 0x79, 0xc7 +}; + +CK_BYTE DH_PUBLIC_B[128] = { + 0xc5, 0xe3, 0xec, 0x7c, 0x29, 0x67, 0x4e, 0x61, 0x54, + 0xd6, 0xbb, 0xba, 0x23, 0xc3, 0xc9, 0x69, 0x05, 0x73, + 0x00, 0x8e, 0xa6, 0x79, 0x5b, 0x58, 0x35, 0x69, 0x70, + 0x0d, 0xd3, 0x42, 0xa2, 0x0c, 0xfa, 0x1e, 0x3d, 0x5a, + 0x5e, 0x21, 0x6c, 0x0e, 0x34, 0xb0, 0xd9, 0x1a, 0xb2, + 0x10, 0xa4, 0x0c, 0xf4, 0xb1, 0xfa, 0x2c, 0x40, 0x09, + 0xbe, 0x92, 0xf9, 0x70, 0xbe, 0x49, 0x79, 0xe0, 0x20, + 0xfc, 0x10, 0xa7, 0xda, 0xaa, 0xb6, 0x0c, 0x3b, 0xd4, + 0x6f, 0x51, 0x42, 0xfd, 0xf6, 0x08, 0x08, 0x4a, 0x0c, + 0xf8, 0xdb, 0xc1, 0x7b, 0x61, 0x36, 0x1c, 0x10, 0xc3, + 0x2c, 0x1a, 0x3b, 0xcb, 0xda, 0xae, 0x45, 0xfd, 0x0a, + 0xd7, 0x50, 0xc3, 0xf1, 0xfc, 0xfa, 0xeb, 0xc2, 0x64, + 0x18, 0xce, 0x4d, 0xd1, 0xd3, 0xfd, 0x1f, 0x31, 0x30, + 0x11, 0xe8, 0xaa, 0x40, 0xa4, 0xb8, 0x1d, 0xba, 0x24, + 0xf2, 0x75 +}; + +/* + * Generate/Import DH key-pairs for parties A and B. + * Derive keys based on Diffie Hellman key agreement defined in PKCS#3. + * + */ +CK_RV do_DeriveDHKey(CK_BBOOL do_import) +{ + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE priv_key = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE peer_publ_key = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE peer_priv_key = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE secret_key = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE peer_secret_key = CK_INVALID_HANDLE; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rc = CKR_OK, loc_rc = CKR_OK; + + int i = 0; + CK_BYTE clear[32]; + CK_BYTE cipher[32]; + CK_BYTE re_cipher[32]; + CK_ULONG cipher_len = 32; + CK_ULONG re_cipher_len = 32; + CK_BBOOL ltrue = 1; + + CK_OBJECT_CLASS pub_key_class = CKO_PUBLIC_KEY; + CK_KEY_TYPE key_type = CKK_DH; + CK_UTF8CHAR publ_label[] = "A DH public key object"; + CK_OBJECT_CLASS priv_key_class = CKO_PRIVATE_KEY; + CK_UTF8CHAR priv_label[] = "A DH private key object"; + + CK_ULONG secret_key_size = sizeof(DH_PUBL_PRIME); + CK_OBJECT_CLASS secret_key_class = CKO_SECRET_KEY; + CK_KEY_TYPE secret_key_type = CKK_GENERIC_SECRET; + CK_UTF8CHAR secret_label[] = "A generic secret key object"; + + CK_BYTE key1_value[sizeof(DH_PUBL_PRIME) * 2]; + CK_BYTE key2_value[sizeof(DH_PUBL_PRIME) * 2]; + + CK_ATTRIBUTE publ_tmpl[] = { + {CKA_CLASS, &pub_key_class, sizeof(pub_key_class)}, + {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, + {CKA_LABEL, publ_label, sizeof(publ_label) - 1}, + {CKA_PRIME, DH_PUBL_PRIME, sizeof(DH_PUBL_PRIME)}, + {CKA_BASE, DH_PUBL_BASE, sizeof(DH_PUBL_BASE)} + }; + + CK_ATTRIBUTE priv_tmpl[] = { + {CKA_CLASS, &priv_key_class, sizeof(priv_key_class)}, + {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, + {CKA_LABEL, priv_label, sizeof(priv_label) - 1}, + {CKA_DERIVE, <rue, sizeof(ltrue)} + }; + + CK_ATTRIBUTE secret_tmpl[] = { + {CKA_CLASS, &secret_key_class, sizeof(secret_key_class)}, + {CKA_KEY_TYPE, &secret_key_type, sizeof(secret_key_type)}, + {CKA_VALUE_LEN, &secret_key_size, sizeof(secret_key_size)}, + {CKA_LABEL, secret_label, sizeof(secret_label) - 1} + }; + + CK_ATTRIBUTE extr1_tmpl[] = { + {CKA_VALUE, key1_value, sizeof(key1_value)} + }; + + CK_ATTRIBUTE extr2_tmpl[] = { + {CKA_VALUE, key2_value, sizeof(key2_value)} + }; + + if (do_import) + testcase_begin("starting do_ImportDeriveDHKey..."); + else + testcase_begin("starting do_GenerateDeriveDHKey..."); + testcase_rw_session(); + testcase_user_login(); + + // Testcase #1 - Generate 2 DH key pairs. + testcase_new_assertion(); + + if (!do_import) { + // First, generate the DH key Pair for Party A + mech.mechanism = CKM_DH_PKCS_KEY_PAIR_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rc = funcs->C_GenerateKeyPair(session, &mech, publ_tmpl, 5, + priv_tmpl, 4, &publ_key, &priv_key); + if (rc != CKR_OK) { + testcase_fail("C_GenerateKeyPair #1: rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // Now generate a key-pair for party B (the peer) + mech.mechanism = CKM_DH_PKCS_KEY_PAIR_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rc = funcs->C_GenerateKeyPair(session, &mech, publ_tmpl, 5, + priv_tmpl, 4, &peer_publ_key, + &peer_priv_key); + if (rc != CKR_OK) { + testcase_fail("C_GenerateKeyPair #2: rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // Extract the peer's public key + rc = funcs->C_GetAttributeValue(session, peer_publ_key, extr1_tmpl, 1); + if (rc != CKR_OK) { + testcase_error("C_GetAttributeValue #1: rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // Make sure peer's key is the right size + if ((extr1_tmpl[0].ulValueLen != sizeof(DH_PUBL_PRIME)) && + (extr1_tmpl[0].ulValueLen != sizeof(DH_PUBL_PRIME) - 1)) { + testcase_fail("ERROR:size error peer's key %ld", + extr1_tmpl[0].ulValueLen); + goto testcase_cleanup; + } else { + testcase_pass("Successfully generated DH keys"); + } + } else { + // First, import the DH key Pair for Party A + + // import the private key for Party A + rc = create_DHPrivateKey(session, + DH_PUBL_PRIME, sizeof(DH_PUBL_PRIME), + DH_PUBL_BASE, sizeof(DH_PUBL_BASE), + DH_PRIVATE_A, sizeof(DH_PRIVATE_A), &priv_key); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject (DH Private Key) failed rc=%s", + p11_get_ckr(rc)); + goto testcase_cleanup; + } + // import the public key for Party A + rc = create_DHPublicKey(session, + DH_PUBL_PRIME, sizeof(DH_PUBL_PRIME), + DH_PUBL_BASE, sizeof(DH_PUBL_BASE), + DH_PUBLIC_A, sizeof(DH_PUBLIC_A), &publ_key); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject (DH Public Key) failed rc=%s", + p11_get_ckr(rc)); + goto testcase_cleanup; + } + // import the private key for Party B + rc = create_DHPrivateKey(session, + DH_PUBL_PRIME, sizeof(DH_PUBL_PRIME), + DH_PUBL_BASE, sizeof(DH_PUBL_BASE), + DH_PRIVATE_B, sizeof(DH_PRIVATE_B), + &peer_priv_key); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject (DH Private Key) failed rc=%s", + p11_get_ckr(rc)); + goto testcase_cleanup; + } + // import the public key for Party B + rc = create_DHPublicKey(session, + DH_PUBL_PRIME, sizeof(DH_PUBL_PRIME), + DH_PUBL_BASE, sizeof(DH_PUBL_BASE), + DH_PUBLIC_B, sizeof(DH_PUBLIC_B), + &peer_publ_key); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject (DH Public Key) failed rc=%s", + p11_get_ckr(rc)); + goto testcase_cleanup; + } + // Extract the peer's public key + rc = funcs->C_GetAttributeValue(session, peer_publ_key, extr1_tmpl, 1); + if (rc != CKR_OK) { + testcase_error("C_GetAttributeValue #1: rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // Make sure peer's key is the right size + if ((extr1_tmpl[0].ulValueLen != sizeof(DH_PUBL_PRIME)) && + (extr1_tmpl[0].ulValueLen != sizeof(DH_PUBL_PRIME) - 1)) { + testcase_fail("ERROR:size error peer's key %ld", + extr1_tmpl[0].ulValueLen); + goto testcase_cleanup; + } else { + testcase_pass("Successfully imported DH keys"); + } + } + + // Testcase #2 - Now derive the secrets... + if (!securekey) { + // Note: this is a clear key token testcase since comparing + // key values. + testcase_new_assertion(); + + /* Now, derive a generic secret key using party A's + * private key and peer's public key + */ + mech.mechanism = CKM_DH_PKCS_DERIVE; + mech.ulParameterLen = extr1_tmpl[0].ulValueLen; + mech.pParameter = key1_value; + + rc = funcs->C_DeriveKey(session, &mech, priv_key, secret_tmpl, + 4, &secret_key); + if (rc != CKR_OK) { + testcase_fail("C_DeriveKey #1: rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // Do the same for the peer + + // Extract party A's public key + rc = funcs->C_GetAttributeValue(session, publ_key, extr2_tmpl, 1); + if (rc != CKR_OK) { + testcase_error("C_GetAttributeValue #2: rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // Make sure party A's key is the right size + if ((extr2_tmpl[0].ulValueLen != sizeof(DH_PUBL_PRIME)) && + (extr2_tmpl[0].ulValueLen != sizeof(DH_PUBL_PRIME) - 1)) { + testcase_fail("ERROR:size error party A's key %ld", + extr2_tmpl[0].ulValueLen); + goto testcase_cleanup; + } + // Now, derive a generic secret key using peer's private key + // and A's public key + mech.mechanism = CKM_DH_PKCS_DERIVE; + mech.ulParameterLen = extr2_tmpl[0].ulValueLen; + mech.pParameter = key2_value; + + rc = funcs->C_DeriveKey(session, &mech, peer_priv_key, + secret_tmpl, 4, &peer_secret_key); + if (rc != CKR_OK) { + testcase_fail("C_DeriveKey #2: rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // Extract the derived keys and compare them + + memset(key1_value, 0, sizeof(key1_value)); + extr1_tmpl[0].ulValueLen = sizeof(key1_value); + + rc = funcs->C_GetAttributeValue(session, secret_key, extr1_tmpl, 1); + if (rc != CKR_OK) { + testcase_error("C_GetAttributeValue #3:rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + if (extr1_tmpl[0].ulValueLen != sizeof(DH_PUBL_PRIME) || + *((int *) extr1_tmpl[0].pValue) == 0) { + testcase_fail("ERROR:derived key #1 length or value %ld", + extr1_tmpl[0].ulValueLen); + goto testcase_cleanup; + } + + memset(key2_value, 0, sizeof(key2_value)); + extr2_tmpl[0].ulValueLen = sizeof(key2_value); + + rc = funcs->C_GetAttributeValue(session, peer_secret_key, + extr2_tmpl, 1); + if (rc != CKR_OK) { + testcase_error("C_GetAttributeValue #4:rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + if (extr2_tmpl[0].ulValueLen != sizeof(DH_PUBL_PRIME) || + *((int *) extr2_tmpl[0].pValue) == 0) { + testcase_fail("ERROR:derived key #2 length or value %ld", + extr2_tmpl[0].ulValueLen); + goto testcase_cleanup; + } + + if (memcmp(key1_value, key2_value, sizeof(DH_PUBL_PRIME)) != 0) { + testcase_fail("ERROR:derived key mismatch"); + goto testcase_cleanup; + } + + testcase_pass("Generating DH key pairs and deriving secrets"); + + goto testcase_cleanup; + + } else { + + // Testcase for secure key token - encode/decode with secrect key and + // peer secret key + testcase_new_assertion(); + + secret_key_size = 32; + secret_key_type = CKK_AES; + for (i = 0; i < 32; i++) + clear[i] = i; + + /* Now, derive a generic secret key using party A's + * private key and peer's public key + */ + mech.mechanism = CKM_DH_PKCS_DERIVE; + mech.ulParameterLen = extr1_tmpl[0].ulValueLen; + mech.pParameter = key1_value; + + rc = funcs->C_DeriveKey(session, &mech, priv_key, secret_tmpl, + 4, &secret_key); + if (rc != CKR_OK) { + testcase_fail("C_DeriveKey #1: rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // Do the same for the peer + + // Extract party A's public key + rc = funcs->C_GetAttributeValue(session, publ_key, extr2_tmpl, 1); + if (rc != CKR_OK) { + testcase_error("C_GetAttributeValue #2: rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // Make sure party A's key is the right size + if ((extr2_tmpl[0].ulValueLen != sizeof(DH_PUBL_PRIME)) && + (extr2_tmpl[0].ulValueLen != sizeof(DH_PUBL_PRIME) - 1)) { + testcase_fail("ERROR:size error party A's key %ld", + extr2_tmpl[0].ulValueLen); + goto testcase_cleanup; + } + // Now, derive a generic secret key using peer's private key + // and A's public key + mech.mechanism = CKM_DH_PKCS_DERIVE; + mech.ulParameterLen = extr2_tmpl[0].ulValueLen; + mech.pParameter = key2_value; + + rc = funcs->C_DeriveKey(session, &mech, peer_priv_key, + secret_tmpl, 4, &peer_secret_key); + if (rc != CKR_OK) { + testcase_fail("C_DeriveKey #2: rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // Extract the derived keys and compare them + + mech.mechanism = CKM_AES_ECB; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rc = funcs->C_EncryptInit(session, &mech, secret_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit secret_key: rc = %s", + p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_Encrypt(session, clear, 32, cipher, &cipher_len); + if (rc != CKR_OK) { + testcase_error("C_Encrypt secret_key: rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_DecryptInit(session, &mech, peer_secret_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit peer_secret_key: rc = %s", + p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_Decrypt(session, cipher, cipher_len, re_cipher, + &re_cipher_len); + if (rc != CKR_OK) { + testcase_error("C_Decrypt peer secret_key: rc = %s", + p11_get_ckr(rc)); + goto testcase_cleanup; + } + + if (memcmp(clear, re_cipher, 32) != 0) { + testcase_fail("ERROR:data mismatch"); + goto testcase_cleanup; + } + + testcase_pass("Generating DH key pairs and deriving secrets"); + } + +testcase_cleanup: + funcs->C_DestroyObject(session, publ_key); + funcs->C_DestroyObject(session, priv_key); + funcs->C_DestroyObject(session, peer_priv_key); + funcs->C_DestroyObject(session, peer_publ_key); + funcs->C_DestroyObject(session, secret_key); + funcs->C_DestroyObject(session, peer_secret_key); + + loc_rc = funcs->C_CloseSession(session); + if (loc_rc != CKR_OK) + testcase_error("C_CloseSession, loc_rc = %s", p11_get_ckr(loc_rc)); + + return rc; +} /* end do_DeriveDHKey() */ + +CK_RV dh_functions() +{ + CK_RV rv, rv2; + CK_MECHANISM_INFO mechinfo; + + /** get mech info **/ + rv = funcs->C_GetMechanismInfo(SLOT_ID, CKM_DH_PKCS_KEY_PAIR_GEN, + &mechinfo); + rv2 = funcs->C_GetMechanismInfo(SLOT_ID, CKM_DH_PKCS_DERIVE, &mechinfo); + + if ((rv == CKR_OK) && (rv2 == CKR_OK)) { + rv = do_DeriveDHKey(FALSE); + + if ((rv == CKR_OK) && (rv2 == CKR_OK)) + rv = do_DeriveDHKey(TRUE); + } else { + /* + ** One of the above mechanism is not available, so skip + ** the test but do not report any + ** rv = CKR_MECHANISM_INVALID; + ** invalid or however failures as this is not a failure. + **/ + return CKR_OK; + } + + return rv; +} + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + int rc; + CK_RV rv; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: no_init: %d\n", no_init); + + rc = do_GetFunctionList(); + if (!rc) { + PRINT_ERR("ERROR do_GetFunctionList() Failed , rc = 0x%0x\n", rc); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + // SAB Add calls to ALL functions before the C_Initialize gets hit + + funcs->C_Initialize(&cinit_args); + + /* + * -securekey option is needed on CCA and EP11 token, + * otherwise the testcase will fail. However, now this + * will be done automatically here. + */ + if (is_ep11_token(SLOT_ID) || is_cca_token(SLOT_ID)) + securekey = 1; + + { + CK_SESSION_HANDLE hsess = 0; + + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + } + + testcase_setup(0); + + rv = dh_functions(); + + testcase_print_result(); + + funcs->C_Finalize(NULL); + + /* make sure we return non-zero if rv is non-zero */ + return ((rv == 0) || (rv % 256) ? (int)rv : -1); +} diff --git a/testcases/crypto/digest.h b/testcases/crypto/digest.h new file mode 100644 index 0000000..e906a32 --- /dev/null +++ b/testcases/crypto/digest.h @@ -0,0 +1,11126 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2011-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 + */ + +#include "pkcs11types.h" + +#define MAX_KEY_SIZE 150 +#define MAX_DATA_SIZE 512 +#define MAX_HASH_SIZE 64 +#define MAX_CHUNKS 8 + +CK_ULONG four = 4; +CK_ULONG ten = 10; +CK_ULONG sixteen = 16; +CK_ULONG twentyfour = 24; +CK_ULONG thirtytwo = 32; + +struct DIGEST_TEST_VECTOR { + CK_BYTE data[512]; + CK_ULONG data_len; + CK_BYTE hash[512]; + CK_ULONG hash_len; + int chunks[MAX_CHUNKS]; + int num_chunks; +}; + + +/** The hash function RIPEMD-160 +http://homes.esat.kuleuven.be/~bosselae/ripemd160.html + **/ +struct DIGEST_TEST_VECTOR ripemd128_digest_test_vector[] = { + { + .data = "", + .data_len = 0, + .hash = {0xcd,0xf2,0x62,0x13,0xa1,0x50,0xdc,0x3e,0xcb, + 0x61,0x0f,0x18,0xf6,0xb3,0x8b,0x46}, + .hash_len = 16, + } +}; + +/** The hash function RIPEMD-160 +http://homes.esat.kuleuven.be/~bosselae/ripemd160.html + **/ +struct DIGEST_TEST_VECTOR ripemd160_digest_test_vector[] = { + { + .data = "", + .data_len = 0, + .hash = {0x9c,0x11,0x85,0xa5,0xc5,0xe9,0xfc,0x54,0x61, + 0x28,0x08,0x97,0x7e,0xe8,0xf5,0x48,0xb2,0x25, + 0x8d,0x31}, + .hash_len = 20, + } +}; + +/** The MD2 Message-Digest Algorithm +http://tools.ietf.org/html/rfc1319 +A.5 Test suite + **/ +struct DIGEST_TEST_VECTOR md2_digest_test_vector[] = { + { + .data = "", + .data_len = 0, + .hash = {0x83,0x50,0xe5,0xa3,0xe2,0x4c,0x15,0x3d,0xf2, + 0x27,0x5c,0x9f,0x80,0x69,0x27,0x73}, + .hash_len = 16, + }, { + .data = "a", + .data_len = 1, + .hash = {0x32,0xec,0x01,0xec,0x4a,0x6d,0xac,0x72,0xc0, + 0xab,0x96,0xfb,0x34,0xc0,0xb5,0xd1}, + .hash_len = 16, + }, { + .data = "abc", + .data_len = 3, + .hash = {0xda,0x85,0x3b,0x0d,0x3f,0x88,0xd9,0x9b,0x30, + 0x28,0x3a,0x69,0xe6,0xde,0xd6,0xbb}, + .hash_len = 16, + }, { + .data = "message digest", + .data_len = 14, + .hash = {0xab,0x4f,0x49,0x6b,0xfb,0x2a,0x53,0x0b,0x21, + 0x9f,0xf3,0x30,0x31,0xfe,0x06,0xb0}, + .hash_len = 20, + }, { + .data = "abcdefghijklmnopqrstuvwxyz", + .data_len = 26, + .hash = {0x4e,0x8d,0xdf,0xf3,0x65,0x02,0x92,0xab,0x5a, + 0x41,0x08,0xc3,0xaa,0x47,0x94,0x0b}, + .hash_len = 20, + }, { + .data = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + .data_len = 62, + .hash = {0xda,0x33,0xde,0xf2,0xa4,0x2d,0xf1,0x39,0x75, + 0x35,0x28,0x46,0xc3,0x03,0x38,0xcd}, + .hash_len = 20, + }, { + .data = "12345678901234567890123456789012345678901234567890123456789012" + "345678901234567890", + .data_len = 80, + .hash = {0xd5,0x97,0x6f,0x79,0xd8,0x3d,0x3a,0x0d,0xc9, + 0x80,0x6c,0x3c,0x66,0xf3,0xef,0xd8}, + .hash_len = 20, + } +}; + +/** The MD5 Message-Digest Algorithm +http://tools.ietf.org/html/rfc1321 +A.5 Test suite + **/ +struct DIGEST_TEST_VECTOR md5_digest_test_vector[] = { + { + .data = "", + .data_len = 0, + .hash = {0xd4,0x1d,0x8c,0xd9,0x8f,0x00,0xb2,0x04,0xe9, + 0x80,0x09,0x98,0xec,0xf8,0x42,0x7e}, + .hash_len = 16, + }, { + .data = "a", + .data_len = 1, + .hash = {0x0c,0xc1,0x75,0xb9,0xc0,0xf1,0xb6,0xa8,0x31, + 0xc3,0x99,0xe2,0x69,0x77,0x26,0x61}, + .hash_len = 16, + }, { + .data = "abc", + .data_len = 3, + .hash = {0x90,0x01,0x50,0x98,0x3c,0xd2,0x4f,0xb0,0xd6, + 0x96,0x3f,0x7d,0x28,0xe1,0x7f,0x72}, + .hash_len = 16, + } +}; + +/** SHA test Vectors for Hashing Byte-Oriented Messages +http://csrc.nist.gov/groups/STM/cavp/documents/shs/shabytetestvectors.zip +SHA1ShortMsg.rsp and SHA1LongMsg.rsp + +FIPS PUB 180-1 +http://www.itl.nist.gov/fipspubs/fip180-1.htm + **/ +struct DIGEST_TEST_VECTOR sha1_digest_test_vector[] = { + { // #0 + .data = "", + .data_len = 0, + .hash = {0xda,0x39,0xa3,0xee,0x5e,0x6b,0x4b,0x0d,0x32, + 0x55,0xbf,0xef,0x95,0x60,0x18,0x90,0xaf,0xd8, + 0x07,0x09}, + .hash_len = 20, + }, { // #1 + .data = "abc", + .data_len = 3, + .hash = {0xA9,0x99,0x3E,0x36,0x47,0x06,0x81,0x6A,0xBA, + 0x3E,0x25,0x71,0x78,0x50,0xC2,0x6C,0x9C,0xD0, + 0xD8,0x9D}, + .hash_len = 20, + }, { // #2 + .data = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + .data_len = 56, + .hash = {0x84,0x98,0x3E,0x44,0x1C,0x3B,0xD2,0x6E,0xBA, + 0xAE,0x4A,0xA1,0xF9,0x51,0x29,0xE5,0xE5,0x46, + 0x70,0xF1}, + .hash_len = 20, + .chunks = {28, 0, 28}, + .num_chunks = 3, + }, { // #3 + .data = {0x03,0x21,0x79,0x4b,0x73,0x94,0x18,0xc2,0x4e, + 0x7c,0x2e,0x56,0x52,0x74,0x79,0x1c,0x4b,0xe7, + 0x49,0x75,0x2a,0xd2,0x34,0xed,0x56,0xcb,0x0a, + 0x63,0x47,0x43,0x0c,0x6b}, + .data_len = 32, + .hash = {0xb8,0x99,0x62,0xc9,0x4d,0x60,0xf6,0xa3,0x32, + 0xfd,0x60,0xf6,0xf0,0x7d,0x4f,0x03,0x2a,0x58, + 0x6b,0x76}, + .hash_len = 20, + .num_chunks = 5, + .chunks = {8,8,8,-1,8}, + }, { // #4 + .data = {0x45,0x92,0x7e,0x32,0xdd,0xf8,0x01,0xca,0xf3, + 0x5e,0x18,0xe7,0xb5,0x07,0x8b,0x7f,0x54,0x35, + 0x27,0x82,0x12,0xec,0x6b,0xb9,0x9d,0xf8,0x84, + 0xf4,0x9b,0x32,0x7c,0x64,0x86,0xfe,0xae,0x46, + 0xba,0x18,0x7d,0xc1,0xcc,0x91,0x45,0x12,0x1e, + 0x14,0x92,0xe6,0xb0,0x6e,0x90,0x07,0x39,0x4d, + 0xc3,0x3b,0x77,0x48,0xf8,0x6a,0xc3,0x20,0x7c, + 0xfe}, + .data_len = 64, + .hash = {0xa7,0x0c,0xfb,0xfe,0x75,0x63,0xdd,0x0e,0x66, + 0x5c,0x7c,0x67,0x15,0xa9,0x6a,0x8d,0x75,0x69, + 0x50,0xc0}, + .hash_len = 20, + }, { // #5 + .data = {0x7c,0x9c,0x67,0x32,0x3a,0x1d,0xf1,0xad,0xbf, + 0xe5,0xce,0xb4,0x15,0xea,0xef,0x01,0x55,0xec, + 0xe2,0x82,0x0f,0x4d,0x50,0xc1,0xec,0x22,0xcb, + 0xa4,0x92,0x8a,0xc6,0x56,0xc8,0x3f,0xe5,0x85, + 0xdb,0x6a,0x78,0xce,0x40,0xbc,0x42,0x75,0x7a, + 0xba,0x7e,0x5a,0x3f,0x58,0x24,0x28,0xd6,0xca, + 0x68,0xd0,0xc3,0x97,0x83,0x36,0xa6,0xef,0xb7, + 0x29,0x61,0x3e,0x8d,0x99,0x79,0x01,0x62,0x04, + 0xbf,0xd9,0x21,0x32,0x2f,0xdd,0x52,0x22,0x18, + 0x35,0x54,0x44,0x7d,0xe5,0xe6,0xe9,0xbb,0xe6, + 0xed,0xf7,0x6d,0x7b,0x71,0xe1,0x8d,0xc2,0xe8, + 0xd6,0xdc,0x89,0xb7,0x39,0x83,0x64,0xf6,0x52, + 0xfa,0xfc,0x73,0x43,0x29,0xaa,0xfa,0x3d,0xcd, + 0x45,0xd4,0xf3,0x1e,0x38,0x8e,0x4f,0xaf,0xd7, + 0xfc,0x64,0x95,0xf3,0x7c,0xa5,0xcb,0xab,0x7f, + 0x54,0xd5,0x86,0x46,0x3d,0xa4,0xbf,0xea,0xa3, + 0xba,0xe0,0x9f,0x7b,0x8e,0x92,0x39,0xd8,0x32, + 0xb4,0xf0,0xa7,0x33,0xaa,0x60,0x9c,0xc1,0xf8, + 0xd4}, + .data_len = 163, + .hash = {0xd8,0xfd,0x6a,0x91,0xef,0x3b,0x6c,0xed,0x05, + 0xb9,0x83,0x58,0xa9,0x91,0x07,0xc1,0xfa,0xc8, + 0xc8,0x07}, + .hash_len = 20, + .num_chunks = 4, + .chunks = {50, 50, 50, 13}, + }, { // #6 + .data = {0x6c,0xb7,0x0d,0x19,0xc0,0x96,0x20,0x0f,0x92, + 0x49,0xd2,0xdb,0xc0,0x42,0x99,0xb0,0x08,0x5e, + 0xb0,0x68,0x25,0x75,0x60,0xbe,0x3a,0x30,0x7d, + 0xbd,0x74,0x1a,0x33,0x78,0xeb,0xfa,0x03,0xfc, + 0xca,0x61,0x08,0x83,0xb0,0x7f,0x7f,0xea,0x56, + 0x3a,0x86,0x65,0x71,0x82,0x24,0x72,0xda,0xde, + 0x8a,0x0b,0xec,0x4b,0x98,0x20,0x2d,0x47,0xa3, + 0x44,0x31,0x29,0x76,0xa7,0xbc,0xb3,0x96,0x44, + 0x27,0xea,0xcb,0x5b,0x05,0x25,0xdb,0x22,0x06, + 0x65,0x99,0xb8,0x1b,0xe4,0x1e,0x5a,0xda,0xf1, + 0x57,0xd9,0x25,0xfa,0xc0,0x4b,0x06,0xeb,0x6e, + 0x01,0xde,0xb7,0x53,0xba,0xbf,0x33,0xbe,0x16, + 0x16,0x2b,0x21,0x4e,0x8d,0xb0,0x17,0x21,0x2f, + 0xaf,0xa5,0x12,0xcd,0xc8,0xc0,0xd0,0xa1,0x5c, + 0x10,0xf6,0x32,0xe8,0xf4,0xf4,0x77,0x92,0xc6, + 0x4d,0x3f,0x02,0x60,0x04,0xd1,0x73,0xdf,0x50, + 0xcf,0x0a,0xa7,0x97,0x60,0x66,0xa7,0x9a,0x8d, + 0x78,0xde,0xee,0xec,0x95,0x1d,0xab,0x7c,0xc9, + 0x0f,0x68,0xd1,0x6f,0x78,0x66,0x71,0xfe,0xba, + 0x0b,0x7d,0x26,0x9d,0x92,0x94,0x1c,0x4f,0x02, + 0xf4,0x32,0xaa,0x5c,0xe2,0xaa,0xb6,0x19,0x4d, + 0xcc,0x6f,0xd3,0xae,0x36,0xc8,0x43,0x32,0x74, + 0xef,0x6b,0x1b,0xd0,0xd3,0x14,0x63,0x6b,0xe4, + 0x7b,0xa3,0x8d,0x19,0x48,0x34,0x3a,0x38,0xbf, + 0x94,0x06,0x52,0x3a,0x0b,0x2a,0x8c,0xd7,0x8e, + 0xd6,0x26,0x6e,0xe3,0xc9,0xb5,0xc6,0x06,0x20, + 0xb3,0x08,0xcc,0x6b,0x3a,0x73,0xc6,0x06,0x0d, + 0x52,0x68,0xa7,0xd8,0x2b,0x6a,0x33,0xb9,0x3a, + 0x6f,0xd6,0xfe,0x1d,0xe5,0x52,0x31,0xd1,0x2c, + 0x97}, + .data_len = 262, + .hash = {0x4a,0x75,0xa4,0x06,0xf4,0xde,0x5f,0x9e,0x11, + 0x32,0x06,0x9d,0x66,0x71,0x7f,0xc4,0x24,0x37, + 0x63,0x88}, + .hash_len = 20, + .num_chunks = 5, + .chunks = {75, 75, 75, 37, 0}, + }, +}; + +/** SHA test Vectors for Hashing Byte-Oriented Messages +http://csrc.nist.gov/groups/STM/cavp/documents/shs/shabytetestvectors.zip +SHA256ShortMsg.rsp & SHA256LongMsg.rsp + +http://csrc.nist.gov/groups/ST/toolkit/examples.html + **/ +struct DIGEST_TEST_VECTOR sha224_digest_test_vector[] = { + { + .data = {0x00}, + .data_len = 0, + .hash = {0xd1,0x4a,0x02,0x8c,0x2a,0x3a,0x2b,0xc9,0x47, + 0x61,0x02,0xbb,0x28,0x82,0x34,0xc4,0x15,0xa2, + 0xb0,0x1f,0x82,0x8e,0xa6,0x2a,0xc5,0xb3,0xe4, + 0x2f}, + .hash_len = 28, + }, { + .data = "abc", + .data_len = 3, + .hash = {0x23,0x09,0x7d,0x22,0x34,0x05,0xd8,0x22,0x86, + 0x42,0xa4,0x77,0xbd,0xa2,0x55,0xb3,0x2a,0xad, + 0xbc,0xe4,0xbd,0xa0,0xb3,0xf7,0xe3,0x6c,0x9d, + 0xa7}, + .hash_len = 28, + }, { + .data = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + .data_len = 56, + .hash = {0x75,0x38,0x8b,0x16,0x51,0x27,0x76,0xcc,0x5d, + 0xba,0x5d,0xa1,0xfd,0x89,0x01,0x50,0xb0,0xc6, + 0x45,0x5c,0xb4,0xf5,0x8b,0x19,0x52,0x52,0x25, + 0x25}, + .hash_len = 28, + .chunks = {28, 0, 28}, + .num_chunks = 3, + }, { + .data = {0xfe,0x1f,0x0f,0xb0,0x2c,0x90,0x11,0xf4,0xc8, + 0xc5,0x90,0x59,0x34,0xed,0x15,0x13,0x67,0x71, + 0x73,0x7c,0xe3,0x1c,0x58,0x59,0xe6,0x7f,0x23, + 0x5f,0xe5,0x94,0xf5,0xf6}, + .data_len = 32, + .hash = {0xbb,0xea,0xac,0xc6,0x32,0xc2,0xa3,0xdb,0x2a, + 0x9b,0x47,0xf1,0x57,0xab,0x54,0xaa,0x27,0x77, + 0x6c,0x6e,0x74,0xcf,0x0b,0xca,0xa9,0x1b,0x06, + 0xd5}, + .hash_len = 28, + .chunks = {16, -1, 16, 0}, + .num_chunks = 4, + }, { + .data = {0xa3,0x31,0x0b,0xa0,0x64,0xbe,0x2e,0x14,0xad, + 0x32,0x27,0x6e,0x18,0xcd,0x03,0x10,0xc9,0x33, + 0xa6,0xe6,0x50,0xc3,0xc7,0x54,0xd0,0x24,0x3c, + 0x6c,0x61,0x20,0x78,0x65,0xb4,0xb6,0x52,0x48, + 0xf6,0x6a,0x08,0xed,0xf6,0xe0,0x83,0x26,0x89, + 0xa9,0xdc,0x3a,0x2e,0x5d,0x20,0x95,0xee,0xea, + 0x50,0xbd,0x86,0x2b,0xac,0x88,0xc8,0xbd,0x31, + 0x8d}, + .data_len = 64, + .hash = {0xb2,0xa5,0x58,0x6d,0x9c,0xbf,0x0b,0xaa,0x99, + 0x91,0x57,0xb4,0xaf,0x06,0xd8,0x8a,0xe0,0x8d, + 0x7c,0x9f,0xaa,0xb4,0xbc,0x1a,0x96,0x82,0x9d, + 0x65}, + .hash_len = 28, + .chunks = {20, 14, 30}, + .num_chunks = 3, + }, { + .data = {0xf1,0x49,0xe4,0x1d,0x84,0x8f,0x59,0x27,0x6c, + 0xfd,0xdd,0x74,0x3b,0xaf,0xa9,0xa9,0x0e,0x1e, + 0xe4,0xa2,0x63,0xa1,0x18,0x14,0x2b,0x33,0xe3, + 0x70,0x21,0x76,0xef,0x0a,0x59,0xf8,0x23,0x7a, + 0x1c,0xb5,0x1b,0x42,0xf3,0xde,0xd6,0xb2,0x02, + 0xd9,0xaf,0x09,0x97,0x89,0x8f,0xdd,0x03,0xcf, + 0x60,0xbd,0xa9,0x51,0xc5,0x14,0x54,0x7a,0x08, + 0x50,0xce,0xc2,0x54,0x44,0xae,0x2f,0x24,0xcb, + 0x71,0x1b,0xfb,0xaf,0xcc,0x39,0x56,0xc9,0x41, + 0xd3,0xde,0x69,0xf1,0x55,0xe3,0xf8,0xb1,0x0f, + 0x06,0xdb,0x5f,0x37,0x35,0x9b,0x77,0x2d,0xdd, + 0x43,0xe1,0x03,0x5a,0x0a,0x0d,0x3d,0xb3,0x32, + 0x42,0xd5,0x84,0x30,0x33,0x83,0x3b,0x0d,0xd4, + 0x3b,0x87,0x0c,0x6b,0xf6,0x0e,0x8d,0xea,0xb5, + 0x5f,0x31,0x7c,0xc3,0x27,0x3f,0x5e,0x3b,0xa7, + 0x47,0xf0,0xcb,0x65,0x05,0x0c,0xb7,0x22,0x87, + 0x96,0x21,0x0d,0x92,0x54,0x87,0x36,0x43,0x00, + 0x8d,0x45,0xf2,0x9c,0xfd,0x6c,0x5b,0x06,0x0c, + 0x9a}, + .data_len = 163, + .hash = {0x9d,0xb6,0xdc,0x3a,0x23,0xab,0xd7,0xb6,0xc3, + 0xd7,0x2c,0x38,0xf4,0x84,0x3c,0x7d,0xe4,0x8a, + 0x71,0xd0,0xba,0x91,0xa8,0x6b,0x18,0x39,0x3e, + 0x5f}, + .hash_len = 28, + .chunks = {54, 54, 54, 1, 0}, + .num_chunks = 5, + } +}; + + +/** SHA test Vectors for Hashing Byte-Oriented Messages +http://csrc.nist.gov/groups/STM/cavp/documents/shs/shabytetestvectors.zip +SHA256ShortMsg.rsp & SHA256LongMsg.rsp + +http://csrc.nist.gov/groups/ST/toolkit/examples.html + **/ +struct DIGEST_TEST_VECTOR sha256_digest_test_vector[] = { + { + .data = {0x00}, + .data_len = 0, + .hash = {0xe3,0xb0,0xc4,0x42,0x98,0xfc,0x1c,0x14,0x9a, + 0xfb,0xf4,0xc8,0x99,0x6f,0xb9,0x24,0x27,0xae, + 0x41,0xe4,0x64,0x9b,0x93,0x4c,0xa4,0x95,0x99, + 0x1b,0x78,0x52,0xb8,0x55}, + .hash_len = 32, + }, { + .data = "abc", + .data_len = 3, + .hash = {0xba,0x78,0x16,0xbf,0x8f,0x01,0xcf,0xea,0x41, + 0x41,0x40,0xde,0x5d,0xae,0x22,0x23,0xb0,0x03, + 0x61,0xa3,0x96,0x17,0x7a,0x9c,0xb4,0x10,0xff, + 0x61,0xf2,0x00,0x15,0xad}, + .hash_len = 32, + }, { + .data = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + .data_len = 56, + .hash = {0x24,0x8d,0x6a,0x61,0xd2,0x06,0x38,0xb8,0xe5, + 0xc0,0x26,0x93,0x0c,0x3e,0x60,0x39,0xa3,0x3c, + 0xe4,0x59,0x64,0xff,0x21,0x67,0xf6,0xec,0xed, + 0xd4,0x19,0xdb,0x06,0xc1}, + .hash_len = 32, + .chunks = {28, 0, 28}, + .num_chunks = 3, + }, { + .data = {0x09,0xfc,0x1a,0xcc,0xc2,0x30,0xa2,0x05,0xe4, + 0xa2,0x08,0xe6,0x4a,0x8f,0x20,0x42,0x91,0xf5, + 0x81,0xa1,0x27,0x56,0x39,0x2d,0xa4,0xb8,0xc0, + 0xcf,0x5e,0xf0,0x2b,0x95}, + .data_len = 32, + .hash = {0x4f,0x44,0xc1,0xc7,0xfb,0xeb,0xb6,0xf9,0x60, + 0x18,0x29,0xf3,0x89,0x7b,0xfd,0x65,0x0c,0x56, + 0xfa,0x07,0x84,0x4b,0xe7,0x64,0x89,0x07,0x63, + 0x56,0xac,0x18,0x86,0xa4}, + .hash_len = 32, + .chunks = {16, -1, 16, 0}, + .num_chunks = 4, + }, { + .data = {0x5a,0x86,0xb7,0x37,0xea,0xea,0x8e,0xe9,0x76, + 0xa0,0xa2,0x4d,0xa6,0x3e,0x7e,0xd7,0xee,0xfa, + 0xd1,0x8a,0x10,0x1c,0x12,0x11,0xe2,0xb3,0x65, + 0x0c,0x51,0x87,0xc2,0xa8,0xa6,0x50,0x54,0x72, + 0x08,0x25,0x1f,0x6d,0x42,0x37,0xe6,0x61,0xc7, + 0xbf,0x4c,0x77,0xf3,0x35,0x39,0x03,0x94,0xc3, + 0x7f,0xa1,0xa9,0xf9,0xbe,0x83,0x6a,0xc2,0x85, + 0x09}, + .data_len = 64, + .hash = {0x42,0xe6,0x1e,0x17,0x4f,0xbb,0x38,0x97,0xd6, + 0xdd,0x6c,0xef,0x3d,0xd2,0x80,0x2f,0xe6,0x7b, + 0x33,0x19,0x53,0xb0,0x61,0x14,0xa6,0x5c,0x77, + 0x28,0x59,0xdf,0xc1,0xaa}, + .hash_len = 32, + .chunks = {20, 14, 30}, + .num_chunks = 3, + }, { + .data = {0x45,0x11,0x01,0x25,0x0e,0xc6,0xf2,0x66,0x52, + 0x24,0x9d,0x59,0xdc,0x97,0x4b,0x73,0x61,0xd5, + 0x71,0xa8,0x10,0x1c,0xdf,0xd3,0x6a,0xba,0x3b, + 0x58,0x54,0xd3,0xae,0x08,0x6b,0x5f,0xdd,0x45, + 0x97,0x72,0x1b,0x66,0xe3,0xc0,0xdc,0x5d,0x8c, + 0x60,0x6d,0x96,0x57,0xd0,0xe3,0x23,0x28,0x3a, + 0x52,0x17,0xd1,0xf5,0x3f,0x2f,0x28,0x4f,0x57, + 0xb8,0x5c,0x8a,0x61,0xac,0x89,0x24,0x71,0x1f, + 0x89,0x5c,0x5e,0xd9,0x0e,0xf1,0x77,0x45,0xed, + 0x2d,0x72,0x8a,0xbd,0x22,0xa5,0xf7,0xa1,0x34, + 0x79,0xa4,0x62,0xd7,0x1b,0x56,0xc1,0x9a,0x74, + 0xa4,0x0b,0x65,0x5c,0x58,0xed,0xfe,0x0a,0x18, + 0x8a,0xd2,0xcf,0x46,0xcb,0xf3,0x05,0x24,0xf6, + 0x5d,0x42,0x3c,0x83,0x7d,0xd1,0xff,0x2b,0xf4, + 0x62,0xac,0x41,0x98,0x00,0x73,0x45,0xbb,0x44, + 0xdb,0xb7,0xb1,0xc8,0x61,0x29,0x8c,0xdf,0x61, + 0x98,0x2a,0x83,0x3a,0xfc,0x72,0x8f,0xae,0x1e, + 0xda,0x2f,0x87,0xaa,0x2c,0x94,0x80,0x85,0x8b, + 0xec}, + .data_len = 163, + .hash = {0x3c,0x59,0x3a,0xa5,0x39,0xfd,0xcd,0xae,0x51, + 0x6c,0xdf,0x2f,0x15,0x00,0x0f,0x66,0x34,0x18, + 0x5c,0x88,0xf5,0x05,0xb3,0x97,0x75,0xfb,0x9a, + 0xb1,0x37,0xa1,0x0a,0xa2}, + .hash_len = 32, + .chunks = {54, 54, 54, 1, 0}, + .num_chunks = 5, + } +}; + +/** SHA test Vectors for Hashing Byte-Oriented Messages +http://csrc.nist.gov/groups/STM/cavp/documents/shs/shabytetestvectors.zip +SHA384ShortMsg.rsp & SHA384LongMsg.rsp + +http://csrc.nist.gov/groups/ST/toolkit/examples.html + **/ +struct DIGEST_TEST_VECTOR sha384_digest_test_vector[] = { + { + .data = {0x00}, + .data_len = 0, + .hash = {0x38,0xb0,0x60,0xa7,0x51,0xac,0x96,0x38,0x4c, + 0xd9,0x32,0x7e,0xb1,0xb1,0xe3,0x6a,0x21,0xfd, + 0xb7,0x11,0x14,0xbe,0x07,0x43,0x4c,0x0c,0xc7, + 0xbf,0x63,0xf6,0xe1,0xda,0x27,0x4e,0xde,0xbf, + 0xe7,0x6f,0x65,0xfb,0xd5,0x1a,0xd2,0xf1,0x48, + 0x98,0xb9,0x5b}, + .hash_len = 48, + },{ + .data = "abc", + .data_len = 3, + .hash = {0xcb,0x00,0x75,0x3f,0x45,0xa3,0x5e,0x8b,0xb5, + 0xa0,0x3d,0x69,0x9a,0xc6,0x50,0x07,0x27,0x2c, + 0x32,0xab,0x0e,0xde,0xd1,0x63,0x1a,0x8b,0x60, + 0x5a,0x43,0xff,0x5b,0xed,0x80,0x86,0x07,0x2b, + 0xa1,0xe7,0xcc,0x23,0x58,0xba,0xec,0xa1,0x34, + 0xc8,0x25,0xa7}, + .hash_len = 48, + },{ + .data = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklm" + "noijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + .data_len = 112, + .hash = {0x09,0x33,0x0c,0x33,0xf7,0x11,0x47,0xe8,0x3d, + 0x19,0x2f,0xc7,0x82,0xcd,0x1b,0x47,0x53,0x11, + 0x1b,0x17,0x3b,0x3b,0x05,0xd2,0x2f,0xa0,0x80, + 0x86,0xe3,0xb0,0xf7,0x12,0xfc,0xc7,0xc7,0x1a, + 0x55,0x7e,0x2d,0xb9,0x66,0xc3,0xe9,0xfa,0x91, + 0x74,0x60,0x39}, + .hash_len = 48, + .chunks = {24, 40, 0, 48}, + .num_chunks = 4, + }, { + .data = {0xbe,0x01,0xe5,0x20,0xe6,0x9f,0x04,0x17,0x4c, + 0xcf,0x95,0x45,0x5b,0x1c,0x81,0x44,0x52,0x98, + 0x26,0x4d,0x9a,0xdc,0x49,0x58,0x57,0x4a,0x52, + 0x84,0x3d,0x95,0xb8,0xba}, + .data_len = 32, + .hash = {0xc5,0xcf,0x54,0xb8,0xe3,0x10,0x5b,0x1c,0x7b, + 0xf7,0xa4,0x37,0x54,0xd9,0x15,0xb0,0x94,0x7f, + 0x28,0xb6,0xdc,0x94,0xa0,0x19,0x18,0x29,0x29, + 0xb5,0xc8,0x48,0xe1,0x14,0x41,0xc9,0xe4,0xe9, + 0x0c,0x74,0x49,0xf4,0xc3,0xcd,0x12,0x95,0x4f, + 0x0f,0x5d,0x99}, + .hash_len = 48, + .chunks = {16, -1, 16, 0}, + .num_chunks = 4, + }, { + .data = {0x93,0x03,0x5d,0x3a,0x13,0xae,0x1b,0x06,0xdd, + 0x03,0x3e,0x76,0x4a,0xca,0x01,0x24,0x96,0x1d, + 0xa7,0x9c,0x36,0x6c,0x6c,0x75,0x6b,0xc4,0xbc, + 0xc1,0x18,0x50,0xa3,0xa8,0xd1,0x20,0x85,0x4f, + 0x34,0x29,0x0f,0xff,0x7c,0x8d,0x6d,0x83,0x53, + 0x1d,0xbd,0xd1,0xe8,0x1c,0xc4,0xed,0x42,0x46, + 0xe0,0x0b,0xd4,0x11,0x3e,0xf4,0x51,0x33,0x4d, + 0xaa}, + .data_len = 64, + .hash = {0x8d,0x46,0xcc,0x84,0xb6,0xc2,0xde,0xb2,0x06, + 0xaa,0x5c,0x86,0x17,0x98,0x79,0x87,0x51,0xa2, + 0x6e,0xe7,0x4b,0x1d,0xaf,0x3a,0x55,0x7c,0x41, + 0xae,0xbd,0x65,0xad,0xc0,0x27,0x55,0x9f,0x7c, + 0xd9,0x2b,0x25,0x5b,0x37,0x4c,0x83,0xbd,0x55, + 0x56,0x8b,0x45}, + .hash_len = 48, + .chunks = {20, 14, 30}, + .num_chunks = 3 + }, { + .data = {0x3b,0xf5,0x2c,0xc5,0xee,0x86,0xb9,0xa0,0x19, + 0x0f,0x39,0x0a,0x5c,0x03,0x66,0xa5,0x60,0xb5, + 0x57,0x00,0x0d,0xbe,0x51,0x15,0xfd,0x9e,0xe1, + 0x16,0x30,0xa6,0x27,0x69,0x01,0x15,0x75,0xf1, + 0x58,0x81,0x19,0x8f,0x22,0x78,0x76,0xe8,0xfe, + 0x68,0x5a,0x69,0x39,0xbc,0x8b,0x89,0xfd,0x48, + 0xa3,0x4e,0xc5,0xe7,0x1e,0x13,0x14,0x62,0xb2, + 0x88,0x67,0x94,0xdf,0xfa,0x68,0xcc,0xc6,0xd5, + 0x64,0x73,0x3e,0x67,0xff,0xef,0x25,0xe6,0x27, + 0xc6,0xf4,0xb5,0x46,0x07,0x96,0xe3,0xbc,0xe6, + 0x7b,0xf5,0x8c,0xa6,0xe8,0xe5,0x55,0xbc,0x91, + 0x6a,0x85,0x31,0x69,0x7a,0xc9,0x48,0xb9,0x0d, + 0xc8,0x61,0x6f,0x25,0x10,0x1d,0xb9,0x0b,0x50, + 0xc3,0xd3,0xdb,0xc9,0xe2,0x1e,0x42,0xff,0x38, + 0x71,0x87}, + .data_len = 128, + .hash = {0x12,0xb6,0xcb,0x35,0xed,0xa9,0x2e,0xe3,0x73, + 0x56,0xdd,0xee,0x77,0x78,0x1a,0x17,0xb3,0xd9, + 0x0e,0x56,0x38,0x24,0xa9,0x84,0xfa,0xff,0xc6, + 0xfd,0xd1,0x69,0x3b,0xd7,0x62,0x60,0x39,0x63, + 0x55,0x63,0xcf,0xc3,0xb9,0xa2,0xb0,0x0f,0x9c, + 0x65,0xee,0xfd}, + .hash_len = 48, + .chunks = {48, 48, -1, 32}, + .num_chunks = 4, + }, { + .data = {0x62,0xc6,0xa1,0x69,0xb9,0xbe,0x02,0xb3,0xd7, + 0xb4,0x71,0xa9,0x64,0xfc,0x0b,0xcc,0x72,0xb4, + 0x80,0xd2,0x6a,0xec,0xb2,0xed,0x46,0x0b,0x7f, + 0x50,0x01,0x6d,0xda,0xf0,0x4c,0x51,0x21,0x87, + 0x83,0xf3,0xaa,0xdf,0xdf,0xf5,0xa0,0x4d,0xed, + 0x03,0x0d,0x7b,0x3f,0xb7,0x37,0x6b,0x61,0xba, + 0x30,0xb9,0x0e,0x2d,0xa9,0x21,0xa4,0x47,0x07, + 0x40,0xd6,0x3f,0xb9,0x9f,0xa1,0x6c,0xc8,0xed, + 0x81,0xab,0xaf,0x8c,0xe4,0x01,0x6e,0x50,0xdf, + 0x81,0xda,0x83,0x20,0x70,0x37,0x2c,0x24,0xa8, + 0x08,0x90,0xaa,0x3a,0x26,0xfa,0x67,0x57,0x10, + 0xb8,0xfb,0x71,0x82,0x66,0x24,0x9d,0x49,0x6f, + 0x31,0x3c,0x55,0xd0,0xba,0xda,0x10,0x1f,0x8f, + 0x56,0xee,0xcc,0xee,0x43,0x45,0xa8,0xf9,0x8f, + 0x60,0xa3,0x66,0x62,0xcf,0xda,0x79,0x49,0x00, + 0xd1,0x2f,0x94,0x14,0xfc,0xbd,0xfd,0xeb,0x85, + 0x38,0x8a,0x81,0x49,0x96,0xb4,0x7e,0x24,0xd5, + 0xc8,0x08,0x6e,0x7a,0x8e,0xdc,0xc5,0x3d,0x29, + 0x9d,0x0d,0x03,0x3e,0x6b,0xb6,0x0c,0x58,0xb8, + 0x3d,0x6e,0x8b,0x57,0xf6,0xc2,0x58,0xd6,0x08, + 0x1d,0xd1,0x0e,0xb9,0x42,0xfd,0xf8,0xec,0x15, + 0x7e,0xc3,0xe7,0x53,0x71,0x23,0x5a,0x81,0x96, + 0xeb,0x9d,0x22,0xb1,0xde,0x3a,0x2d,0x30,0xc2, + 0xab,0xbe,0x0d,0xb7,0x65,0x0c,0xf6,0xc7,0x15, + 0x9b,0xac,0xbe,0x29,0xb3,0xa9,0x3c,0x92,0x10, + 0x05,0x08}, + .data_len = 227, + .hash = {0x07,0x30,0xe1,0x84,0xe7,0x79,0x55,0x75,0x56, + 0x9f,0x87,0x03,0x02,0x60,0xbb,0x8e,0x54,0x49, + 0x8e,0x0e,0x5d,0x09,0x6b,0x18,0x28,0x5e,0x98, + 0x8d,0x24,0x5b,0x6f,0x34,0x86,0xd1,0xf2,0x44, + 0x7d,0x5f,0x85,0xbc,0xbe,0x59,0xd5,0x68,0x9f, + 0xc4,0x94,0x25}, + .hash_len = 48, + .chunks = {30, 30, 30, 30, 30, 30, 30, 17}, + .num_chunks = 8, + }, { + .data = {0xff,0xd6,0x78,0x90,0xff,0x77,0xf3,0x44,0xad, + 0x4f,0x06,0x7d,0xf2,0xf4,0xff,0x1d,0xb8,0xf5, + 0x41,0xc7,0xa2,0xbd,0x9a,0xe9,0xfa,0xba,0xd0, + 0xfa,0xeb,0xbf,0x7d,0x00,0xf0,0xa7,0x1d,0x56, + 0x8c,0x3c,0x66,0xac,0x3c,0x57,0xd8,0x4f,0xaa, + 0x48,0x94,0xab,0x23,0x77,0x71,0x0e,0x4b,0x4c, + 0x4d,0xae,0x0f,0x4d,0xa1,0xee,0xdc,0x86,0x58, + 0xdd,0x0e,0x2e,0xe2,0xff,0xac,0x87,0x84,0x51, + 0x52,0x06,0xf2,0x87,0x6e,0xb4,0x1f,0x98,0xaf, + 0xd4,0x54,0x7c,0xbb,0xc6,0x80,0x34,0x21,0x2b, + 0xcf,0x0c,0x8e,0x4a,0x7d,0x1d,0x43,0xb3,0xed, + 0x15,0xc6,0x21,0xf5,0x3b,0xd8,0xa5,0x7c,0xad, + 0xa8,0x01,0x48,0xec,0x46,0x52,0x11,0x9b,0x5a, + 0xf3,0xda,0x84,0x16,0x9d,0x81,0xdc,0x69,0xd3, + 0x94,0xc8,0x76,0x7d,0x66,0x20,0x44,0xd3,0x62, + 0x72,0xb7,0x7c,0xa0,0x4a,0xbf,0xf7,0xb6,0xb0, + 0xcf,0x3b,0xd1,0xf3,0x91,0x9a,0x04,0xa5,0xd8, + 0xeb,0xdf,0xe7,0xd6,0xe8,0x44,0xe7,0x8f,0xd5, + 0x76,0xa6,0x8d,0x63,0x73,0xff,0xd5,0xd3,0x84, + 0xe5,0x1b,0x5e,0x12,0xec,0x32,0xd5,0xbb,0x0a, + 0xc6,0x85,0xa5,0x9f,0x4d,0x5d,0x12,0xb4,0x3b, + 0x53,0x35,0x80,0x75,0x03,0x45,0x31,0x09,0x99, + 0xcf,0xe9,0x1c,0xf2,0x50,0x06,0x24,0xfe,0x03, + 0xa6,0x57,0x69,0xf8,0x6a,0x62,0x7a,0x66,0x7b, + 0x5f,0x3b,0x42,0xcb,0x01,0xda,0x10,0x9e,0x12, + 0x4f,0xfa,0x48,0x20,0x3f,0x1f,0x38,0x73,0x20, + 0x2d,0x35,0x42,0x9f,0x32,0xe8,0x26,0x3e,0xaf, + 0x9b,0xce,0x42,0xef,0x40,0xf5,0xcc,0x96,0xb5, + 0x91,0x46,0x7d,0x46,0x4d,0x00,0xbd,0x74,0x3a, + 0x1b,0x0a,0xf4,0xc1,0xa7,0x43,0xfb,0xdd,0x08, + 0x46,0xb9,0x87,0x9e,0x09,0x23,0x71,0xa5,0xe7, + 0xf6,0xf6,0x59,0x37,0xf9,0x51,0x5e,0x23,0x82, + 0x0e,0x60,0xb8,0x3b,0xbf,0xf7,0x39,0x26,0xf0, + 0xcd,0xb9,0xdf,0x5d,0x02,0xe8,0x22,0x62,0xcf, + 0x2e,0x8c,0xb2,0x6a,0xf6,0xa6,0x4c,0x2a,0x4d, + 0x1f,0xab,0xec,0xab,0x59,0x3d,0xb5,0x10,0x28, + 0x17,0x99}, + .data_len = 326, + .hash = {0x13,0x96,0xfe,0xa9,0x5c,0xe0,0xc1,0xc1,0xc2, + 0x24,0xb5,0x0a,0x07,0xdd,0x71,0x97,0xf1,0xd6, + 0x2b,0x99,0x3c,0x7f,0xe9,0xe1,0xcc,0x1a,0x56, + 0x10,0x19,0x20,0xd4,0xb0,0xfe,0xce,0xf5,0x87, + 0xfb,0xcd,0x56,0xb8,0x54,0xc8,0xc9,0xda,0x95, + 0x13,0x2f,0x02}, + .hash_len = 48, + .chunks = {163, 163}, + .num_chunks = 2, + } +}; + +/** SHA test Vectors for Hashing Byte-Oriented Messages +http://csrc.nist.gov/groups/STM/cavp/documents/shs/shabytetestvectors.zip +SHA512ShortMsg.rsp & SHA512LongMsg.rsp + +http://csrc.nist.gov/groups/ST/toolkit/examples.html + **/ +struct DIGEST_TEST_VECTOR sha512_digest_test_vector[] = { + { + .data = {0x00}, + .data_len = 0, + .hash = {0xcf,0x83,0xe1,0x35,0x7e,0xef,0xb8,0xbd,0xf1, + 0x54,0x28,0x50,0xd6,0x6d,0x80,0x07,0xd6,0x20, + 0xe4,0x05,0x0b,0x57,0x15,0xdc,0x83,0xf4,0xa9, + 0x21,0xd3,0x6c,0xe9,0xce,0x47,0xd0,0xd1,0x3c, + 0x5d,0x85,0xf2,0xb0,0xff,0x83,0x18,0xd2,0x87, + 0x7e,0xec,0x2f,0x63,0xb9,0x31,0xbd,0x47,0x41, + 0x7a,0x81,0xa5,0x38,0x32,0x7a,0xf9,0x27,0xda, + 0x3e}, + .hash_len = 64, + },{ + .data = "abc", + .data_len = 3, + .hash = {0xdd,0xaf,0x35,0xa1,0x93,0x61,0x7a,0xba,0xcc, + 0x41,0x73,0x49,0xae,0x20,0x41,0x31,0x12,0xe6, + 0xfa,0x4e,0x89,0xa9,0x7e,0xa2,0x0a,0x9e,0xee, + 0xe6,0x4b,0x55,0xd3,0x9a,0x21,0x92,0x99,0x2a, + 0x27,0x4f,0xc1,0xa8,0x36,0xba,0x3c,0x23,0xa3, + 0xfe,0xeb,0xbd,0x45,0x4d,0x44,0x23,0x64,0x3c, + 0xe8,0x0e,0x2a,0x9a,0xc9,0x4f,0xa5,0x4c,0xa4, + 0x9f}, + .hash_len = 64, + }, { + .data = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklm" + "noijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + .data_len = 112, + .hash = {0x8e,0x95,0x9b,0x75,0xda,0xe3,0x13,0xda,0x8c, + 0xf4,0xf7,0x28,0x14,0xfc,0x14,0x3f,0x8f,0x77, + 0x79,0xc6,0xeb,0x9f,0x7f,0xa1,0x72,0x99,0xae, + 0xad,0xb6,0x88,0x90,0x18,0x50,0x1d,0x28,0x9e, + 0x49,0x00,0xf7,0xe4,0x33,0x1b,0x99,0xde,0xc4, + 0xb5,0x43,0x3a,0xc7,0xd3,0x29,0xee,0xb6,0xdd, + 0x26,0x54,0x5e,0x96,0xe5,0x5b,0x87,0x4b,0xe9, + 0x09}, + .hash_len = 64, + .chunks = {24, 40, 0, 48}, + .num_chunks = 4, + }, { + .data = {0xfd,0x22,0x03,0xe4,0x67,0x57,0x4e,0x83,0x4a, + 0xb0,0x7c,0x90,0x97,0xae,0x16,0x45,0x32,0xf2, + 0x4b,0xe1,0xeb,0x5d,0x88,0xf1,0xaf,0x77,0x48, + 0xce,0xff,0x0d,0x2c,0x67,0xa2,0x1f,0x4e,0x40, + 0x97,0xf9,0xd3,0xbb,0x4e,0x9f,0xbf,0x97,0x18, + 0x6e,0x0d,0xb6,0xdb,0x01,0x00,0x23,0x0a,0x52, + 0xb4,0x53,0xd4,0x21,0xf8,0xab,0x9c,0x9a,0x60, + 0x43,0xaa,0x32,0x95,0xea,0x20,0xd2,0xf0,0x6a, + 0x2f,0x37,0x47,0x0d,0x8a,0x99,0x07,0x5f,0x1b, + 0x8a,0x83,0x36,0xf6,0x22,0x8c,0xf0,0x8b,0x59, + 0x42,0xfc,0x1f,0xb4,0x29,0x9c,0x7d,0x24,0x80, + 0xe8,0xe8,0x2b,0xce,0x17,0x55,0x40,0xbd,0xfa, + 0xd7,0x75,0x2b,0xc9,0x5b,0x57,0x7f,0x22,0x95, + 0x15,0x39,0x4f,0x3a,0xe5,0xce,0xc8,0x70,0xa4, + 0xb2,0xf8}, + .data_len = 128, + .hash = {0xa2,0x1b,0x10,0x77,0xd5,0x2b,0x27,0xac,0x54, + 0x5a,0xf6,0x3b,0x32,0x74,0x6c,0x6e,0x3c,0x51, + 0xcb,0x0c,0xb9,0xf2,0x81,0xeb,0x9f,0x35,0x80, + 0xa6,0xd4,0x99,0x6d,0x5c,0x99,0x17,0xd2,0xa6, + 0xe4,0x84,0x62,0x7a,0x9d,0x5a,0x06,0xfa,0x1b, + 0x25,0x32,0x7a,0x9d,0x71,0x0e,0x02,0x73,0x87, + 0xfc,0x3e,0x07,0xd7,0xc4,0xd1,0x4c,0x60,0x86, + 0xcc}, + .hash_len = 64, + .chunks = {64, 64, -1}, + .num_chunks = 3, + }, { + .data = {0xc1,0xca,0x70,0xae,0x12,0x79,0xba,0x0b,0x91, + 0x81,0x57,0x55,0x8b,0x49,0x20,0xd6,0xb7,0xfb, + 0xa8,0xa0,0x6b,0xe5,0x15,0x17,0x0f,0x20,0x2f, + 0xaf,0xd3,0x6f,0xb7,0xf7,0x9d,0x69,0xfa,0xd7, + 0x45,0xdb,0xa6,0x15,0x05,0x68,0xdb,0x1e,0x2b, + 0x72,0x85,0x04,0x11,0x3e,0xea,0xc3,0x4f,0x52, + 0x7f,0xc8,0x2f,0x22,0x00,0xb4,0x62,0xec,0xbf, + 0x5d}, + .data_len = 64, + .hash = {0x04,0x6e,0x46,0x62,0x39,0x12,0xb3,0x93,0x2b, + 0x8d,0x66,0x2a,0xb4,0x25,0x83,0x42,0x38,0x43, + 0x20,0x63,0x01,0xb5,0x8b,0xf2,0x0a,0xb6,0xd7, + 0x6f,0xd4,0x7f,0x1c,0xbb,0xcf,0x42,0x1d,0xf5, + 0x36,0xec,0xd7,0xe5,0x6d,0xb5,0x35,0x4e,0x7e, + 0x0f,0x98,0x82,0x2d,0x21,0x29,0xc1,0x97,0xf6, + 0xf0,0xf2,0x22,0xb8,0xec,0x52,0x31,0xf3,0x96, + 0x7d}, + .hash_len = 64, + .chunks = {20, 14, 30}, + .num_chunks = 3, + }, { + .data = {0x4f,0x05,0x60,0x09,0x50,0x66,0x4d,0x51,0x90, + 0xa2,0xeb,0xc2,0x9c,0x9e,0xdb,0x89,0xc2,0x00, + 0x79,0xa4,0xd3,0xe6,0xbc,0x3b,0x27,0xd7,0x5e, + 0x34,0xe2,0xfa,0x3d,0x02,0x76,0x85,0x02,0xbd, + 0x69,0x79,0x00,0x78,0x59,0x8d,0x5f,0xcf,0x3d, + 0x67,0x79,0xbf,0xed,0x12,0x84,0xbb,0xe5,0xad, + 0x72,0xfb,0x45,0x60,0x15,0x18,0x1d,0x95,0x87, + 0xd6,0xe8,0x64,0xc9,0x40,0x56,0x4e,0xaa,0xfb, + 0x4f,0x2f,0xea,0xd4,0x34,0x6e,0xa0,0x9b,0x68, + 0x77,0xd9,0x34,0x0f,0x6b,0x82,0xeb,0x15,0x15, + 0x88,0x08,0x72,0x21,0x3d,0xa3,0xad,0x88,0xfe, + 0xba,0x9f,0x4f,0x13,0x81,0x7a,0x71,0xd6,0xf9, + 0x0a,0x1a,0x17,0xc4,0x3a,0x15,0xc0,0x38,0xd9, + 0x88,0xb5,0xb2,0x9e,0xdf,0xfe,0x2d,0x6a,0x06, + 0x28,0x13,0xce,0xdb,0xe8,0x52,0xcd,0xe3,0x02, + 0xb3,0xe3,0x3b,0x69,0x68,0x46,0xd2,0xa8,0xe3, + 0x6b,0xd6,0x80,0xef,0xcc,0x6c,0xd3,0xf9,0xe9, + 0xa4,0xc1,0xae,0x8c,0xac,0x10,0xcc,0x52,0x44, + 0xd1,0x31,0x67,0x71,0x40,0x39,0x91,0x76,0xed, + 0x46,0x70,0x00,0x19,0xa0,0x04,0xa1,0x63,0x80, + 0x6f,0x7f,0xa4,0x67,0xfc,0x4e,0x17,0xb4,0x61, + 0x7b,0xbd,0x76,0x41,0xaa,0xff,0x7f,0xf5,0x63, + 0x96,0xba,0x8c,0x08,0xa8,0xbe,0x10,0x0b,0x33, + 0xa2,0x0b,0x5d,0xaf,0x13,0x4a,0x2a,0xef,0xa5, + 0xe1,0xc3,0x49,0x67,0x70,0xdc,0xf6,0xba,0xa4, + 0xf7,0xbb}, + .data_len = 227, + .hash = {0xa9,0xdb,0x49,0x0c,0x70,0x8c,0xc7,0x25,0x48, + 0xd7,0x86,0x35,0xaa,0x7d,0xa7,0x9b,0xb2,0x53, + 0xf9,0x45,0xd7,0x10,0xe5,0xcb,0x67,0x7a,0x47, + 0x4e,0xfc,0x7c,0x65,0xa2,0xaa,0xb4,0x5b,0xc7, + 0xca,0x11,0x13,0xc8,0xce,0x0f,0x3c,0x32,0xe1, + 0x39,0x9d,0xe9,0xc4,0x59,0x53,0x5e,0x88,0x16, + 0x52,0x1a,0xb7,0x14,0xb2,0xa6,0xcd,0x20,0x05, + 0x25}, + .hash_len = 64, + .chunks = {30, 30, 30, 30, 30, 30, 30, 17}, + .num_chunks = 8, + }, { + .data = {0xd5,0xe3,0x78,0xae,0x9f,0xc2,0x64,0x8f,0x4a, + 0x13,0xbb,0xec,0x4b,0x09,0x35,0xaf,0xb4,0xf8, + 0x22,0xf5,0xfe,0x0d,0x50,0x63,0x05,0x3d,0x2f, + 0xbd,0x54,0x7b,0x33,0xb4,0xa3,0x2e,0x7a,0x00, + 0x9e,0xe2,0xaf,0xaf,0xe8,0x3d,0x2e,0xbd,0x60, + 0x35,0x68,0xe4,0xa3,0x81,0x89,0xb5,0xd2,0x4d, + 0x59,0xe8,0x95,0x32,0x60,0xf1,0x5f,0x65,0x4e, + 0xd4,0xf4,0x2f,0x9a,0x39,0x29,0x9d,0x68,0xc3, + 0xeb,0x78,0xb0,0x9e,0x83,0x77,0x9d,0x57,0x18, + 0xb4,0x33,0xf1,0x76,0x5d,0x35,0x35,0x0e,0xac, + 0x46,0x49,0x3d,0x19,0x4e,0x84,0xd1,0xce,0x1f, + 0x81,0xc9,0x5b,0x59,0x72,0x5c,0xab,0x8a,0xb7, + 0x3d,0x36,0x9a,0xb0,0x1e,0x79,0x67,0xcf,0x73, + 0xa3,0xac,0xf1,0x78,0x92,0x27,0xee,0x75,0xfd, + 0xfb,0x6e,0x40,0xf3,0x53,0xff,0x04,0x84,0x48, + 0x65,0x42,0xbe,0x05,0x31,0x15,0xdb,0x28,0x96, + 0xba,0xb8,0x6c,0x77,0x4f,0x89,0x85,0xc4,0xdb, + 0xcc,0x4c,0x07,0x8f,0x7b,0x1c,0x3a,0x4c,0x86, + 0x7c,0xdc,0x65,0x80,0xfe,0x44,0xa5,0x98,0x67, + 0x34,0x94,0xcc,0x0f,0xb1,0xf6,0x59,0x8b,0x12, + 0x95,0x76,0x8a,0x58,0x40,0x41,0xfd,0xbd,0x14, + 0xfa,0x7b,0x90,0xfa,0x6f,0xe3,0x3f,0x71,0xb7, + 0x43,0xb6,0x8e,0x23,0xf8,0xe7,0x40,0x72,0x17, + 0xaa,0xd9,0x44,0x0c,0xc8,0xca,0xd2,0x81,0x52, + 0xae,0xdb,0x82,0x38,0x8b,0xe2,0xde,0x16,0x54, + 0x96,0xd0,0x51,0xb2,0x92,0xde,0x63,0x03,0x46, + 0x02,0x73,0xa4,0x35,0x08,0x29,0x6b,0x62,0x37, + 0xc0,0x78,0x04,0x33,0x5d,0x2e,0x81,0x22,0x9f, + 0x7c,0x9a,0x0e,0x77,0x61,0xe3,0x8a,0x3a,0xaf, + 0x77,0x99,0xf4,0x0f,0xe9,0xcb,0x00,0x45,0x7e, + 0xa9,0xd5,0xb5,0x99,0x53,0x23,0x26,0x76,0x68, + 0x1f,0xc7,0x1b,0x26,0x1a,0x6f,0x8c,0xd3,0x59, + 0x29,0x3f,0x5b,0x21,0xf0,0xcf,0x3a,0x11,0xb7, + 0xf4,0x9c,0xb5,0xad,0xb3,0xc3,0x57,0xbe,0xd2, + 0xaa,0x18,0x5d,0x8f,0xe8,0x40,0x81,0x92,0xd6, + 0xd3,0xed,0x1f,0xf4,0x65,0xb5,0x90,0x89,0x2e, + 0xfe,0x03}, + .data_len = 326, + .hash = {0xa7,0x0c,0x75,0xb9,0xb1,0xf0,0xac,0x2e,0xd2, + 0xc2,0x79,0x77,0x63,0xac,0x9a,0x66,0x01,0xd9, + 0x5f,0x46,0x88,0x9b,0x00,0xfc,0x3d,0xda,0xe4, + 0xd0,0xac,0x69,0x23,0x75,0x0a,0x10,0x8d,0x79, + 0xeb,0x76,0x4e,0x77,0xac,0x07,0xb7,0xcb,0x5c, + 0x01,0xcb,0x4b,0x37,0x47,0xdc,0xf6,0x9b,0xa3, + 0xb3,0x5c,0x51,0xfb,0x99,0x5d,0xa2,0x63,0x2e, + 0x70}, + .hash_len = 64, + .chunks = {163, 163}, + .num_chunks = 2, + } +}; + +/** SHA test Vectors for Hashing Byte-Oriented Messages + http://csrc.nist.gov/groups/STM/cavp/documents/shs/shabytetestvectors.zip + SHA512_224ShortMsg.rsp & SHA512_224LongMsg.rsp + + http://csrc.nist.gov/groups/ST/toolkit/examples.html +**/ +struct DIGEST_TEST_VECTOR sha512_224_digest_test_vector[] = { + { + .data = {0x00}, + .data_len = 0, + .hash = {0x6e,0xd0,0xdd,0x02,0x80,0x6f,0xa8,0x9e,0x25, + 0xde,0x06,0x0c,0x19,0xd3,0xac,0x86,0xca,0xbb, + 0x87,0xd6,0xa0,0xdd,0xd0,0x5c,0x33,0x3b,0x84, + 0xf4}, + .hash_len = 28, + }, { + .data = {0x49,0x76,0x04 }, + .data_len = 3, + .hash = {0xa9,0xc3,0x45,0xd5,0x8a,0x95,0x9a,0xf2,0x0a, + 0x42,0xc8,0x4e,0x28,0x52,0x3b,0xa4,0x7e,0x3b, + 0xf8,0xfa,0xd8,0xe8,0xc3,0xf3,0x2b,0x7a,0x72, + 0xae}, + .hash_len = 28, + }, { + .data = {0x4c,0xd2,0x73,0x24,0xc2,0x83,0x64,0x87,0x3c, + 0x6d,0xdb,0xc3,0xe3,0xa7,0xe2,0xcd,0xa9,0xe8, + 0xa7,0x2a,0xd2,0xf7,0x22,0x01,0xb2,0x62,0xf8, + 0x74,0xb8,0x73,0x9f,0x30,0xab,0x60,0xc3,0x43, + 0x34,0xc2,0xe9,0x2f,0x9d,0x48,0x53,0x3c,0xd8, + 0xad,0x23,0x12,0xc3,0xe7,0xc3,0x86,0xaa,0xa2, + 0x83,0xb5,0x0d,0xec,0x84,0x4f,0xa4,0x32,0xd6, + 0x36}, + .data_len = 64, + .hash = {0xce,0xd6,0x08,0x17,0x61,0xff,0x52,0x59,0xf1, + 0x32,0xaa,0x83,0x1b,0x7a,0x1b,0x43,0x2d,0x09, + 0x3f,0xc8,0x57,0xda,0x0e,0xee,0xb8,0x2b,0xe7, + 0x1f}, + .hash_len = 28, + .chunks = {20, 14, 30}, + .num_chunks = 3, + }, { + .data = {0xd2,0x4d,0xf7,0x5a,0x00,0xcf,0x92,0x67,0x7b, + 0xb4,0x1a,0x62,0x0f,0xae,0x51,0x97,0x23,0x93, + 0x7e,0xbf,0xe1,0xf7,0xb4,0x30,0x97,0x00,0x56, + 0x50,0x5d,0x76,0xdb,0x4f,0xf9,0x1a,0xcf,0x16, + 0xff,0x39,0x1a,0x7a,0x3d,0x80,0x85,0xb6,0x55, + 0x12,0x7a,0x18,0xac,0xd8,0x0b,0xfa,0x83,0x18, + 0x37,0xf4,0x64,0x4a,0x68,0x50,0xc0,0x27,0x3f, + 0xbe,0xd6,0x02,0x94,0x49,0xd6,0x5b,0xb9,0x8a, + 0x47,0xb2,0xff,0x1c,0xa6,0x99,0x7c,0x50,0x50, + 0x0d,0x0b,0x21,0xa2,0x06,0x93,0x6a,0x5e,0x4d, + 0x8d,0x56,0x50,0x8e,0xc0,0x18,0x32,0xae,0x4f, + 0xdd,0xce,0x5e,0xf6,0xff,0x62,0xf1,0x91,0x7c, + 0x48,0x6a,0xde,0xa6}, + .data_len = 112, + .hash = {0x5c,0xae,0x12,0xea,0x96,0x52,0x26,0x9e,0xa2, + 0xaa,0xfc,0x65,0x6c,0xb8,0x34,0x24,0x74,0x6e, + 0xa1,0xd5,0xd4,0x91,0xf9,0xa1,0x59,0x59,0x4b, + 0x2a}, + .hash_len = 28, + .chunks = {24, 40, 0, 48}, + .num_chunks = 4, + }, { + .data = {0x9e,0x12,0x78,0x70,0xbe,0x24,0x31,0xbc,0xb4, + 0xf4,0xeb,0x4e,0xfd,0x5c,0x2a,0x6c,0x58,0x70, + 0xc5,0x5e,0x7a,0x5e,0x3b,0x75,0x03,0x99,0x4a, + 0x4c,0xb1,0x36,0xbe,0x4e,0xd3,0x96,0x88,0x78, + 0x01,0x45,0x0f,0x60,0x0b,0x22,0xcb,0x77,0x2f, + 0xc0,0x0f,0x8b,0x8f,0x0d,0x26,0x90,0xe2,0x31, + 0xa2,0x9f,0x69,0xb9,0xf1,0x3f,0x24,0xf5,0x31, + 0xe4,0x47,0x9e,0x45,0xb5,0xe8,0xbc,0x29,0x92, + 0xfa,0xc7,0x82,0x56,0x7e,0x0d,0x7a,0x59,0xf8, + 0x53,0xca,0x3a,0x20,0xbf,0x18,0xdb,0xdb,0xf6, + 0x84,0xac,0x69,0x81,0x7e,0x2d,0xe0,0x75,0xda, + 0xae,0xd9,0x53,0x26,0x59,0x69,0x2d,0x3b,0x73, + 0x53,0x0a,0x12,0xdf,0x7b,0x8c,0xd9,0xe4,0x9e, + 0xd0,0x46,0x30,0x41,0x96,0x2c,0x1c,0xe7,0xa2, + 0x4c,0x31}, + .data_len = 128, + .hash = {0x7e,0x2c,0xf6,0x22,0x66,0x23,0x53,0x57,0x84, + 0xc5,0x9c,0xd6,0xa7,0xb2,0x7d,0xac,0x60,0xee, + 0x23,0xfd,0xce,0x8a,0x80,0x4d,0xbd,0x6d,0xfe, + 0xdd}, + .hash_len = 28, + .chunks = {64, 64, -1}, + .num_chunks = 3, + }, { + .data = {0x96,0x25,0xae,0x61,0x8e,0xa6,0x33,0xfd,0x7a, + 0xe5,0xb2,0x0c,0xea,0xfd,0x6b,0x1f,0x3a,0xb1, + 0xa6,0xaa,0x20,0xad,0xed,0x66,0x81,0x0e,0x78, + 0xf3,0x89,0x25,0xe9,0xc2,0xfa,0x78,0x3a,0x32, + 0xc4,0x0a,0xf3,0xf9,0xd7,0xdd,0xa0,0xc6,0x35, + 0xb4,0x82,0x25,0x4b,0x1d,0x85,0xa2,0x81,0xaf, + 0x72,0x31,0x10,0x91,0x66,0xcd,0x13,0x3c,0x83, + 0x60,0xe2,0x81,0xe5,0xe3,0x9b,0xcd,0xd7,0xc6, + 0x01,0xac,0x47,0x92,0x8a,0x8c,0x78,0xcd,0xb3, + 0xc4,0xf7,0x1e,0x97,0xd4,0xd0,0xb1,0xc0,0xee, + 0x01,0xdd,0x3d,0xb6,0x2f,0x04,0xf4,0x47,0x98, + 0xbb,0x3a,0x76,0x49,0x2b,0xa1,0x5a,0x91,0xb7, + 0x11,0x0c,0xb5,0xe0,0x1b,0xab,0xe5,0x65,0x89, + 0xa3,0x6f,0xae,0x3a,0x2f,0x33,0x6a,0x2d,0x1d, + 0x57,0x78,0xdb,0xd2,0x3c,0x03,0xca,0x8d,0xb0, + 0xf2,0x5f,0xf0,0x65,0x7f,0xf4,0xbc,0xa1,0x25, + 0x2a,0xdc,0x38,0xc0,0x80,0xa5,0xb8,0xf0,0x25, + 0x5c,0xe3,0xbe,0x0b,0xf8,0x62,0x82,0x3d,0x2a, + 0xb7,0x04,0x72,0x9b,0x74,0xe1,0xe2,0x75,0xaa, + 0x30,0x58,0x24,0xa5,0x66,0x89,0x5e,0xd6,0x77, + 0xa4,0x60,0x11,0x3e,0x2a,0x7b,0xf9,0x1f,0x00, + 0xd0,0xb8,0xeb,0xc3,0x58,0xf3,0x03,0x5b,0x27, + 0xfc,0xc1,0xd3,0xf1,0x4a,0x13,0x67,0xcd,0x27, + 0x69,0xdf,0x39,0xa9,0xd2,0x1c,0x5e,0xe3,0x61, + 0xf1,0x96,0x5c,0xd6,0x34,0x2c,0xc1,0x7a,0x14, + 0x63,0xd6}, + .data_len = 227, + .hash = {0x72,0x64,0x0a,0x79,0xfb,0xb1,0xcf,0xb2,0x6e, + 0x09,0xb4,0xb3,0x53,0x85,0x38,0x9e,0xd6,0x33, + 0xa5,0x5e,0x09,0x29,0x06,0xd0,0x1a,0x71,0x86, + 0xe1}, + .hash_len = 28, + .chunks = {30, 30, 30, 30, 30, 30, 30, 17}, + .num_chunks = 8, + }, { + .data = {0x0c,0x20,0x65,0x08,0x01,0xdf,0x97,0x65,0x48, + 0x2e,0x7e,0x79,0xf6,0xa0,0xef,0x0d,0xc5,0xdb, + 0x8a,0x94,0x64,0x9d,0xa8,0x56,0x11,0xfd,0x8e, + 0xcd,0x6a,0xf4,0xe7,0x4f,0x80,0x1b,0x71,0xee, + 0x2e,0xb6,0xf6,0x9d,0xa9,0xf2,0x7e,0x94,0x57, + 0x6b,0xc3,0xf5,0xe5,0xf1,0xe5,0xaf,0x94,0x8c, + 0x5f,0xa2,0xd3,0xbd,0x3a,0x05,0x13,0x07,0x80, + 0x05,0xd7,0xae,0xf4,0xaf,0x0a,0xbf,0x00,0x10, + 0x96,0x50,0xef,0x9b,0x32,0x09,0x5c,0xcb,0x7b, + 0xe4,0xea,0x09,0x47,0x30,0x36,0xcf,0x36,0xdc, + 0x0a,0x0e,0x8a,0xf2,0xd4,0xcd,0x38,0x62,0x56, + 0x13,0x3e,0x01,0x9e,0x08,0x38,0xd1,0x39,0x57, + 0x2e,0x83,0xa4,0xd6,0xb1,0x3a,0x03,0x69,0x26, + 0x92,0x15,0x24,0x61,0xe1,0x68,0xaf,0x76,0xbd, + 0xc9,0xef,0xcb,0xbe,0xff,0xe2,0x72,0x84,0xb9, + 0xcb,0xb6,0xfc,0xc4,0x90,0xf4,0xe0,0x81,0x60, + 0xad,0x7d,0x97,0x98,0xd8,0xb9,0xe5,0xe8,0x7d, + 0x54,0xbb,0xb2,0x7f,0x6e,0x49,0xb2,0xba,0x4a, + 0x57,0xe4,0x4d,0x51,0x37,0xa2,0x39,0x5a,0xf8, + 0x0d,0x2c,0x28,0xdd,0xaf,0x97,0x34,0x0d,0x5f, + 0x06,0xad,0x8c,0x64,0xb1,0xbe,0x6a,0xdd,0x4e, + 0x0f,0x3b,0x60,0x2a,0x8e,0xc7,0xe1,0x78,0x6f, + 0x02,0xd5,0xe9,0x71,0x3e,0x98,0x7d,0x64,0x9f, + 0x0c,0x98,0xe8,0xcf,0x84,0x58,0x77,0xf4,0xe0, + 0x26,0xa6,0xdf,0xf9,0x8b,0xa7,0x86,0x3f,0x45, + 0x13,0xb5,0xa0,0x9b,0xe6,0x00,0xac,0xed,0xcc, + 0xfc,0xf7,0x8f,0x9b,0xaf,0xbf,0xd8,0x20,0x44, + 0xcf,0x75,0x1e,0x03,0xa3,0x03,0x94,0x81,0xcd, + 0xde,0x3f,0x14,0x98,0x33,0x60,0x8a,0xea,0x5d, + 0xbf,0x1b,0x6f,0x6e,0xf0,0x9b,0xf3,0x0b,0xd5, + 0xf5,0x10,0x7e,0x64,0xd4,0x0a,0x06,0xaa,0xa3, + 0xf7,0x71,0x10,0xb8,0x23,0xed,0xde,0xcc,0xb2, + 0x1c,0xfd,0xaf,0x87,0x66,0x01,0x39,0x65,0x93, + 0x67,0x84,0x54,0x99,0x1a,0x58,0x47,0xb2,0x3c, + 0xe7,0xfb,0xb2,0x24,0xbb,0x22,0x98,0xa3,0xec, + 0xc1,0x63,0x8c,0x96,0xd7,0x27,0x73,0x8a,0x3f, + 0x5f,0xb4}, + .data_len = 326, + .hash = {0xaf,0xf2,0x28,0x7a,0xb9,0x78,0xd6,0x04,0xba, + 0xb6,0xfe,0x2b,0x5f,0xb4,0x98,0xd1,0x4c,0x4b, + 0x16,0x9f,0x68,0x80,0x64,0xe1,0x96,0x40,0xb5, + 0x97}, + .hash_len = 28, + .chunks = {163, 163}, + .num_chunks = 2, + } +}; + +/** SHA test Vectors for Hashing Byte-Oriented Messages + http://csrc.nist.gov/groups/STM/cavp/documents/shs/shabytetestvectors.zip + SHA512_256ShortMsg.rsp & SHA512_256LongMsg.rsp + + http://csrc.nist.gov/groups/ST/toolkit/examples.html +**/ +struct DIGEST_TEST_VECTOR sha512_256_digest_test_vector[] = { + { + .data = {0x00}, + .data_len = 0, + .hash = {0xc6,0x72,0xb8,0xd1,0xef,0x56,0xed,0x28,0xab, + 0x87,0xc3,0x62,0x2c,0x51,0x14,0x06,0x9b,0xdd, + 0x3a,0xd7,0xb8,0xf9,0x73,0x74,0x98,0xd0,0xc0, + 0x1e,0xce,0xf0,0x96,0x7a}, + .hash_len = 32, + }, { + .data = {0x6f,0x63,0xb4}, + .data_len = 3, + .hash = {0xa9,0xe2,0x42,0x7c,0xec,0x31,0x4b,0x28,0x14, + 0xaa,0xba,0x87,0x03,0x94,0x85,0xfc,0x8d,0x3a, + 0xde,0x99,0x2f,0xa1,0xd9,0xac,0xbb,0x7f,0x67, + 0x69,0x46,0x0a,0x73,0x17}, + .hash_len = 32, + }, { + .data = {0xd2,0xbc,0x0c,0xe7,0x21,0x7f,0xf2,0xe9,0x44, + 0xe1,0xae,0x47,0xad,0x58,0x73,0xbf,0x39,0x1f, + 0x1b,0x0c,0xc0,0x7f,0x61,0x51,0xeb,0x4c,0x50, + 0xbb,0x45,0xb2,0xfb,0x62,0x95,0x32,0x6f,0x71, + 0x6c,0xe7,0xe6,0x87,0xfa,0x0e,0x3d,0x5d,0x25, + 0xc5,0xa8,0xa8,0xdd,0x13,0xa5,0x41,0xa9,0x29, + 0x2e,0x83,0x86,0xe7,0x33,0xf4,0xf2,0xa2,0x47, + 0x28}, + .data_len = 64, + .hash = {0x9c,0x1f,0xea,0x57,0x86,0x70,0x2d,0x02,0x7b, + 0xb5,0xb6,0x6b,0x3f,0xa9,0x2d,0xe3,0x46,0x21, + 0xa8,0x62,0x69,0x82,0xec,0x21,0xc0,0xec,0xf8, + 0xda,0xa7,0x9d,0xea,0x05}, + .hash_len = 32, + .chunks = {20, 14, 30}, + .num_chunks = 3, + }, { + .data = {0x92,0xb2,0x3c,0x0b,0xc4,0xd8,0xd0,0x7d,0x22, + 0xe2,0x88,0x12,0x71,0x0d,0xff,0x06,0xcb,0x9b, + 0xbe,0xce,0xa2,0xc9,0x60,0xac,0x02,0x00,0xf4, + 0x80,0x16,0x4f,0xa2,0xe1,0xee,0x19,0x92,0x6c, + 0x7f,0x0b,0x09,0x5c,0xec,0x51,0xd5,0x5c,0x04, + 0x0a,0xec,0x99,0x0b,0xf9,0x50,0x1a,0xbd,0x7d, + 0x35,0x54,0x90,0xc3,0x66,0xf9,0x3a,0x3a,0xe5, + 0x12,0x73,0x47,0xd1,0x4d,0xfc,0x3b,0x8d,0x98, + 0xe0,0x82,0x1f,0xee,0xfa,0x1c,0xd6,0x71,0xb7, + 0x52,0x30,0xba,0x1d,0xa1,0xfa,0x6d,0x0c,0xfb, + 0xb9,0x10,0xc4,0x2f,0x49,0x1d,0xa8,0xa5,0xc4, + 0x55,0x42,0x4e,0xa6,0x58,0x86,0xdb,0x2e,0x73, + 0x5b,0x2d,0x07,0xb9}, + .data_len = 112, + .hash = {0x55,0xa0,0x59,0x7f,0x11,0xff,0x71,0xc4,0x26, + 0x20,0x17,0x15,0xbe,0xb5,0x85,0xf2,0x54,0xbb, + 0x31,0xc1,0xdb,0xad,0xe5,0x33,0xf0,0x4e,0x49, + 0x9c,0x33,0x91,0xff,0x79}, + .hash_len = 32, + .chunks = {24, 40, 0, 48}, + .num_chunks = 4, + }, { + .data = {0xbc,0x81,0x73,0xc8,0x78,0xca,0x60,0xe9,0xa0, + 0xf8,0x23,0xf9,0xa5,0x89,0xd4,0xff,0x84,0x54, + 0x7b,0x38,0x9b,0x11,0x7f,0xb6,0xbb,0x1b,0x61, + 0x4e,0x7e,0x75,0xa9,0xb1,0xdb,0x0b,0x21,0xd9, + 0xf7,0x3b,0x42,0xa7,0x3e,0x94,0xec,0xca,0xb3, + 0xde,0x5a,0xe2,0x84,0x5a,0x54,0xe5,0xe2,0x4b, + 0xa6,0xc2,0x0f,0xb4,0xd2,0x45,0xb9,0x64,0x02, + 0x3b,0x86,0x30,0x40,0xd6,0xf0,0x80,0xe9,0x53, + 0x53,0x0d,0x5f,0xd9,0x44,0xe8,0xff,0xa5,0x25, + 0xbf,0x53,0x64,0xf6,0x5c,0x88,0xe0,0x6e,0x6e, + 0x22,0xdf,0x4b,0x8c,0xee,0x48,0xe6,0x77,0x38, + 0x88,0x0a,0x9f,0x3f,0x34,0x06,0xe9,0xe6,0xf0, + 0x01,0xb0,0xac,0x8f,0x8e,0x0a,0xde,0x7c,0x81, + 0x4c,0x0c,0x58,0x00,0xd0,0xb9,0xe4,0xdd,0xf5, + 0x56,0x22}, + .data_len = 128, + .hash = {0xf6,0x91,0xd0,0x1e,0xe9,0xab,0x67,0x5f,0x38, + 0x72,0x31,0x3b,0x77,0xe6,0xa4,0x54,0x3c,0x71, + 0xe3,0xe8,0x9a,0xa9,0x4c,0x48,0xf9,0x1d,0x6e, + 0xe7,0xfa,0x1a,0xb4,0xfb}, + .hash_len = 32, + .chunks = {64, 64, -1}, + .num_chunks = 3, + }, { + .data = {0x97,0xe0,0x03,0x90,0x3b,0xb9,0x71,0xa5,0x23, + 0xce,0x0c,0x82,0xbd,0xa5,0xd6,0x73,0x3c,0x76, + 0xb9,0x0d,0xeb,0x30,0x75,0x59,0xc1,0xbd,0xdd, + 0x35,0x36,0x87,0x43,0xf6,0x56,0x3b,0x31,0x52, + 0x14,0xcd,0x5a,0x7e,0xe0,0xbc,0xcf,0x93,0x7c, + 0x97,0x76,0x36,0x0b,0xc0,0xb9,0x78,0x6b,0x70, + 0x7b,0xfb,0xc4,0xfb,0x50,0x57,0x61,0x55,0xed, + 0xbb,0xbf,0xd5,0xdd,0xd8,0xe4,0x3a,0x76,0xfa, + 0xf2,0xec,0x0c,0x78,0xfc,0x84,0x64,0x4f,0x18, + 0x8d,0x6b,0x0a,0xb6,0x8c,0x28,0xe5,0x30,0x3f, + 0xf0,0x31,0xa2,0x23,0xd9,0xfa,0xfb,0x38,0x71, + 0xe8,0x54,0x08,0xaf,0x63,0x81,0xe6,0x29,0xfa, + 0xe6,0x74,0x88,0x06,0x8c,0x68,0x39,0x8a,0x75, + 0x8f,0x66,0x5e,0x2c,0x12,0x25,0x8d,0x9f,0xf8, + 0xef,0xfb,0x31,0xec,0x53,0x4b,0x0c,0x40,0xeb, + 0xff,0xb4,0x33,0x90,0xe1,0xe2,0x6f,0xca,0xa2, + 0x8f,0xd6,0x8a,0xc2,0x4f,0x7e,0x1c,0xaf,0xe0, + 0xfa,0x57,0x31,0x03,0xdc,0x17,0x05,0x8a,0x77, + 0xed,0xc9,0xb3,0xea,0x14,0x18,0xb4,0x5a,0xa7, + 0xf5,0x97,0x7e,0x12,0x6d,0x48,0x61,0xc7,0x78, + 0xed,0x63,0x32,0x21,0x75,0x81,0xee,0xe6,0x74, + 0xd7,0x39,0x62,0x2e,0x63,0xa5,0x29,0xf1,0x0c, + 0x11,0xf4,0xa9,0xe3,0xd8,0xfe,0xae,0xa8,0x48, + 0xad,0xe0,0x90,0x56,0x75,0xf6,0x45,0x8f,0xfa, + 0x13,0x2f,0x52,0x74,0x9a,0xf2,0x3d,0x58,0x44, + 0x38,0xe5}, + .data_len = 227, + .hash = {0x00,0xce,0x3b,0x59,0x2d,0x4e,0x1a,0x65,0xf7, + 0x80,0xdf,0x35,0x1f,0xa7,0xb2,0xc0,0x1b,0x49, + 0xdf,0x4e,0xa9,0x13,0xc3,0xfa,0xb2,0x42,0x97, + 0xf5,0x79,0x1b,0x18,0xe5}, + .hash_len = 32, + .chunks = {30, 30, 30, 30, 30, 30, 30, 17}, + .num_chunks = 8, + }, { + .data = {0x77,0x3e,0x10,0x98,0xb7,0x25,0xab,0x1a,0x74, + 0x65,0xc6,0x78,0x92,0xa3,0x84,0x14,0x7b,0xf0, + 0xc3,0x27,0x14,0xee,0xab,0x05,0xf1,0x34,0x87, + 0xa3,0xc5,0xf4,0xd4,0x56,0x1c,0xdb,0x98,0xdd, + 0x4c,0x39,0xf6,0xa2,0xa8,0x62,0xfe,0x3d,0xf8, + 0x54,0xca,0x3a,0x26,0x9a,0xc6,0x1c,0x3a,0x70, + 0x4f,0xa1,0x88,0x27,0x80,0x48,0x28,0xcb,0x48, + 0x11,0xa7,0x04,0xc0,0x84,0xfc,0x3a,0xbc,0xf4, + 0xbe,0xfc,0xa1,0x05,0x94,0xa3,0x76,0x6c,0xec, + 0x32,0x3d,0xf6,0xf0,0x81,0x83,0xcc,0xb5,0x9b, + 0x36,0xf5,0xb6,0x64,0xb7,0x1c,0x82,0x7f,0x30, + 0x94,0xb1,0x6e,0x28,0x99,0x1c,0xfb,0x54,0xd9, + 0x4e,0xd7,0xb0,0x33,0x35,0x82,0xcf,0xbe,0x1d, + 0x6a,0x6f,0x0d,0xe0,0x57,0x51,0xb1,0x56,0x06, + 0x48,0x00,0x13,0x14,0x8f,0x15,0x52,0x1f,0x5f, + 0x18,0x2c,0x27,0xc1,0xc0,0x0e,0x3a,0xa2,0x15, + 0x69,0x50,0x25,0x7b,0xab,0x74,0x3d,0xec,0x6f, + 0x24,0x7a,0x85,0xf0,0xfb,0x23,0x44,0xc4,0x8d, + 0x86,0x10,0xc7,0x93,0x8c,0xf9,0x55,0x48,0x90, + 0xc2,0xbc,0x12,0x71,0x9c,0xf0,0x65,0xe6,0x35, + 0x81,0xe4,0x12,0xf1,0xcb,0xca,0x59,0x77,0x6d, + 0x89,0x71,0x70,0xfc,0xb1,0xbc,0x8b,0xf8,0x12, + 0xd5,0xc5,0xfe,0x25,0x69,0xe7,0x40,0xa8,0x48, + 0x50,0x33,0x89,0xbb,0xf4,0x87,0x05,0x19,0xa5, + 0x5c,0x11,0x95,0x92,0xb3,0xf9,0x5a,0x0d,0x22, + 0x47,0xda,0x91,0xcd,0xe6,0x62,0x03,0x91,0x87, + 0xf2,0x38,0x82,0x44,0x4d,0xb8,0x98,0x83,0x4c, + 0xc1,0xa5,0x1e,0x77,0x8f,0x8a,0xc1,0xd6,0xdb, + 0xab,0x93,0x05,0xa2,0xa0,0x18,0x87,0x27,0x2e, + 0x56,0x5c,0x3b,0x75,0x36,0xd6,0xbc,0x6a,0x2e, + 0xa8,0x5c,0x88,0x1d,0x40,0xa3,0xc3,0x76,0x57, + 0x38,0xbe,0xa1,0xc6,0x5c,0x3d,0x9e,0x9b,0xb7, + 0xdd,0xec,0x6c,0x57,0x03,0xa9,0xeb,0xf6,0x12, + 0xfa,0xbb,0x7b,0xe1,0xad,0x82,0xc4,0x6c,0x1d, + 0x40,0xa3,0xc9,0x56,0xdf,0x26,0x5e,0x7a,0x0b, + 0x1c,0x52,0x64,0x43,0xd4,0x41,0x8a,0x30,0x28, + 0x34,0x28}, + .data_len = 326, + .hash = {0xf3,0xe5,0x24,0xf6,0x45,0x88,0x1c,0x45,0x31, + 0x80,0x30,0x62,0x4b,0xaf,0x25,0x4f,0xc6,0xb3, + 0x38,0x9d,0x7b,0xb7,0xa2,0x2a,0xa5,0x5e,0xf5, + 0x28,0xc2,0xfd,0x3c,0xf0}, + .hash_len = 32, + .chunks = {163, 163}, + .num_chunks = 2, + } +}; + +/** SHA3 test Vectors for Hashing Byte-Oriented Messages +NIST SHA3-224 test vectors +http://csrc.nist.gov/groups/STM/cavp/secure-hashing.html + **/ +struct DIGEST_TEST_VECTOR sha3_224_digest_test_vector[] = { + { + .data = { 0x00 }, + .data_len = 0, + .hash = { 0x6b,0x4e,0x03,0x42,0x36,0x67,0xdb,0xb7,0x3b, + 0x6e,0x15,0x45,0x4f,0x0e,0xb1,0xab,0xd4,0x59, + 0x7f,0x9a,0x1b,0x07,0x8e,0x3f,0x5b,0x5a,0x6b, + 0xc7 }, + .hash_len = 28, + }, { + .data = { 0x01 }, + .data_len = 1, + .hash = { 0x48,0x82,0x86,0xd9,0xd3,0x27,0x16,0xe5,0x88, + 0x1e,0xa1,0xee,0x51,0xf3,0x6d,0x36,0x60,0xd7, + 0x0f,0x0d,0xb0,0x3b,0x3f,0x61,0x2c,0xe9,0xed, + 0xa4 }, + .hash_len = 28, + }, { + .data = { 0xbf,0x58,0x31 }, + .data_len = 3, + .hash = { 0x1b,0xb3,0x6b,0xeb,0xde,0x5f,0x3c,0xb6,0xd8, + 0xe4,0x67,0x2a,0xcf,0x6e,0xec,0x87,0x28,0xf3, + 0x1a,0x54,0xda,0xcc,0x25,0x60,0xda,0x2a,0x00, + 0xcc }, + .hash_len = 28, + }, { + .data = { 0xdd,0x0f,0x85,0xb5,0x5f,0xdf,0x56,0xba,0x25, + 0x4e,0x06,0xf8,0xc2,0xb6,0x50,0xcc,0x6b,0x86, + 0xbf,0x28,0xa1,0x4d,0x71,0x40,0x11,0x14,0x1a, + 0x86,0xb8,0xf1,0x4b,0xd9 }, + .data_len = 32, + .hash = { 0x0f,0xe9,0x24,0x69,0x29,0x7c,0x2c,0x34,0x91, + 0x1e,0xae,0x42,0x47,0x10,0xdb,0x6d,0x31,0x20, + 0x47,0x89,0x8b,0x97,0x56,0xed,0xc5,0xc2,0xde, + 0xb2 }, + .hash_len = 28, + .chunks = { 16, -1, 16, 0 }, + .num_chunks = 4, + }, { + .data = { 0x6b,0x2b,0x92,0x58,0x41,0x46,0xa4,0x33,0xbe, + 0xe8,0xb9,0x47,0xcc,0x1f,0x35,0xb6,0x17,0xb7, + 0x3f,0x5b,0x1e,0x03,0x76,0xac,0x8b,0xda,0xdf, + 0xe5,0xbf,0xdf,0x22,0x63,0xb2,0x05,0xf7,0x4d, + 0xfa,0x53,0xdb,0x7a,0x29,0xe5,0x07,0x8f,0x5c, + 0x34,0xa2,0x68,0x11,0x97,0x36,0xba,0x39,0x09, + 0x61,0xf6 }, + .data_len = 56, + .hash = { 0x13,0x2c,0xfa,0x7e,0x71,0xfe,0x09,0x91,0xab, + 0xbd,0x88,0xef,0x58,0x8a,0xc9,0x5a,0xc9,0x28, + 0x9b,0x1d,0x77,0x5b,0x42,0x03,0x35,0x67,0xdd, + 0x33 }, + .hash_len = 28, + .chunks = { 28, 0, 28 }, + .num_chunks = 3, + }, { + .data = { 0x0e,0xef,0x94,0x7f,0x1e,0x4f,0x01,0xcd,0xb5, + 0x48,0x1c,0xa6,0xea,0xa2,0x5f,0x2c,0xac,0xa4, + 0xc4,0x01,0x61,0x28,0x88,0xfe,0xce,0xf5,0x2e, + 0x28,0x37,0x48,0xc8,0xdf,0xc7,0xb4,0x72,0x59, + 0x32,0x2c,0x1f,0x4f,0x98,0x5f,0x98,0xf6,0xad, + 0x44,0xc1,0x31,0x17,0xf5,0x1e,0x05,0x17,0xc0, + 0x97,0x4d,0x6c,0x7b,0x78,0xaf,0x74,0x19,0xbc, + 0xce,0x95,0x7b,0x8b,0xc1,0xdb,0x88,0x01,0xc5, + 0xe2,0x80,0x31,0x2e,0xf7,0x8d,0x6a,0xa4,0x7a, + 0x9c,0xb9,0x8b,0x86,0x6a,0xae,0xc3,0xd5,0xe2, + 0x63,0x92,0xdd,0xa6,0xbb,0xde,0x3f,0xec,0xe8, + 0xa0,0x62,0x8b,0x30,0x95,0x5b,0x55,0xf0,0x37, + 0x11,0xa8,0xe1,0xeb,0x9e,0x40,0x9a,0x7c,0xf8, + 0x4f,0x56,0xc8,0xd0,0xd0,0xf8,0xb9,0xba,0x18, + 0x4c,0x77,0x8f,0xae,0x90,0xdc,0x0f,0x5c,0x33, + 0x29,0xcb,0x86,0xdc,0xf7,0x43,0xbb,0xae }, + .data_len = 143, + .hash = { 0x98,0xec,0x52,0xc2,0x1c,0xb9,0x88,0xb1,0x43, + 0x4b,0x16,0x53,0xdd,0x4a,0xc8,0x06,0xd1,0x18, + 0xde,0x6a,0xf1,0xbb,0x47,0x1c,0x16,0x57,0x7c, + 0x34 }, + .hash_len = 28, + .chunks = { 71, 71, 1, 0 }, + .num_chunks = 4, + } +}; + +/** SHA3 test Vectors for Hashing Byte-Oriented Messages +NIST SHA3-256 test vectors +http://csrc.nist.gov/groups/STM/cavp/secure-hashing.html + **/ +struct DIGEST_TEST_VECTOR sha3_256_digest_test_vector[] = { + { + .data = { 0x00 }, + .data_len = 0, + .hash = { 0xa7,0xff,0xc6,0xf8,0xbf,0x1e,0xd7,0x66,0x51, + 0xc1,0x47,0x56,0xa0,0x61,0xd6,0x62,0xf5,0x80, + 0xff,0x4d,0xe4,0x3b,0x49,0xfa,0x82,0xd8,0x0a, + 0x4b,0x80,0xf8,0x43,0x4a }, + .hash_len = 32, + }, { + .data = { 0xe9 }, + .data_len = 1, + .hash = { 0xf0,0xd0,0x4d,0xd1,0xe6,0xcf,0xc2,0x9a,0x44, + 0x60,0xd5,0x21,0x79,0x68,0x52,0xf2,0x5d,0x9e, + 0xf8,0xd2,0x8b,0x44,0xee,0x91,0xff,0x5b,0x75, + 0x9d,0x72,0xc1,0xe6,0xd6 }, + .hash_len = 32, + }, { + .data = { 0xb0,0x53,0xfa }, + .data_len = 3, + .hash = { 0x9d,0x0f,0xf0,0x86,0xcd,0x0e,0xc0,0x6a,0x68, + 0x2c,0x51,0xc0,0x94,0xdc,0x73,0xab,0xdc,0x49, + 0x20,0x04,0x29,0x23,0x44,0xbd,0x41,0xb8,0x2a, + 0x60,0x49,0x8c,0xcf,0xdb }, + .hash_len = 32, + }, { + .data = { 0xc1,0x78,0xce,0x0f,0x72,0x0a,0x6d,0x73,0xc6, + 0xcf,0x1c,0xaa,0x90,0x5e,0xe7,0x24,0xd5,0xba, + 0x94,0x1c,0x2e,0x26,0x28,0x13,0x6e,0x3a,0xad, + 0x7d,0x85,0x37,0x33,0xba }, + .data_len = 32, + .hash = { 0x64,0x53,0x7b,0x87,0x89,0x28,0x35,0xff,0x09, + 0x63,0xef,0x9a,0xd5,0x14,0x5a,0xb4,0xcf,0xce, + 0x5d,0x30,0x3a,0x0c,0xb0,0x41,0x5b,0x3b,0x03, + 0xf9,0xd1,0x6e,0x7d,0x6b }, + .hash_len = 32, + .chunks = { 16, -1, 16, 0 }, + .num_chunks = 4, + }, { + .data = { 0x00,0xff,0x6c,0x96,0xb7,0xaa,0x3c,0xf2,0x7d, + 0x03,0x6c,0xf2,0x0a,0xf7,0x03,0x14,0x34,0x11, + 0x32,0x52,0x57,0x4b,0xda,0x9c,0xf9,0x24,0x4d, + 0x85,0xae,0xf2,0x59,0x3d,0x3a,0x7a,0x83,0xbf, + 0xf6,0xbe,0x90,0x4b,0x75,0x16,0x4a,0x17,0x66, + 0x82,0x80,0x42,0xbc,0x3f,0x4f,0x09,0x0d,0x98, + 0xa0,0x3d }, + .data_len = 56, + .hash = { 0xd0,0x00,0xea,0xfc,0xa3,0x48,0x15,0x78,0x3b, + 0xed,0x9b,0x05,0x0c,0x69,0x01,0xc9,0x7f,0x2e, + 0x77,0xd4,0x77,0x1a,0x0e,0xd7,0x24,0xdd,0x8f, + 0x6f,0xf1,0x44,0x87,0x91 }, + .hash_len = 32, + .chunks = { 28, 0, 28 }, + .num_chunks = 3, + }, { + .data = { 0xb1,0xf6,0x07,0x65,0x09,0x93,0x84,0x32,0x14, + 0x5b,0xb1,0x5d,0xbe,0x1a,0x7b,0x2e,0x00,0x79, + 0x34,0xbe,0x5f,0x75,0x39,0x08,0xb5,0x0f,0xd2, + 0x43,0x33,0x45,0x59,0x70,0xa7,0x42,0x9f,0x2f, + 0xfb,0xd2,0x8b,0xd6,0xfe,0x18,0x04,0xc4,0x68, + 0x83,0x11,0xf3,0x18,0xfe,0x3f,0xcd,0x9f,0x67, + 0x44,0x41,0x02,0x43,0xe1,0x15,0xbc,0xb0,0x0d, + 0x7e,0x03,0x9a,0x4f,0xee,0x4c,0x32,0x6c,0x2d, + 0x11,0x9c,0x42,0xab,0xd2,0xe8,0xf4,0x15,0x5a, + 0x44,0x47,0x26,0x43,0x70,0x4c,0xc0,0xbc,0x72, + 0x40,0x3b,0x8a,0x8a,0xb0,0xfd,0x4d,0x68,0xe0, + 0x4a,0x05,0x9d,0x6e,0x5e,0xd4,0x50,0x33,0xb9, + 0x06,0x32,0x6a,0xbb,0x4e,0xb4,0x14,0x70,0x52, + 0x77,0x9b,0xad,0x6a,0x03,0xb5,0x5c,0xa5,0xbd, + 0x8b,0x14,0x0e,0x13,0x1b,0xed,0x2d,0xfa,0xda }, + .data_len = 135, + .hash = { 0xf8,0x2d,0x96,0x02,0xb2,0x31,0xd3,0x32,0xd9, + 0x02,0xcb,0x64,0x36,0xb1,0x5a,0xef,0x89,0xac, + 0xc5,0x91,0xcb,0x86,0x26,0x23,0x3c,0xed,0x20, + 0xc0,0xa6,0xe8,0x0d,0x7a }, + .hash_len = 32, + .chunks = { 67, 67, 1, 0 }, + .num_chunks = 4, + } +}; + +/** SHA3 test Vectors for Hashing Byte-Oriented Messages +NIST SHA3-224 test vectors +http://csrc.nist.gov/groups/STM/cavp/secure-hashing.html + **/ +struct DIGEST_TEST_VECTOR sha3_384_digest_test_vector[] = { + { + .data = { 0x00 }, + .data_len = 0, + .hash = { 0x0c,0x63,0xa7,0x5b,0x84,0x5e,0x4f,0x7d,0x01, + 0x10,0x7d,0x85,0x2e,0x4c,0x24,0x85,0xc5,0x1a, + 0x50,0xaa,0xaa,0x94,0xfc,0x61,0x99,0x5e,0x71, + 0xbb,0xee,0x98,0x3a,0x2a,0xc3,0x71,0x38,0x31, + 0x26,0x4a,0xdb,0x47,0xfb,0x6b,0xd1,0xe0,0x58, + 0xd5,0xf0,0x04 }, + .hash_len = 48, + }, { + .data = { 0x80 }, + .data_len = 1, + .hash = { 0x75,0x41,0x38,0x48,0x52,0xe1,0x0f,0xf1,0x0d, + 0x5f,0xb6,0xa7,0x21,0x3a,0x4a,0x6c,0x15,0xcc, + 0xc8,0x6d,0x8b,0xc1,0x06,0x8a,0xc0,0x4f,0x69, + 0x27,0x71,0x42,0x94,0x4f,0x4e,0xe5,0x0d,0x91, + 0xfd,0xc5,0x65,0x53,0xdb,0x06,0xb2,0xf5,0x03, + 0x9c,0x8a,0xb7 }, + .hash_len = 48, + }, { + .data = { 0x6a,0xb7,0xd6 }, + .data_len = 3, + .hash = { 0xea,0x12,0xd6,0xd3,0x2d,0x69,0xad,0x21,0x54, + 0xa5,0x7e,0x0e,0x1b,0xe4,0x81,0xa4,0x5a,0xdd, + 0x73,0x9e,0xe7,0xdd,0x6e,0x2a,0x27,0xe5,0x44, + 0xb6,0xc8,0xb5,0xad,0x12,0x26,0x54,0xbb,0xf9, + 0x51,0x34,0xd5,0x67,0x98,0x71,0x56,0x29,0x5d, + 0x5e,0x57,0xdb }, + .hash_len = 48, + }, { + .data = { 0x61,0x89,0x59,0x7e,0x01,0x98,0xa1,0x8c,0x65, + 0xfa,0x0b,0xdd,0x07,0x97,0xf1,0x30,0x37,0xc7, + 0x5c,0x40,0x58,0xb7,0xd3,0x45,0x4c,0x0f,0x71, + 0xbd,0x2d,0xd1,0x3b,0x6c }, + .data_len = 32, + .hash = { 0x11,0x06,0x30,0xca,0x76,0x31,0xb7,0x62,0x0e, + 0x6b,0xee,0x6e,0xd6,0xe9,0x29,0x09,0x89,0x65, + 0x57,0x19,0x36,0xc3,0x48,0x29,0x48,0x49,0x83, + 0xeb,0xa9,0x53,0x2b,0x81,0x75,0x52,0x8c,0x22, + 0x8c,0x57,0x43,0x94,0x53,0xf0,0x27,0xa4,0xf7, + 0xc8,0x3c,0xa3 }, + .hash_len = 48, + .chunks = { 16, -1, 16, 0 }, + .num_chunks = 4, + }, { + .data = { 0x26,0x8c,0x7b,0x3a,0x84,0x84,0x9f,0xec,0x5c, + 0x76,0x9b,0xc4,0xad,0x37,0x7d,0xea,0x10,0xc9, + 0xd2,0x0c,0x91,0xdd,0x17,0xfd,0xbd,0x96,0x70, + 0xa2,0xfc,0x90,0x9d,0x0e,0x21,0x21,0x29,0xec, + 0x40,0xde,0xe4,0x1d,0xbf,0x61,0x94,0xa3,0xb0, + 0x4a,0xe8,0xbe,0x5e,0x84,0xad,0x54,0x26,0xca, + 0x44,0x96 }, + .data_len = 56, + .hash = { 0x0d,0xfc,0x6f,0xfc,0xf4,0xa3,0x87,0xec,0x09, + 0xff,0x86,0x2c,0x61,0x39,0xa6,0xf7,0xac,0x77, + 0xab,0xb2,0xb5,0xe1,0xf6,0xdc,0x81,0x4e,0xb7, + 0x15,0x25,0xf8,0x65,0x7a,0xc7,0x4a,0x76,0x97, + 0xc2,0x97,0x5c,0x70,0xa5,0x43,0xaf,0x0e,0x22, + 0x7d,0x03,0xca }, + .hash_len = 48, + .chunks = { 28, 0, 28 }, + .num_chunks = 3, + }, { + .data = { 0x6c,0x36,0x14,0x76,0x52,0xe7,0x1b,0x56,0x0b, + 0xec,0xbc,0xa1,0xe7,0x65,0x6c,0x81,0xb4,0xf7, + 0x0b,0xec,0xe2,0x63,0x21,0xd5,0xe5,0x5e,0x67, + 0xa3,0xdb,0x9d,0x89,0xe2,0x6f,0x2f,0x2a,0x38, + 0xfd,0x0f,0x28,0x9b,0xf7,0xfa,0x22,0xc2,0x87, + 0x7e,0x38,0xd9,0x75,0x54,0x12,0x79,0x4c,0xef, + 0x24,0xd7,0xb8,0x55,0x30,0x3c,0x33,0x2e,0x0c, + 0xb5,0xe0,0x1a,0xa5,0x0b,0xb7,0x48,0x44,0xf5, + 0xe3,0x45,0x10,0x8d,0x68,0x11,0xd5,0x01,0x09, + 0x78,0x03,0x8b,0x69,0x9f,0xfa,0xa3,0x70,0xde, + 0x84,0x73,0xf0,0xcd,0xa3,0x8b,0x89,0xa2,0x8e, + 0xd6,0xca,0xba,0xf6 }, + .data_len = 103, + .hash = { 0xb1,0x31,0x91,0x92,0xdf,0x11,0xfa,0xa0,0x0d, + 0x3c,0x4b,0x06,0x8b,0xec,0xc8,0xf1,0xba,0x3b, + 0x00,0xe0,0xd1,0xff,0x1f,0x93,0xc1,0x1a,0x36, + 0x63,0x52,0x2f,0xdb,0x92,0xab,0x3c,0xca,0x38, + 0x96,0x34,0x68,0x7c,0x63,0x2e,0x0a,0x4b,0x5a, + 0x26,0xce,0x92 }, + .hash_len = 48, + .chunks = { 51, 51, 1, 0 }, + .num_chunks = 4, + } +}; + +/** SHA3 test Vectors for Hashing Byte-Oriented Messages +NIST SHA3-224 test vectors +http://csrc.nist.gov/groups/STM/cavp/secure-hashing.html + **/ +struct DIGEST_TEST_VECTOR sha3_512_digest_test_vector[] = { + { + .data = { 0x00 }, + .data_len = 0, + .hash = { 0xa6,0x9f,0x73,0xcc,0xa2,0x3a,0x9a,0xc5,0xc8, + 0xb5,0x67,0xdc,0x18,0x5a,0x75,0x6e,0x97,0xc9, + 0x82,0x16,0x4f,0xe2,0x58,0x59,0xe0,0xd1,0xdc, + 0xc1,0x47,0x5c,0x80,0xa6,0x15,0xb2,0x12,0x3a, + 0xf1,0xf5,0xf9,0x4c,0x11,0xe3,0xe9,0x40,0x2c, + 0x3a,0xc5,0x58,0xf5,0x00,0x19,0x9d,0x95,0xb6, + 0xd3,0xe3,0x01,0x75,0x85,0x86,0x28,0x1d,0xcd, + 0x26 }, + .hash_len = 64, + }, { + .data = { 0xe5 }, + .data_len = 1, + .hash = { 0x15,0x02,0x40,0xba,0xf9,0x5f,0xb3,0x6f,0x8c, + 0xcb,0x87,0xa1,0x9a,0x41,0x76,0x7e,0x7a,0xed, + 0x95,0x12,0x50,0x75,0xa2,0xb2,0xdb,0xba,0x6e, + 0x56,0x5e,0x1c,0xe8,0x57,0x5f,0x2b,0x04,0x2b, + 0x62,0xe2,0x9a,0x04,0xe9,0x44,0x03,0x14,0xa8, + 0x21,0xc6,0x22,0x41,0x82,0x96,0x4d,0x8b,0x55, + 0x7b,0x16,0xa4,0x92,0xb3,0x80,0x6f,0x4c,0x39, + 0xc1 }, + .hash_len = 64, + }, { + .data = { 0x37,0xd5,0x18 }, + .data_len = 3, + .hash = { 0x4a,0xa9,0x6b,0x15,0x47,0xe6,0x40,0x2c,0x0e, + 0xee,0x78,0x1a,0xca,0xa6,0x60,0x79,0x7e,0xfe, + 0x26,0xec,0x00,0xb4,0xf2,0xe0,0xae,0xc4,0xa6, + 0xd1,0x06,0x88,0xdd,0x64,0xcb,0xd7,0xf1,0x2b, + 0x3b,0x6c,0x7f,0x80,0x2e,0x20,0x96,0xc0,0x41, + 0x20,0x8b,0x92,0x89,0xae,0xc3,0x80,0xd1,0xa7, + 0x48,0xfd,0xfc,0xd4,0x12,0x85,0x53,0xd7,0x81, + 0xe3 }, + .hash_len = 64, + }, { + .data = { 0x7c,0x16,0x88,0x21,0x7b,0x31,0x32,0x78,0xb9, + 0xea,0xe8,0xed,0xcf,0x8a,0xa4,0x27,0x16,0x14, + 0x29,0x6d,0x0c,0x1e,0x89,0x16,0xf9,0xe0,0xe9, + 0x40,0xd2,0x8b,0x88,0xc5 }, + .data_len = 32, + .hash = { 0x62,0x7b,0xa4,0xde,0x74,0xd0,0x5b,0xb6,0xdf, + 0x89,0x91,0x11,0x2e,0x4d,0x37,0x3b,0xfc,0xed, + 0x37,0xac,0xde,0x13,0x04,0xe0,0xf6,0x64,0xf2, + 0x9f,0xa1,0x26,0xcb,0x49,0x7c,0x8a,0x1b,0x71, + 0x7b,0x99,0x29,0x12,0x08,0x83,0xec,0x88,0x98, + 0x96,0x8e,0x46,0x49,0x01,0x3b,0x76,0x0a,0x21, + 0x80,0xa9,0xdc,0x0f,0xc9,0xb2,0x7f,0x5b,0x7f, + 0x3b }, + .hash_len = 64, + .chunks = { 16, -1, 16, 0 }, + .num_chunks = 4, + }, { + .data = { 0x30,0x2f,0xa8,0x4f,0xda,0xa8,0x20,0x81,0xb1, + 0x19,0x2b,0x84,0x7b,0x81,0xdd,0xea,0x10,0xa9, + 0xf0,0x5a,0x0f,0x04,0x13,0x8f,0xd1,0xda,0x84, + 0xa3,0x9b,0xa5,0xe1,0x8e,0x18,0xbc,0x3c,0xea, + 0x06,0x2e,0x6d,0xf9,0x2f,0xf1,0xac,0xe8,0x9b, + 0x3c,0x5f,0x55,0x04,0x31,0x30,0x10,0x8a,0xbf, + 0x63,0x1e }, + .data_len = 56, + .hash = { 0x8c,0x8e,0xaa,0xe9,0xa4,0x45,0x64,0x3a,0x37, + 0xdf,0x34,0xcf,0xa6,0xa7,0xf0,0x9d,0xec,0xca, + 0xb2,0xa2,0x22,0xc4,0x21,0xd2,0xfc,0x57,0x4b, + 0xbc,0x56,0x41,0xe5,0x04,0x35,0x43,0x91,0xe8, + 0x1e,0xb5,0x13,0x02,0x80,0xb1,0x22,0x68,0x12, + 0x55,0x6d,0x47,0x4e,0x95,0x1b,0xb7,0x8d,0xbd, + 0xd9,0xb7,0x7d,0x19,0xf6,0x47,0xe2,0xe7,0xd7, + 0xbe }, + .hash_len = 64, + .chunks = { 28, 0, 28 }, + .num_chunks = 3, + }, { + .data = { 0xb0,0xde,0x04,0x30,0xc2,0x00,0xd7,0x4b,0xf4, + 0x1e,0xa0,0xc9,0x2f,0x8f,0x28,0xe1,0x1b,0x68, + 0x00,0x6a,0x88,0x4e,0x0d,0x4b,0x0d,0x88,0x45, + 0x33,0xee,0x58,0xb3,0x8a,0x43,0x8c,0xc1,0xa7, + 0x57,0x50,0xb6,0x43,0x4f,0x46,0x7e,0x2d,0x0c, + 0xd9,0xaa,0x40,0x52,0xce,0xb7,0x93,0x29,0x1b, + 0x93,0xef,0x83,0xfd,0x5d,0x86,0x20,0x45,0x6c, + 0xe1,0xaf,0xf2,0x94,0x1b,0x36,0x05,0xa4 }, + .data_len = 71, + .hash = { 0x9e,0x9e,0x46,0x9c,0xa9,0x22,0x6c,0xd0,0x12, + 0xf5,0xc9,0xcc,0x39,0xc9,0x6a,0xdc,0x22,0xf4, + 0x20,0x03,0x0f,0xce,0xe3,0x05,0xa0,0xed,0x27, + 0x97,0x4e,0x3c,0x80,0x27,0x01,0x60,0x3d,0xac, + 0x87,0x3a,0xe4,0x47,0x6e,0x9c,0x3d,0x57,0xe5, + 0x55,0x24,0x48,0x3f,0xc0,0x1a,0xda,0xef,0x87, + 0xda,0xa9,0xe3,0x04,0x07,0x8c,0x59,0x80,0x27, + 0x57 }, + .hash_len = 64, + .chunks = { 35, 35, 1, 0 }, + .num_chunks = 4, + } +}; + +struct digest_test_suite_info { + const char *name; + unsigned int tvcount; + struct DIGEST_TEST_VECTOR *tv; + CK_MECHANISM mech; +}; + +#define NUM_DIGEST_TEST_SUITES 15 +struct digest_test_suite_info digest_test_suites[] = { + { + .name = "SHA-1", + .tvcount = 7, + .tv = sha1_digest_test_vector, + .mech = {CKM_SHA_1, 0, 0}, + }, { + .name = "SHA-224", + .tvcount = 6, + .tv = sha224_digest_test_vector, + .mech = {CKM_SHA224, 0, 0}, + }, { + .name = "SHA-256", + .tvcount = 6, + .tv = sha256_digest_test_vector, + .mech = {CKM_SHA256, 0, 0}, + }, { + .name = "SHA-384", + .tvcount = 8, + .tv = sha384_digest_test_vector, + .mech = {CKM_SHA384, 0, 0}, + }, { + .name = "SHA-512", + .tvcount = 7, + .tv = sha512_digest_test_vector, + .mech = {CKM_SHA512, 0, 0}, + }, { + .name = "SHA-512/224", + .tvcount = 7, + .tv = sha512_224_digest_test_vector, + .mech = {CKM_SHA512_224, 0, 0}, + }, { + .name = "SHA-512/256", + .tvcount = 7, + .tv = sha512_256_digest_test_vector, + .mech = {CKM_SHA512_256, 0, 0}, + }, { + .name = "MD2", + .tvcount = 7, + .tv = md2_digest_test_vector, + .mech = {CKM_MD2, 0, 0}, + }, { + .name = "MD5", + .tvcount = 3, + .tv = md5_digest_test_vector, + .mech = {CKM_MD5, 0, 0}, + }, { + .name = "RIPEMD-128", + .tvcount = 1, + .tv = ripemd128_digest_test_vector, + .mech = {CKM_RIPEMD128, 0, 0}, + }, { + .name = "RIPEMD-160", + .tvcount = 1, + .tv = ripemd160_digest_test_vector, + .mech = {CKM_RIPEMD160, 0, 0}, + }, { + .name = "IBM-SHA3-224", + .tvcount = 6, + .tv = sha3_224_digest_test_vector, + .mech = {CKM_IBM_SHA3_224, 0, 0}, + }, { + .name = "IBM-SHA3-256", + .tvcount = 6, + .tv = sha3_256_digest_test_vector, + .mech = {CKM_IBM_SHA3_256, 0, 0}, + }, { + .name = "IBM-SHA3-384", + .tvcount = 6, + .tv = sha3_384_digest_test_vector, + .mech = {CKM_IBM_SHA3_384, 0, 0}, + }, { + .name = "IBM-SHA3-512", + .tvcount = 6, + .tv = sha3_512_digest_test_vector, + .mech = {CKM_IBM_SHA3_512, 0, 0}, + }, +}; + +struct HMAC_TEST_VECTOR { + /* test vector inputs */ + CK_BYTE key[512]; + CK_ULONG key_len; + CK_BYTE data[512]; + CK_ULONG data_len; + CK_ULONG mac_len; + CK_BYTE mac[512]; + int chunks[MAX_CHUNKS]; + int num_chunks; +}; + +/* MD5 HMAC test vectors from RFC2202: + * http://www.faqs.org/rfcs/rfc2202.html + */ +struct HMAC_TEST_VECTOR md5_hmac_test_vector[] = { + { + .key = {0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b}, + .key_len = 16, + .data = {"Hi There"}, + .data_len = 8, + .mac_len = 16, + .mac = {0x92,0x94,0x72,0x7a,0x36,0x38,0xBB,0x1C,0x13, + 0xf4,0x8E,0xf8,0x15,0x8b,0xfc,0x9d} + }, { + .key = {'J','e','f','e'}, + .key_len = 4, + .data = {"what do ya want for nothing?"}, + .data_len = 28, + .mac_len = 16, + .mac = {0x75,0x0c,0x78,0x3e,0x6a,0xb0,0xb5,0x03,0xea, + 0xa8,0x6e,0x31,0x0a,0x5d,0xb7,0x38} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 16, + .data = {0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD}, + .data_len = 50, + .mac_len = 16, + .mac = {0x56,0xbe,0x34,0x52,0x1d,0x14,0x4c,0x88,0xdb, + 0xb8,0xc7,0x33,0xf0,0xe8,0xb3,0xf6} + }, { + .key = {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}, + .key_len = 25, + .data = {0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD}, + .data_len = 50, + .mac_len = 16, + .mac = {0x69,0x7e,0xaf,0x0a,0xca,0x3a,0x3a,0xea,0x3a, + 0x75,0x16,0x47,0x46,0xff,0xaa,0x79} + }, { + .key = {0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, + 0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c}, + .key_len = 16, + .data = {"Test With Truncation"}, + .data_len = 20, + .mac_len = 16, + .mac = {0x56,0x46,0x1e,0xf2,0x34,0x2e,0xdc,0x00,0xf9, + 0xba,0xb9,0x95,0x69,0x0e,0xfd,0x4c} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 80, + .data = {"Test Using Larger Than Block-Size Key - Hash Key First"}, + .data_len = 54, + .mac_len = 16, + .mac = {0x6b,0x1a,0xb7,0xfe,0x4b,0xd7,0xbf,0x8f,0x0b, + 0x62,0xe6,0xce,0x61,0xb9,0xd0,0xcd} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 80, + .data = {"Test Using Larger Than Block-Size Key and Larger Than One " + "Block-Size Data" }, + .data_len = 73, + .mac_len = 16, + .mac = {0x6f,0x63,0x0f,0xad,0x67,0xcd,0xa0,0xee,0x1f, + 0xb1,0xf5,0x62,0xdb,0x3a,0xa5,0x3e} + }, +}; + +/* SHA1 HMAC test vectors from RFC2202: + * http://www.faqs.org/rfcs/rfc2202.html + */ +struct HMAC_TEST_VECTOR sha1_hmac_test_vector[] = { + { + .key = {0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b}, + .key_len = 20, + .data = {"Hi There"}, + .data_len = 8, + .mac_len = 20, + .mac = {0xb6,0x17,0x31,0x86,0x55,0x05,0x72,0x64,0xe2, + 0x8b,0xc0,0xb6,0xfb,0x37,0x8c,0x8e,0xf1,0x46, + 0xbe,0x00} + }, { + .key = {'J', 'e', 'f', 'e'}, + .key_len = 4, + .data = {"what do ya want for nothing?"}, + .data_len = 28, + .mac_len = 20, + .mac = {0xef,0xfc,0xdf,0x6a,0xe5,0xeb,0x2f,0xa2,0xd2, + 0x74,0x16,0xd5,0xf1,0x84,0xdf,0x9c,0x25,0x9a, + 0x7c,0x79} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa}, + .key_len = 20, + .data = {0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD}, + .data_len = 50, + .mac_len = 20, + .mac = {0x12,0x5d,0x73,0x42,0xb9,0xac,0x11,0xcd,0x91, + 0xa3,0x9a,0xf4,0x8a,0xa1,0x7b,0x4f,0x63,0xf1, + 0x75,0xd3} + }, { + .key = {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 }, + .key_len = 25, + .data = {0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD}, + .data_len = 50, + .mac_len = 20, + .mac = {0x4c,0x90,0x07,0xf4,0x02,0x62,0x50,0xc6,0xbc, + 0x84,0x14,0xf9,0xbf,0x50,0xc8,0x6c,0x2d,0x72, + 0x35,0xda} + }, { + .key = {0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, + 0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, + 0x0c,0x0c}, + .key_len = 20, + .data = {"Test With Truncation"}, + .data_len = 20, + .mac_len = 20, + .mac = {0x4c,0x1a,0x03,0x42,0x4b,0x55,0xe0,0x7f,0xe7, + 0xf2,0x7b,0xe1,0xd5,0x8b,0xb9,0x32,0x4a,0x9a, + 0x5a,0x04} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 80, + .data = {"Test Using Larger Than Block-Size Key - Hash Key First"}, + .data_len = 54, + .mac_len = 20, + .mac = {0xaa,0x4a,0xe5,0xe1,0x52,0x72,0xd0,0x0e,0x95, + 0x70,0x56,0x37,0xce,0x8a,0x3b,0x55,0xed,0x40, + 0x21,0x12} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 80, + .data = {"Test Using Larger Than Block-Size Key and Larger Than One " + "Block-Size Data"}, + .data_len = 73, + .mac_len = 20, + .mac = {0xe8,0xe9,0x9d,0x0f,0x45,0x23,0x7d,0x78,0x6d, + 0x6b,0xba,0xa7,0x96,0x5c,0x78,0x08,0xbb,0xff, + 0x1a,0x91} + }, +}; + +/* Test vectors for HMAC SHA224 from RFC4231: + * https://tools.ietf.org/html/rfc4231 + */ +struct HMAC_TEST_VECTOR sha224_hmac_test_vector[] = { + { + .key = {0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b}, + .key_len = 20, + .data = {"Hi There"}, + .data_len = 8, + .mac_len = 28, + .mac = {0x89,0x6f,0xb1,0x12,0x8a,0xbb,0xdf,0x19,0x68, + 0x32,0x10,0x7c,0xd4,0x9d,0xf3,0x3f,0x47,0xb4, + 0xb1,0x16,0x99,0x12,0xba,0x4f,0x53,0x68,0x4b, + 0x22} + }, { + .key = {'J', 'e', 'f', 'e'}, + .key_len = 4, + .data = {"what do ya want for nothing?"}, + .data_len = 28, + .mac_len = 28, + .mac = {0xa3,0x0e,0x01,0x09,0x8b,0xc6,0xdb,0xbf,0x45, + 0x69,0x0f,0x3a,0x7e,0x9e,0x6d,0x0f,0x8b,0xbe, + 0xa2,0xa3,0x9e,0x61,0x48,0x00,0x8f,0xd0,0x5e, + 0x44} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa}, + .key_len = 20, + .data = {0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD}, + .data_len = 50, + .mac_len = 28, + .mac = {0x7f,0xb3,0xcb,0x35,0x88,0xc6,0xc1,0xf6,0xff, + 0xa9,0x69,0x4d,0x7d,0x6a,0xd2,0x64,0x93,0x65, + 0xb0,0xc1,0xf6,0x5d,0x69,0xd1,0xec,0x83,0x33, + 0xea} + }, { + .key = {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}, + .key_len = 25, + .data = {0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD}, + .data_len = 50, + .mac_len = 28, + .mac = {0x6c,0x11,0x50,0x68,0x74,0x01,0x3c,0xac,0x6a, + 0x2a,0xbc,0x1b,0xb3,0x82,0x62,0x7c,0xec,0x6a, + 0x90,0xd8,0x6e,0xfc,0x01,0x2d,0xe7,0xaf,0xec, + 0x5a} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 131, + .data = {0x54,0x65,0x73,0x74,0x20,0x55,0x73,0x69,0x6e, + 0x67,0x20,0x4c,0x61,0x72,0x67,0x65,0x72,0x20, + 0x54,0x68,0x61,0x6e,0x20,0x42,0x6c,0x6f,0x63, + 0x6b,0x2d,0x53,0x69,0x7a,0x65,0x20,0x4b,0x65, + 0x79,0x20,0x2d,0x20,0x48,0x61,0x73,0x68,0x20, + 0x4b,0x65,0x79,0x20,0x46,0x69,0x72,0x73,0x74}, + .data_len = 54, + .mac_len = 28, + .mac = {0x95,0xe9,0xa0,0xdb,0x96,0x20,0x95,0xad,0xae, + 0xbe,0x9b,0x2d,0x6f,0x0d,0xbc,0xe2,0xd4,0x99, + 0xf1,0x12,0xf2,0xd2,0xb7,0x27,0x3f,0xa6,0x87, + 0x0e} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 131, + .data = {0x54,0x68,0x69,0x73,0x20,0x69,0x73,0x20,0x61, + 0x20,0x74,0x65,0x73,0x74,0x20,0x75,0x73,0x69, + 0x6e,0x67,0x20,0x61,0x20,0x6c,0x61,0x72,0x67, + 0x65,0x72,0x20,0x74,0x68,0x61,0x6e,0x20,0x62, + 0x6c,0x6f,0x63,0x6b,0x2d,0x73,0x69,0x7a,0x65, + 0x20,0x6b,0x65,0x79,0x20,0x61,0x6e,0x64,0x20, + 0x61,0x20,0x6c,0x61,0x72,0x67,0x65,0x72,0x20, + 0x74,0x68,0x61,0x6e,0x20,0x62,0x6c,0x6f,0x63, + 0x6b,0x2d,0x73,0x69,0x7a,0x65,0x20,0x64,0x61, + 0x74,0x61,0x2e,0x20,0x54,0x68,0x65,0x20,0x6b, + 0x65,0x79,0x20,0x6e,0x65,0x65,0x64,0x73,0x20, + 0x74,0x6f,0x20,0x62,0x65,0x20,0x68,0x61,0x73, + 0x68,0x65,0x64,0x20,0x62,0x65,0x66,0x6f,0x72, + 0x65,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x75, + 0x73,0x65,0x64,0x20,0x62,0x79,0x20,0x74,0x68, + 0x65,0x20,0x48,0x4d,0x41,0x43,0x20,0x61,0x6c, + 0x67,0x6f,0x72,0x69,0x74,0x68,0x6d,0x2e}, + .data_len = 152, + .mac_len = 28, + .mac = {0x3a,0x85,0x41,0x66,0xac,0x5d,0x9f,0x02,0x3f, + 0x54,0xd5,0x17,0xd0,0xb3,0x9d,0xbd,0x94,0x67, + 0x70,0xdb,0x9c,0x2b,0x95,0xc9,0xf6,0xf5,0x65, + 0xd1} + } +}; + +/* Test vectors for HMAC SHA256 from RFC4868: + * http://tools.ietf.org/html/rfc4868 + */ +struct HMAC_TEST_VECTOR sha256_hmac_test_vector[] = { + { + .key = {0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b}, + .key_len = 20, + .data = {"Hi There"}, + .data_len = 8, + .mac_len = 32, + .mac = {0xb0,0x34,0x4c,0x61,0xd8,0xdb,0x38,0x53,0x5c, + 0xa8,0xaf,0xce,0xaf,0x0b,0xf1,0x2b,0x88,0x1d, + 0xc2,0x00,0xc9,0x83,0x3d,0xa7,0x26,0xe9,0x37, + 0x6c,0x2e,0x32,0xcf,0xf7} + }, { + .key = {'J', 'e', 'f', 'e'}, + .key_len = 4, + .data = {"what do ya want for nothing?"}, + .data_len = 28, + .mac_len = 32, + .mac = {0x5b,0xdc,0xc1,0x46,0xbf,0x60,0x75,0x4e,0x6a, + 0x04,0x24,0x26,0x08,0x95,0x75,0xc7,0x5a,0x00, + 0x3f,0x08,0x9d,0x27,0x39,0x83,0x9d,0xec,0x58, + 0xb9,0x64,0xec,0x38,0x43} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa}, + .key_len = 20, + .data = {0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD}, + .data_len = 50, + .mac_len = 32, + .mac = {0x77,0x3e,0xa9,0x1e,0x36,0x80,0x0e,0x46,0x85, + 0x4d,0xb8,0xeb,0xd0,0x91,0x81,0xa7,0x29,0x59, + 0x09,0x8b,0x3e,0xf8,0xc1,0x22,0xd9,0x63,0x55, + 0x14,0xce,0xd5,0x65,0xfe} + }, { + .key = {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}, + .key_len = 25, + .data = {0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD}, + .data_len = 50, + .mac_len = 32, + .mac = {0x82,0x55,0x8a,0x38,0x9a,0x44,0x3c,0x0e,0xa4, + 0xcc,0x81,0x98,0x99,0xf2,0x08,0x3a,0x85,0xf0, + 0xfa,0xa3,0xe5,0x78,0xf8,0x07,0x7a,0x2e,0x3f, + 0xf4,0x67,0x29,0x66,0x5b} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 131, + .data = {0x54,0x65,0x73,0x74,0x20,0x55,0x73,0x69,0x6e, + 0x67,0x20,0x4c,0x61,0x72,0x67,0x65,0x72,0x20, + 0x54,0x68,0x61,0x6e,0x20,0x42,0x6c,0x6f,0x63, + 0x6b,0x2d,0x53,0x69,0x7a,0x65,0x20,0x4b,0x65, + 0x79,0x20,0x2d,0x20,0x48,0x61,0x73,0x68,0x20, + 0x4b,0x65,0x79,0x20,0x46,0x69,0x72,0x73,0x74}, + .data_len = 54, + .mac_len = 32, + .mac = {0x60,0xe4,0x31,0x59,0x1e,0xe0,0xb6,0x7f,0x0d, + 0x8a,0x26,0xaa,0xcb,0xf5,0xb7,0x7f,0x8e,0x0b, + 0xc6,0x21,0x37,0x28,0xc5,0x14,0x05,0x46,0x04, + 0x0f,0x0e,0xe3,0x7f,0x54} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 131, + .data = {0x54,0x68,0x69,0x73,0x20,0x69,0x73,0x20,0x61, + 0x20,0x74,0x65,0x73,0x74,0x20,0x75,0x73,0x69, + 0x6e,0x67,0x20,0x61,0x20,0x6c,0x61,0x72,0x67, + 0x65,0x72,0x20,0x74,0x68,0x61,0x6e,0x20,0x62, + 0x6c,0x6f,0x63,0x6b,0x2d,0x73,0x69,0x7a,0x65, + 0x20,0x6b,0x65,0x79,0x20,0x61,0x6e,0x64,0x20, + 0x61,0x20,0x6c,0x61,0x72,0x67,0x65,0x72,0x20, + 0x74,0x68,0x61,0x6e,0x20,0x62,0x6c,0x6f,0x63, + 0x6b,0x2d,0x73,0x69,0x7a,0x65,0x20,0x64,0x61, + 0x74,0x61,0x2e,0x20,0x54,0x68,0x65,0x20,0x6b, + 0x65,0x79,0x20,0x6e,0x65,0x65,0x64,0x73,0x20, + 0x74,0x6f,0x20,0x62,0x65,0x20,0x68,0x61,0x73, + 0x68,0x65,0x64,0x20,0x62,0x65,0x66,0x6f,0x72, + 0x65,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x75, + 0x73,0x65,0x64,0x20,0x62,0x79,0x20,0x74,0x68, + 0x65,0x20,0x48,0x4d,0x41,0x43,0x20,0x61,0x6c, + 0x67,0x6f,0x72,0x69,0x74,0x68,0x6d,0x2e}, + .data_len = 152, + .mac_len = 32, + .mac = {0x9b,0x09,0xff,0xa7,0x1b,0x94,0x2f,0xcb,0x27, + 0x63,0x5f,0xbc,0xd5,0xb0,0xe9,0x44,0xbf,0xdc, + 0x63,0x64,0x4f,0x07,0x13,0x93,0x8a,0x7f,0x51, + 0x53,0x5c,0x3a,0x35,0xe2} + } +}; + +/* Test vectors for HMAC SHA384 from RFC4868: + * http://tools.ietf.org/html/rfc4868 + */ +struct HMAC_TEST_VECTOR sha384_hmac_test_vector[] = { + { + .key = {0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b}, + .key_len = 20, + .data = {"Hi There"}, + .data_len = 8, + .mac_len = 48, + .mac = {0xaf,0xd0,0x39,0x44,0xd8,0x48,0x95,0x62,0x6b, + 0x08,0x25,0xf4,0xab,0x46,0x90,0x7f,0x15,0xf9, + 0xda,0xdb,0xe4,0x10,0x1e,0xc6,0x82,0xaa,0x03, + 0x4c,0x7c,0xeb,0xc5,0x9c,0xfa,0xea,0x9e,0xa9, + 0x07,0x6e,0xde,0x7f,0x4a,0xf1,0x52,0xe8,0xb2, + 0xfa,0x9c,0xb6} + }, { + .key = {'J', 'e', 'f', 'e'}, + .key_len = 4, + .data = {"what do ya want for nothing?"}, + .data_len = 28, + .mac_len = 48, + .mac = {0xaf,0x45,0xd2,0xe3,0x76,0x48,0x40,0x31,0x61, + 0x7f,0x78,0xd2,0xb5,0x8a,0x6b,0x1b,0x9c,0x7e, + 0xf4,0x64,0xf5,0xa0,0x1b,0x47,0xe4,0x2e,0xc3, + 0x73,0x63,0x22,0x44,0x5e,0x8e,0x22,0x40,0xca, + 0x5e,0x69,0xe2,0xc7,0x8b,0x32,0x39,0xec,0xfa, + 0xb2,0x16,0x49} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa}, + .key_len = 20, + .data = {0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD}, + .data_len = 50, + .mac_len = 48, + .mac = {0x88,0x06,0x26,0x08,0xd3,0xe6,0xad,0x8a,0x0a, + 0xa2,0xac,0xe0,0x14,0xc8,0xa8,0x6f,0x0a,0xa6, + 0x35,0xd9,0x47,0xac,0x9f,0xeb,0xe8,0x3e,0xf4, + 0xe5,0x59,0x66,0x14,0x4b,0x2a,0x5a,0xb3,0x9d, + 0xc1,0x38,0x14,0xb9,0x4e,0x3a,0xb6,0xe1,0x01, + 0xa3,0x4f,0x27} + }, { + .key = {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}, + .key_len = 25, + .data = {0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD}, + .data_len = 50, + .mac_len = 48, + .mac = {0x3e,0x8a,0x69,0xb7,0x78,0x3c,0x25,0x85,0x19, + 0x33,0xab,0x62,0x90,0xaf,0x6c,0xa7,0x7a,0x99, + 0x81,0x48,0x08,0x50,0x00,0x9c,0xc5,0x57,0x7c, + 0x6e,0x1f,0x57,0x3b,0x4e,0x68,0x01,0xdd,0x23, + 0xc4,0xa7,0xd6,0x79,0xcc,0xf8,0xa3,0x86,0xc6, + 0x74,0xcf,0xfb} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 131, + .data = {0x54,0x65,0x73,0x74,0x20,0x55,0x73,0x69,0x6e, + 0x67,0x20,0x4c,0x61,0x72,0x67,0x65,0x72,0x20, + 0x54,0x68,0x61,0x6e,0x20,0x42,0x6c,0x6f,0x63, + 0x6b,0x2d,0x53,0x69,0x7a,0x65,0x20,0x4b,0x65, + 0x79,0x20,0x2d,0x20,0x48,0x61,0x73,0x68,0x20, + 0x4b,0x65,0x79,0x20,0x46,0x69,0x72,0x73,0x74}, + .data_len = 54, + .mac_len = 48, + .mac = {0x4e,0xce,0x08,0x44,0x85,0x81,0x3e,0x90,0x88, + 0xd2,0xc6,0x3a,0x04,0x1b,0xc5,0xb4,0x4f,0x9e, + 0xf1,0x01,0x2a,0x2b,0x58,0x8f,0x3c,0xd1,0x1f, + 0x05,0x03,0x3a,0xc4,0xc6,0x0c,0x2e,0xf6,0xab, + 0x40,0x30,0xfe,0x82,0x96,0x24,0x8d,0xf1,0x63, + 0xf4,0x49,0x52} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 131, + .data = {0x54,0x68,0x69,0x73,0x20,0x69,0x73,0x20,0x61, + 0x20,0x74,0x65,0x73,0x74,0x20,0x75,0x73,0x69, + 0x6e,0x67,0x20,0x61,0x20,0x6c,0x61,0x72,0x67, + 0x65,0x72,0x20,0x74,0x68,0x61,0x6e,0x20,0x62, + 0x6c,0x6f,0x63,0x6b,0x2d,0x73,0x69,0x7a,0x65, + 0x20,0x6b,0x65,0x79,0x20,0x61,0x6e,0x64,0x20, + 0x61,0x20,0x6c,0x61,0x72,0x67,0x65,0x72,0x20, + 0x74,0x68,0x61,0x6e,0x20,0x62,0x6c,0x6f,0x63, + 0x6b,0x2d,0x73,0x69,0x7a,0x65,0x20,0x64,0x61, + 0x74,0x61,0x2e,0x20,0x54,0x68,0x65,0x20,0x6b, + 0x65,0x79,0x20,0x6e,0x65,0x65,0x64,0x73,0x20, + 0x74,0x6f,0x20,0x62,0x65,0x20,0x68,0x61,0x73, + 0x68,0x65,0x64,0x20,0x62,0x65,0x66,0x6f,0x72, + 0x65,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x75, + 0x73,0x65,0x64,0x20,0x62,0x79,0x20,0x74,0x68, + 0x65,0x20,0x48,0x4d,0x41,0x43,0x20,0x61,0x6c, + 0x67,0x6f,0x72,0x69,0x74,0x68,0x6d,0x2e}, + .data_len = 152, + .mac_len = 48, + .mac = {0x66,0x17,0x17,0x8e,0x94,0x1f,0x02,0x0d,0x35, + 0x1e,0x2f,0x25,0x4e,0x8f,0xd3,0x2c,0x60,0x24, + 0x20,0xfe,0xb0,0xb8,0xfb,0x9a,0xdc,0xce,0xbb, + 0x82,0x46,0x1e,0x99,0xc5,0xa6,0x78,0xcc,0x31, + 0xe7,0x99,0x17,0x6d,0x38,0x60,0xe6,0x11,0x0c, + 0x46,0x52,0x3e} + } +}; + +/* Test vectors for HMAC SHA512 from RFC4868: + * http://tools.ietf.org/html/rfc4868 + */ +struct HMAC_TEST_VECTOR sha512_hmac_test_vector[] = { + { + .key = {0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b}, + .key_len = 20, + .data = {"Hi There"}, + .data_len = 8, + .mac_len = 64, + .mac = {0x87,0xaa,0x7c,0xde,0xa5,0xef,0x61,0x9d,0x4f, + 0xf0,0xb4,0x24,0x1a,0x1d,0x6c,0xb0,0x23,0x79, + 0xf4,0xe2,0xce,0x4e,0xc2,0x78,0x7a,0xd0,0xb3, + 0x05,0x45,0xe1,0x7c,0xde,0xda,0xa8,0x33,0xb7, + 0xd6,0xb8,0xa7,0x02,0x03,0x8b,0x27,0x4e,0xae, + 0xa3,0xf4,0xe4,0xbe,0x9d,0x91,0x4e,0xeb,0x61, + 0xf1,0x70,0x2e,0x69,0x6c,0x20,0x3a,0x12,0x68, + 0x54} + }, { + .key = {'J', 'e', 'f', 'e'}, + .key_len = 4, + .data = {"what do ya want for nothing?"}, + .data_len = 28, + .mac_len = 64, + .mac = {0x16,0x4b,0x7a,0x7b,0xfc,0xf8,0x19,0xe2,0xe3, + 0x95,0xfb,0xe7,0x3b,0x56,0xe0,0xa3,0x87,0xbd, + 0x64,0x22,0x2e,0x83,0x1f,0xd6,0x10,0x27,0x0c, + 0xd7,0xea,0x25,0x05,0x54,0x97,0x58,0xbf,0x75, + 0xc0,0x5a,0x99,0x4a,0x6d,0x03,0x4f,0x65,0xf8, + 0xf0,0xe6,0xfd,0xca,0xea,0xb1,0xa3,0x4d,0x4a, + 0x6b,0x4b,0x63,0x6e,0x07,0x0a,0x38,0xbc,0xe7, + 0x37} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa}, + .key_len = 20, + .data = {0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD}, + .data_len = 50, + .mac_len = 64, + .mac = {0xfa,0x73,0xb0,0x08,0x9d,0x56,0xa2,0x84,0xef, + 0xb0,0xf0,0x75,0x6c,0x89,0x0b,0xe9,0xb1,0xb5, + 0xdb,0xdd,0x8e,0xe8,0x1a,0x36,0x55,0xf8,0x3e, + 0x33,0xb2,0x27,0x9d,0x39,0xbf,0x3e,0x84,0x82, + 0x79,0xa7,0x22,0xc8,0x06,0xb4,0x85,0xa4,0x7e, + 0x67,0xc8,0x07,0xb9,0x46,0xa3,0x37,0xbe,0xe8, + 0x94,0x26,0x74,0x27,0x88,0x59,0xe1,0x32,0x92, + 0xfb} + }, { + .key = {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}, + .key_len = 25, + .data = {0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD}, + .data_len = 50, + .mac_len = 64, + .mac = {0xb0,0xba,0x46,0x56,0x37,0x45,0x8c,0x69,0x90, + 0xe5,0xa8,0xc5,0xf6,0x1d,0x4a,0xf7,0xe5,0x76, + 0xd9,0x7f,0xf9,0x4b,0x87,0x2d,0xe7,0x6f,0x80, + 0x50,0x36,0x1e,0xe3,0xdb,0xa9,0x1c,0xa5,0xc1, + 0x1a,0xa2,0x5e,0xb4,0xd6,0x79,0x27,0x5c,0xc5, + 0x78,0x80,0x63,0xa5,0xf1,0x97,0x41,0x12,0x0c, + 0x4f,0x2d,0xe2,0xad,0xeb,0xeb,0x10,0xa2,0x98, + 0xdd} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 131, + .data = {0x54,0x65,0x73,0x74,0x20,0x55,0x73,0x69,0x6e, + 0x67,0x20,0x4c,0x61,0x72,0x67,0x65,0x72,0x20, + 0x54,0x68,0x61,0x6e,0x20,0x42,0x6c,0x6f,0x63, + 0x6b,0x2d,0x53,0x69,0x7a,0x65,0x20,0x4b,0x65, + 0x79,0x20,0x2d,0x20,0x48,0x61,0x73,0x68,0x20, + 0x4b,0x65,0x79,0x20,0x46,0x69,0x72,0x73,0x74}, + .data_len = 54, + .mac_len = 64, + .mac = {0x80,0xb2,0x42,0x63,0xc7,0xc1,0xa3,0xeb,0xb7, + 0x14,0x93,0xc1,0xdd,0x7b,0xe8,0xb4,0x9b,0x46, + 0xd1,0xf4,0x1b,0x4a,0xee,0xc1,0x12,0x1b,0x01, + 0x37,0x83,0xf8,0xf3,0x52,0x6b,0x56,0xd0,0x37, + 0xe0,0x5f,0x25,0x98,0xbd,0x0f,0xd2,0x21,0x5d, + 0x6a,0x1e,0x52,0x95,0xe6,0x4f,0x73,0xf6,0x3f, + 0x0a,0xec,0x8b,0x91,0x5a,0x98,0x5d,0x78,0x65, + 0x98} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 131, + .data = {0x54,0x68,0x69,0x73,0x20,0x69,0x73,0x20,0x61, + 0x20,0x74,0x65,0x73,0x74,0x20,0x75,0x73,0x69, + 0x6e,0x67,0x20,0x61,0x20,0x6c,0x61,0x72,0x67, + 0x65,0x72,0x20,0x74,0x68,0x61,0x6e,0x20,0x62, + 0x6c,0x6f,0x63,0x6b,0x2d,0x73,0x69,0x7a,0x65, + 0x20,0x6b,0x65,0x79,0x20,0x61,0x6e,0x64,0x20, + 0x61,0x20,0x6c,0x61,0x72,0x67,0x65,0x72,0x20, + 0x74,0x68,0x61,0x6e,0x20,0x62,0x6c,0x6f,0x63, + 0x6b,0x2d,0x73,0x69,0x7a,0x65,0x20,0x64,0x61, + 0x74,0x61,0x2e,0x20,0x54,0x68,0x65,0x20,0x6b, + 0x65,0x79,0x20,0x6e,0x65,0x65,0x64,0x73,0x20, + 0x74,0x6f,0x20,0x62,0x65,0x20,0x68,0x61,0x73, + 0x68,0x65,0x64,0x20,0x62,0x65,0x66,0x6f,0x72, + 0x65,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x75, + 0x73,0x65,0x64,0x20,0x62,0x79,0x20,0x74,0x68, + 0x65,0x20,0x48,0x4d,0x41,0x43,0x20,0x61,0x6c, + 0x67,0x6f,0x72,0x69,0x74,0x68,0x6d,0x2e}, + .data_len = 152, + .mac_len = 64, + .mac = {0xe3,0x7b,0x6a,0x77,0x5d,0xc8,0x7d,0xba,0xa4, + 0xdf,0xa9,0xf9,0x6e,0x5e,0x3f,0xfd,0xde,0xbd, + 0x71,0xf8,0x86,0x72,0x89,0x86,0x5d,0xf5,0xa3, + 0x2d,0x20,0xcd,0xc9,0x44,0xb6,0x02,0x2c,0xac, + 0x3c,0x49,0x82,0xb1,0x0d,0x5e,0xeb,0x55,0xc3, + 0xe4,0xde,0x15,0x13,0x46,0x76,0xfb,0x6d,0xe0, + 0x44,0x60,0x65,0xc9,0x74,0x40,0xfa,0x8c,0x6a, + 0x58} + } +}; + +/* Test vectors for HMAC SHA3-224: + */ +struct HMAC_TEST_VECTOR sha3_224_hmac_test_vector[] = { + { + .key = {0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b}, + .key_len = 20, + .data = {"Hi There"}, + .data_len = 8, + .mac_len = 28, + .mac = {0x3b,0x16,0x54,0x6b,0xbc,0x7b,0xe2,0x70,0x6a, + 0x03,0x1d,0xca,0xfd,0x56,0x37,0x3d,0x98,0x84, + 0x36,0x76,0x41,0xd8,0xc5,0x9a,0xf3,0xc8,0x60, + 0xf7} + }, { + .key = {'J', 'e', 'f', 'e'}, + .key_len = 4, + .data = {"what do ya want for nothing?"}, + .data_len = 28, + .mac_len = 28, + .mac = {0x7f,0xdb,0x8d,0xd8,0x8b,0xd2,0xf6,0x0d,0x1b, + 0x79,0x86,0x34,0xad,0x38,0x68,0x11,0xc2,0xcf, + 0xc8,0x5b,0xfa,0xf5,0xd5,0x2b,0xba,0xce,0x5e, + 0x66} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa}, + .key_len = 20, + .data = {0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD}, + .data_len = 50, + .mac_len = 28, + .mac = {0x67,0x6c,0xfc,0x7d,0x16,0x15,0x36,0x38,0x78, + 0x03,0x90,0x69,0x2b,0xe1,0x42,0xd2,0xdf,0x7c, + 0xe9,0x24,0xb9,0x09,0xc0,0xc0,0x8d,0xbf,0xdc, + 0x1a} + }, { + .key = {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}, + .key_len = 25, + .data = {0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD}, + .data_len = 50, + .mac_len = 28, + .mac = {0xa9,0xd7,0x68,0x5a,0x19,0xc4,0xe0,0xdb,0xd9, + 0xdf,0x25,0x56,0xcc,0x8a,0x7d,0x2a,0x77,0x33, + 0xb6,0x76,0x25,0xce,0x59,0x4c,0x78,0x27,0x0e, + 0xeb} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 131, + .data = {0x54,0x65,0x73,0x74,0x20,0x55,0x73,0x69,0x6e, + 0x67,0x20,0x4c,0x61,0x72,0x67,0x65,0x72,0x20, + 0x54,0x68,0x61,0x6e,0x20,0x42,0x6c,0x6f,0x63, + 0x6b,0x2d,0x53,0x69,0x7a,0x65,0x20,0x4b,0x65, + 0x79,0x20,0x2d,0x20,0x48,0x61,0x73,0x68,0x20, + 0x4b,0x65,0x79,0x20,0x46,0x69,0x72,0x73,0x74}, + .data_len = 54, + .mac_len = 28, + .mac = {0xb4,0xa1,0xf0,0x4c,0x00,0x28,0x7a,0x9b,0x7f, + 0x60,0x75,0xb3,0x13,0xd2,0x79,0xb8,0x33,0xbc, + 0x8f,0x75,0x12,0x43,0x52,0xd0,0x5f,0xb9,0x99, + 0x5f} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 131, + .data = {0x54,0x68,0x69,0x73,0x20,0x69,0x73,0x20,0x61, + 0x20,0x74,0x65,0x73,0x74,0x20,0x75,0x73,0x69, + 0x6e,0x67,0x20,0x61,0x20,0x6c,0x61,0x72,0x67, + 0x65,0x72,0x20,0x74,0x68,0x61,0x6e,0x20,0x62, + 0x6c,0x6f,0x63,0x6b,0x2d,0x73,0x69,0x7a,0x65, + 0x20,0x6b,0x65,0x79,0x20,0x61,0x6e,0x64,0x20, + 0x61,0x20,0x6c,0x61,0x72,0x67,0x65,0x72,0x20, + 0x74,0x68,0x61,0x6e,0x20,0x62,0x6c,0x6f,0x63, + 0x6b,0x2d,0x73,0x69,0x7a,0x65,0x20,0x64,0x61, + 0x74,0x61,0x2e,0x20,0x54,0x68,0x65,0x20,0x6b, + 0x65,0x79,0x20,0x6e,0x65,0x65,0x64,0x73,0x20, + 0x74,0x6f,0x20,0x62,0x65,0x20,0x68,0x61,0x73, + 0x68,0x65,0x64,0x20,0x62,0x65,0x66,0x6f,0x72, + 0x65,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x75, + 0x73,0x65,0x64,0x20,0x62,0x79,0x20,0x74,0x68, + 0x65,0x20,0x48,0x4d,0x41,0x43,0x20,0x61,0x6c, + 0x67,0x6f,0x72,0x69,0x74,0x68,0x6d,0x2e}, + .data_len = 152, + .mac_len = 28, + .mac = {0x05,0xd8,0xcd,0x6d,0x00,0xfa,0xea,0x8d,0x1e, + 0xb6,0x8a,0xde,0x28,0x73,0x0b,0xbd,0x3c,0xba, + 0xb6,0x92,0x9f,0x0a,0x08,0x6b,0x29,0xcd,0x62, + 0xa0} + } +}; + +/* Test vectors for HMAC SHA3-256: + */ +struct HMAC_TEST_VECTOR sha3_256_hmac_test_vector[] = { + { + .key = {0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b}, + .key_len = 20, + .data = {"Hi There"}, + .data_len = 8, + .mac_len = 32, + .mac = {0xba,0x85,0x19,0x23,0x10,0xdf,0xfa,0x96,0xe2, + 0xa3,0xa4,0x0e,0x69,0x77,0x43,0x51,0x14,0x0b, + 0xb7,0x18,0x5e,0x12,0x02,0xcd,0xcc,0x91,0x75, + 0x89,0xf9,0x5e,0x16,0xbb} + }, { + .key = {'J', 'e', 'f', 'e'}, + .key_len = 4, + .data = {"what do ya want for nothing?"}, + .data_len = 28, + .mac_len = 32, + .mac = {0xc7,0xd4,0x07,0x2e,0x78,0x88,0x77,0xae,0x35, + 0x96,0xbb,0xb0,0xda,0x73,0xb8,0x87,0xc9,0x17, + 0x1f,0x93,0x09,0x5b,0x29,0x4a,0xe8,0x57,0xfb, + 0xe2,0x64,0x5e,0x1b,0xa5} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa}, + .key_len = 20, + .data = {0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD}, + .data_len = 50, + .mac_len = 32, + .mac = {0x84,0xec,0x79,0x12,0x4a,0x27,0x10,0x78,0x65, + 0xce,0xdd,0x8b,0xd8,0x2d,0xa9,0x96,0x5e,0x5e, + 0xd8,0xc3,0x7b,0x0a,0xc9,0x80,0x05,0xa7,0xf3, + 0x9e,0xd5,0x8a,0x42,0x07} + }, { + .key = {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}, + .key_len = 25, + .data = {0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD}, + .data_len = 50, + .mac_len = 32, + .mac = {0x57,0x36,0x6a,0x45,0xe2,0x30,0x53,0x21,0xa4, + 0xbc,0x5a,0xa5,0xfe,0x2e,0xf8,0xa9,0x21,0xf6, + 0xaf,0x82,0x73,0xd7,0xfe,0x7b,0xe6,0xcf,0xed, + 0xb3,0xf0,0xae,0xa6,0xd7} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 131, + .data = {0x54,0x65,0x73,0x74,0x20,0x55,0x73,0x69,0x6e, + 0x67,0x20,0x4c,0x61,0x72,0x67,0x65,0x72,0x20, + 0x54,0x68,0x61,0x6e,0x20,0x42,0x6c,0x6f,0x63, + 0x6b,0x2d,0x53,0x69,0x7a,0x65,0x20,0x4b,0x65, + 0x79,0x20,0x2d,0x20,0x48,0x61,0x73,0x68,0x20, + 0x4b,0x65,0x79,0x20,0x46,0x69,0x72,0x73,0x74}, + .data_len = 54, + .mac_len = 32, + .mac = {0xed,0x73,0xa3,0x74,0xb9,0x6c,0x00,0x52,0x35, + 0xf9,0x48,0x03,0x2f,0x09,0x67,0x4a,0x58,0xc0, + 0xce,0x55,0x5c,0xfc,0x1f,0x22,0x3b,0x02,0x35, + 0x65,0x60,0x31,0x2c,0x3b} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 131, + .data = {0x54,0x68,0x69,0x73,0x20,0x69,0x73,0x20,0x61, + 0x20,0x74,0x65,0x73,0x74,0x20,0x75,0x73,0x69, + 0x6e,0x67,0x20,0x61,0x20,0x6c,0x61,0x72,0x67, + 0x65,0x72,0x20,0x74,0x68,0x61,0x6e,0x20,0x62, + 0x6c,0x6f,0x63,0x6b,0x2d,0x73,0x69,0x7a,0x65, + 0x20,0x6b,0x65,0x79,0x20,0x61,0x6e,0x64,0x20, + 0x61,0x20,0x6c,0x61,0x72,0x67,0x65,0x72,0x20, + 0x74,0x68,0x61,0x6e,0x20,0x62,0x6c,0x6f,0x63, + 0x6b,0x2d,0x73,0x69,0x7a,0x65,0x20,0x64,0x61, + 0x74,0x61,0x2e,0x20,0x54,0x68,0x65,0x20,0x6b, + 0x65,0x79,0x20,0x6e,0x65,0x65,0x64,0x73,0x20, + 0x74,0x6f,0x20,0x62,0x65,0x20,0x68,0x61,0x73, + 0x68,0x65,0x64,0x20,0x62,0x65,0x66,0x6f,0x72, + 0x65,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x75, + 0x73,0x65,0x64,0x20,0x62,0x79,0x20,0x74,0x68, + 0x65,0x20,0x48,0x4d,0x41,0x43,0x20,0x61,0x6c, + 0x67,0x6f,0x72,0x69,0x74,0x68,0x6d,0x2e}, + .data_len = 152, + .mac_len = 32, + .mac = {0x65,0xc5,0xb0,0x6d,0x4c,0x3d,0xe3,0x2a,0x7a, + 0xef,0x87,0x63,0x26,0x1e,0x49,0xad,0xb6,0xe2, + 0x29,0x3e,0xc8,0xe7,0xc6,0x1e,0x8d,0xe6,0x17, + 0x01,0xfc,0x63,0xe1,0x23} + } +}; + +/* Test vectors for HMAC SHA3-384: + */ +struct HMAC_TEST_VECTOR sha3_384_hmac_test_vector[] = { + { + .key = {0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b}, + .key_len = 20, + .data = {"Hi There"}, + .data_len = 8, + .mac_len = 48, + .mac = {0x68,0xd2,0xdc,0xf7,0xfd,0x4d,0xdd,0x0a,0x22, + 0x40,0xc8,0xa4,0x37,0x30,0x5f,0x61,0xfb,0x73, + 0x34,0xcf,0xb5,0xd0,0x22,0x6e,0x1b,0xc2,0x7d, + 0xc1,0x0a,0x2e,0x72,0x3a,0x20,0xd3,0x70,0xb4, + 0x77,0x43,0x13,0x0e,0x26,0xac,0x7e,0x3d,0x53, + 0x28,0x86,0xbd} + }, { + .key = {'J', 'e', 'f', 'e'}, + .key_len = 4, + .data = {"what do ya want for nothing?"}, + .data_len = 28, + .mac_len = 48, + .mac = {0xf1,0x10,0x1f,0x8c,0xbf,0x97,0x66,0xfd,0x67, + 0x64,0xd2,0xed,0x61,0x90,0x3f,0x21,0xca,0x9b, + 0x18,0xf5,0x7c,0xf3,0xe1,0xa2,0x3c,0xa1,0x35, + 0x08,0xa9,0x32,0x43,0xce,0x48,0xc0,0x45,0xdc, + 0x00,0x7f,0x26,0xa2,0x1b,0x3f,0x5e,0x0e,0x9d, + 0xf4,0xc2,0x0a} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa}, + .key_len = 20, + .data = {0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD}, + .data_len = 50, + .mac_len = 48, + .mac = {0x27,0x5c,0xd0,0xe6,0x61,0xbb,0x8b,0x15,0x1c, + 0x64,0xd2,0x88,0xf1,0xf7,0x82,0xfb,0x91,0xa8, + 0xab,0xd5,0x68,0x58,0xd7,0x2b,0xab,0xb2,0xd4, + 0x76,0xf0,0x45,0x83,0x73,0xb4,0x1b,0x6a,0xb5, + 0xbf,0x17,0x4b,0xec,0x42,0x2e,0x53,0xfc,0x31, + 0x35,0xac,0x6e} + }, { + .key = {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}, + .key_len = 25, + .data = {0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD}, + .data_len = 50, + .mac_len = 48, + .mac = {0x3a,0x5d,0x7a,0x87,0x97,0x02,0xc0,0x86,0xbc, + 0x96,0xd1,0xdd,0x8a,0xa1,0x5d,0x9c,0x46,0x44, + 0x6b,0x95,0x52,0x13,0x11,0xc6,0x06,0xfd,0xc4, + 0xe3,0x08,0xf4,0xb9,0x84,0xda,0x2d,0x0f,0x94, + 0x49,0xb3,0xba,0x84,0x25,0xec,0x7f,0xb8,0xc3, + 0x1b,0xc1,0x36} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 131, + .data = {0x54,0x65,0x73,0x74,0x20,0x55,0x73,0x69,0x6e, + 0x67,0x20,0x4c,0x61,0x72,0x67,0x65,0x72,0x20, + 0x54,0x68,0x61,0x6e,0x20,0x42,0x6c,0x6f,0x63, + 0x6b,0x2d,0x53,0x69,0x7a,0x65,0x20,0x4b,0x65, + 0x79,0x20,0x2d,0x20,0x48,0x61,0x73,0x68,0x20, + 0x4b,0x65,0x79,0x20,0x46,0x69,0x72,0x73,0x74}, + .data_len = 54, + .mac_len = 48, + .mac = {0x0f,0xc1,0x95,0x13,0xbf,0x6b,0xd8,0x78,0x03, + 0x70,0x16,0x70,0x6a,0x0e,0x57,0xbc,0x52,0x81, + 0x39,0x83,0x6b,0x9a,0x42,0xc3,0xd4,0x19,0xe4, + 0x98,0xe0,0xe1,0xfb,0x96,0x16,0xfd,0x66,0x91, + 0x38,0xd3,0x3a,0x11,0x05,0xe0,0x7c,0x72,0xb6, + 0x95,0x3b,0xcc} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 131, + .data = {0x54,0x68,0x69,0x73,0x20,0x69,0x73,0x20,0x61, + 0x20,0x74,0x65,0x73,0x74,0x20,0x75,0x73,0x69, + 0x6e,0x67,0x20,0x61,0x20,0x6c,0x61,0x72,0x67, + 0x65,0x72,0x20,0x74,0x68,0x61,0x6e,0x20,0x62, + 0x6c,0x6f,0x63,0x6b,0x2d,0x73,0x69,0x7a,0x65, + 0x20,0x6b,0x65,0x79,0x20,0x61,0x6e,0x64,0x20, + 0x61,0x20,0x6c,0x61,0x72,0x67,0x65,0x72,0x20, + 0x74,0x68,0x61,0x6e,0x20,0x62,0x6c,0x6f,0x63, + 0x6b,0x2d,0x73,0x69,0x7a,0x65,0x20,0x64,0x61, + 0x74,0x61,0x2e,0x20,0x54,0x68,0x65,0x20,0x6b, + 0x65,0x79,0x20,0x6e,0x65,0x65,0x64,0x73,0x20, + 0x74,0x6f,0x20,0x62,0x65,0x20,0x68,0x61,0x73, + 0x68,0x65,0x64,0x20,0x62,0x65,0x66,0x6f,0x72, + 0x65,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x75, + 0x73,0x65,0x64,0x20,0x62,0x79,0x20,0x74,0x68, + 0x65,0x20,0x48,0x4d,0x41,0x43,0x20,0x61,0x6c, + 0x67,0x6f,0x72,0x69,0x74,0x68,0x6d,0x2e}, + .data_len = 152, + .mac_len = 48, + .mac = {0x02,0x6f,0xdf,0x6b,0x50,0x74,0x1e,0x37,0x38, + 0x99,0xc9,0xf7,0xd5,0x40,0x6d,0x4e,0xb0,0x9f, + 0xc6,0x66,0x56,0x36,0xfc,0x1a,0x53,0x00,0x29, + 0xdd,0xf5,0xcf,0x3c,0xa5,0xa9,0x00,0xed,0xce, + 0x01,0xf5,0xf6,0x1e,0x2f,0x40,0x8c,0xdf,0x2f, + 0xd3,0xe7,0xe8} + } +}; + +/* Test vectors for HMAC SHA3-512: + */ +struct HMAC_TEST_VECTOR sha3_512_hmac_test_vector[] = { + { + .key = {0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b}, + .key_len = 20, + .data = {"Hi There"}, + .data_len = 8, + .mac_len = 64, + .mac = {0xeb,0x3f,0xbd,0x4b,0x2e,0xaa,0xb8,0xf5,0xc5, + 0x04,0xbd,0x3a,0x41,0x46,0x5a,0xac,0xec,0x15, + 0x77,0x0a,0x7c,0xab,0xac,0x53,0x1e,0x48,0x2f, + 0x86,0x0b,0x5e,0xc7,0xba,0x47,0xcc,0xb2,0xc6, + 0xf2,0xaf,0xce,0x8f,0x88,0xd2,0x2b,0x6d,0xc6, + 0x13,0x80,0xf2,0x3a,0x66,0x8f,0xd3,0x88,0x8b, + 0xb8,0x05,0x37,0xc0,0xa0,0xb8,0x64,0x07,0x68, + 0x9e} + }, { + .key = {'J', 'e', 'f', 'e'}, + .key_len = 4, + .data = {"what do ya want for nothing?"}, + .data_len = 28, + .mac_len = 64, + .mac = {0x5a,0x4b,0xfe,0xab,0x61,0x66,0x42,0x7c,0x7a, + 0x36,0x47,0xb7,0x47,0x29,0x2b,0x83,0x84,0x53, + 0x7c,0xdb,0x89,0xaf,0xb3,0xbf,0x56,0x65,0xe4, + 0xc5,0xe7,0x09,0x35,0x0b,0x28,0x7b,0xae,0xc9, + 0x21,0xfd,0x7c,0xa0,0xee,0x7a,0x0c,0x31,0xd0, + 0x22,0xa9,0x5e,0x1f,0xc9,0x2b,0xa9,0xd7,0x7d, + 0xf8,0x83,0x96,0x02,0x75,0xbe,0xb4,0xe6,0x20, + 0x24} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa}, + .key_len = 20, + .data = {0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD}, + .data_len = 50, + .mac_len = 64, + .mac = {0x30,0x9e,0x99,0xf9,0xec,0x07,0x5e,0xc6,0xc6, + 0xd4,0x75,0xed,0xa1,0x18,0x06,0x87,0xfc,0xf1, + 0x53,0x11,0x95,0x80,0x2a,0x99,0xb5,0x67,0x74, + 0x49,0xa8,0x62,0x51,0x82,0x85,0x1c,0xb3,0x32, + 0xaf,0xb6,0xa8,0x9c,0x41,0x13,0x25,0xfb,0xcb, + 0xcd,0x42,0xaf,0xcb,0x7b,0x6e,0x5a,0xab,0x7e, + 0xa4,0x2c,0x66,0x0f,0x97,0xfd,0x85,0x84,0xbf, + 0x03} + }, { + .key = {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}, + .key_len = 25, + .data = {0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD}, + .data_len = 50, + .mac_len = 64, + .mac = {0xb2,0x7e,0xab,0x1d,0x6e,0x8d,0x87,0x46,0x1c, + 0x29,0xf7,0xf5,0x73,0x9d,0xd5,0x8e,0x98,0xaa, + 0x35,0xf8,0xe8,0x23,0xad,0x38,0xc5,0x49,0x2a, + 0x20,0x88,0xfa,0x02,0x81,0x99,0x3b,0xbf,0xff, + 0x9a,0x0e,0x9c,0x6b,0xf1,0x21,0xae,0x9e,0xc9, + 0xbb,0x09,0xd8,0x4a,0x5e,0xba,0xc8,0x17,0x18, + 0x2e,0xa9,0x74,0x67,0x3f,0xb1,0x33,0xca,0x0d, + 0x1d} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 131, + .data = {0x54,0x65,0x73,0x74,0x20,0x55,0x73,0x69,0x6e, + 0x67,0x20,0x4c,0x61,0x72,0x67,0x65,0x72,0x20, + 0x54,0x68,0x61,0x6e,0x20,0x42,0x6c,0x6f,0x63, + 0x6b,0x2d,0x53,0x69,0x7a,0x65,0x20,0x4b,0x65, + 0x79,0x20,0x2d,0x20,0x48,0x61,0x73,0x68,0x20, + 0x4b,0x65,0x79,0x20,0x46,0x69,0x72,0x73,0x74}, + .data_len = 54, + .mac_len = 64, + .mac = {0x00,0xf7,0x51,0xa9,0xe5,0x06,0x95,0xb0,0x90, + 0xed,0x69,0x11,0xa4,0xb6,0x55,0x24,0x95,0x1c, + 0xdc,0x15,0xa7,0x3a,0x5d,0x58,0xbb,0x55,0x21, + 0x5e,0xa2,0xcd,0x83,0x9a,0xc7,0x9d,0x2b,0x44, + 0xa3,0x9b,0xaf,0xab,0x27,0xe8,0x3f,0xde,0x9e, + 0x11,0xf6,0x34,0x0b,0x11,0xd9,0x91,0xb1,0xb9, + 0x1b,0xf2,0xee,0xe7,0xfc,0x87,0x24,0x26,0xc3, + 0xa4} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 131, + .data = {0x54,0x68,0x69,0x73,0x20,0x69,0x73,0x20,0x61, + 0x20,0x74,0x65,0x73,0x74,0x20,0x75,0x73,0x69, + 0x6e,0x67,0x20,0x61,0x20,0x6c,0x61,0x72,0x67, + 0x65,0x72,0x20,0x74,0x68,0x61,0x6e,0x20,0x62, + 0x6c,0x6f,0x63,0x6b,0x2d,0x73,0x69,0x7a,0x65, + 0x20,0x6b,0x65,0x79,0x20,0x61,0x6e,0x64,0x20, + 0x61,0x20,0x6c,0x61,0x72,0x67,0x65,0x72,0x20, + 0x74,0x68,0x61,0x6e,0x20,0x62,0x6c,0x6f,0x63, + 0x6b,0x2d,0x73,0x69,0x7a,0x65,0x20,0x64,0x61, + 0x74,0x61,0x2e,0x20,0x54,0x68,0x65,0x20,0x6b, + 0x65,0x79,0x20,0x6e,0x65,0x65,0x64,0x73,0x20, + 0x74,0x6f,0x20,0x62,0x65,0x20,0x68,0x61,0x73, + 0x68,0x65,0x64,0x20,0x62,0x65,0x66,0x6f,0x72, + 0x65,0x20,0x62,0x65,0x69,0x6e,0x67,0x20,0x75, + 0x73,0x65,0x64,0x20,0x62,0x79,0x20,0x74,0x68, + 0x65,0x20,0x48,0x4d,0x41,0x43,0x20,0x61,0x6c, + 0x67,0x6f,0x72,0x69,0x74,0x68,0x6d,0x2e}, + .data_len = 152, + .mac_len = 64, + .mac = {0x38,0xa4,0x56,0xa0,0x04,0xbd,0x10,0xd3,0x2c, + 0x9a,0xb8,0x33,0x66,0x84,0x11,0x28,0x62,0xc3, + 0xdb,0x61,0xad,0xcc,0xa3,0x18,0x29,0x35,0x5e, + 0xaf,0x46,0xfd,0x5c,0x73,0xd0,0x6a,0x1f,0x0d, + 0x13,0xfe,0xc9,0xa6,0x52,0xfb,0x38,0x11,0xb5, + 0x77,0xb1,0xb1,0xd1,0xb9,0x78,0x9f,0x97,0xae, + 0x5b,0x83,0xc6,0xf4,0x4d,0xfc,0xf1,0xd6,0x7e, + 0xba} + } +}; + +/* MD5 HMAC test vectors from RFC2202: + * http://www.faqs.org/rfcs/rfc2202.html + * Note: These are same test vectors as md5_hmac_test_vector but + * the mac_len is different. + */ +struct HMAC_TEST_VECTOR md5_hmac_general_test_vector[] = { + { + .key = {0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b}, + .key_len = 16, + .data = {"Hi There"}, + .data_len = 8, + .mac_len = 4, + .mac = {0x92,0x94,0x72,0x7a,0x36,0x38,0xBB,0x1C,0x13, + 0xf4,0x8E,0xf8,0x15,0x8b,0xfc,0x9d} + }, { + .key = {'J', 'e', 'f', 'e'}, + .key_len = 4, + .data = {"what do ya want for nothing?"}, + .data_len = 28, + .mac_len = 4, + .mac = {0x75,0x0c,0x78,0x3e,0x6a,0xb0,0xb5,0x03,0xea, + 0xa8,0x6e,0x31,0x0a,0x5d,0xb7,0x38} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 16, + .data = {0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD}, + .data_len = 50, + .mac_len = 4, + .mac = {0x56,0xbe,0x34,0x52,0x1d,0x14,0x4c,0x88,0xdb, + 0xb8,0xc7,0x33,0xf0,0xe8,0xb3,0xf6} + }, { + .key = {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}, + .key_len = 25, + .data = {0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD}, + .data_len = 50, + .mac_len = 4, + .mac = {0x69,0x7e,0xaf,0x0a,0xca,0x3a,0x3a,0xea,0x3a, + 0x75,0x16,0x47,0x46,0xff,0xaa,0x79} + }, { + .key = {0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, + 0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c}, + .key_len = 16, + .data = {"Test With Truncation"}, + .data_len = 20, + .mac_len = 4, + .mac = {0x56,0x46,0x1e,0xf2,0x34,0x2e,0xdc,0x00,0xf9, + 0xba,0xb9,0x95,0x69,0x0e,0xfd,0x4c} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 80, + .data = {"Test Using Larger Than Block-Size Key - Hash Key First"}, + .data_len = 54, + .mac_len = 4, + .mac = {0x6b,0x1a,0xb7,0xfe,0x4b,0xd7,0xbf,0x8f,0x0b, + 0x62,0xe6,0xce,0x61,0xb9,0xd0,0xcd} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 80, + .data = {"Test Using Larger Than Block-Size Key and Larger Than One " + "Block-Size Data"}, + .data_len = 73, + .mac_len = 4, + .mac = {0x6f,0x63,0x0f,0xad,0x67,0xcd,0xa0,0xee,0x1f, + 0xb1,0xf5,0x62,0xdb,0x3a,0xa5,0x3e} + }, +}; + +/* SHA1 HMAC test vectors from RFC2202: + * http://www.faqs.org/rfcs/rfc2202.html + * Note: These are same test vectors as sha1_hmac_test_vector but + * the mac_len is different. + */ +struct HMAC_TEST_VECTOR sha1_hmac_general_test_vector[] = { + { + .key = {0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b}, + .key_len = 20, + .data = {"Hi There"}, + .data_len = 8, + .mac_len = 10, + .mac = {0xb6,0x17,0x31,0x86,0x55,0x05,0x72,0x64,0xe2, + 0x8b,0xc0,0xb6,0xfb,0x37,0x8c,0x8e,0xf1,0x46, + 0xbe,0x00} + }, { + .key = {'J', 'e', 'f', 'e'}, + .key_len = 4, + .data = {"what do ya want for nothing?"}, + .data_len = 28, + .mac_len = 10, + .mac = {0xef,0xfc,0xdf,0x6a,0xe5,0xeb,0x2f,0xa2,0xd2, + 0x74,0x16,0xd5,0xf1,0x84,0xdf,0x9c,0x25,0x9a, + 0x7c,0x79} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa}, + .key_len = 20, + .data = {0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD}, + .data_len = 50, + .mac_len = 10, + .mac = {0x12,0x5d,0x73,0x42,0xb9,0xac,0x11,0xcd,0x91, + 0xa3,0x9a,0xf4,0x8a,0xa1,0x7b,0x4f,0x63,0xf1, + 0x75,0xd3} + }, { + .key = {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}, + .key_len = 25, + .data = {0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD}, + .data_len = 50, + .mac_len = 10, + .mac = {0x4c,0x90,0x07,0xf4,0x02,0x62,0x50,0xc6,0xbc, + 0x84,0x14,0xf9,0xbf,0x50,0xc8,0x6c,0x2d,0x72, + 0x35,0xda} + }, { + .key = {0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, + 0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, + 0x0c,0x0c}, + .key_len = 20, + .data = {"Test With Truncation"}, + .data_len = 20, + .mac_len = 10, + .mac = {0x4c,0x1a,0x03,0x42,0x4b,0x55,0xe0,0x7f,0xe7, + 0xf2,0x7b,0xe1,0xd5,0x8b,0xb9,0x32,0x4a,0x9a, + 0x5a,0x04} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 80, + .data = {"Test Using Larger Than Block-Size Key - Hash Key First"}, + .data_len = 54, + .mac_len = 10, + .mac = {0xaa,0x4a,0xe5,0xe1,0x52,0x72,0xd0,0x0e,0x95, + 0x70,0x56,0x37,0xce,0x8a,0x3b,0x55,0xed,0x40, + 0x21,0x12} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 80, + .data = {"Test Using Larger Than Block-Size Key and Larger Than One " + "Block-Size Data"}, + .data_len = 73, + .mac_len = 10, + .mac = {0xe8,0xe9,0x9d,0x0f,0x45,0x23,0x7d,0x78,0x6d, + 0x6b,0xba,0xa7,0x96,0x5c,0x78,0x08,0xbb,0xff, + 0x1a,0x91} + } +}; + +/* Test vectors for HMAC SHA256 from RFC4868: + * http://tools.ietf.org/html/rfc4868 + * Note: These are same test vectors as sha256_hmac_test_vector but + * the mac_len is different. + */ +struct HMAC_TEST_VECTOR sha224_hmac_general_test_vector[] = { + { + .key = {0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b}, + .key_len = 20, + .data = {"Hi There"}, + .data_len = 8, + .mac_len = 16, + .mac = {0x89,0x6f,0xb1,0x12,0x8a,0xbb,0xdf,0x19,0x68, + 0x32,0x10,0x7c,0xd4,0x9d,0xf3,0x3f} + }, { + .key = {'J', 'e', 'f', 'e'}, + .key_len = 4, + .data = {"what do ya want for nothing?"}, + .data_len = 28, + .mac_len = 16, + .mac = {0xa3,0x0e,0x01,0x09,0x8b,0xc6,0xdb,0xbf,0x45, + 0x69,0x0f,0x3a,0x7e,0x9e,0x6d,0x0f} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa}, + .key_len = 20, + .data = {0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD}, + .data_len = 50, + .mac_len = 16, + .mac = {0x7f,0xb3,0xcb,0x35,0x88,0xc6,0xc1,0xf6,0xff, + 0xa9,0x69,0x4d,0x7d,0x6a,0xd2,0x64} + }, { + .key = {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}, + .key_len = 25, + .data = {0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD}, + .data_len = 50, + .mac_len = 16, + .mac = {0x6c,0x11,0x50,0x68,0x74,0x01,0x3c,0xac,0x6a, + 0x2a,0xbc,0x1b,0xb3,0x82,0x62,0x7c} + } +}; + + +struct HMAC_TEST_VECTOR sha256_hmac_general_test_vector[] = { + { + .key = {0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b}, + .key_len = 32, + .data = {"Hi There"}, + .data_len = 8, + .mac_len = 16, + .mac = {0x19,0x8a,0x60,0x7e,0xb4,0x4b,0xfb,0xc6,0x99, + 0x03,0xa0,0xf1,0xcf,0x2b,0xbd,0xc5} + }, { + .key = {0x4a,0x65,0x66,0x65,0x4a,0x65,0x66,0x65,0x4a, + 0x65,0x66,0x65,0x4a,0x65,0x66,0x65,0x4a,0x65, + 0x66,0x65,0x4a,0x65,0x66,0x65,0x4a,0x65,0x66, + 0x65,0x4a,0x65,0x66,0x65}, + .key_len = 32, + .data = {"what do ya want for nothing?"}, + .data_len = 28, + .mac_len = 16, + .mac = {0x16,0x7f,0x92,0x85,0x88,0xc5,0xcc,0x2e,0xef, + 0x8e,0x30,0x93,0xca,0xa0,0xe8,0x7c}, + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa}, + .key_len = 32, + .data = {0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD}, + .data_len = 50, + .mac_len = 16, + .mac = {0xcd,0xcb,0x12,0x20,0xd1,0xec,0xcc,0xea,0x91, + 0xe5,0x3a,0xba,0x30,0x92,0xf9,0x62} + }, { + .key = {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}, + .key_len = 32, + .data = {0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD}, + .data_len = 50, + .mac_len = 16, + .mac = {0x37,0x2e,0xfc,0xf9,0xb4,0x0b,0x35,0xc2,0x11, + 0x5b,0x13,0x46,0x90,0x3d,0x2e,0xf4} + } +}; + +/* Test vectors for HMAC SHA384 from RFC4868: + * http://tools.ietf.org/html/rfc4868 + * Note: These are same test vectors as sha384_hmac_test_vector but + * the mac_len is different. + */ +struct HMAC_TEST_VECTOR sha384_hmac_general_test_vector[] = { + { + .key = {0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b}, + .key_len = 48, + .data = {"Hi There"}, + .data_len = 8, + .mac_len = 24, + .mac = {0xb6,0xa8,0xd5,0x63,0x6f,0x5c,0x6a,0x72,0x24, + 0xf9,0x97,0x7d,0xcf,0x7e,0xe6,0xc7,0xfb,0x6d, + 0x0c,0x48,0xcb,0xde,0xe9,0x73} + }, { + .key = {0x4a,0x65,0x66,0x65,0x4a,0x65,0x66,0x65,0x4a, + 0x65,0x66,0x65,0x4a,0x65,0x66,0x65,0x4a,0x65, + 0x66,0x65,0x4a,0x65,0x66,0x65,0x4a,0x65,0x66, + 0x65,0x4a,0x65,0x66,0x65,0x4a,0x65,0x66,0x65, + 0x4a,0x65,0x66,0x65,0x4a,0x65,0x66,0x65,0x4a, + 0x65,0x66,0x65}, + .key_len = 48, + .data = {"what do ya want for nothing?"}, + .data_len = 28, + .mac_len = 24, + .mac = {0x2c,0x73,0x53,0x97,0x4f,0x18,0x42,0xfd,0x66, + 0xd5,0x3c,0x45,0x2c,0xa4,0x21,0x22,0xb2,0x8c, + 0x0b,0x59,0x4c,0xfb,0x18,0x4d} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa}, + .key_len = 48, + .data = {0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD}, + .data_len = 50, + .mac_len = 24, + .mac = {0x80,0x9f,0x43,0x9b,0xe0,0x02,0x74,0x32,0x1d, + 0x4a,0x53,0x86,0x52,0x16,0x4b,0x53,0x55,0x4a, + 0x50,0x81,0x84,0xa0,0xc3,0x16} + }, { + .key = {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,0x0a,0x0b,0x0c,0x0d, + 0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16, + 0x17,0x18,0x19}, + .key_len = 48, + .data = {0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD}, + .data_len = 50, + .mac_len = 24, + .mac = {0x5b,0x54,0x00,0x85,0xc6,0xe6,0x35,0x80,0x96, + 0x53,0x2b,0x24,0x93,0x60,0x9e,0xd1,0xcb,0x29, + 0x8f,0x77,0x4f,0x87,0xbb,0x5c} + } +}; + +/* Test vectors for HMAC SHA512 from RFC4868: + * http://tools.ietf.org/html/rfc4868 + * Note: These are same test vectors as sha512_hmac_test_vector but + * the mac_len is different. + */ +struct HMAC_TEST_VECTOR sha512_hmac_general_test_vector[] = { + { + .key = {0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b}, + .key_len = 64, + .data = {"Hi There"}, + .data_len = 8, + .mac_len = 32, + .mac = {0x63,0x7e,0xdc,0x6e,0x01,0xdc,0xe7,0xe6,0x74, + 0x2a,0x99,0x45,0x1a,0xae,0x82,0xdf,0x23,0xda, + 0x3e,0x92,0x43,0x9e,0x59,0x0e,0x43,0xe7,0x61, + 0xb3,0x3e,0x91,0x0f,0xb8} + }, { + .key = {0x4a,0x65,0x66,0x65,0x4a,0x65,0x66,0x65,0x4a, + 0x65,0x66,0x65,0x4a,0x65,0x66,0x65,0x4a,0x65, + 0x66,0x65,0x4a,0x65,0x66,0x65,0x4a,0x65,0x66, + 0x65,0x4a,0x65,0x66,0x65,0x4a,0x65,0x66,0x65, + 0x4a,0x65,0x66,0x65,0x4a,0x65,0x66,0x65,0x4a, + 0x65,0x66,0x65,0x4a,0x65,0x66,0x65,0x4a,0x65, + 0x66,0x65,0x4a,0x65,0x66,0x65,0x4a,0x65,0x66, + 0x65}, + .key_len = 64, + .data = {"what do ya want for nothing?"}, + .data_len = 28, + .mac_len = 32, + .mac = {0xcb,0x37,0x09,0x17,0xae,0x8a,0x7c,0xe2,0x8c, + 0xfd,0x1d,0x8f,0x47,0x05,0xd6,0x14,0x1c,0x17, + 0x3b,0x2a,0x93,0x62,0xc1,0x5d,0xf2,0x35,0xdf, + 0xb2,0x51,0xb1,0x54,0x54} + }, { + .key = {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa}, + .key_len = 64, + .data = {0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD, + 0xDD,0xDD,0xDD,0xDD,0xDD}, + .data_len = 50, + .mac_len = 32, + .mac = {0x2e,0xe7,0xac,0xd7,0x83,0x62,0x4c,0xa9,0x39, + 0x87,0x10,0xf3,0xee,0x05,0xae,0x41,0xb9,0xf9, + 0xb0,0x51,0x0c,0x87,0xe4,0x9e,0x58,0x6c,0xc9, + 0xbf,0x96,0x17,0x33,0xd8} + }, { + .key = {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,0x21,0x22,0x23,0x24, + 0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d, + 0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36, + 0x37,0x38, 0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x40}, + .key_len = 64, + .data = {0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD,0xCD, + 0xCD,0xCD,0xCD,0xCD,0xCD}, + .data_len = 50, + .mac_len = 32, + .mac = {0x5e,0x66,0x88,0xe5,0xa3,0xda,0xec,0x82,0x6c, + 0xa3,0x2e,0xae,0xa2,0x24,0xef,0xf5,0xe7,0x00, + 0x62,0x89,0x47,0x47,0x0e,0x13,0xad,0x01,0x30, + 0x25,0x61,0xba,0xb1,0x08} + } +}; + +/* FIPS HMAC test vectors from + * http://csrc.nist.gov/groups/STM/cavp/documents/mac/hmactestvectors.zip + * Notes: + * The test vectors have various mac sizes, so suitable for HMAC + * GENERAL mechanisms. + * The second number in parentheisis is the "Count" in the HMAC.rsp. + */ + +struct HMAC_TEST_VECTOR fips_sha1_hmac_test_vector[] = { + { // 0 (45) + .key = {0x59,0x78,0x59,0x28,0xd7,0x25,0x16,0xe3,0x12,0x72}, + .key_len = 10, + .data = {0xa3,0xce,0x88,0x99,0xdf,0x10,0x22,0xe8,0xd2, + 0xd5,0x39,0xb4,0x7b,0xf0,0xe3,0x09,0xc6,0x6f, + 0x84,0x09,0x5e,0x21,0x43,0x8e,0xc3,0x55,0xbf, + 0x11,0x9c,0xe5,0xfd,0xcb,0x4e,0x73,0xa6,0x19, + 0xcd,0xf3,0x6f,0x25,0xb3,0x69,0xd8,0xc3,0x8f, + 0xf4,0x19,0x99,0x7f,0x0c,0x59,0x83,0x01,0x08, + 0x22,0x36,0x06,0xe3,0x12,0x23,0x48,0x3f,0xd3, + 0x9e,0xde,0xaa,0x4d,0x3f,0x0d,0x21,0x19,0x88, + 0x62,0xd2,0x39,0xc9,0xfd,0x26,0x07,0x41,0x30, + 0xff,0x6c,0x86,0x49,0x3f,0x52,0x27,0xab,0x89, + 0x5c,0x8f,0x24,0x4b,0xd4,0x2c,0x7a,0xfc,0xe5, + 0xd1,0x47,0xa2,0x0a,0x59,0x07,0x98,0xc6,0x8e, + 0x70,0x8e,0x96,0x49,0x02,0xd1,0x24,0xda,0xde, + 0xcd,0xbd,0xa9,0xdb,0xd0,0x05,0x1e,0xd7,0x10, + 0xe9,0xbf}, + .data_len = 128, + .mac_len = 20, + .mac = {0x3c,0x81,0x62,0x58,0x9a,0xaf,0xae,0xe0,0x24, + 0xfc,0x9a,0x5c,0xa5,0x0d,0xd2,0x33,0x6f,0xe3, + 0xeb,0x28}, + .chunks = {25, 25, 25, 25, 3, 25}, + .num_chunks = 6, + }, { // 1 (46) + .key = {0xc5,0x21,0x09,0xc9,0xd0,0xda,0x92,0x58,0xeb,0x73}, + .key_len = 10, + .data = {0x52,0xb1,0x13,0x61,0x4b,0x80,0xb9,0x70,0x51, + 0x0f,0x65,0xa2,0x5d,0x46,0xed,0xc0,0x23,0xd9, + 0xc7,0xb8,0xe7,0xca,0x7c,0x41,0x92,0x30,0x59, + 0xc2,0x05,0x36,0x68,0x70,0xad,0x66,0x9f,0xb7, + 0x57,0x28,0x56,0xdc,0x46,0x85,0xff,0xe0,0x83, + 0x31,0x11,0xa7,0x75,0xc9,0x45,0x5a,0xb1,0x59, + 0x05,0x09,0x13,0x21,0x21,0x95,0x0e,0x99,0xc5, + 0xcd,0x40,0xb2,0xa8,0xd7,0x4a,0x5f,0x85,0xd2, + 0xde,0x54,0xcf,0xb9,0x1a,0x0d,0xa1,0x8a,0x14, + 0x13,0xf4,0xa8,0xb6,0x7b,0x14,0x7e,0xcc,0xaf, + 0x55,0x66,0x5b,0x71,0x01,0xc9,0x34,0x1c,0x96, + 0x87,0xca,0x2d,0x2e,0x99,0x41,0x03,0x3f,0xf5, + 0xc7,0xe3,0x84,0xb1,0x27,0x3f,0x3b,0x6c,0x9b, + 0x38,0x91,0xea,0xe2,0x61,0x5b,0xfe,0x93,0xc6, + 0x06,0xad}, + .data_len = 128, + .mac_len = 20, + .mac = {0x2f,0xec,0xb4,0x66,0xbc,0x92,0x0f,0x61,0x0e, + 0x3e,0xae,0x99,0x49,0xe0,0x0f,0x45,0x4a,0x71, + 0x4a,0xb5}, + .chunks = {54, 0, 54, -1, 20}, + .num_chunks = 5, + }, { // 2 (105) + .key = {0x89,0x58,0x68,0xf1,0x96,0x95,0xc1,0xf5,0xa2, + 0x6d,0x8a,0xe3,0x39,0xc5,0x67,0xe5,0xab,0x43, + 0xb0,0xfc,0xc8,0x05,0x60,0x50,0xe9,0x92,0x2e, + 0xc5,0x30,0x10,0xf9,0xce}, + .key_len = 32, + .data = {0x88,0x3e,0x6c,0xa2,0xb1,0x9e,0xf5,0x46,0x40, + 0xbb,0x83,0x33,0xf8,0x5a,0x93,0x80,0xe1,0x72, + 0x11,0xf6,0xee,0x3d,0x1d,0xc7,0xdc,0x8f,0x0e, + 0x7c,0x5d,0x67,0xb7,0x30,0x76,0xc3,0xea,0xfc, + 0x26,0xb9,0x3b,0xb2,0x48,0xc4,0x06,0xce,0xba, + 0x5c,0xb4,0xa9,0xbf,0xc9,0x39,0xf0,0xa2,0x38, + 0xe1,0x55,0x9d,0x0f,0x4d,0x84,0xf8,0x7e,0xb8, + 0x59,0x75,0x56,0x80,0x50,0xec,0x1f,0xe1,0x3d, + 0x33,0x65,0x03,0x3d,0x40,0x52,0x37,0xec,0x92, + 0x82,0x7d,0xd8,0xcd,0x12,0x4b,0x36,0xa4,0xfa, + 0x89,0xd4,0xfb,0x9d,0xe0,0x4f,0x4d,0x9f,0x34, + 0x86,0x4c,0xf7,0x6f,0x4e,0xc8,0x45,0x81,0x68, + 0xd2,0x65,0xa5,0xb0,0x21,0x44,0xe5,0x96,0xb5, + 0xf2,0xe0,0xd2,0xb9,0xf9,0xcb,0x54,0xae,0xee, + 0xb6,0x7a}, + .data_len = 128, + .mac_len = 20, + .mac = {0x37,0x4c,0x88,0xf4,0x48,0x0f,0x5e,0x8a,0xaa, + 0x9f,0x44,0x8b,0x77,0x75,0x57,0xc5,0x00,0x65, + 0xe9,0xac}, + }, { // 3 (106) + .key = {0x95,0x0f,0xb0,0xcd,0xe3,0x0f,0x34,0xf5,0x97, + 0xaf,0x5c,0xaa,0x2b,0x16,0xfc,0x86,0xa5,0xc3, + 0xef,0x06,0x5d,0x36,0xff,0xdd,0x06,0xec,0x04, + 0x8e,0xec,0x91,0x50,0x39}, + .key_len = 32, + .data = {0xe4,0x63,0x62,0x65,0x06,0x14,0x4c,0xec,0xe5, + 0x5d,0xfb,0x7a,0xa2,0x2e,0xb2,0x1e,0xa3,0xa4, + 0x27,0x7d,0x89,0x2c,0x21,0x17,0x62,0xea,0x45, + 0xcc,0x20,0x5c,0x2d,0x9e,0x4b,0x3a,0xbb,0xb8, + 0xf2,0xa1,0xad,0xb0,0xe7,0x71,0x71,0x09,0x2c, + 0xf4,0x3a,0xfc,0xa8,0xc0,0x53,0x77,0x1e,0xde, + 0xb4,0x67,0x60,0x2b,0xd3,0x33,0xc0,0xff,0xbc, + 0x88,0xc8,0x0d,0x64,0x5c,0x2b,0x8a,0x3a,0x2d, + 0xfa,0x92,0x00,0x8a,0x1b,0xc7,0xd9,0xd5,0xf8, + 0x3b,0xa3,0x47,0x74,0x90,0x86,0x34,0x23,0x5d, + 0xcd,0x91,0xba,0xd4,0xf5,0xb3,0xc4,0xa2,0x04, + 0x59,0x97,0x17,0x1d,0xed,0x87,0x87,0x50,0x07, + 0x59,0xf0,0xb6,0x33,0xfb,0xdc,0xbe,0xf4,0x72, + 0x89,0xc2,0x09,0x13,0x48,0xde,0xee,0xf6,0x23, + 0x01,0xa6}, + .data_len = 128, + .mac_len = 20, + .mac = {0x8c,0x90,0x48,0x0e,0xa6,0x41,0x45,0x53,0xdf, + 0x17,0xe5,0x3c,0xf9,0x6d,0xcb,0x16,0x6b,0x94, + 0xbe,0x35}, + }, { // 4 (165) + .key = {0xb9,0x57,0x5f,0x4d,0x5e,0xcc,0x0f,0x4f,0x62, + 0xe4,0xa0,0x55,0x6b,0xb8,0x94,0x64,0xba,0x97, + 0xd4,0x57,0x0e,0x55,0xac,0xd4,0xc5,0xe5,0x17, + 0x7e,0x45,0x2a,0x3d,0x6c,0x9a,0x0b,0x3a,0xdb, + 0x60,0xc6,0x21,0x1f,0xe4,0x86,0x40,0xe0,0x86, + 0x37,0xa6,0x82,0x62,0x99,0xe3,0xe5,0x2f,0x93, + 0x0f,0x4f,0x66,0xcb,0x0e,0xa6,0xa7,0x73,0x11, + 0xe3}, + .key_len = 64, + .data = {0x8c,0x83,0x87,0xf4,0xae,0x2c,0xa1,0xa6,0xdd, + 0x13,0xd2,0x9e,0x93,0x58,0x0b,0x1c,0xdf,0x62, + 0x68,0xda,0x66,0xcf,0x58,0x9c,0xa8,0xb1,0xff, + 0x08,0x84,0xf7,0xd8,0xb8,0xfe,0x29,0x9f,0x8e, + 0x41,0x59,0x6e,0x47,0xe0,0x56,0x26,0x53,0x61, + 0x22,0x10,0xe4,0xfc,0xa6,0xc4,0x46,0xa0,0xa5, + 0x4a,0x6e,0x37,0xef,0x80,0xd5,0x2b,0xd7,0xbb, + 0x87,0x29,0xe6,0xb1,0x76,0x25,0xd1,0x97,0x15, + 0x9e,0xa9,0x86,0x22,0x23,0x52,0x23,0xc3,0x16, + 0x36,0x7f,0xd5,0xb0,0x3a,0x3c,0x81,0x45,0xf2, + 0xf2,0x10,0xc9,0x10,0xd0,0x00,0x94,0x23,0x87, + 0x57,0x62,0x7e,0x63,0x37,0x9e,0x75,0xbb,0xb3, + 0xe0,0xd0,0x8c,0xe1,0xb4,0x79,0x61,0x30,0x9d, + 0x78,0x76,0xfc,0x59,0x21,0x1c,0x60,0x67,0x8c, + 0x5f,0x4c}, + .data_len = 128, + .mac_len = 20, + .mac = {0x15,0xaf,0x23,0x33,0x16,0x48,0x17,0x14,0x99, + 0xb5,0x80,0x42,0xdb,0xe7,0xb2,0xd5,0xdf,0x72, + 0xd1,0x52}, + }, { // 5 (166) + .key = {0xd2,0x91,0xad,0xbf,0x05,0xb0,0x65,0x96,0xc2, + 0xf3,0x6f,0x41,0xa8,0xcd,0x80,0x70,0x37,0x0c, + 0x42,0xf6,0x87,0xb8,0xa6,0xcc,0x3a,0x3e,0x7b, + 0x59,0xaf,0xcd,0x40,0xf0,0x78,0x01,0x36,0x9b, + 0x0f,0xbf,0xba,0x17,0xc4,0x60,0xd2,0x1f,0xfa, + 0x11,0x06,0xee,0x93,0x79,0x71,0xff,0xa9,0x9d, + 0x17,0x17,0x7f,0x01,0x79,0x85,0xb7,0x10,0x67, + 0xa8}, + .key_len = 64, + .data = {0x50,0xbc,0xdf,0x31,0x38,0x9e,0xad,0xac,0x5b, + 0xb8,0x19,0x7e,0xe9,0x49,0xf2,0x86,0x4e,0xde, + 0x28,0x4c,0x07,0xd0,0x39,0xa0,0xb4,0x0e,0xed, + 0x7e,0x6f,0x1c,0x43,0x35,0x5d,0x5c,0xab,0xc8, + 0x82,0x8d,0x75,0x95,0xda,0x91,0x8a,0x34,0xa5, + 0x73,0x5a,0xa2,0x02,0xa8,0x15,0x9f,0xbf,0x95, + 0x1e,0x54,0x70,0x52,0xbd,0x39,0xbe,0xae,0x14, + 0x36,0x02,0x73,0x54,0x09,0x13,0xeb,0x30,0xe7, + 0x5b,0xa2,0x92,0x66,0x31,0x6e,0x8d,0x9a,0x63, + 0xad,0x94,0x7e,0x11,0xce,0xe9,0x96,0xc2,0x13, + 0x57,0xd3,0xb1,0x94,0x24,0xb7,0x68,0x88,0x42, + 0xb9,0x90,0xc0,0xc5,0xeb,0x08,0x74,0x9a,0xda, + 0x34,0x42,0x75,0xb6,0x98,0x74,0x0b,0xb3,0xa5, + 0x82,0x82,0xae,0xd2,0xd7,0x25,0x14,0xef,0xd8, + 0x5d,0x00}, + .data_len = 128, + .mac_len = 20, + .mac = {0x5f,0x7a,0x57,0xd4,0x2e,0x3e,0xbb,0xcb,0x85, + 0xb0,0x85,0x65,0x30,0x4d,0xab,0x94,0x1d,0x62, + 0x34,0xf3}, + }, { // 6 (225) + .key = {0xf0,0xda,0xe6,0xd8,0x75,0x30,0x76,0xb1,0x89, + 0x5c,0x01,0x26,0x2c,0xa9,0xb5,0x76,0x33,0xeb, + 0x28,0xb3,0xf9,0x63,0xa7,0xc7,0x52,0xe2,0xcb, + 0xb4,0xc0,0x31,0x4c,0x20,0xea,0xb1,0x1a,0x10, + 0x49,0x3f,0xaa,0xf4,0x25,0x5a,0x8e,0xe4,0xc0, + 0x88,0x49,0x29,0xd1,0xf5,0x61,0xff,0x33,0x5e, + 0xb6,0x99,0xdf,0x2d,0x11,0x66,0x18,0xe6,0x00, + 0x93,0xe5,0xc1,0xe2,0xd1,0xc4,0x99}, + .key_len = 70, + .data = {0x61,0xcb,0x9e,0x1f,0x1e,0x4b,0x3a,0x3b,0x3b, + 0xdf,0xf8,0xcd,0x5f,0x24,0x56,0x6b,0x98,0x7f, + 0x75,0xc8,0xa0,0x53,0x77,0x85,0x5f,0x77,0x2b, + 0x49,0xb0,0xe7,0xec,0x13,0x68,0xb9,0xc6,0xcf, + 0x95,0x53,0xdb,0x28,0x03,0xdc,0x05,0x9e,0x05, + 0xf0,0xbd,0xd8,0x71,0x98,0x3c,0x3b,0xed,0x79, + 0xdf,0xbb,0x69,0x4b,0xd0,0xf1,0xed,0x8d,0xe3, + 0x6e,0x95,0x77,0xbe,0x50,0xda,0x31,0x3d,0x13, + 0x12,0x42,0x15,0xa9,0x3a,0x4b,0xb7,0xcc,0xf4, + 0xf5,0x77,0x93,0xcc,0x28,0xed,0x43,0xbf,0x7e, + 0x9b,0x68,0xfe,0xf7,0xd1,0x25,0xef,0xee,0xce, + 0xc9,0x75,0x4b,0x28,0xa2,0x71,0xfb,0x6e,0x16, + 0x89,0x9d,0x0b,0xef,0x28,0x7e,0x6d,0xf7,0xc5, + 0xc8,0x67,0xc5,0x69,0xf6,0xd4,0xd6,0x6b,0x8b, + 0x7e,0xe0}, + .data_len = 128, + .mac_len = 20, + .mac = {0x62,0xac,0x95,0x6a,0xda,0x19,0xf0,0x4b,0xe5, + 0x0c,0x23,0xf2,0x32,0x8a,0x32,0x47,0x7c,0xd5, + 0x8f,0xb9}, + }, { // 7 (226) + .key = {0x65,0xaf,0x1f,0x17,0xcd,0x7f,0xda,0xa5,0x23, + 0xb9,0xb7,0xa9,0x82,0x9d,0x49,0x7c,0xac,0x73, + 0x03,0xd4,0x50,0xc5,0x9e,0x98,0x88,0xcb,0xba, + 0xf3,0xa6,0x27,0xc8,0xa8,0x30,0xd3,0x27,0xa5, + 0x29,0x57,0x8d,0xda,0x92,0x3f,0xa9,0x4b,0x31, + 0xcc,0x07,0x64,0x91,0xea,0x33,0x8d,0x4a,0x62, + 0x21,0xff,0x82,0x51,0xcc,0xd6,0xb4,0xd9,0x1e, + 0x67,0xb1,0x16,0x10,0xd3,0xe4,0x53}, + .key_len = 70, + .data = {0x9a,0xb4,0x66,0x7b,0x2d,0xf7,0xeb,0x4b,0xe8, + 0x86,0x3a,0xa5,0x3e,0x9b,0xf9,0xaf,0x8b,0xae, + 0x0f,0xc0,0x9d,0xe9,0x4f,0x73,0x73,0xdc,0x56, + 0xfa,0x44,0x72,0xb6,0xb5,0xc4,0x23,0x54,0x03, + 0xa2,0x6c,0x0e,0x59,0x55,0x7c,0xa1,0x91,0x18, + 0x31,0xca,0x84,0x33,0x42,0xac,0xda,0x7d,0xbe, + 0x72,0x21,0x1f,0xb5,0x35,0x1d,0x9a,0x34,0x20, + 0x5f,0x0c,0x77,0xd2,0x19,0xaf,0x5b,0x03,0x31, + 0xa2,0x12,0x6b,0x94,0xec,0x1a,0xdf,0xcd,0xbe, + 0x70,0xbe,0xd6,0xf8,0x01,0x8b,0x2e,0xef,0x61, + 0xdb,0x2b,0x6d,0xbf,0x72,0x92,0xfa,0x19,0xa9, + 0x65,0x5a,0xac,0x13,0xfc,0x57,0xaf,0x5f,0x57, + 0xc1,0x40,0x80,0xb3,0xb2,0x9f,0x0c,0x5b,0x16, + 0x9a,0xe2,0xc1,0x6b,0x48,0x10,0xcd,0xc6,0xfa, + 0xf4,0x75}, + .data_len = 128, + .mac_len = 20, + .mac = {0xa2,0x79,0xd0,0x55,0xe2,0xd7,0x33,0x06,0xa8, + 0x18,0x73,0x44,0xfc,0x32,0xcb,0x0b,0x5b,0x80, + 0xcd,0x35}, + }, { // 8 (285) + .key = {0x4d,0xdd,0x00,0xd0,0xab,0x6a,0xab,0x21,0x00, + 0xce,0x97,0x54,0xc3,0xb3,0x98,0x7c,0x06,0xf7, + 0xe5,0x86,0x56,0x01,0x1d,0x26,0xe3,0x51,0x87, + 0x11,0xe1,0x5b,0x9e,0x6d,0x2d,0x96,0xcd,0x85, + 0x34,0xd0,0x77,0xc2,0x11,0xc4,0x3a,0xd7,0xf5, + 0xee,0x75,0x3b,0xcc,0x9e,0x07,0xdc,0x1d,0x4c, + 0x5a,0x12,0x32,0x2b,0xa1,0xd1,0x7a,0x00,0x5d, + 0x24,0x2b,0x35,0x26,0xd6,0x2b,0x29,0xa8,0x72, + 0x31,0xcb,0xec,0x6f,0x28,0x67,0xd9,0xa4}, + .key_len = 80, + .data = {0x28,0xbe,0x0d,0x9e,0x62,0xdc,0x89,0xe2,0xa9, + 0x13,0x06,0x4c,0x0d,0x3d,0xbf,0xb3,0x5a,0x0c, + 0x77,0x66,0xf7,0x56,0x74,0x1b,0x0e,0xaf,0xcc, + 0x28,0xed,0x3d,0xdf,0xf6,0xad,0xc8,0x25,0xb2, + 0x11,0x11,0x2a,0x45,0xb0,0x65,0xd6,0x87,0x57, + 0x71,0xf2,0xaf,0xa9,0x58,0xe8,0x0f,0x08,0x03, + 0xca,0xfe,0xb9,0xb9,0x96,0x15,0x42,0xef,0xb9, + 0x9e,0x17,0x61,0xd1,0x49,0x76,0x61,0xb7,0x21, + 0x90,0x6f,0xbd,0xbf,0xe9,0x0b,0x34,0xbd,0x01, + 0xc7,0x32,0x6e,0x34,0xa0,0x92,0xcc,0xdf,0x8e, + 0x3b,0xb2,0xc4,0x5a,0xa6,0x4c,0xb0,0xb0,0x9a, + 0xcb,0x5b,0x75,0x3a,0x5d,0x8f,0x5a,0x42,0x5c, + 0x8c,0xb2,0x8e,0xc5,0xac,0x81,0xdc,0xed,0x43, + 0xd5,0xd2,0x6f,0xc9,0x59,0x43,0x69,0x3b,0x27, + 0xae,0xe8}, + .data_len = 128, + .mac_len = 20, + .mac = {0x39,0x32,0x38,0xd3,0xaf,0xdb,0x7d,0x97,0x0b, + 0x96,0x6d,0x37,0x4f,0xe0,0x97,0xec,0x87,0x97, + 0xa8,0x70}, + }, { // 9 (286) + .key = {0x7a,0x31,0x55,0x3b,0x05,0xe9,0x6a,0x8d,0xa0, + 0xa4,0xd5,0xb8,0x1a,0x85,0x7d,0x19,0x2a,0xfb, + 0x6a,0xab,0xb1,0xf1,0x27,0xd7,0x40,0x45,0x6a, + 0x8e,0xda,0x7c,0xf6,0x96,0xfb,0xb4,0xc1,0x21, + 0xd8,0xd9,0x52,0xa4,0xe9,0x1c,0x6e,0xe6,0xa5, + 0xa1,0xf3,0x58,0x8d,0x78,0x04,0xa4,0x6b,0xcf, + 0x66,0x88,0xdc,0x66,0x2a,0xe5,0x0c,0x43,0x8d, + 0x13,0xc1,0xa6,0x1c,0x78,0x9b,0x3f,0x1c,0x59, + 0x9a,0x9f,0x28,0xef,0xe0,0xed,0x1c,0xbe}, + .key_len = 80, + .data = {0xfb,0x09,0x1d,0xdd,0x95,0xb1,0x00,0xdf,0xcf, + 0x89,0x2d,0x78,0xe5,0xe7,0x70,0xd3,0xa3,0x7b, + 0x8c,0x38,0x85,0xdf,0x80,0x3c,0x1d,0x6f,0x09, + 0x35,0xb5,0x5b,0x68,0xf1,0x36,0xfb,0x65,0xa8, + 0x48,0x62,0x94,0x2e,0xbb,0x35,0xd7,0x6d,0x26, + 0xbe,0x24,0x13,0xcd,0x3c,0x89,0x88,0xc8,0x7d, + 0x6d,0x23,0x62,0xaf,0x18,0x9d,0xc0,0x74,0x76, + 0xc6,0xc3,0x34,0x17,0x76,0x2e,0xb7,0x7b,0xc7, + 0x0c,0xf3,0x8d,0x81,0x4c,0x22,0x6d,0xd6,0xaf, + 0x18,0x72,0x50,0xe4,0xd4,0x70,0x07,0xf1,0x55, + 0x36,0x17,0xd4,0xaf,0x5b,0x51,0x6a,0x5d,0x3b, + 0x31,0x91,0xd9,0x3c,0x10,0x89,0x6a,0x56,0x9b, + 0xa1,0x3d,0xd2,0x84,0x0f,0xb8,0x51,0x78,0x1f, + 0x0b,0x11,0x50,0x90,0x08,0x6c,0x8b,0x3a,0x34, + 0xa1,0xfc}, + .data_len = 128, + .mac_len = 20, + .mac = {0x0f,0xdd,0x3f,0x83,0x6d,0xd7,0xe5,0xc5,0x06, + 0xab,0x21,0xad,0xde,0x9a,0xe5,0xdc,0x09,0xcb, + 0x35,0x9d}, + } +}; + +struct HMAC_TEST_VECTOR fips_sha224_hmac_test_vector[] = { + { // 0 (60) + .key = {0xcf,0x12,0x75,0x79,0xd6,0xb2,0xb0,0xb3,0xa6, + 0x07,0xa6,0x31,0x4b,0xf8,0x73,0x30,0x61,0xc3, + 0x2a,0x04,0x35,0x93,0x19,0x55,0x27,0x54,0x4f, + 0x87,0x53,0xc6,0x5c,0x7a,0x70,0xd0,0x58,0x74, + 0xf7,0x18,0x27,0x5b,0x88,0xd0,0xfa,0x28,0x8b, + 0xd3,0x19,0x98,0x13,0xf0}, + .key_len = 50, + .data = {0xfa,0x7e,0x18,0xcc,0x54,0x43,0x98,0x1f,0x22, + 0xc0,0xa5,0xab,0xa2,0x11,0x79,0x15,0xf8,0x9c, + 0x77,0x81,0xc3,0x4f,0x61,0xf9,0xf4,0x29,0xcb, + 0x13,0xe0,0xfc,0xd0,0xce,0x94,0x71,0x03,0xbe, + 0x68,0x4c,0xa8,0x69,0xd7,0xf1,0x25,0xf0,0x8d, + 0x27,0xb3,0xf2,0xc2,0x1d,0x59,0xad,0xc7,0xab, + 0x1b,0x66,0xde,0xd9,0x6f,0x0b,0x4f,0xa5,0xf0, + 0x18,0xb8,0x01,0x56,0xb7,0xa5,0x1c,0xa6,0x2b, + 0x60,0xe2,0xa6,0x6e,0x0b,0xc6,0x94,0x19,0xeb, + 0xbf,0x17,0x85,0x07,0x90,0x76,0x30,0xf2,0x4d, + 0x08,0x62,0xe5,0x1b,0xec,0x10,0x10,0x37,0xf9, + 0x00,0x32,0x3a,0xf8,0x2e,0x68,0x9b,0x11,0x6f, + 0x42,0x75,0x84,0x54,0x1c,0x8a,0x9a,0x51,0xac, + 0x89,0xda,0x1e,0xd7,0x8c,0x7f,0x5e,0xc9,0xe5, + 0x2a,0x7f}, + .data_len = 128, + .mac_len = 28, + .mac = {0x35,0x4f,0x87,0xe9,0x8d,0x27,0x64,0x46,0x83, + 0x6e,0xa0,0x43,0x0c,0xe4,0x52,0x92,0x72,0xa0, + 0x17,0xc2,0x90,0x03,0x9a,0x9d,0xfe,0xa4,0x34, + 0x9b}, + .chunks = {32, 0, 64, 32}, + .num_chunks = 4, + }, { // 1 (61) + .key = {0x82,0xa2,0x89,0xb0,0x91,0x1f,0x55,0xc5,0x32, + 0xe2,0x57,0x18,0x66,0xfa,0x35,0x4d,0x97,0x39, + 0x48,0xec,0x7b,0x89,0x9d,0x57,0x3b,0x83,0x3f, + 0x00,0xd5,0x3e,0xb8,0xd8,0xbf,0x65,0xd5,0x0b, + 0xcd,0x8d,0xaa,0xea,0x54,0xc5,0xd6,0x28,0x90, + 0x6e,0x08,0x4a,0x43,0x4d}, + .key_len = 50, + .data = {0xd0,0x6d,0x29,0x6c,0xad,0x7d,0x42,0x8b,0x56, + 0xb2,0x5c,0x53,0xfd,0xfc,0xf5,0x58,0xb5,0xbc, + 0x42,0x11,0xed,0x31,0xcf,0xe6,0x37,0x32,0x67, + 0x8a,0x4f,0x23,0x33,0x8b,0x58,0x22,0x25,0x28, + 0x68,0x81,0x98,0x62,0x47,0x79,0x30,0x56,0x74, + 0x1c,0x08,0xc9,0x69,0x8c,0x0c,0x05,0x20,0x6b, + 0xa3,0xe4,0xd6,0x92,0x92,0x2a,0x0f,0x06,0x1d, + 0x17,0xda,0x27,0x6e,0x3d,0x56,0x2b,0x3b,0x90, + 0x75,0xcb,0xa4,0xbc,0x00,0x3c,0x5a,0xbb,0xdc, + 0x61,0x06,0xa6,0x8b,0x3f,0xe9,0xcb,0xf5,0xb1, + 0xbf,0x01,0x69,0x5d,0xea,0x38,0xdf,0xe6,0xcc, + 0x54,0x80,0x64,0x75,0x3c,0x68,0x11,0x7e,0x2d, + 0xaa,0x44,0x34,0x55,0x94,0xa4,0xfa,0x9d,0x35, + 0x95,0xe8,0xc6,0x1d,0xf7,0xb8,0xb7,0x64,0x10, + 0xe3,0x15}, + .data_len = 128, + .mac_len = 28, + .mac = {0x55,0x07,0xc4,0xc7,0xc1,0x27,0x04,0x6c,0x04, + 0xd1,0x61,0xfd,0xc7,0x5e,0xc2,0xf5,0x12,0x2e, + 0xd4,0x4e,0x86,0x67,0x9c,0x39,0xc6,0x9c,0x5a, + 0xe8}, + .chunks = {64, -1, 64}, + .num_chunks = 3, + }, { // 2 (135) + .key = {0xb3,0x4a,0x6e,0xba,0x59,0xe6,0x32,0xe3,0xc3, + 0x34,0xdf,0x58,0x2f,0xd0,0xb0,0x3a,0xca,0x7f, + 0x64,0x1c,0x69,0x14,0x92,0x0a,0x79,0x94,0x3d, + 0xca,0x39,0x98,0xa8,0x61,0x27,0xf3,0x6b,0xda, + 0xb7,0x95,0xc7,0x42,0x4b,0xaf,0x37,0xf7,0x60, + 0x18,0x47,0x23,0x05,0xf0,0xa9,0x83,0x92,0x83, + 0x86}, + .key_len = 55, + .data = {0xd0,0x3d,0xd9,0x4e,0x43,0xd9,0x6c,0xa4,0x59, + 0x92,0x8a,0xa9,0x6d,0x2b,0x81,0xc3,0x5e,0xd5, + 0x45,0x66,0xe3,0x3e,0x66,0x35,0x1f,0xca,0x40, + 0x6b,0x76,0x20,0x72,0x7a,0x9e,0xe9,0x91,0xf2, + 0xf9,0xd4,0x1d,0xa3,0x22,0xde,0xb3,0x06,0xc6, + 0xd0,0x85,0xd9,0xb5,0x09,0x08,0x0a,0x38,0x7d, + 0xec,0xd6,0xa6,0xfe,0x51,0x32,0x32,0xbb,0x38, + 0x6a,0x07,0x06,0x37,0x08,0x97,0x5a,0x72,0xf7, + 0x2f,0x9c,0xc6,0xe8,0xcf,0xa1,0x47,0xf5,0x3a, + 0xf1,0xed,0x84,0x49,0xca,0x8a,0x6f,0x84,0x68, + 0xff,0x62,0xf3,0x84,0xb0,0x84,0x32,0x1b,0x35, + 0x59,0xc4,0x70,0x53,0xe7,0xa9,0x54,0x2a,0x17, + 0x33,0xa5,0xaf,0x5f,0x15,0x15,0x5d,0x9e,0xbd, + 0x2c,0x28,0x47,0xe4,0x91,0xb3,0xc2,0x63,0x85, + 0xc2,0x0f}, + .data_len = 128, + .mac_len = 28, + .mac = {0x1c,0x49,0x44,0x84,0x3c,0x3e,0xe7,0xf9,0x8a, + 0xb5,0x29,0x87,0xe0,0xd2,0xd4,0x49,0x4a,0xa7, + 0x25,0x48,0xbf,0xdc,0x36,0x02,0xdb,0x45,0xb5, + 0xf4}, + }, { // 3 (136) + .key = {0x2f,0xd5,0x86,0x3a,0xb5,0xac,0x01,0x09,0xcd, + 0x1c,0xc8,0xa6,0x59,0x8e,0x75,0xd8,0x58,0x11, + 0xa8,0x4d,0x0d,0xf1,0x4c,0xd5,0x5e,0x8b,0x1c, + 0xce,0x7a,0x5f,0x65,0xdf,0xbe,0x67,0x0d,0xea, + 0xda,0xa8,0xd4,0x3b,0x2f,0x06,0xda,0x06,0x7c, + 0x5c,0x62,0x10,0xba,0xcc,0xd5,0xac,0x44,0x54, + 0x0a}, + .key_len = 55, + .data = {0x85,0xc0,0x2d,0x7c,0xfa,0xb2,0x9f,0x8a,0xdf, + 0x0f,0xa5,0x5e,0xf3,0x67,0x22,0xa0,0x47,0x57, + 0xc8,0x86,0x50,0x53,0xd2,0xaf,0x3b,0xa2,0xf6, + 0x4e,0x80,0xaa,0x95,0x8a,0xba,0x6e,0x36,0x25, + 0xb6,0x55,0x32,0x5c,0xca,0x2d,0xb0,0x0f,0x68, + 0x6f,0xd4,0x22,0xf2,0xc5,0x34,0x23,0xd0,0xc9, + 0x8c,0x2d,0xc1,0x10,0xb2,0x0c,0x6e,0x67,0xcc, + 0xa1,0x45,0x5c,0xc0,0x88,0x84,0x01,0xec,0xf9, + 0x94,0xec,0x18,0xec,0x99,0x82,0xa8,0x81,0x47, + 0x76,0x16,0x9e,0xf7,0x8c,0xa0,0xda,0xfa,0xa3, + 0x3e,0x9a,0x2d,0xf2,0xd7,0x79,0xcd,0x92,0xb4, + 0xee,0x8d,0x3c,0x35,0x29,0xe6,0x55,0xc3,0x3d, + 0xaf,0x27,0x05,0x84,0xed,0x72,0x57,0x3f,0xec, + 0x23,0x78,0x7e,0x8f,0x63,0x82,0x40,0xe4,0xd3, + 0x20,0xda}, + .data_len = 128, + .mac_len = 28, + .mac = {0xea,0xbb,0xa9,0xf3,0x5b,0xa3,0x9c,0xfb,0x92, + 0x83,0x39,0x0d,0x54,0x25,0x68,0x7c,0xdd,0x70, + 0xd4,0xcb,0x1f,0xea,0x43,0x39,0x25,0x64,0x7c, + 0x79}, + }, { // 4 (210) + .key = {0xf3,0xaa,0x51,0xee,0x90,0xaa,0x06,0xe9,0x8e, + 0x23,0x88,0xdf,0x7a,0x3a,0xf2,0xcd,0x69,0x7f, + 0x2a,0x52,0x8f,0x2a,0x14,0x14,0x0d,0xa4,0x05, + 0x60,0x0b,0x4a,0x7b,0x10,0x07,0x6d,0x0b,0xb2, + 0x6c,0x9d,0x9a,0xe6,0x67,0x27,0xd0,0x08,0xf6, + 0xdc,0xca,0x0f,0x42,0x14,0x0f,0xb5,0x2e,0xf3, + 0xc6,0xd9,0x30,0xeb,0x26,0x21,0x60,0x82,0x2d, + 0xe3}, + .key_len = 64, + .data = {0x2c,0x07,0x0e,0x5e,0xb0,0xa7,0xef,0xbf,0xc4, + 0x0b,0x23,0x43,0x14,0xc0,0x55,0xfc,0x43,0x6c, + 0xe1,0xe2,0x30,0x05,0x39,0xb3,0x78,0x42,0x87, + 0xfd,0x3c,0x4f,0x94,0x78,0x24,0xc5,0xe8,0x9a, + 0xa3,0xd9,0x33,0x66,0x7d,0xd4,0xeb,0x85,0x87, + 0xc3,0x37,0x97,0xae,0x6f,0x0c,0xcb,0x3b,0x8f, + 0x95,0xad,0x56,0x3d,0xd9,0x40,0xc8,0xa7,0x98, + 0x4d,0x05,0x07,0x75,0xfa,0x69,0xd5,0x5b,0x9e, + 0xc2,0x3a,0x19,0xd4,0x0f,0xc9,0x4f,0xcf,0x87, + 0x6a,0x8e,0xed,0xdd,0x96,0xbb,0x8e,0xc3,0xca, + 0xb4,0x26,0xad,0x35,0x36,0x91,0xd7,0xb4,0xff, + 0xa7,0x89,0x01,0x2f,0x11,0x9a,0x28,0xf4,0x5b, + 0x33,0x3a,0x66,0x49,0xd5,0x44,0xb0,0x6f,0x9d, + 0x82,0x71,0xfc,0xc7,0xd1,0x62,0xd7,0x72,0x63, + 0x38,0xed}, + .data_len = 128, + .mac_len = 28, + .mac = {0x69,0x5c,0x32,0x8d,0xc8,0x58,0xa4,0x6b,0xe7, + 0xac,0x8b,0x8d,0xeb,0xf5,0x8d,0xd9,0xa9,0xbd, + 0x72,0xd7,0xa4,0x08,0xa4,0x3e,0x6b,0xbc,0x69, + 0xa3}, + }, { // 5 (211) + .key = {0xa2,0x7f,0x5b,0xa4,0xa0,0xd5,0xa8,0x0c,0xb4, + 0xef,0x9b,0xb1,0x8d,0x4f,0xfc,0x4a,0xd4,0x87, + 0x68,0x0c,0xb5,0xa8,0xf6,0xc6,0x9c,0xfe,0x1b, + 0x29,0x3c,0xfa,0xcb,0x67,0xd6,0x70,0xe1,0x01, + 0xb8,0x03,0xc1,0xd9,0x04,0xdd,0x3c,0x8f,0xb2, + 0xa3,0xb4,0x0a,0xd8,0xa7,0x80,0x55,0x29,0x60, + 0x91,0xad,0xbc,0x18,0x56,0xd8,0x10,0xe5,0xde, + 0xb8}, + .key_len = 64, + .data = {0x80,0x2e,0xd2,0x88,0x73,0xc2,0x16,0x05,0x62, + 0xfb,0x91,0x62,0x24,0x6b,0x60,0xd7,0x5e,0x2f, + 0xfb,0x8c,0xec,0xc5,0xbb,0x08,0x83,0x1e,0x9a, + 0xec,0x94,0xf4,0x3b,0xe1,0x73,0x5e,0x2a,0xcf, + 0xb8,0xa2,0x64,0x50,0xe6,0x4a,0x1a,0x64,0x4a, + 0x7a,0xb2,0x66,0x26,0x80,0x0f,0x3e,0x0f,0xad, + 0x12,0xd9,0x94,0x63,0x60,0xd6,0x20,0x70,0x66, + 0x82,0x22,0x9a,0x9b,0x07,0x6a,0x7b,0x05,0xe0, + 0xd6,0x90,0xff,0x90,0x2f,0x8c,0x39,0x94,0x4e, + 0xf2,0x00,0x96,0x83,0xe2,0xc0,0xe3,0x37,0x33, + 0xc7,0x1f,0xcf,0xc3,0x4b,0x38,0xd4,0x0b,0xaf, + 0x98,0x51,0xf7,0x02,0x9f,0x7d,0xf4,0xc9,0x50, + 0x9a,0x4a,0xfe,0x4a,0x1d,0xac,0x58,0xfa,0x0f, + 0x0d,0xcd,0x10,0xb3,0xb6,0x56,0x2f,0x69,0x96, + 0xf2,0xe9}, + .data_len = 128, + .mac_len = 28, + .mac = {0xee,0x63,0xe8,0x6a,0xac,0x85,0xf3,0x69,0x61, + 0xd6,0x97,0x45,0x12,0x88,0xcf,0x78,0x00,0x41, + 0xea,0xfe,0x46,0x2c,0xa6,0x55,0x70,0x35,0xd9, + 0x2a}, + }, { // 6 (285) + .key = {0x5f,0x44,0x8c,0x3d,0x3d,0xf6,0xce,0xab,0x97, + 0x35,0x68,0x19,0xda,0x0d,0x45,0x96,0x62,0xb2, + 0xd5,0xa7,0x36,0x6a,0x5d,0x46,0xf2,0xa6,0x91, + 0x2a,0x04,0x72,0x64,0x49,0x1b,0x10,0x1f,0x9c, + 0xdd,0xe0,0xb0,0x22,0xd9,0x84,0x45,0x27,0xbc, + 0x40,0x1a,0xc6,0xc7,0xa7,0x8f,0xad,0x80,0x74, + 0x7e,0x20,0xa8,0xb6,0xcb,0x41,0x6e,0x30,0x3d, + 0x8e,0xe2,0xff}, + .key_len = 66, + .data = {0xd5,0x2f,0xce,0x9d,0x18,0x22,0x00,0x1f,0x8a, + 0x25,0x2e,0x34,0xb4,0xad,0xc8,0x18,0x31,0xf9, + 0xda,0x37,0x0f,0xec,0x92,0x9d,0x79,0x1c,0xfd, + 0xae,0x93,0x27,0x11,0x17,0xa6,0x46,0xf0,0x04, + 0x7d,0x24,0x6b,0x94,0x0f,0xf0,0xc5,0x89,0x5e, + 0xb0,0xba,0x45,0x9e,0xd9,0xc0,0xf2,0x9a,0x1d, + 0x8d,0x00,0x54,0x85,0xd9,0xd4,0xeb,0xbf,0x65, + 0xbe,0xc2,0xb9,0x3c,0x2c,0xdf,0x6f,0x39,0x1e, + 0x91,0x01,0xc9,0xda,0x56,0x08,0xf2,0xe1,0xfb, + 0x2a,0x95,0x21,0x05,0xec,0xf0,0x6c,0x50,0xc8, + 0x66,0x29,0xf6,0x80,0x83,0x4a,0x72,0xb1,0x3b, + 0x7e,0x06,0xab,0x72,0xa7,0x5a,0x80,0xc2,0x8e, + 0x65,0x5b,0x78,0xd5,0x90,0x13,0xdf,0x2e,0x19, + 0x00,0xc2,0xcb,0xb6,0x0e,0x2c,0x16,0x7c,0x0f, + 0x72,0xa1}, + .data_len = 128, + .mac_len = 28, + .mac = {0x1b,0x34,0x59,0xef,0x88,0x67,0x1f,0x03,0x1b, + 0xe6,0x02,0x52,0x70,0x12,0x31,0xfe,0xc1,0x71, + 0x32,0xa0,0xba,0xa7,0x5d,0x13,0x93,0x8f,0xbc, + 0x9a}, + }, { // 7 (286) + .key = {0x08,0xe1,0x3b,0xab,0x53,0x26,0x36,0x9a,0x27, + 0x06,0xc2,0xb3,0xe7,0xe8,0xf9,0xb7,0x1c,0xbe, + 0x56,0x46,0xbd,0x37,0x1a,0xad,0xae,0x35,0xef, + 0xff,0x86,0x81,0xcc,0x67,0x95,0xbe,0x18,0xbc, + 0x26,0x9b,0x12,0x56,0x01,0x4d,0x70,0x20,0x34, + 0x3d,0x46,0xef,0x13,0xfd,0x2a,0x12,0x7e,0x81, + 0x96,0x2b,0x62,0x8c,0x8e,0x3d,0x82,0x68,0x82, + 0x05,0x78,0xda}, + .key_len = 66, + .data = {0x9e,0xe9,0x13,0x62,0x40,0xb9,0xc4,0x31,0x74, + 0x7b,0xa3,0x63,0xa9,0xb2,0xb8,0x36,0x3b,0x1d, + 0x57,0xfb,0x45,0x38,0x98,0xbc,0xb7,0x06,0x08, + 0x21,0xa8,0x0e,0x9e,0x94,0xed,0xa3,0xf1,0xa4, + 0xea,0x69,0xa7,0xa7,0xa8,0x15,0x31,0xa4,0x28, + 0x74,0xb6,0x70,0xf7,0xaf,0x4c,0x16,0x03,0xcd, + 0x6e,0x7c,0xad,0x79,0xab,0x44,0x1f,0x06,0x9b, + 0xf1,0xe0,0xb0,0x17,0x4b,0xa5,0x25,0xa9,0x04, + 0x6b,0x44,0x42,0x9b,0xc2,0x24,0x2b,0x81,0x6c, + 0x58,0x3e,0x7b,0x26,0x71,0x56,0x47,0xc6,0xc5, + 0x04,0x82,0x86,0x6f,0x84,0xc9,0xa0,0x97,0xef, + 0x1f,0x1b,0xf4,0xb1,0x8e,0xe4,0x8e,0x3e,0x11, + 0x20,0xc9,0x01,0xb2,0xc1,0x9f,0x95,0xf0,0x57, + 0x2d,0x38,0x63,0x29,0x71,0x7d,0xa3,0x85,0x52, + 0x41,0x65}, + .data_len = 128, + .mac_len = 28, + .mac = {0xf6,0xf7,0x42,0xb7,0x0c,0x95,0xce,0x5f,0x69, + 0xfa,0x8a,0xb7,0x27,0x00,0x4e,0xf5,0x46,0xd6, + 0xde,0x9d,0x8f,0x05,0xad,0x9f,0x84,0xa0,0x21, + 0x0a}, + }, { // 8 (360) + .key = {0x4b,0x0f,0x8f,0xda,0x08,0x01,0x7b,0x10,0xb6, + 0x47,0xfc,0xd6,0xcd,0x04,0xf7,0x87,0x0c,0x92, + 0xb2,0x68,0x75,0x74,0xf2,0x38,0x99,0x8c,0x60, + 0x08,0x15,0x8e,0x31,0x4d,0x5d,0xb5,0x06,0x34, + 0xb8,0xb5,0x11,0x35,0x8c,0xf0,0x7a,0xeb,0xdc, + 0xec,0x01,0x23,0x0f,0x05,0xe4,0x33,0xf3,0x5f, + 0x03,0x8d,0x01,0x1f,0x42,0x93,0xe3,0xdb,0x2f, + 0xad,0x33}, + .key_len = 65, + .data = {0x29,0x17,0xcd,0x57,0x24,0x31,0x9d,0xcb,0x5c, + 0x08,0xd9,0x17,0xb6,0x7f,0x25,0x62,0x8d,0x15, + 0x54,0x3f,0xf7,0x17,0xd1,0x82,0x49,0x15,0x3d, + 0x51,0xdd,0x92,0x59,0x7e,0x12,0xff,0x27,0x14, + 0x95,0xeb,0x4c,0x2f,0xdf,0x74,0xb9,0x11,0xff, + 0x01,0x8a,0x73,0x9a,0x33,0x2e,0x19,0x30,0x18, + 0xc9,0xa9,0xa0,0xa2,0xd6,0xbd,0xef,0x58,0x11, + 0x37,0x45,0x4c,0x94,0xd5,0x38,0x4d,0x40,0x05, + 0x4d,0x5d,0x5e,0xfa,0xbc,0x66,0x86,0xff,0x74, + 0x28,0xc0,0x0b,0x5f,0x76,0xea,0x96,0xe7,0xa2, + 0x5a,0xac,0xb9,0x36,0xc4,0x40,0xc9,0xe4,0x5d, + 0xc2,0x96,0xc0,0x40,0xf4,0xaf,0xad,0x11,0xf9, + 0x76,0x15,0xe1,0xae,0x24,0xde,0x52,0x3e,0x0d, + 0x99,0xfc,0xf1,0x26,0xfc,0x0f,0x45,0xc4,0x92, + 0x39,0x40}, + .data_len = 128, + .mac_len = 28, + .mac = {0x45,0x3b,0x23,0x73,0xce,0x46,0x59,0x58,0x55, + 0xf6,0x03,0x0d,0x24,0x3d,0x16,0x46,0x29,0x38, + 0x89,0x41,0x6f,0x05,0x37,0x3e,0x78,0x12,0x6f, + 0x59}, + }, { // 9 (361) + .key = {0x28,0x9e,0x2a,0xec,0xe1,0x04,0x86,0x74,0xbd, + 0x57,0x1a,0x4d,0xac,0x53,0x04,0x33,0x51,0xa7, + 0x89,0x64,0xbd,0xa6,0xfd,0xf6,0x7e,0x3f,0xe3, + 0x6d,0xd8,0x2f,0x56,0x8d,0x52,0x75,0xa8,0x6d, + 0x75,0x06,0x48,0xcd,0xd0,0xc3,0xe9,0xa9,0x3f, + 0xa8,0xe0,0x0f,0x6d,0x46,0xce,0x2d,0x98,0x73, + 0x80,0xae,0x94,0x40,0x13,0x47,0x13,0x2b,0x5c, + 0x8c,0x23}, + .key_len = 65, + .data = {0xb4,0x53,0xfc,0x9e,0x54,0x12,0x2b,0x18,0x14, + 0x83,0x00,0x5c,0x41,0x53,0xcb,0x8b,0x47,0xce, + 0xf4,0x7a,0x74,0x99,0xe3,0x07,0xfe,0x9f,0x1e, + 0xae,0x48,0x4d,0xb1,0x57,0x61,0x02,0xd3,0x72, + 0xcd,0xc1,0xc6,0x46,0x89,0x2a,0xff,0x86,0x49, + 0xa8,0x87,0x26,0x04,0xeb,0xa1,0x6c,0xb2,0x99, + 0xad,0x4a,0x55,0x40,0x4c,0xeb,0x36,0x90,0xc5, + 0x8c,0x71,0xc7,0xa8,0x8d,0xb3,0x6c,0xb1,0xc8, + 0x43,0x40,0xee,0x21,0x3f,0x72,0x24,0x5e,0x29, + 0x12,0x70,0x3a,0xa2,0xc8,0x2a,0xb4,0x74,0xc6, + 0x0e,0xad,0xd6,0xfb,0x9e,0xb2,0xec,0x89,0xc2, + 0x17,0x8e,0x7a,0xb2,0x45,0x4a,0xae,0x15,0x54, + 0xac,0x18,0x6b,0xdd,0xbc,0x2b,0xa8,0x09,0xc9, + 0x8e,0x21,0xee,0x65,0x17,0xac,0x1c,0xb1,0xf7, + 0x03,0x72}, + .data_len = 128, + .mac_len = 28, + .mac = {0x01,0xda,0xfb,0x71,0x6c,0x50,0xb0,0x94,0x57, + 0xec,0xc8,0x77,0x81,0x41,0xca,0x84,0xb6,0x45, + 0xa2,0x32,0xa4,0xa3,0x9e,0xd0,0x23,0x0c,0x73, + 0x49}, + } +}; + +struct HMAC_TEST_VECTOR fips_sha256_hmac_test_vector[] = { + { // 0 (30) + .key = {0x97,0x79,0xd9,0x12,0x06,0x42,0x79,0x7f,0x17, + 0x47,0x02,0x5d,0x5b,0x22,0xb7,0xac,0x60,0x7c, + 0xab,0x08,0xe1,0x75,0x8f,0x2f,0x3a,0x46,0xc8, + 0xbe,0x1e,0x25,0xc5,0x3b,0x8c,0x6a,0x8f,0x58, + 0xff,0xef,0xa1,0x76}, + .key_len = 40, + .data = {0xb1,0x68,0x9c,0x25,0x91,0xea,0xf3,0xc9,0xe6, + 0x60,0x70,0xf8,0xa7,0x79,0x54,0xff,0xb8,0x17, + 0x49,0xf1,0xb0,0x03,0x46,0xf9,0xdf,0xe0,0xb2, + 0xee,0x90,0x5d,0xcc,0x28,0x8b,0xaf,0x4a,0x92, + 0xde,0x3f,0x40,0x01,0xdd,0x9f,0x44,0xc4,0x68, + 0xc3,0xd0,0x7d,0x6c,0x6e,0xe8,0x2f,0xac,0xea, + 0xfc,0x97,0xc2,0xfc,0x0f,0xc0,0x60,0x17,0x19, + 0xd2,0xdc,0xd0,0xaa,0x2a,0xec,0x92,0xd1,0xb0, + 0xae,0x93,0x3c,0x65,0xeb,0x06,0xa0,0x3c,0x9c, + 0x93,0x5c,0x2b,0xad,0x04,0x59,0x81,0x02,0x41, + 0x34,0x7a,0xb8,0x7e,0x9f,0x11,0xad,0xb3,0x04, + 0x15,0x42,0x4c,0x6c,0x7f,0x5f,0x22,0xa0,0x03, + 0xb8,0xab,0x8d,0xe5,0x4f,0x6d,0xed,0x0e,0x3a, + 0xb9,0x24,0x5f,0xa7,0x95,0x68,0x45,0x1d,0xfa, + 0x25,0x8e}, + .data_len = 128, + .mac_len = 32, + .mac = {0x76,0x9f,0x00,0xd3,0xe6,0xa6,0xcc,0x1f,0xb4, + 0x26,0xa1,0x4a,0x4f,0x76,0xc6,0x46,0x2e,0x61, + 0x49,0x72,0x6e,0x0d,0xee,0x0e,0xc0,0xcf,0x97, + 0xa1,0x66,0x05,0xac,0x8b}, + .chunks = {32, 0, 64, 32}, + .num_chunks = 4, + }, { // 1 (31) + .key = {0x09,0x67,0x5f,0x2d,0xcc,0x47,0x83,0xb5,0x99, + 0xf1,0x8f,0xb7,0x65,0x58,0x36,0x68,0xa0,0xfd, + 0x8a,0xe4,0x09,0x6f,0x6f,0xcd,0xc6,0x0d,0x4f, + 0x35,0xb4,0x13,0x0f,0xbe,0xfc,0xd5,0x42,0xff, + 0xe7,0x45,0x9d,0x2a}, + .key_len = 40, + .data = {0x0c,0xf2,0x19,0x8c,0x31,0x37,0x6f,0x5c,0x89, + 0x15,0x66,0x01,0x37,0x72,0x5f,0x2b,0xbc,0x18, + 0x0a,0x98,0x6e,0x5a,0x7b,0xda,0x27,0xfa,0x81, + 0x59,0x3a,0x4a,0x33,0x9b,0xab,0x92,0xcb,0xc3, + 0x9f,0xb2,0xb8,0x58,0x11,0x08,0xee,0x48,0xc7, + 0x94,0x81,0x2d,0x84,0x5a,0x72,0xce,0x80,0x08, + 0xc9,0xe9,0x15,0xd9,0xe3,0x30,0xbb,0xb9,0x0e, + 0x91,0x36,0xaa,0x53,0xba,0x0e,0x66,0x93,0xdd, + 0x40,0x46,0xd6,0xb0,0x33,0x62,0xdf,0xb9,0xed, + 0xfa,0x04,0xc8,0x87,0x15,0x3c,0xc5,0xde,0x67, + 0x7a,0xab,0x8c,0x78,0x39,0xd5,0x17,0x03,0x58, + 0x79,0x67,0x9c,0x29,0x72,0x7e,0x96,0xc5,0x42, + 0x63,0x24,0xa2,0x57,0x5f,0xbe,0x67,0x8d,0x6c, + 0xc7,0xfe,0xf5,0xeb,0x6c,0xeb,0xd5,0x95,0xcf, + 0xdd,0xef}, + .data_len = 128, + .mac_len = 32, + .mac = {0x6b,0x14,0x2d,0x4d,0xfe,0x21,0x7f,0x18,0x81, + 0xaa,0x0e,0x64,0x83,0xb2,0x71,0xdd,0x5d,0x43, + 0xf7,0x0b,0x85,0x60,0x59,0x53,0xa0,0xfe,0xf2, + 0x72,0xdd,0xde,0x46,0xca}, + .chunks = {64, -1, 64}, + .num_chunks = 3, + }, { // 2 (75) + .key = {0xb7,0x63,0x26,0x3d,0xc4,0xfc,0x62,0xb2,0x27, + 0xcd,0x3f,0x6b,0x4e,0x9e,0x35,0x8c,0x21,0xca, + 0x03,0x6c,0xe3,0x96,0xab,0x92,0x59,0xc1,0xbe, + 0xdd,0x2f,0x5c,0xd9,0x02,0x97,0xdc,0x70,0x3c, + 0x33,0x6e,0xca,0x3e,0x35,0x8a,0x4d,0x6d,0xc5}, + .key_len = 45, + .data = {0x53,0xcb,0x09,0xd0,0xa7,0x88,0xe4,0x46,0x6d, + 0x01,0x58,0x8d,0xf6,0x94,0x5d,0x87,0x28,0xd9, + 0x36,0x3f,0x76,0xcd,0x01,0x2a,0x10,0x30,0x8d, + 0xad,0x56,0x2b,0x6b,0xe0,0x93,0x36,0x48,0x92, + 0xe8,0x39,0x7a,0x8d,0x86,0xf1,0xd8,0x1a,0x20, + 0x96,0xcf,0xc8,0xa1,0xbb,0xb2,0x6a,0x1a,0x75, + 0x52,0x5f,0xfe,0xbf,0xcf,0x16,0x91,0x1d,0xad, + 0xd0,0x9e,0x80,0x2a,0xa8,0x68,0x6a,0xcf,0xd1, + 0xe4,0x52,0x46,0x20,0x25,0x4a,0x6b,0xca,0x18, + 0xdf,0xa5,0x6e,0x71,0x41,0x77,0x56,0xe5,0xa4, + 0x52,0xfa,0x9a,0xe5,0xae,0xc5,0xdc,0x71,0x59, + 0x1c,0x11,0x63,0x0e,0x9d,0xef,0xec,0x49,0xa4, + 0xec,0xf8,0x5a,0x14,0xf6,0x0e,0xb8,0x54,0x65, + 0x78,0x99,0x97,0x2e,0xa5,0xbf,0x61,0x59,0xcb, + 0x95,0x47}, + .data_len =128, + .mac_len = 32, + .mac = {0x73,0x73,0x01,0xde,0xa9,0x3d,0xb6,0xbc,0xba, + 0xdd,0x7b,0xf7,0x96,0x69,0x39,0x61,0x31,0x7c, + 0xa6,0x80,0xb3,0x80,0x41,0x6f,0x12,0xf4,0x66, + 0xf0,0x65,0x26,0xb3,0x6b}, + }, { // 3 (76) + .key = {0x9f,0xe4,0x2d,0xfa,0xc9,0x2a,0x4a,0x13,0x6f, + 0xa7,0xc9,0xf6,0xe3,0x31,0xb5,0xd3,0xa6,0x1a, + 0xa7,0x30,0x35,0xb5,0x3a,0x8d,0x25,0x17,0xbe, + 0x43,0x72,0x1b,0x31,0xb2,0x15,0xa9,0x6b,0x9b, + 0xd4,0x37,0x98,0xcb,0x5e,0x8f,0xeb,0xfa,0x97}, + .key_len = 45, + .data = {0xf9,0x66,0x0f,0xb7,0x84,0xc1,0x4b,0x5f,0xbe, + 0xc2,0x80,0x52,0x6a,0x69,0xc2,0x29,0x4f,0xba, + 0x12,0xae,0xa1,0x63,0x78,0x9b,0xbe,0x9f,0x52, + 0xa5,0x1b,0x5a,0xeb,0xb9,0x7d,0x96,0x4f,0x86, + 0x6c,0x0d,0x5e,0x3b,0xe4,0x18,0x20,0x92,0x4f, + 0xcf,0x58,0x0d,0xb0,0x72,0x5c,0x7f,0x21,0x08, + 0x23,0xcf,0x7f,0x45,0xa0,0xf9,0x64,0xb1,0x4e, + 0x55,0x55,0x07,0x0d,0x1c,0x3d,0xdb,0x2c,0x28, + 0x1a,0x80,0xc7,0xfb,0xf7,0x29,0x53,0x03,0x1a, + 0x4e,0x77,0x1d,0x7e,0x52,0x1d,0x57,0x84,0x62, + 0xca,0xfa,0xe5,0xa0,0x2a,0xc8,0xeb,0x81,0xf0, + 0x82,0xe1,0x73,0xdd,0xad,0xc8,0xc4,0x1d,0x96, + 0x4b,0xbf,0xda,0x94,0xf5,0x18,0x0c,0x8d,0xa2, + 0x8a,0x8e,0xbb,0x33,0xbe,0x77,0xb0,0x86,0x6f, + 0xa7,0x98}, + .data_len = 128, + .mac_len = 32, + .mac = {0x77,0x86,0xc1,0x55,0xd1,0x0c,0x74,0x1b,0x63, + 0xec,0x65,0x0b,0x7b,0x1a,0xa3,0xbf,0xd7,0x1a, + 0xc7,0x18,0x81,0xad,0x06,0xae,0x98,0xfb,0x08, + 0x2f,0x17,0xe0,0xca,0xa0}, + }, { // 4 (120) + .key = {0x99,0x28,0x68,0x50,0x4d,0x25,0x64,0xc4,0xfb, + 0x47,0xbc,0xbd,0x4a,0xe4,0x82,0xd8,0xfb,0x0e, + 0x8e,0x56,0xd7,0xb8,0x18,0x64,0xe6,0x19,0x86, + 0xa0,0xe2,0x56,0x82,0xda,0xeb,0x5b,0x50,0x17, + 0x7c,0x09,0x5e,0xdc,0x9e,0x97,0x1d,0xa9,0x5c, + 0x32,0x10,0xc3,0x76,0xe7,0x23,0x36,0x5a,0xc3, + 0x3d,0x1b,0x4f,0x39,0x18,0x17,0xf4,0xc3,0x51, + 0x24}, + .key_len = 64, + .data = {0xed,0x4f,0x26,0x9a,0x88,0x51,0xeb,0x31,0x54, + 0x77,0x15,0x16,0xb2,0x72,0x28,0x15,0x52,0x00, + 0x77,0x80,0x49,0xb2,0xdc,0x19,0x63,0xf3,0xac, + 0x32,0xba,0x46,0xea,0x13,0x87,0xcf,0xbb,0x9c, + 0x39,0x15,0x1a,0x2c,0xc4,0x06,0xcd,0xc1,0x3c, + 0x3c,0x98,0x60,0xa2,0x7e,0xb0,0xb7,0xfe,0x8a, + 0x72,0x01,0xad,0x11,0x55,0x2a,0xfd,0x04,0x1e, + 0x33,0xf7,0x0e,0x53,0xd9,0x7c,0x62,0xf1,0x71, + 0x94,0xb6,0x61,0x17,0x02,0x8f,0xa9,0x07,0x1c, + 0xc0,0xe0,0x4b,0xd9,0x2d,0xe4,0x97,0x2c,0xd5, + 0x4f,0x71,0x90,0x10,0xa6,0x94,0xe4,0x14,0xd4, + 0x97,0x7a,0xbe,0xd7,0xca,0x6b,0x90,0xba,0x61, + 0x2d,0xf6,0xc3,0xd4,0x67,0xcd,0xed,0x85,0x03, + 0x25,0x98,0xa4,0x85,0x46,0x80,0x4f,0x9c,0xf2, + 0xec,0xfe}, + .data_len = 128, + .mac_len = 32, + .mac = {0x2f,0x83,0x21,0xf4,0x16,0xb9,0xbb,0x24,0x9f, + 0x11,0x3b,0x13,0xfc,0x12,0xd7,0x0e,0x16,0x68, + 0xdc,0x33,0x28,0x39,0xc1,0x0d,0xaa,0x57,0x17, + 0x89,0x6c,0xb7,0x0d,0xdf}, + }, { // 5 (121) + .key = {0xce,0xab,0x39,0x8e,0x41,0x07,0x48,0x3e,0xde, + 0x64,0xce,0x10,0x7c,0x92,0x70,0xe6,0x02,0x27, + 0x78,0xb6,0x1f,0x6a,0x25,0x8d,0x3b,0x70,0x45, + 0xd4,0xad,0x85,0x06,0xd3,0x2e,0xce,0x0a,0x73, + 0x8d,0x2c,0xb9,0x48,0xa5,0x62,0xdb,0xce,0x8d, + 0x7b,0x66,0xf3,0x0e,0x66,0x94,0xd6,0x5a,0xe4, + 0x39,0xcf,0xfa,0xa4,0x54,0xaf,0x09,0xab,0xe4, + 0x49}, + .key_len = 64, + .data = {0x6d,0xde,0x9a,0xe8,0x67,0xe2,0xfe,0xb3,0x67, + 0x00,0x8a,0x97,0x5d,0x78,0x53,0xed,0x8f,0x89, + 0x69,0x0f,0x3c,0x87,0xa1,0x10,0x7f,0x2e,0x98, + 0xaa,0x77,0x36,0xf4,0x77,0xa5,0x27,0xed,0x64, + 0x95,0x6f,0x0d,0x64,0xc1,0xb2,0x33,0x61,0xb2, + 0x61,0xde,0x78,0x68,0x8e,0xa8,0x65,0xfc,0xff, + 0x11,0x3c,0x84,0x81,0x7e,0x5b,0x37,0x7e,0x82, + 0x9c,0xd2,0xd2,0x5b,0xcf,0x3a,0xdb,0xc0,0x67, + 0x62,0xcf,0xda,0x73,0x6f,0x53,0x90,0xd0,0x1a, + 0x49,0x07,0x9d,0x56,0xe9,0x69,0xf0,0x33,0x13, + 0xe6,0xc7,0x03,0xe3,0xf9,0x42,0xbb,0x87,0xed, + 0x0f,0x9c,0x4d,0x9f,0x25,0x12,0x00,0x85,0xb5, + 0xdc,0x75,0xef,0x5d,0x6d,0x61,0x8d,0xa0,0x92, + 0x6d,0x32,0x93,0x56,0x8d,0xd7,0xd8,0x23,0x8d, + 0xe3,0xd0}, + .data_len = 128, + .mac_len = 32, + .mac = {0x2d,0x3a,0x76,0x05,0x95,0xf3,0xfb,0x19,0x29, + 0x3c,0xc6,0xd2,0x36,0x51,0x22,0x2a,0x9f,0x5a, + 0x4f,0x02,0x28,0x44,0x57,0xa9,0xc1,0xed,0x4c, + 0x43,0xac,0x99,0x3c,0xa5}, + }, { // 6 (165) + .key = {0xc0,0x9e,0x29,0x07,0x1c,0x40,0x5d,0x5e,0x82, + 0x0d,0x34,0x5a,0x46,0xdb,0xbf,0x1e,0x0f,0x82, + 0x02,0xe9,0x2d,0xe3,0xed,0x3e,0x2d,0x29,0x8e, + 0x43,0xaa,0x4f,0x84,0x68,0x66,0xe3,0xb7,0x48, + 0x99,0x09,0x46,0xd4,0x88,0xc2,0xc1,0xae,0x5a, + 0x6e,0x99,0xd3,0x27,0x90,0xd4,0x7d,0x53,0xd2, + 0x05,0x48,0x1a,0x49,0x7c,0x93,0x6b,0xf9,0xba, + 0x29,0xfa,0x9c,0x28,0x21,0x91,0x9f}, + .key_len = 70, + .data = {0xea,0x72,0x40,0x52,0x99,0x80,0x07,0x6d,0x3b, + 0x02,0x8a,0x08,0x3e,0xbc,0x4e,0x24,0xef,0xda, + 0xa0,0x6c,0x9c,0x84,0xd7,0x6b,0xf5,0xb2,0xd9, + 0xfd,0xb8,0x42,0xe1,0x03,0x8e,0x48,0x7f,0x5b, + 0x30,0xa5,0xe0,0x10,0xcd,0xdb,0x4f,0xcd,0xb0, + 0x1f,0xfc,0x98,0x1e,0xb0,0xfc,0xbc,0x7d,0x68, + 0x92,0x07,0xbc,0x90,0xad,0x36,0xee,0xf9,0xb1, + 0xae,0x38,0x48,0x7a,0x6d,0xee,0x92,0x9f,0x3f, + 0xf9,0x29,0xf3,0x35,0x7c,0xb5,0x52,0x53,0xb7, + 0x86,0x9a,0x89,0x2b,0x28,0xf7,0xe5,0xfe,0x38, + 0x64,0x06,0xa2,0x77,0x6e,0xd4,0xb2,0x1d,0x3b, + 0x6e,0x1c,0x70,0xcc,0x64,0x85,0x94,0x7f,0x27, + 0xe9,0xa5,0xd8,0xbd,0x82,0x03,0x80,0xb9,0xec, + 0xed,0x8e,0x6b,0x86,0x52,0x06,0x54,0x1b,0xe3, + 0x9f,0xdc}, + .data_len = 128, + .mac_len = 32, + .mac = {0x49,0xae,0x1c,0x4a,0x7a,0x57,0x0f,0xde,0x47, + 0xf7,0x51,0x7a,0xb1,0x88,0x98,0xb1,0xb9,0x91, + 0xd0,0x3c,0xfc,0xf8,0xc4,0x5b,0xb3,0x61,0x5b, + 0x5f,0x75,0x5d,0xa6,0x82}, + }, { // 7 (166) + .key = {0xbc,0xe5,0x0c,0xdf,0xff,0x84,0x38,0x85,0xd4, + 0xf3,0x64,0xd6,0x9f,0x93,0xbf,0x58,0xa2,0x32, + 0x2c,0x70,0x7b,0x82,0xe8,0x78,0xee,0xc9,0x6d, + 0x11,0xe5,0xdb,0x97,0xbb,0xb5,0x46,0x06,0xa3, + 0xa3,0xcc,0xc3,0xbb,0xa7,0x16,0x26,0x10,0x70, + 0xa6,0xf7,0x59,0xa7,0x0e,0xd3,0xcb,0x78,0x5f, + 0xd1,0x35,0x4f,0xe5,0x66,0x48,0xdf,0x11,0x86, + 0x36,0x69,0xb7,0x0c,0x80,0x3b,0x7a}, + .key_len = 70, + .data = {0x93,0xb7,0xef,0x0e,0x47,0x0d,0xdf,0xac,0x6a, + 0xef,0x93,0xc0,0xdc,0xd3,0x7b,0x8f,0x1c,0x4b, + 0xaf,0x5e,0xad,0xd9,0x78,0xe3,0xbf,0x05,0x12, + 0xfa,0x0b,0xae,0xb0,0x99,0xff,0x9e,0xc1,0x06, + 0x1b,0x61,0x72,0x47,0x9b,0x56,0x74,0xdb,0x56, + 0x06,0xff,0xa7,0xe6,0xb5,0x17,0x33,0x09,0x37, + 0x0e,0x16,0x47,0x05,0x4a,0xaf,0xd5,0x90,0x48, + 0x16,0xba,0xd5,0xe1,0x52,0x30,0x32,0xcc,0xcd, + 0x4d,0x78,0x65,0x05,0xe2,0x41,0xac,0x83,0xa4, + 0x84,0x91,0x11,0x89,0x66,0x6f,0x28,0x75,0x53, + 0xd6,0xa8,0x16,0x4e,0x8d,0xcb,0x0c,0x85,0xd7, + 0x5c,0x4e,0x29,0xf6,0x24,0xc9,0x7c,0xee,0xa6, + 0x4a,0x2c,0x8b,0x0c,0x9d,0xdf,0xa5,0x60,0xf7, + 0x0f,0xa3,0xff,0x91,0x18,0x3e,0x4b,0x96,0x8f, + 0x88,0xa1}, + .data_len = 128, + .mac_len = 32, + .mac = {0x37,0xf9,0xf3,0x29,0x18,0x30,0x82,0x10,0x84, + 0x9d,0xfe,0xbf,0x8d,0xd4,0x56,0x80,0x4b,0xab, + 0xd6,0x84,0x5a,0xf0,0x72,0x18,0xf9,0xd9,0xbe, + 0x9d,0xf9,0x74,0x3d,0x55}, + }, { // 8 (210) + .key = {0x81,0x57,0x43,0x23,0xc9,0x73,0x54,0x07,0x19, + 0xd1,0x92,0x83,0x3d,0xdb,0x51,0xf1,0x3a,0x52, + 0xdc,0xba,0xe2,0x94,0xae,0xbe,0xa5,0x1b,0xe5, + 0xf6,0xaa,0x47,0xf3,0x57,0x1f,0x5d,0x97,0xfa, + 0xcd,0xcf,0x0c,0x7b,0xef,0xbe,0x80,0x9f,0x44, + 0xbd,0xc7,0x39,0x63,0xd8,0x51,0x4e,0x4f,0xd5, + 0x59,0x77,0x4b,0xb9,0x60,0x87,0xef,0x8e,0xda, + 0x6e,0x7c,0x64,0x27,0x5d,0x6d,0x96,0xc4,0x2b, + 0x4e,0x4e}, + .key_len = 74, + .data = {0xb9,0xe9,0x44,0xe0,0xb4,0x2d,0x0f,0xf4,0x54, + 0xf7,0xf8,0xaa,0x24,0xf0,0x0e,0x9e,0xe0,0x39, + 0x05,0x8c,0xe4,0x09,0x41,0x11,0xe3,0x97,0x31, + 0xb6,0xdc,0x3a,0xde,0x2a,0x4a,0xce,0xc4,0xcf, + 0x9c,0x5b,0xe0,0x78,0xe4,0xf1,0x0a,0x72,0xd3, + 0xd6,0x85,0xc1,0xe5,0xe4,0xd5,0xab,0xd9,0x2c, + 0xd0,0x7b,0x64,0xdf,0xf8,0x7f,0x26,0x6f,0x08, + 0x53,0xdd,0xf1,0xcd,0x61,0xd9,0xc6,0x37,0xa9, + 0xb0,0x7a,0xb0,0xbe,0x32,0xec,0xac,0x11,0x9f, + 0xaf,0x82,0x72,0x18,0xb1,0x7a,0xd4,0x54,0x1a, + 0x27,0x51,0x94,0x77,0xf7,0x6e,0xd9,0x18,0x08, + 0x9f,0x54,0xb6,0x3d,0x0e,0x1e,0x5a,0x92,0x98, + 0x29,0x79,0xac,0x18,0x77,0x64,0xb5,0xe9,0x89, + 0xe0,0x66,0xa6,0x1b,0x10,0x65,0x34,0x0e,0x9c, + 0xd2,0x03}, + .data_len = 128, + .mac_len = 32, + .mac = {0x51,0x4b,0xd1,0x84,0x95,0xf6,0xde,0x0e,0x23, + 0x70,0x54,0xb8,0xe3,0xba,0x1a,0x74,0xc3,0xfa, + 0xda,0x42,0x79,0xad,0x6b,0x85,0x50,0xf3,0xa1, + 0x47,0x12,0xc5,0x28,0xdf}, + }, { // 9 (211) + .key = {0x44,0xf7,0x1c,0x23,0x17,0xcd,0xe5,0x21,0x51, + 0xc8,0x42,0x60,0xd1,0xd3,0xc0,0x4a,0x28,0xcc, + 0x15,0xce,0x5b,0x38,0x02,0xb2,0xe5,0x35,0x7e, + 0x2b,0xfc,0xaf,0x10,0xab,0x15,0xd7,0x7d,0xfa, + 0xaa,0xd1,0xa3,0x88,0x3b,0xad,0xa5,0x02,0x93, + 0x99,0x48,0x23,0x4c,0x55,0x9d,0xcd,0x95,0xe7, + 0xe1,0x58,0x33,0x8f,0xa1,0x2a,0xc6,0xfd,0x21, + 0x87,0x4e,0xc2,0xff,0xab,0xed,0x05,0x14,0x16, + 0xef,0x77}, + .key_len = 74, + .data = {0x2a,0xc0,0xbb,0x05,0x24,0xc2,0x2b,0x90,0x2d, + 0xe3,0x4c,0xe6,0x4e,0x61,0x72,0xd1,0xb2,0x07, + 0x4e,0x15,0x9f,0x51,0x7a,0xb1,0xab,0xd1,0x52, + 0x62,0x2c,0xd1,0x06,0x69,0xf0,0x3a,0xed,0x8e, + 0x2e,0xb5,0x1c,0x65,0xbd,0x0f,0x38,0xd0,0x84, + 0xe2,0x88,0xc5,0x32,0x72,0x4e,0x51,0x2f,0xd5, + 0x58,0xdd,0xd2,0x57,0xd2,0xb1,0xd4,0x1c,0x5e, + 0xb6,0x04,0x07,0x67,0x80,0x3d,0xdb,0xb1,0x8b, + 0x95,0xa0,0x35,0xc5,0xd8,0x49,0x2d,0x4d,0x35, + 0x93,0x6b,0x7b,0x36,0x30,0xee,0x20,0xf6,0x25, + 0xb7,0x0f,0x8e,0x71,0xd9,0xdc,0xd0,0xef,0xd0, + 0xe3,0x38,0x7d,0x13,0x8c,0x1f,0x5e,0xed,0xce, + 0x32,0xdd,0x88,0xf2,0x23,0x33,0x4b,0x9a,0x9e, + 0xab,0x65,0x01,0x7f,0x04,0xaa,0x84,0x42,0x17, + 0x9f,0x62}, + .data_len = 128, + .mac_len = 32, + .mac = {0xca,0x00,0x53,0xd5,0x1f,0x6c,0xf6,0xf9,0x99, + 0x8f,0xf1,0xe0,0xdb,0x00,0xb9,0x0e,0x82,0xc7, + 0xb1,0x8c,0xb5,0x37,0x7a,0xcc,0x8e,0xbe,0x9a, + 0xfe,0x20,0xda,0x1c,0x3d}, + } +}; + +struct HMAC_TEST_VECTOR fips_sha384_hmac_test_vector[] = { + { // 0 (45) + .key = {0x5e,0xab,0x0d,0xfa,0x27,0x31,0x12,0x60,0xd7,0xbd, + 0xdc,0xf7,0x71,0x12,0xb2,0x3d,0x8b,0x42,0xeb,0x7a, + 0x5d,0x72,0xa5,0xa3,0x18,0xe1,0xba,0x7e,0x79,0x27, + 0xf0,0x07,0x9d,0xbb,0x70,0x13,0x17,0xb8,0x7a,0x33, + 0x40,0xe1,0x56,0xdb,0xce,0xe2,0x8e,0xc3,0xa8,0xd9}, + .key_len = 50, + .data = {0xf4,0x13,0x80,0x12,0x3c,0xcb,0xec,0x4c,0x52,0x7b, + 0x42,0x56,0x52,0x64,0x11,0x91,0xe9,0x0a,0x17,0xd4, + 0x5e,0x2f,0x62,0x06,0xcf,0x01,0xb5,0xed,0xbe,0x93, + 0x2d,0x41,0xcc,0x8a,0x24,0x05,0xc3,0x19,0x56,0x17, + 0xda,0x2f,0x42,0x05,0x35,0xee,0xd4,0x22,0xac,0x60, + 0x40,0xd9,0xcd,0x65,0x31,0x42,0x24,0xf0,0x23,0xf3, + 0xba,0x73,0x0d,0x19,0xdb,0x98,0x44,0xc7,0x1c,0x32, + 0x9c,0x8d,0x9d,0x73,0xd0,0x4d,0x8c,0x5f,0x24,0x4a, + 0xea,0x80,0x48,0x82,0x92,0xdc,0x80,0x3e,0x77,0x24, + 0x02,0xe7,0x2d,0x2e,0x9f,0x1b,0xab,0xa5,0xa6,0x00, + 0x4f,0x00,0x06,0xd8,0x22,0xb0,0xb2,0xd6,0x5e,0x9e, + 0x4a,0x30,0x2d,0xd4,0xf7,0x76,0xb4,0x7a,0x97,0x22, + 0x50,0x05,0x1a,0x70,0x1f,0xab,0x2b,0x70}, + .data_len = 128, + .mac_len = 48, + .mac = {0x7c,0xf5,0xa0,0x61,0x56,0xad,0x3d,0xe5,0x40,0x5a, + 0x5d,0x26,0x1d,0xe9,0x02,0x75,0xf9,0xbb,0x36,0xde, + 0x45,0x66,0x7f,0x84,0xd0,0x8f,0xbc,0xb3,0x08,0xca, + 0x8f,0x53,0xa4,0x19,0xb0,0x7d,0xea,0xb3,0xb5,0xf8, + 0xea,0x23,0x1c,0x5b,0x03,0x6f,0x88,0x75}, + }, { // 1 (46) + .key = {0xf8,0x69,0x02,0xe5,0xe5,0xdb,0x47,0x8e,0xc6,0xe2, + 0x78,0x69,0x27,0x28,0xa8,0x12,0xc4,0xcd,0x87,0x45, + 0xf9,0x0a,0x7d,0x9f,0x79,0x15,0xf5,0xa9,0x43,0x45, + 0xfc,0x12,0xd2,0x77,0x0a,0x3c,0x94,0xb0,0x1f,0xfb, + 0x9e,0x04,0x12,0x99,0x9e,0xb6,0x26,0x1d,0x11,0xa0}, + .key_len = 50, + .data = {0xe0,0xbc,0xac,0xbe,0x96,0xda,0xd6,0xf6,0x0e,0x51, + 0x12,0x9f,0x35,0xac,0xd0,0x3e,0x12,0x27,0x6a,0x91, + 0xfa,0x13,0xfc,0x15,0x03,0x7c,0x75,0xca,0xbb,0x0a, + 0xee,0x3a,0x19,0x25,0x3b,0xb8,0xb3,0x5c,0xc0,0xe6, + 0x32,0x08,0x86,0x7a,0x03,0x2c,0x8f,0x41,0x50,0xa0, + 0x66,0x64,0x2f,0x6f,0xf9,0xea,0x19,0x7d,0xab,0x7e, + 0x9d,0x6d,0xa6,0x72,0x55,0xc1,0x6e,0x05,0x1a,0x43, + 0xbc,0xe1,0x74,0xa4,0x89,0xe8,0x54,0x64,0x69,0x30, + 0x06,0xf1,0x1a,0x4c,0x61,0x13,0x5d,0xce,0x41,0x87, + 0x04,0x09,0x37,0xeb,0x4d,0x1c,0x7e,0xda,0x6e,0x2c, + 0x31,0x57,0x71,0xf0,0xbc,0x6f,0x42,0x73,0x91,0x1a, + 0x07,0x15,0x1c,0x63,0xaf,0xd3,0xf8,0xc8,0xce,0xc9, + 0x63,0xe4,0xa8,0xf5,0xef,0x4b,0x8b,0x3e}, + .data_len = 128, + .mac_len = 48, + .mac = {0x4b,0xb4,0xeb,0x2d,0xb2,0xcc,0x92,0x1b,0x15,0x9b, + 0x78,0xa2,0xbb,0x9e,0xdc,0x16,0x08,0xbb,0x2a,0x1c, + 0xa9,0x87,0x3b,0x41,0x1a,0xe3,0x0a,0x63,0x38,0x6e, + 0x46,0x2f,0x9f,0x69,0xd9,0xf5,0xfc,0x83,0x8f,0xf1, + 0x81,0x87,0x48,0xaa,0xb7, 0x4d,0xa9,0x4f}, + }, { // 2 (105) + .key = {0xbf,0xe6,0xbb,0x4c,0x9b,0x17,0x1b,0x93,0xd2,0x8e, + 0x9f,0x8f,0x86,0xb8,0x8d,0xbe,0x50,0x9c,0x66,0xee, + 0xd4,0x18,0x18,0xa1,0x98,0x6d,0x75,0xb6,0x16,0xfe, + 0xe4,0x46,0x0f,0x54,0x56,0xcd,0x23,0x66,0x7c,0x8a, + 0x9f,0x17,0x38,0x28,0x96,0x01,0x51,0x9d,0x33,0x71, + 0x6a,0x53,0x4d,0xb2,0x35}, + .key_len = 55, + .data = {0x5b,0x7a,0x07,0x8f,0x98,0x0b,0xb8,0x91,0x97,0x43, + 0xbb,0xce,0x52,0xfd,0x0b,0xa3,0xc2,0x20,0x83,0xd2, + 0xb0,0x25,0x4e,0x28,0xc8,0xd3,0xa0,0x5d,0xef,0x4d, + 0xa3,0x3b,0xd6,0x4f,0xb5,0x02,0xcf,0xb5,0xd0,0x0c, + 0xe0,0x3d,0x49,0xad,0x16,0x8d,0xbe,0x5d,0x1c,0x78, + 0x4a,0x19,0x0c,0x7d,0xfa,0x06,0x85,0x90,0x85,0x58, + 0xfe,0x1e,0x37,0x72,0x5a,0x4b,0x2f,0x4e,0xbc,0x7e, + 0xca,0x20,0x9c,0x1f,0x5f,0x36,0x1b,0x9f,0x2d,0x23, + 0x93,0xb9,0x91,0x1c,0x73,0xf8,0x7d,0xa2,0x4a,0x7a, + 0x25,0x62,0x21,0xf3,0xfb,0x59,0x0e,0xf4,0xde,0x3b, + 0x06,0x6e,0x8e,0x16,0xf3,0x72,0x64,0x32,0x06,0x3a, + 0x40,0x3d,0x4f,0x6d,0xc2,0xa4,0x8b,0x9f,0xbd,0x44, + 0x3d,0x17,0xe8,0x42,0x00,0xd6,0xd7,0x37}, + .data_len = 128, + .mac_len = 48, + .mac = {0xe8,0x2e,0xeb,0x7f,0x4b,0x74,0x15,0xa4,0xc9,0x5d, + 0xc8,0x2c,0x46,0xbb,0x59,0x71,0x5f,0xda,0x4e,0x0b, + 0xda,0xf6,0x4a,0x7f,0xb3,0xaf,0x3c,0x70,0x58,0xec, + 0x7d,0x2a,0x17,0x2b,0x82,0x93,0x05,0x7b,0x72,0xf9, + 0x66,0x44,0x54,0xe7,0xde,0xe1,0x1d,0x95}, + }, { // 3 (106) + .key = {0x4c,0xf5,0x4e,0xb8,0xcf,0x7b,0xd4,0x21,0xdd,0xb0, + 0x58,0x6a,0xc4,0xfa,0xb9,0xc4,0x78,0xcd,0xae,0xdd, + 0x89,0xcc,0x5a,0x19,0x53,0x32,0x21,0x1f,0x75,0x71, + 0xb9,0x98,0x84,0x19,0x84,0x33,0x00,0xfa,0x1d,0xed, + 0x86,0x8d,0x31,0x8f,0x48,0x90,0x90,0x78,0xbb,0xf1, + 0x83,0x9c,0x8f,0xed,0x61}, + .key_len = 55, + .data = {0xd2,0x2f,0x19,0x4a,0x1a,0xf3,0x3c,0xd8,0xcd,0xff, + 0xe9,0x96,0x7f,0x67,0x7a,0xcb,0x68,0x50,0x0d,0x6c, + 0xbb,0xf7,0x7a,0x3f,0x34,0xf5,0x88,0x40,0xf0,0xc1, + 0x60,0x44,0x82,0x76,0x41,0xdc,0x43,0xd6,0x76,0x7c, + 0xe9,0x8f,0x85,0xdd,0x5c,0xbe,0xaa,0x9f,0xc5,0xb2, + 0x83,0x33,0xe7,0xf2,0x0d,0xf8,0xb2,0x81,0xcf,0xa4, + 0x15,0x60,0x55,0xe6,0x15,0x55,0xe0,0x4a,0x1c,0xeb, + 0x5c,0x5c,0x93,0xba,0x92,0x10,0xb2,0xe8,0x9f,0x61, + 0x97,0xf0,0xa5,0x39,0x96,0xa2,0xc0,0x91,0xd1,0x6c, + 0x3c,0xd9,0x08,0xd7,0x05,0x9a,0xb2,0x54,0x5e,0x5a, + 0x4c,0x39,0xd6,0xc0,0xf1,0x07,0x78,0xf8,0x2b,0xee, + 0x43,0x59,0x09,0x93,0xda,0x45,0x71,0x10,0x7c,0x51, + 0xb8,0x3c,0x35,0xa6,0x70,0x2e,0x56,0xa8}, + .data_len = 128, + .mac_len = 48, + .mac = {0x83,0x0b,0x4a,0x79,0x8f,0x85,0xc4,0x48,0xb3,0xd5, + 0x4a,0xbf,0xee,0x61,0xb3,0x76,0x59,0x7f,0x65,0x66, + 0x6d,0x83,0xa2,0x10,0x52,0xcb,0x3f,0x44,0x66,0xf4, + 0x47,0x47,0x43,0x16,0x07,0xbc,0x65,0x9c,0x91,0xcb, + 0x52,0x03,0x08,0xfb,0xf4,0xfc,0xdb,0x58}, + }, { // 4 (165) + .key = {0xb6,0x19,0xd9,0xd0,0x74,0x61,0xc1,0x1b,0xc9,0xfb, + 0x66,0x11,0x7d,0x61,0xed,0x90,0x00,0x13,0x66,0xbb, + 0xff,0xdb,0xff,0x58,0x35,0x56,0x77,0x75,0x84,0xb0, + 0xd6,0x52,0x44,0xaf,0x5c,0x7b,0xdb,0xf3,0xb7,0x35, + 0x8d,0x7c,0x79,0x1b,0x96,0x6c,0xc8,0x09,0x76,0x0e, + 0x57,0x39,0x8d,0x18,0x96,0xac,0xe7,0x2d,0x26,0xcc, + 0x59,0xa6,0x90,0x4f,0xcd,0x92,0x36,0x5e,0xda,0xfb, + 0x8a,0xf7,0x98,0x6c,0x7d,0x90,0xb2,0xaf,0x3b,0xfd, + 0xbc,0xdb,0x15,0x93,0xc7,0x8f,0xbe,0x8e,0x33,0x78, + 0xbb,0xb0,0xc5,0x19,0x15,0x2b,0xf9,0xcb,0x51,0xc1, + 0x9a,0x02,0xa1,0x2a,0x8f,0xd3,0x5c,0xb6,0xf8,0xb3, + 0xac,0x33,0x7a,0x82,0x87,0x11,0xd6,0xc8,0xe0,0xc4, + 0xc1,0x3e,0x1e,0x6a,0xf0,0x90,0xcd,0xae}, + .key_len = 128, + .data = {0x5a,0x81,0xe7,0x11,0xad,0xfe,0x50,0x77,0xdd,0x8c, + 0x8b,0x57,0xc9,0x5e,0x8e,0x1f,0x3d,0xe3,0x9f,0x4f, + 0xc4,0x48,0xc5,0x23,0xbd,0x3e,0x7c,0x72,0xb1,0xfd, + 0xac,0xd6,0xe4,0x89,0xdc,0x0d,0x2a,0x34,0xa3,0x9f, + 0xfc,0x64,0x60,0xc1,0xcb,0x96,0x2b,0x7a,0x94,0xa3, + 0x0c,0x04,0xb5,0x42,0x6a,0x75,0xff,0xcf,0xc6,0x9f, + 0x0c,0x4b,0xa9,0x34,0xd3,0xa3,0xda,0x2e,0x79,0x35, + 0xd5,0x6d,0x6b,0x90,0x79,0xa2,0xa9,0x7b,0x01,0x6d, + 0x65,0x3a,0x35,0xc2,0xcc,0x0c,0xe1,0x91,0x24,0xf8, + 0x87,0xa6,0x17,0xc9,0x51,0xce,0x4e,0x58,0x49,0x3b, + 0x42,0x09,0xcc,0x29,0x4f,0x98,0x3c,0xc2,0x0b,0x16, + 0xf6,0x3f,0xd5,0x2e,0x84,0x51,0xb1,0xad,0x13,0xbf, + 0x53,0x42,0x27,0x50,0x79,0x81,0x8d,0xeb}, + .data_len = 128, + .mac_len = 48, + .mac = {0x8b,0x42,0x58,0xbe,0x4c,0x09,0x4a,0xa4,0x05,0x6f, + 0x33,0x2e,0xde,0x8c,0x73,0x37,0x72,0x66,0x4b,0x08, + 0x8b,0xa2,0x2e,0xf8,0xca,0xae,0x7c,0xef,0xd7,0x7e, + 0xce,0xb3,0x5e,0x83,0xaf,0x8d,0x9c,0x12,0x83,0xcb, + 0xbf,0xfe,0x4a,0x37,0x2b,0x69,0x9c,0x21}, + }, { // 5 (166) + .key = {0xe4,0x88,0x25,0xa5,0x50,0x3a,0x6a,0xfe,0x0b,0xf9, + 0xa2,0x40,0xc6,0x7f,0x27,0xac,0xd4,0xa8,0xf6,0x99, + 0x38,0x34,0x64,0x5e,0x03,0xc8,0x0c,0x72,0xdd,0x37, + 0x0c,0xd2,0xe1,0x00,0x71,0xa3,0xae,0x18,0xef,0x19, + 0xba,0xe9,0xd6,0x97,0xea,0x9a,0x41,0x18,0x60,0x91, + 0x90,0xcd,0x95,0x36,0x19,0x07,0xa7,0xfa,0x1b,0x58, + 0xf4,0x99,0xf3,0xf5,0xe7,0x9b,0x93,0x5f,0x12,0x21, + 0x2f,0x43,0x7d,0xde,0x39,0x9e,0x3e,0x64,0x90,0x24, + 0x4a,0xa1,0xf5,0xe3,0x8b,0xa9,0xbe,0x24,0x33,0xb6, + 0xce,0x92,0x4f,0x6c,0xc4,0x9e,0x9f,0x62,0x73,0x21, + 0xa5,0xdf,0x93,0x43,0xfc,0xe1,0xb5,0x9d,0xeb,0x64, + 0x7d,0x9a,0x3a,0xe0,0x0b,0x23,0x44,0x14,0xba,0x7b, + 0x4e,0x02,0x0d,0x67,0x17,0x3b,0xe6,0x93}, + .key_len = 128, + .data = {0x85,0x61,0x86,0x5a,0xc2,0xce,0x12,0x83,0x27,0x46, + 0xf8,0x25,0x84,0xa4,0xb9,0x8e,0x7f,0x4c,0x3a,0xe2, + 0x41,0x0e,0x18,0x19,0x6f,0x4e,0x3b,0x47,0x5c,0x62, + 0xae,0x20,0x7d,0x3c,0xad,0xbb,0x1d,0x49,0x00,0x96, + 0x51,0x98,0x88,0xdb,0x2f,0x3f,0x18,0xe1,0x3b,0xfb, + 0x86,0xf6,0x22,0x16,0x01,0x5c,0xab,0x8e,0xa4,0x91, + 0xea,0x73,0x4c,0xd3,0xb7,0x91,0xa7,0xe4,0x5e,0x4f, + 0x8e,0x0b,0x98,0xd7,0x95,0x5b,0xba,0x77,0xe0,0x37, + 0x2d,0x47,0x38,0x16,0x1e,0x0d,0x5d,0x84,0x76,0x5d, + 0x9e,0x6a,0x0d,0x05,0xa8,0x8e,0x1a,0xa8,0x9c,0x5d, + 0xef,0xa8,0x64,0xe9,0xe3,0x49,0x46,0x2e,0x8f,0x14, + 0xb9,0x99,0x3d,0x7a,0x78,0xcb,0x9d,0xba,0xd6,0x9a, + 0xba,0x05,0x51,0x58,0x2d,0xdf,0x69,0x58}, + .data_len = 128, + .mac_len = 48, + .mac = {0xec,0x78,0x0a,0x91,0x5e,0xc7,0xde,0xeb,0xa2,0xc8, + 0xc9,0xe2,0xab,0x15,0xc9,0x76,0x2a,0x3e,0xb1,0x8f, + 0xaf,0xa2,0xd4,0x8a,0x55,0x4a,0xe1,0xfe,0x6c,0x44, + 0x59,0xda,0x1a,0x54,0xe2,0xd5,0x8b,0xdf,0x06,0xfe, + 0xa0,0x74,0x00,0x98,0xee,0xbb,0xb6,0x99}, + }, { // 6 (225) + .key = {0x74,0xf4,0x1a,0x6b,0x1c,0x4e,0x57,0x13,0x49,0x95, + 0x57,0xd6,0xf7,0xe8,0x89,0xf8,0xa8,0xce,0x2e,0x44, + 0x4e,0x82,0x61,0xfe,0x6a,0x8e,0x55,0x18,0x76,0x9b, + 0xdf,0xa8,0x81,0x88,0x34,0x9a,0x19,0xb9,0xf3,0xa2, + 0x6d,0xb2,0x66,0x75,0xb3,0xe4,0x05,0x39,0xc8,0xc6, + 0x3b,0x3a,0x16,0x28,0x6d,0xde,0xbb,0xc5,0x39,0xdb, + 0xe8,0x17,0xfb,0xa7,0x86,0x6f,0x96,0x31,0x20,0x44, + 0x71,0xce,0xfd,0xcb,0xbf,0x76,0x8c,0xc9,0x04,0x30, + 0x06,0xa6,0xd4,0xcb,0x4e,0xc2,0xde,0xcf,0x1c,0x0c, + 0x2a,0xb3,0x5a,0xd0,0x9f,0x50,0xce,0xd0,0xc8,0x96, + 0xfa,0x97,0xd8,0x7e,0x40,0x0a,0xeb,0x3f,0x4a,0x40, + 0x8e,0xc5,0xa9,0x93,0x82,0x5f,0xbc,0xf7,0xbd,0xb8, + 0xd4,0x8b,0xb2,0x08,0x95,0x6e,0xd2,0x8b,0xa0,0xd4}, + .key_len = 130, + .data = {0x9a,0x12,0x14,0x82,0xc7,0x77,0x5a,0x8b,0x5f,0xda, + 0xf1,0xc2,0xfb,0x7d,0xe1,0xa8,0x6e,0xf9,0x31,0xb1, + 0xa8,0x8c,0xf2,0x3d,0xdb,0xb4,0x7f,0xc9,0xdc,0xfd, + 0x02,0x67,0xcb,0x17,0x3a,0x6b,0xf6,0x2b,0x7c,0x68, + 0xfb,0x6f,0xf8,0x5b,0x2d,0xf9,0x3e,0x25,0x39,0xd1, + 0x01,0x3f,0x0a,0x49,0x1a,0xa9,0xe9,0x91,0xcf,0x23, + 0xe9,0x86,0x56,0xa0,0x82,0xcb,0x95,0xf8,0x7c,0x1b, + 0x2c,0xdd,0x0e,0xdd,0xb5,0x10,0x48,0xf9,0x4a,0xd4, + 0xae,0xeb,0x48,0xa4,0x26,0x16,0x53,0x21,0x14,0x5a, + 0x9b,0x4e,0xc3,0xe8,0x5d,0xff,0x07,0x55,0xac,0x8f, + 0x20,0xee,0x71,0xd2,0xe2,0x4c,0xb1,0x4a,0x13,0x28, + 0x0e,0x9e,0x15,0x70,0x91,0x47,0xc4,0x99,0xa6,0x8d, + 0xa2,0x38,0x68,0xb2,0x32,0xcc,0x1f,0x6d}, + .data_len = 128, + .mac_len = 48, + .mac = {0xb0,0xda,0x90,0xc0,0x43,0x49,0x35,0x11,0xd9,0x4f, + 0x22,0xfa,0xc3,0x5b,0x59,0x62,0x74,0x9c,0x49,0x97, + 0x2f,0xb4,0x35,0x71,0xb8,0x47,0x87,0x64,0xdf,0xfc, + 0x1c,0x25,0xe3,0xa7,0x52,0x3f,0xd4,0x05,0x33,0x8a, + 0x04,0x8d,0x38,0xdd,0x1b,0x75,0x51,0x1d}, + }, { // 7 (226) + .key = {0xd8,0x7f,0xb6,0xba,0x27,0x21,0x5e,0x5c,0xb6,0x5c, + 0x3b,0x5b,0x34,0xac,0x2a,0x32,0x03,0x7f,0x30,0xe1, + 0xf7,0xea,0x60,0x3d,0x5a,0x9b,0xff,0x8a,0x33,0x0f, + 0xe7,0x4b,0xc7,0x05,0x29,0x59,0x61,0x32,0xf6,0x33, + 0x4f,0x36,0xc0,0x95,0x2d,0xcf,0x9c,0x4c,0x66,0x4c, + 0xeb,0x48,0xf7,0x45,0x39,0xf3,0x76,0x8a,0x65,0xc1, + 0x53,0x59,0x02,0x08,0x5f,0xd4,0xfe,0x13,0x8a,0xb1, + 0x81,0x72,0xf1,0x34,0x18,0x93,0x18,0x5a,0x13,0x97, + 0x73,0x58,0x2c,0x5e,0x2c,0x43,0x69,0xe4,0x20,0x11, + 0x43,0xd1,0x2b,0xc0,0x07,0x4b,0xa5,0xd5,0x7d,0x0f, + 0x2c,0x08,0xc8,0xc0,0xa4,0x3e,0x8d,0x7e,0x7d,0xb7, + 0x57,0xbb,0x34,0x89,0x3a,0x4a,0x1d,0x4d,0xb7,0xb9, + 0x5f,0x18,0xe0,0xe1,0x40,0xad,0xbc,0xbb,0xa3,0xf0}, + .key_len = 130, + .data = {0x9e,0x1a,0x5d,0x9f,0x23,0x6e,0xf9,0x3f,0x2c,0xda, + 0x60,0x48,0x91,0x66,0xc8,0x2d,0xce,0x32,0x23,0x27, + 0x04,0x66,0x44,0xcc,0x40,0x6b,0x42,0xe3,0x00,0x5c, + 0x21,0x77,0xf3,0xb7,0xaf,0x2a,0x01,0x59,0xad,0xcc, + 0x8b,0xa9,0x2f,0x2c,0xf4,0x13,0x46,0x2e,0x60,0xb8, + 0xdb,0x1e,0xbb,0x63,0xde,0x44,0xfe,0xbf,0xa1,0xb9, + 0xad,0xc8,0x7e,0x79,0xa4,0x80,0xc0,0xb8,0x14,0xe3, + 0xc1,0x7a,0xc9,0x1c,0x4f,0x5e,0xae,0xf9,0x54,0xba, + 0x92,0x9d,0xb6,0xed,0x2c,0x75,0x7d,0xf1,0x5d,0x6d, + 0x34,0x30,0xb6,0x63,0x91,0x99,0x3a,0xdb,0x58,0xf2, + 0x65,0xf5,0x7c,0x70,0x6d,0x9d,0x87,0x85,0xc7,0x02, + 0x3d,0xf9,0xed,0x49,0x7c,0x3c,0x5f,0x82,0x67,0xfb, + 0xe7,0xdb,0xc4,0xf1,0x22,0x13,0xa1,0x00}, + .data_len = 128, + .mac_len = 48, + .mac = {0x3c,0x7c,0xee,0x96,0x02,0x21,0xc9,0xd9,0xf7,0x46, + 0x4a,0xeb,0x70,0xd1,0x98,0xbd,0x60,0x41,0x4d,0xc3, + 0xff,0xbf,0xa7,0xa2,0x22,0x7a,0x3a,0x37,0x5e,0xbb, + 0x8f,0x64,0x48,0xe5,0x24,0x70,0x6e,0x1e,0x3a,0xe9, + 0x55,0x41,0xbd,0xce,0xf2,0xb3,0x1d,0x9f}, + }, { // 8 (285) + .key = {0xf0,0x5d,0x56,0x1f,0x5a,0xd7,0x04,0x03,0x26,0x4c, + 0x5e,0x0a,0x0e,0xdc,0x12,0xfd,0x47,0x3b,0x19,0xc0, + 0xb4,0x0f,0x8c,0xd8,0x5a,0x99,0xba,0x2a,0x14,0x98, + 0x77,0x05,0x87,0x6a,0xb7,0x63,0x59,0x75,0x5b,0x6c, + 0x9e,0xc5,0x4a,0x3c,0x93,0xf6,0xc4,0xe6,0x8f,0x55, + 0xf3,0xb9,0x36,0x42,0xc3,0xc2,0xf0,0xd9,0xf4,0x91, + 0x9a,0xd1,0x6e,0x40,0x7b,0xa3,0xd4,0xb2,0x79,0xef, + 0x5b,0x19,0x8c,0x1c,0xdd,0xbb,0x74,0x40,0x29,0xf5, + 0xa7,0x3f,0x9e,0x80,0x8e,0x36,0xf8,0xf3,0xf0,0x1a, + 0x69,0x89,0xaf,0x9c,0xec,0x25,0xb2,0x50,0xd6,0x93, + 0x22,0x0f,0xad,0x11,0xd9,0x9a,0x3e,0x0e,0x17,0x7f, + 0xea,0x31,0x77,0x41,0x41,0x9d,0x22,0xb3,0xd2,0x74, + 0x43,0xa5,0x40,0x99,0xbb,0xc2,0x99,0xbb,0x15,0xb9, + 0xe4,0x8f,0xbc,0x9b,0xf9,0x5c,0x6b,0x84,0x96,0xbd, + 0xe6,0x7e,0xae,0xa3,0xe8}, + .key_len = 145, + .data = {0x77,0xd3,0xf3,0xe6,0x47,0xe6,0x77,0x66,0xe5,0xf4, + 0xcf,0x1b,0xce,0x5f,0x63,0x1b,0xd5,0x75,0xdd,0xbd, + 0x02,0xf2,0x96,0x43,0xa0,0xc6,0x4d,0xbd,0x92,0x19, + 0x1f,0x2a,0xe6,0x8d,0xb3,0xdf,0xad,0xc3,0xb6,0x2d, + 0x09,0x20,0x87,0x3e,0x87,0xd1,0x33,0x40,0xaf,0x0c, + 0xa3,0xc5,0xda,0x99,0x14,0x6a,0x44,0x92,0xc8,0xb7, + 0x62,0x67,0xfb,0x47,0x76,0x24,0x19,0x29,0x60,0xf7, + 0x2e,0x85,0xb7,0xed,0x9e,0x83,0x18,0xfc,0x16,0x68, + 0xbe,0x46,0xc2,0x03,0x53,0x9c,0xc1,0x47,0x06,0x41, + 0xd6,0x39,0xde,0xf1,0x60,0x0d,0x4e,0x22,0x8c,0x8b, + 0x09,0x8a,0xc9,0xb8,0x17,0xe1,0x7c,0xb3,0x29,0xe8, + 0xf5,0xdd,0x2a,0xaa,0xa2,0x3c,0x16,0x02,0x83,0x22, + 0x0f,0x5d,0xde,0x09,0xae,0xc1,0x34,0xc2}, + .data_len = 128, + .mac_len = 48, + .mac = {0x72,0x4e,0x5d,0x2d,0x51,0xd9,0x8c,0x15,0xce,0x2e, + 0x78,0xf8,0x61,0xd7,0xb6,0xf8,0x95,0x28,0x82,0xe9, + 0xd9,0x3d,0x40,0x85,0x0b,0x78,0xa2,0x3e,0x63,0x2c, + 0x4e,0x14,0xa2,0x22,0xab,0x37,0x26,0xb1,0xa0,0xaa, + 0x7c,0x6b,0x2c,0xd6,0x60,0x82,0xed,0x95}, + }, { // 9 (286) + .key = {0x95,0xec,0xe1,0xc8,0xae,0x5e,0x94,0xd1,0x6e,0xc9, + 0x98,0x3b,0x10,0x89,0xa3,0x73,0x95,0xad,0x5b,0x1d, + 0x66,0x09,0x16,0xc1,0x3c,0x87,0xe4,0xc1,0x3d,0xbe, + 0xcf,0x8f,0x68,0xc6,0x61,0x1c,0x32,0x4a,0x67,0x94, + 0x71,0xde,0xf5,0x48,0x7a,0x93,0xaa,0xec,0x86,0xc9, + 0x35,0x02,0x5b,0x45,0x18,0x96,0x28,0x84,0xac,0x2c, + 0xb0,0x4e,0x66,0xf7,0xaa,0x8e,0x58,0x4b,0x68,0x60, + 0xfb,0x55,0xb8,0x6c,0x2b,0x0a,0x08,0x73,0x73,0x5d, + 0xcd,0x27,0x8b,0xb5,0x25,0x40,0x1f,0x9e,0xba,0xcc, + 0xd2,0xbe,0xea,0xc6,0x83,0x0c,0x26,0xeb,0xcf,0x3c, + 0x98,0xc9,0xd7,0x7d,0x09,0x19,0x43,0x67,0x01,0x4e, + 0x87,0x2f,0x30,0x6e,0x64,0x1e,0x0c,0x21,0xb2,0x41, + 0xbc,0x08,0x5e,0x61,0x35,0x4f,0xaf,0x35,0xa3,0x86, + 0xcd,0xd7,0x0a,0xac,0x83,0x75,0x2d,0x8d,0x44,0x49, + 0xaf,0x4f,0x6c,0xcb,0x78}, + .key_len = 145, + .data = {0x18,0xdb,0xab,0x9f,0x86,0xb9,0xd7,0x0b,0xbd,0xeb, + 0x01,0x8f,0x6a,0x76,0xea,0x7a,0xf2,0x3e,0xb2,0xff, + 0x11,0x1e,0x9b,0xe3,0xc1,0x38,0x11,0x79,0x5d,0x8a, + 0xe7,0xd0,0x06,0xc3,0xe4,0x2b,0x46,0x54,0x7e,0xb1, + 0xf3,0xc9,0xe5,0x66,0x56,0x5a,0x43,0x5a,0x8d,0xbd, + 0x42,0x21,0x2e,0x3f,0xd0,0x82,0x2d,0x13,0x1f,0x73, + 0x00,0xea,0xef,0x46,0x00,0xc4,0x0f,0x1d,0x13,0x05, + 0x21,0xa3,0x88,0xcb,0x9f,0xfe,0x42,0x7f,0x1b,0xff, + 0x19,0xaa,0xcb,0x9c,0x7d,0x0a,0x44,0xa1,0x5c,0xe6, + 0x86,0xa2,0x46,0x9e,0x39,0x34,0xd0,0x86,0x36,0x5d, + 0x36,0xf4,0x49,0x48,0x44,0x98,0x35,0x3d,0x76,0x0c, + 0xf9,0xd1,0x5e,0xac,0x52,0x5a,0x46,0xa8,0x81,0xa6, + 0x17,0x58,0x4e,0xed,0x79,0xcf,0x4d,0x03}, + .data_len = 128, + .mac_len = 48, + .mac = {0x2b,0xe1,0xbd,0x6a,0x76,0x6e,0x30,0x79,0x21,0x54, + 0xcd,0xa0,0x0a,0xf9,0x7c,0xc5,0x12,0xe8,0x14,0x13, + 0xe0,0xfb,0x76,0x16,0x98,0xf3,0x9a,0x26,0xce,0xcc, + 0x3f,0xac,0xe6,0xf9,0xa9,0x8b,0x7c,0x49,0x60,0x51, + 0x26,0xdf,0xa5,0xaa,0x8d,0xe1,0xad,0x72}, + } +}; + +struct HMAC_TEST_VECTOR fips_sha512_hmac_test_vector[] = { + { // 0 (60) + .key = {0x57,0xc2,0xeb,0x67,0x7b,0x50,0x93,0xb9,0xe8,0x29, + 0xea,0x4b,0xab,0xb5,0x0b,0xde,0x55,0xd0,0xad,0x59, + 0xfe,0xc3,0x4a,0x61,0x89,0x73,0x80,0x2b,0x2a,0xd9, + 0xb7,0x8e,0x26,0xb2,0x04,0x5d,0xda,0x78,0x4d,0xf3, + 0xff,0x90,0xae,0x0f,0x2c,0xc5,0x1c,0xe3,0x9c,0xf5, + 0x48,0x67,0x32,0x0a,0xc6,0xf3,0xba,0x2c,0x6f,0x0d, + 0x72,0x36,0x04,0x80,0xc9,0x66,0x14,0xae,0x66,0x58, + 0x1f,0x26,0x6c,0x35,0xfb,0x79,0xfd,0x28,0x77,0x4a, + 0xfd,0x11,0x3f,0xa5,0x18,0x7e,0xff,0x92,0x06,0xd7, + 0xcb,0xe9,0x0d,0xd8,0xbf,0x67,0xc8,0x44,0xe2,0x02}, + .key_len = 100, + .data = {0x24,0x23,0xdf,0xf4,0x8b,0x31,0x2b,0xe8,0x64,0xcb, + 0x34,0x90,0x64,0x1f,0x79,0x3d,0x2b,0x9f,0xb6,0x8a, + 0x77,0x63,0xb8,0xe2,0x98,0xc8,0x6f,0x42,0x24,0x5e, + 0x45,0x40,0xeb,0x01,0xae,0x4d,0x2d,0x45,0x00,0x37, + 0x0b,0x18,0x86,0xf2,0x3c,0xa2,0xcf,0x97,0x01,0x70, + 0x4c,0xad,0x5b,0xd2,0x1b,0xa8,0x7b,0x81,0x1d,0xaf, + 0x7a,0x85,0x4e,0xa2,0x4a,0x56,0x56,0x5c,0xed,0x42, + 0x5b,0x35,0xe4,0x0e,0x1a,0xcb,0xeb,0xe0,0x36,0x03, + 0xe3,0x5d,0xcf,0x4a,0x10,0x0e,0x57,0x21,0x84,0x08, + 0xa1,0xd8,0xdb,0xcc,0x3b,0x99,0x29,0x6c,0xfe,0xa9, + 0x31,0xef,0xe3,0xeb,0xd8,0xf7,0x19,0xa6,0xd9,0xa1, + 0x54,0x87,0xb9,0xad,0x67,0xea,0xfe,0xdf,0x15,0x55, + 0x9c,0xa4,0x24,0x45,0xb0,0xf9,0xb4,0x2e}, + .data_len = 128, + .mac = {0x33,0xc5,0x11,0xe9,0xbc,0x23,0x07,0xc6,0x27,0x58, + 0xdf,0x61,0x12,0x5a,0x98,0x0e,0xe6,0x4c,0xef,0xeb, + 0xd9,0x09,0x31,0xcb,0x91,0xc1,0x37,0x42,0xd4,0x71, + 0x4c,0x06,0xde,0x40,0x03,0xfa,0xf3,0xc4,0x1c,0x06, + 0xae,0xfc,0x63,0x8a,0xd4,0x7b,0x21,0x90,0x6e,0x6b, + 0x10,0x48,0x16,0xb7,0x2d,0xe6,0x26,0x9e,0x04,0x5a, + 0x1f,0x44,0x29,0xd4}, + .mac_len = 64, + }, { // 1 (61) + .key = {0x7c,0x98,0x91,0x2c,0x74,0x42,0x13,0x62,0xe1,0x12, + 0xa2,0xf9,0x8f,0xed,0x9b,0xab,0xe0,0x05,0x7f,0xc7, + 0x78,0xb4,0x45,0x32,0x39,0xaa,0xf5,0xac,0x72,0x4b, + 0x72,0x55,0x53,0x53,0x97,0x70,0xa5,0xbc,0x86,0x66, + 0xb8,0xe1,0x3d,0x0e,0x9c,0xe3,0x6b,0x2b,0x93,0x4c, + 0x81,0x37,0xc7,0xf2,0x0b,0x5f,0x39,0x1f,0x41,0xce, + 0xfa,0xee,0xd9,0x2e,0x9d,0xf8,0x20,0x6c,0xec,0x30, + 0x49,0xbc,0xda,0x0c,0x05,0xde,0xb9,0xe6,0x54,0x9f, + 0xad,0xa1,0x9a,0xa2,0x61,0x8f,0xf5,0x60,0xf8,0x92, + 0xce,0x6e,0x47,0x82,0xae,0xff,0x41,0xcf,0x53,0xa9}, + .key_len = 100, + .data = {0x74,0xe8,0x93,0x6d,0x83,0xbf,0x3f,0x16,0xb8,0xd0, + 0x3f,0xb7,0x33,0x84,0xed,0x8f,0x46,0xbd,0x32,0x34, + 0x3f,0x5d,0xf8,0x35,0x81,0x07,0xe2,0xfd,0xda,0x29, + 0x3a,0xfa,0x10,0x3a,0x2b,0xff,0xbd,0x40,0x30,0xe7, + 0x5d,0x96,0xcc,0x7c,0xa6,0xec,0x7c,0x97,0x18,0x8f, + 0xea,0x88,0xd4,0xeb,0x63,0xb7,0xb1,0x4e,0x8b,0x8c, + 0x8d,0xee,0x4f,0x8d,0xe1,0x2e,0x1c,0xc6,0x98,0x1d, + 0x4e,0x6e,0x22,0x3f,0xec,0xc7,0xc4,0x91,0x92,0x46, + 0x32,0xc7,0xae,0xf4,0x5f,0xd8,0xef,0x14,0x94,0xbc, + 0xfb,0x06,0xc0,0x74,0x61,0x6b,0x0f,0x4c,0xce,0x8a, + 0xbd,0x5d,0x83,0xf3,0x2d,0x55,0x06,0x61,0x35,0x7b, + 0x18,0xe5,0xbc,0xed,0xe8,0x41,0x88,0x2c,0x86,0x92, + 0x51,0xdb,0x9a,0x33,0x1a,0xc4,0x56,0xdd}, + .data_len = 128, + .mac = {0x4c,0xc2,0x88,0x18,0x48,0x6b,0xb9,0xb1,0xb5,0x2e, + 0x33,0x3d,0xde,0x71,0xf7,0x3a,0xcc,0x22,0x74,0x88, + 0x45,0x3f,0xd9,0x07,0xc6,0xb5,0x1d,0x34,0x9d,0x67, + 0xaf,0x1d,0xf2,0x9a,0x9f,0x22,0x55,0x32,0xce,0x04, + 0xf5,0x03,0x95,0xfe,0xd5,0x65,0xe9,0x8d,0x78,0x97, + 0x86,0x26,0xdf,0x93,0x46,0x2d,0x3f,0x01,0x2f,0x73, + 0x73,0x34,0x72,0x98}, + .mac_len = 64, + }, { // 2 (135) + .key = {0x13,0xfb,0x1e,0xd6,0x38,0x9f,0x32,0xd1,0xde,0x31, + 0x39,0xcb,0x04,0xbc,0xdd,0x53,0x52,0x5c,0x98,0x89, + 0xb8,0x53,0x79,0xd3,0x53,0x5a,0x25,0xd2,0x90,0x35, + 0x1c,0x95,0x93,0x8a,0x3d,0x0c,0xda,0xf3,0x8d,0xbf, + 0x1d,0x52,0x34,0xbf,0x79,0x65,0xc8,0xdd,0xce,0x9a, + 0xce,0x1b,0x66,0x24,0x7e,0x60,0xd7,0x4e,0xc7,0x70, + 0x2a,0x0f,0x93,0x1a,0x3c,0xdf,0x4c,0xb4,0x65,0xca, + 0x9f,0xc4,0x58,0xc3,0x80,0x00,0x4a,0x3a,0x6e,0x79, + 0x57,0xf1,0xf8,0x13,0x21,0x0b,0x80,0x38,0xba,0x66, + 0x3f,0xcd,0xc4,0x2a,0x89,0x65,0xd6,0xa2,0x52,0xb5, + 0x22,0x4b,0xf2,0x49,0x55,0x2b,0x25,0x75,0xbf,0x64, + 0x56,0x8d,0xb4,0x09,0x1d,0x58,0x32,0x30,0x06,0xc3, + 0xc3,0x49,0x94,0xd3,0xa5}, + .key_len = 125, + .data = {0x88,0xad,0x81,0x2f,0xd3,0x4e,0x55,0xc8,0x09,0xe8, + 0x17,0x19,0x96,0x04,0xb4,0xa7,0xf7,0xfe,0xae,0x42, + 0xcd,0xc4,0xc9,0xe9,0x30,0xdb,0x08,0xe8,0x45,0xa3, + 0xd7,0x43,0x13,0xdb,0x8a,0x57,0x92,0x67,0x06,0xbf, + 0x05,0x51,0xbe,0x75,0x8a,0x0f,0xe2,0x39,0xf0,0x04, + 0xd2,0x37,0xc8,0x49,0xd9,0xe4,0xbf,0xac,0x18,0x29, + 0x2b,0xf9,0xc0,0xc3,0xe3,0x79,0x85,0xea,0x54,0xb9, + 0x4f,0x30,0xd1,0x8c,0x32,0xad,0x2b,0x53,0xa0,0x59, + 0x82,0x7c,0xdd,0xb9,0x5a,0x49,0xb4,0xbe,0xf1,0xd3, + 0x69,0xea,0xd1,0x4e,0xee,0xb4,0xa1,0x8e,0x59,0x2e, + 0x40,0xca,0x96,0xe5,0x15,0xa1,0x59,0x08,0xa0,0x5a, + 0x57,0xcd,0x55,0x70,0xb6,0x11,0xab,0x4e,0xc2,0x3f, + 0x70,0x57,0xe1,0x72,0x5f,0x29,0xc9,0xde}, + .data_len = 128, + .mac = {0xa4,0x81,0xe7,0x13,0xcd,0xc8,0x1c,0xa5,0xaf,0xa0, + 0xef,0xcb,0x16,0xe3,0x5c,0xd2,0x0d,0x01,0xaa,0x44, + 0x99,0x58,0xfd,0x2e,0xae,0xde,0x2e,0x25,0xa5,0xba, + 0x54,0x0b,0xea,0xfb,0xa2,0xfa,0xb4,0xad,0xfe,0xf2, + 0xe1,0x46,0xb4,0xc1,0xb2,0xa1,0x83,0x2e,0x93,0xdd, + 0x37,0x3d,0x63,0xfa,0x90,0xbb,0x61,0x49,0x0f,0x65, + 0x68,0x19,0x1f,0x65}, + .mac_len = 64, + }, { // 3 (136) + .key = {0xfd,0x50,0x70,0x36,0x22,0x96,0xc4,0x0d,0x65,0xb1, + 0x05,0xd5,0xab,0x46,0x53,0xfe,0x34,0xe0,0x20,0x05, + 0x16,0x93,0x3f,0x3e,0xea,0xe0,0x3e,0xd0,0xc5,0xd9, + 0xf6,0x01,0x6a,0x85,0x60,0xb4,0xbd,0x86,0xab,0x2f, + 0x7b,0xf9,0x8b,0x22,0x29,0x9e,0xd3,0xe5,0x4a,0x39, + 0x46,0x02,0xd5,0x38,0xaa,0xf3,0xe6,0x95,0x1f,0x2d, + 0xb4,0xfe,0xaf,0x5d,0xc3,0x34,0x26,0xf1,0x5b,0xb1, + 0x24,0xda,0x38,0x8d,0x70,0x90,0x83,0xa2,0x8f,0x57, + 0x01,0xef,0x96,0xc2,0x8b,0x3a,0x3c,0x75,0xbe,0xf9, + 0x33,0x2e,0xf3,0x73,0xb9,0x07,0x71,0x23,0x6a,0xf5, + 0xe2,0x5d,0x58,0x95,0x04,0x34,0x5d,0x28,0xa1,0x9a, + 0xb0,0xdb,0xc1,0xc9,0xb7,0x4d,0x1e,0xe2,0x1c,0x4b, + 0xd8,0xd4,0x23,0xde,0x6a}, + .key_len = 125, + .data = {0x8d,0x2e,0x68,0xd7,0xe9,0x84,0x6c,0xfa,0x30,0xd9, + 0x31,0xa3,0x8e,0xfb,0x59,0xbc,0xce,0xd5,0x3a,0x14, + 0x16,0x4b,0x31,0x63,0xd2,0x65,0x38,0x88,0xee,0xb0, + 0xbb,0x14,0x48,0xe1,0xa8,0x0c,0x65,0xbc,0xc6,0xeb, + 0x63,0x34,0x47,0xe7,0x2e,0xd4,0xa0,0x75,0xf7,0x5d, + 0x98,0x0f,0xe2,0xb1,0x9f,0x35,0xff,0xef,0x62,0xb2, + 0x7c,0xe0,0x9c,0x20,0x19,0x92,0x2f,0xae,0xdb,0x42, + 0x73,0x21,0x05,0x7f,0xce,0x19,0x44,0x8d,0x85,0x96, + 0x2a,0x08,0xd1,0xba,0xdd,0xc9,0x36,0xd1,0x11,0x0e, + 0x10,0x8e,0x33,0xd4,0x6f,0x97,0xe7,0x88,0x24,0x45, + 0xb5,0xdf,0x1c,0xa4,0xff,0x03,0xed,0xc2,0x37,0xef, + 0xaf,0x26,0x4f,0x1c,0x0d,0x9e,0x70,0x5d,0x9b,0x3e, + 0xee,0x07,0x6b,0xa5,0x7c,0x56,0xdb,0x82}, + .data_len = 128, + .mac = {0xb6,0xca,0xd1,0xca,0x5b,0xa5,0x05,0x49,0x8a,0x8f, + 0x66,0xa9,0x42,0x2b,0xf5,0x39,0x42,0x6a,0x8a,0x55, + 0x33,0x4f,0xab,0x9c,0x6b,0x9e,0x08,0xe3,0xa5,0x17, + 0x9d,0x15,0x7d,0x1e,0xfa,0x0f,0x91,0xd5,0xc5,0xe2, + 0x6f,0xfa,0x43,0xf5,0xc1,0xcb,0x7c,0xa5,0xf9,0x06, + 0xce,0x4f,0x0e,0xfc,0xf4,0xe8,0x71,0x82,0x0b,0x83, + 0x53,0xe8,0x90,0xe4}, + .mac_len = 64, + }, { // 4 (210) + .key = {0xe9,0xe4,0x48,0x0d,0x1c,0x4a,0x62,0x1e,0x0c,0x4e, + 0x15,0x05,0x99,0x25,0x56,0x34,0x7a,0x7a,0xb3,0x4f, + 0xd2,0xb2,0x89,0x91,0x04,0x74,0x76,0x6c,0xc9,0x69, + 0x11,0x6f,0x80,0x40,0xd9,0x6d,0xc5,0xf6,0x6c,0xdc, + 0x44,0x54,0xfa,0x7b,0xcf,0xb9,0xf8,0x38,0xaf,0x19, + 0x19,0x50,0x38,0x46,0x7a,0xb8,0xa1,0x6e,0x1c,0xbc, + 0x12,0xe5,0x98,0xe6,0xfd,0x25,0x0e,0x21,0xb2,0x14, + 0x5f,0x1e,0x2e,0x85,0x9c,0xf7,0x34,0x00,0xbe,0x12, + 0xa0,0xc6,0x97,0x49,0xf7,0x10,0x08,0x47,0x42,0x98, + 0x75,0x35,0x1d,0x5a,0x76,0x97,0x0b,0x9c,0xcf,0x70, + 0x0c,0x2c,0xa3,0xad,0x72,0xe9,0xe4,0xc0,0xf0,0x84, + 0x0e,0x8c,0xf4,0x88,0x15,0x81,0x36,0x98,0x9b,0x08, + 0x91,0xf8,0x67,0x21,0x13,0x50,0x13,0x4a}, + .key_len = 128, + .data = {0xb8,0x2e,0xef,0xb2,0x08,0x1b,0xd1,0x4d,0xab,0x0e, + 0x9e,0x34,0x52,0x48,0xa3,0x4a,0xde,0x73,0xf3,0x29, + 0x18,0x86,0xb9,0x1e,0xa3,0xe8,0xcc,0x74,0x2f,0xd8, + 0x84,0xf6,0xee,0x0c,0xcd,0xaf,0x4c,0x98,0x79,0xf4, + 0xdb,0x12,0xdb,0xa5,0x8c,0xf4,0x91,0xaf,0x25,0x41, + 0xa1,0xd5,0xef,0x6c,0xc8,0xb1,0xaf,0x75,0x0e,0xf5, + 0xd8,0x55,0x9e,0xf7,0xff,0x9c,0xd5,0x6d,0x8f,0x59, + 0x99,0x74,0xbe,0x3a,0xec,0xd8,0xc0,0xf4,0xc0,0x8f, + 0x3a,0xe5,0x0d,0x86,0xf9,0xf8,0x22,0xa1,0xe4,0xca, + 0x39,0xfd,0x2f,0x0b,0x4d,0x78,0xd2,0x26,0x30,0x73, + 0x3a,0x24,0xd8,0xd6,0x3e,0xcd,0xf9,0x55,0x54,0x11, + 0xda,0xf2,0x05,0xa7,0x61,0xc3,0x9e,0xf4,0x6f,0xf6, + 0x29,0x2e,0x74,0x12,0x9b,0xc1,0x3a,0x7f}, + .data_len = 128, + .mac = {0x90,0x09,0x3b,0xdc,0xc4,0x5d,0xa7,0x33,0x8b,0xd2, + 0xef,0xe9,0x2e,0x30,0x93,0x3b,0x14,0xf7,0x55,0x82, + 0x73,0x9c,0x74,0x7f,0x75,0x72,0xb3,0x27,0x0b,0x10, + 0x4f,0x33,0xaf,0x0c,0x93,0x9e,0x3c,0x8a,0xe5,0x3b, + 0x20,0x66,0xfc,0x8c,0x97,0xcc,0xf3,0x87,0x85,0xcd, + 0x2e,0xc3,0xd7,0x9e,0x69,0x46,0x49,0x9d,0x36,0x12, + 0x1e,0x44,0xa3,0xe7}, + .mac_len = 64, + }, { // 5 (211) + .key = {0xd3,0xfb,0xd6,0xfe,0x4e,0x35,0x6a,0xc1,0xc8,0xc1, + 0x20,0xd4,0x32,0xd7,0x20,0x4d,0x9d,0x57,0x9b,0x2a, + 0x5a,0x5d,0x0c,0x8b,0x60,0x16,0xbd,0x1e,0xef,0xd3, + 0x8d,0xda,0x73,0x5c,0xf2,0xf0,0xab,0x87,0x3a,0xfe, + 0x0a,0x09,0x16,0x86,0x5e,0x8b,0x58,0xa0,0xaf,0x01, + 0xfc,0xeb,0x6a,0x37,0x65,0xc9,0xbf,0xac,0xea,0xcc, + 0x47,0xa4,0x91,0x6b,0xea,0x79,0x1a,0xfa,0x00,0x32, + 0x40,0xd9,0xb6,0x56,0x3b,0xeb,0xb3,0x03,0x89,0x49, + 0xfc,0x3a,0xee,0x38,0x15,0x7d,0xba,0x59,0x6a,0x9c, + 0x4a,0x20,0xed,0xcc,0xd1,0x87,0xff,0xf9,0x59,0x04, + 0x94,0x5d,0x04,0xb8,0x92,0x52,0x98,0xe9,0x7b,0x64, + 0x3a,0xb2,0x4c,0xab,0x7a,0xf9,0xa5,0x58,0x90,0xa2, + 0x29,0x8d,0xe5,0x02,0x28,0x72,0xd6,0x97}, + .key_len = 128, + .data = {0xb9,0x67,0xc7,0xd9,0xc0,0xa9,0x41,0xf0,0x2e,0x87, + 0x72,0x3c,0xf2,0x82,0xea,0xda,0x43,0x47,0xb2,0x81, + 0x93,0xd3,0xe0,0xbf,0xbe,0xda,0x69,0x85,0x88,0x6a, + 0x37,0xe6,0x46,0xcc,0x7b,0x1c,0xdb,0xab,0x45,0xcc, + 0xe6,0x77,0x52,0x8b,0x3a,0x0c,0x24,0xa0,0x8f,0x8f, + 0x58,0x0b,0x77,0x99,0x35,0xc7,0x93,0x98,0x81,0x4d, + 0x06,0x72,0x98,0x59,0x2a,0x6b,0xbf,0xf0,0x82,0x48, + 0xb5,0xa2,0xf0,0xb4,0x8b,0x0d,0x28,0xe4,0xb6,0xa2, + 0x65,0x77,0x63,0xac,0x5b,0xa0,0x0a,0x8d,0x6c,0x86, + 0x46,0x4b,0x1e,0xeb,0xe4,0x4c,0xcd,0x0c,0x39,0x5e, + 0x9d,0xc9,0xb9,0xfb,0xb3,0x06,0xc6,0xca,0xa5,0x51, + 0xc6,0x68,0x2e,0xc5,0x78,0x69,0x27,0x2e,0x88,0x9a, + 0xb2,0x6e,0x61,0x89,0xb9,0x1f,0x42,0x48}, + .data_len = 128, + .mac = {0xbc,0x9a,0x83,0xd7,0x82,0xe5,0x0b,0xa5,0xa8,0x01, + 0x14,0x6f,0x8d,0xa3,0x90,0x95,0xd9,0x23,0x87,0xd7, + 0x59,0xeb,0x4a,0xd5,0x2b,0xbd,0x9e,0x99,0xd9,0xf6, + 0x8f,0x4a,0x0f,0x6f,0x64,0x70,0xc6,0x53,0xc4,0x59, + 0x79,0xc2,0xe1,0x95,0x43,0x80,0x4c,0xed,0x59,0x2e, + 0xe9,0xc5,0x3e,0xb6,0x8a,0x5b,0x1b,0x77,0x46,0xed, + 0x40,0x3e,0xbe,0x67}, + .mac_len = 64, + }, { // 6 (285) + .key = {0x95,0xaf,0x10,0x92,0x0d,0xc7,0x88,0x26,0x9e,0x70, + 0xb8,0x56,0x0b,0x73,0x13,0x5c,0xf7,0xf6,0xf5,0xb0, + 0x4a,0x50,0x2c,0x7b,0xd6,0x1c,0xb7,0x4f,0x3b,0x8c, + 0xcd,0x16,0x07,0x01,0x22,0x49,0x22,0xd8,0x65,0x63, + 0x6a,0x86,0x0d,0x94,0x9a,0xe7,0x55,0xb9,0x70,0xd3, + 0x85,0x8c,0x0f,0xf3,0x74,0x18,0xa2,0xd2,0x4b,0x71, + 0x42,0x37,0x8b,0xa1,0x1a,0xb3,0x52,0xe5,0xc8,0x76, + 0xda,0x1a,0x07,0x66,0x42,0x72,0x8b,0x73,0x91,0x6b, + 0x2d,0x24,0xf8,0x02,0x48,0x76,0x57,0x23,0x63,0xe7, + 0x03,0x65,0x10,0xce,0xc7,0xf4,0x13,0xed,0x28,0xce, + 0xc7,0x49,0xed,0x33,0xbe,0x3a,0xdf,0x56,0xa8,0xbe, + 0xce,0x59,0x76,0x12,0xd4,0x78,0xbf,0x84,0xde,0x85, + 0x62,0x83,0x67,0x94,0x6d,0xf8,0x87,0xf7,0x3d,0xd9, + 0x2d,0x6d,0xe7,0xfa,0xa8,0x96,0xd7,0x27,0x6d}, + .key_len = 139, + .data = {0x61,0xd9,0x1f,0x31,0x7a,0x90,0x2e,0xa0,0x94,0x4e, + 0x11,0xe9,0x2e,0x66,0x57,0xa5,0x89,0xe1,0x7a,0xbc, + 0x02,0x7f,0xcd,0x86,0x9f,0xf8,0xb0,0x30,0xe8,0x87, + 0x06,0x62,0xf8,0xa9,0xe9,0x1e,0xd3,0x23,0x9c,0xec, + 0xfa,0x42,0xc0,0x34,0x3d,0x66,0xcb,0xeb,0xd1,0xc2, + 0xb7,0x71,0xa2,0x5d,0xf7,0xba,0xea,0x5c,0xaf,0xad, + 0x03,0x84,0x24,0xc9,0x7a,0xfb,0x72,0x0e,0x64,0x4e, + 0x7d,0x1b,0xf5,0xb8,0x29,0x94,0x4e,0xa2,0xce,0xc6, + 0x97,0x66,0xe6,0x8e,0x4e,0x58,0x09,0x76,0xde,0x07, + 0x1c,0x22,0x74,0xc0,0xc5,0xeb,0x0e,0x54,0x21,0xc9, + 0xd5,0x1b,0xba,0x76,0xac,0x39,0xb3,0xd0,0x09,0x20, + 0x46,0x80,0x03,0x57,0x71,0xd9,0xad,0x79,0xeb,0x02, + 0xa3,0x80,0x5d,0x58,0xe2,0x43,0xcf,0x0e}, + .data_len = 128, + .mac = {0x6e,0x98,0x9e,0xc9,0xcb,0xf0,0x10,0xad,0x66,0x91, + 0xa6,0x72,0xff,0x4c,0xa9,0x0a,0x00,0x27,0x5f,0x9b, + 0xa4,0xc8,0x1c,0xd1,0x47,0xcc,0x50,0x6e,0x1d,0xbc, + 0x8b,0xc9,0x3b,0x1d,0x96,0xa3,0x75,0xe4,0x93,0x50, + 0x3c,0x0a,0xc6,0x97,0xf7,0xc4,0x5e,0x4f,0xad,0xf1, + 0x38,0x24,0x2d,0xf7,0xe0,0x6e,0x67,0x7d,0xe2,0x45, + 0xaf,0xa9,0x77,0x80}, + .mac_len = 64, + }, { // 7 (286) + .key = {0x27,0xe6,0xc9,0xf2,0x70,0xb9,0x85,0x5c,0x96,0x58, + 0xad,0x0e,0x3d,0x6c,0x9a,0x11,0x1a,0x62,0x4f,0x66, + 0xfa,0x64,0xa4,0x9a,0x06,0x88,0xa4,0x9b,0x45,0x47, + 0x33,0xca,0x62,0x30,0xf4,0x51,0xb0,0xdd,0x69,0xb7, + 0x6b,0x27,0x5c,0xb2,0x41,0x96,0x7e,0x3c,0x10,0x1b, + 0x4f,0xe8,0xf2,0x02,0x3d,0x77,0x77,0x22,0x10,0xa6, + 0x31,0x57,0x85,0x4b,0x76,0x32,0x39,0xa0,0x61,0xee, + 0xc9,0xdf,0x1a,0xa6,0x38,0x0f,0x57,0xc6,0x91,0x1d, + 0x23,0xc0,0xcd,0x2e,0xdf,0x00,0xf6,0x34,0x86,0x21, + 0x8d,0xbf,0x35,0x61,0x2a,0x17,0xea,0x52,0x62,0x87, + 0x8b,0xd3,0xed,0xfb,0x2b,0x3f,0x08,0xce,0x8a,0xe4, + 0x19,0xdd,0xda,0xb7,0x92,0xe0,0xc9,0x45,0x17,0xfa, + 0xbb,0xed,0xe3,0x8e,0x57,0x4d,0x68,0x55,0x46,0xfa, + 0x35,0xad,0x37,0x74,0x1d,0x34,0x27,0x59,0x96}, + .key_len = 139, + .data = {0xdf,0x24,0x27,0x9b,0xf8,0x27,0x7a,0xd1,0x09,0x19, + 0x72,0xb8,0x25,0x94,0xd8,0x46,0x77,0xe5,0x4f,0xe5, + 0xd6,0x57,0x86,0xd1,0x9a,0xb5,0xb2,0xc1,0xae,0x0a, + 0x3c,0xc9,0xe7,0xab,0xb6,0x7f,0x94,0x77,0x14,0x5d, + 0x57,0x5e,0x19,0x66,0x33,0x20,0x0f,0x0c,0xe5,0x57, + 0xbb,0x52,0x78,0xb8,0x90,0x2e,0x14,0x96,0x23,0x31, + 0x17,0xa7,0xdf,0x69,0x66,0x0b,0xfa,0x87,0x06,0x8a, + 0xa7,0x3d,0xe6,0x1e,0x8e,0xea,0xff,0xb1,0x79,0x79, + 0x9f,0x27,0x50,0x86,0x02,0x9f,0x47,0xc3,0x23,0xf6, + 0x56,0x9b,0xd1,0x8d,0xea,0x15,0x05,0x4d,0xda,0xfa, + 0x73,0xe8,0x9c,0x3a,0x5f,0x61,0xb9,0x8c,0xb2,0xce, + 0x7e,0x55,0x4d,0x5d,0xf4,0xcb,0x9d,0x95,0x13,0x5a, + 0x70,0xde,0x33,0x47,0x07,0x44,0xc3,0x93}, + .data_len = 128, + .mac = {0xe6,0xf6,0x06,0x12,0x75,0xa8,0x93,0x45,0xf5,0x46, + 0x3c,0xfa,0x19,0x8d,0x52,0x8e,0x14,0x04,0x7d,0x47, + 0x8f,0x69,0xad,0x7a,0x73,0x43,0x2f,0x18,0xf8,0x8b, + 0xc6,0x8a,0x1b,0x8a,0xba,0x2c,0x3b,0x02,0x5c,0x93, + 0xb2,0x5d,0xeb,0x8f,0x40,0x37,0x63,0xa5,0x50,0x24, + 0x40,0x8a,0x97,0xa9,0x03,0xe9,0x5f,0x0c,0xb6,0x17, + 0x8e,0x7b,0xe3,0x89}, + .mac_len = 64, + }, { // 8 (360) + .key = {0x01,0xb9,0x5a,0x88,0x79,0x27,0xce,0x31,0xb1,0x24, + 0x23,0x91,0xbb,0xd0,0x09,0x65,0xeb,0x77,0xa9,0x03, + 0xd4,0xb8,0x39,0x9b,0x72,0xe6,0xce,0xbd,0xa9,0xae, + 0x72,0x1b,0xee,0xfa,0x77,0x91,0x45,0x16,0x0b,0x62, + 0x6b,0x11,0x0c,0xc5,0x54,0x67,0x1d,0xa0,0xd8,0xdc, + 0xf9,0x93,0xa9,0xab,0x07,0x38,0x88,0xe0,0x2f,0xa9, + 0xb8,0x03,0xed,0x43,0xb3,0xf6,0xa3,0xaa,0x1d,0x20, + 0x34,0x0d,0xf6,0xcc,0xce,0xac,0x13,0xcb,0x07,0x97, + 0xcf,0x61,0x2c,0xb8,0xfe,0x5f,0xd5,0x13,0x22,0x8c, + 0xbd,0x4d,0xe2,0x49,0xd1,0x6b,0xb7,0x75,0x87,0xdd, + 0xe9,0x8f,0x71,0xbb,0xba,0x1a,0x12,0x4e,0xe0,0x46, + 0xf0,0xd2,0x39,0xcc,0xea,0x7a,0xbb,0x1a,0xcc,0xb5, + 0xaa,0xb0,0x21,0xb0,0x0d,0xca,0x49,0x1c,0x62,0x3f, + 0xcb,0x31,0x91,0xa9,0xec,0xf3,0x1f,0xc6,0x80,0xb4, + 0xa4,0x1e}, + .key_len = 142, + .data = {0x63,0x2a,0xfa,0x8e,0x79,0xb1,0x4b,0x2a,0x36,0x04, + 0xf5,0x85,0x5d,0x2b,0xf1,0x82,0xd3,0xc5,0x6d,0x68, + 0x53,0xf2,0x1f,0xe4,0x62,0x71,0xda,0x52,0x86,0x06, + 0x5f,0x38,0xb3,0x1f,0x75,0x13,0x06,0xb6,0x3c,0x57, + 0xb6,0x79,0xbe,0xb1,0x47,0x29,0xc7,0x8f,0x00,0x40, + 0xf7,0xe2,0xa0,0xd6,0x15,0x22,0x4d,0xc5,0xa6,0x93, + 0xcd,0x0c,0xbe,0xc8,0xf8,0x71,0x17,0x65,0x6d,0x6b, + 0x60,0x29,0x85,0x3e,0xd7,0x2b,0x85,0x68,0x1a,0x63, + 0x18,0x3c,0x3a,0x6d,0xfc,0xcd,0x12,0x8a,0xfb,0x0d, + 0xd7,0xe8,0x1d,0x36,0xf0,0x23,0x1c,0x69,0x07,0x0b, + 0x18,0x95,0x60,0xa8,0x8c,0x9b,0x69,0x7b,0x81,0xb0, + 0x93,0x07,0x01,0x02,0x61,0x90,0xcf,0x9e,0xbe,0x23, + 0x55,0x91,0x94,0xd6,0xde,0x4d,0x9a,0x51}, + .data_len = 128, + .mac = {0x21,0x0a,0xd4,0x5c,0xa2,0xfd,0x1f,0x10,0x5c,0x0a, + 0x18,0xf9,0x93,0x77,0x4f,0x93,0x3e,0xce,0x57,0xac, + 0xe4,0xda,0x61,0x96,0x89,0xe1,0xcb,0x8b,0x49,0x1a, + 0x18,0x9c,0xc6,0xe4,0xee,0x19,0x54,0xa3,0x22,0x01, + 0x07,0x2e,0x70,0xf9,0x34,0x83,0x7c,0x0f,0xb6,0xe2, + 0x39,0xb4,0xfd,0xfb,0xd2,0x6e,0xbf,0x11,0xb9,0xa9, + 0x19,0xea,0xfd,0x09}, + .mac_len = 64, + }, { // 9 (361) + .key = {0x61,0x09,0x6f,0x4f,0xe5,0x34,0x04,0x88,0x91,0x6d, + 0xe2,0x93,0xbe,0x38,0xcc,0x3a,0xe0,0xc8,0x77,0x67, + 0x0c,0x71,0x36,0x37,0xb7,0x60,0xd7,0x4f,0xc1,0x8a, + 0xc7,0x73,0xb2,0xe2,0x7d,0x55,0x43,0xcf,0x16,0xaa, + 0x20,0xdd,0x3d,0x83,0xec,0xb3,0x4e,0xdb,0x85,0x45, + 0xbb,0x6c,0x8a,0x4a,0xae,0xc8,0x1b,0xf1,0xf0,0xa4, + 0xe0,0xcf,0x09,0x77,0x4d,0x1c,0xa9,0x44,0x24,0x20, + 0x46,0xb3,0x3b,0xe8,0x07,0x67,0x7f,0x3d,0xe1,0x8c, + 0x39,0xd7,0x00,0xaf,0x90,0xcd,0x68,0xd3,0x4f,0x50, + 0xdc,0xc1,0xe9,0x99,0xfe,0x9f,0xbb,0x20,0xb9,0xc4, + 0x90,0x0f,0xdc,0xcb,0x6a,0xf6,0x07,0xe6,0x80,0xc0, + 0xcb,0x75,0x83,0xe6,0x0d,0xd8,0x25,0xe2,0xab,0x81, + 0xdc,0xe7,0x63,0x4d,0xe3,0xcf,0xf0,0x14,0x83,0x55, + 0x75,0x7f,0x90,0x84,0x1f,0x19,0x36,0x6f,0x06,0xa9, + 0xf6,0x23}, + .key_len = 142, + .data = {0x67,0xe7,0x04,0x04,0x6f,0x98,0xcb,0x5a,0xa9,0x7d, + 0xa9,0x5b,0x19,0x14,0x73,0x91,0xf0,0x57,0x88,0xf8, + 0x11,0x36,0x6b,0x0e,0xce,0x44,0xb1,0x2a,0xf2,0xb1, + 0x1e,0x0e,0x05,0x78,0x0b,0xbf,0xcb,0xd9,0x0a,0x95, + 0x0e,0x0a,0xcd,0x8e,0x9d,0x2a,0x44,0xe7,0x95,0x76, + 0x06,0xee,0xdf,0xbf,0xf2,0x12,0xfa,0x1c,0x16,0x3c, + 0xfb,0xdc,0xd0,0x62,0xd2,0xbe,0x32,0x59,0xce,0x65, + 0xab,0xea,0x64,0x06,0xe4,0x29,0x2c,0x64,0xe9,0x02, + 0x2c,0xfe,0x89,0x15,0x59,0x86,0xff,0xc4,0x5b,0x96, + 0xd2,0x89,0x91,0x9f,0xf9,0x8d,0x55,0x22,0x43,0x77, + 0x81,0x22,0xf6,0x82,0x31,0xd9,0xb6,0xd3,0xcb,0xaa, + 0xa9,0x09,0x3d,0x57,0xd9,0x15,0x86,0x74,0xda,0x4c, + 0x78,0x1b,0xac,0xba,0xbc,0xe2,0xe2,0xba}, + .data_len = 128, + .mac = {0x9a,0x2d,0x14,0x7e,0x50,0x82,0x71,0x57,0xf3,0x86, + 0x6e,0x86,0x8c,0x1c,0xca,0x9f,0x08,0x15,0x79,0xc9, + 0x2f,0x25,0xda,0x8c,0xeb,0xc9,0xed,0x24,0x99,0x28, + 0xc8,0x2b,0xea,0xd3,0x9d,0x48,0x0e,0xcb,0xb5,0xb5, + 0xd0,0xe0,0x75,0x50,0x29,0xae,0xbf,0x3e,0x02,0x06, + 0x98,0x4f,0x3e,0xa8,0x3f,0x4d,0x63,0x72,0xf4,0x45, + 0x33,0x90,0xe0,0x70}, + .mac_len = 64, + }, +}; + +struct HMAC_TEST_VECTOR fips_sha1_hmac_general_test_vector[] = { + { // 0 (0) + .key = {0x82,0xf3,0xb6,0x9a,0x1b,0xff,0x4d,0xe1,0x5c,0x33}, + .key_len = 10, + .data = {0xfc,0xd6,0xd9,0x8b,0xef,0x45,0xed,0x68,0x50, + 0x80,0x6e,0x96,0xf2,0x55,0xfa,0x0c,0x81,0x14, + 0xb7,0x28,0x73,0xab,0xe8,0xf4,0x3c,0x10,0xbe, + 0xa7,0xc1,0xdf,0x70,0x6f,0x10,0x45,0x8e,0x6d, + 0x4e,0x1c,0x92,0x01,0xf0,0x57,0xb8,0x49,0x2f, + 0xa1,0x0f,0xe4,0xb5,0x41,0xd0,0xfc,0x9d,0x41, + 0xef,0x83,0x9a,0xcf,0xf1,0xbc,0x76,0xe3,0xfd, + 0xfe,0xbf,0x22,0x35,0xb5,0xbd,0x03,0x47,0xa9, + 0xa6,0x30,0x3e,0x83,0x15,0x2f,0x9f,0x8d,0xb9, + 0x41,0xb1,0xb9,0x4a,0x8a,0x1c,0xe5,0xc2,0x73, + 0xb5,0x5d,0xc9,0x4d,0x99,0xa1,0x71,0x37,0x79, + 0x69,0x23,0x41,0x34,0xe7,0xda,0xd1,0xab,0x4c, + 0x8e,0x46,0xd1,0x8d,0xf4,0xdc,0x01,0x67,0x64, + 0xcf,0x95,0xa1,0x1a,0xc4,0xb4,0x91,0xa2,0x64, + 0x6b,0xe1}, + .data_len = 128, + .mac_len = 10, + .mac = {0x1b,0xa0,0xe6,0x6c,0xf7,0x2e,0xfc,0x34,0x92,0x07}, + .chunks = {64, 64}, + .num_chunks = 2, + }, { // 1 (1) + .key = {0x47,0x66,0xe6,0xfe,0x5d,0xff,0xc9,0x8a,0x5c,0x50}, + .key_len = 10, + .data = {0xd6,0x8b,0x82,0x8a,0x15,0x3f,0x51,0x98,0xc0, + 0x05,0xee,0x36,0xc0,0xaf,0x2f,0xf9,0x2e,0x84, + 0x90,0x75,0x17,0xf0,0x1d,0x9b,0x7c,0x79,0x93, + 0x46,0x9d,0xf5,0xc2,0x10,0x78,0xfa,0x35,0x6a, + 0x8c,0x97,0x15,0xec,0xe2,0x41,0x4b,0xe9,0x4e, + 0x10,0xe5,0x47,0xf3,0x2c,0xbb,0x8d,0x05,0x82, + 0x52,0x3e,0xd3,0xbb,0x00,0x66,0x04,0x6e,0x51, + 0x72,0x20,0x94,0xaa,0x44,0x53,0x3d,0x2c,0x87, + 0x6e,0x82,0xdb,0x40,0x2f,0xbb,0x00,0xa6,0xc2, + 0xf2,0xcc,0x34,0x87,0x97,0x3d,0xfc,0x16,0x74, + 0x46,0x3e,0x81,0xe4,0x2a,0x39,0xd9,0x40,0x29, + 0x41,0xf3,0x9b,0x5e,0x12,0x6b,0xaf,0xe8,0x64, + 0xea,0x16,0x48,0xc0,0xa5,0xbe,0x0a,0x91,0x26, + 0x97,0xa8,0x7e,0x4f,0x8e,0xab,0xf7,0x9c,0xbf, + 0x13,0x0e}, + .data_len = 128, + .mac_len = 10, + .mac = {0x00,0x7e,0x45,0x04,0x04,0x1a,0x12,0xf9,0xe3,0x45}, + .chunks = {32, 32, 32, 32}, + .num_chunks = 4, + }, { // 2 (15) + .key = {0x13,0x79,0xa7,0xaf,0xcc,0x09,0x05,0xa5,0xfc,0x81}, + .key_len = 10, + .data = {0x96,0xfa,0x56,0x19,0xfa,0xc6,0x48,0x84,0x3d, + 0xb7,0x88,0xcb,0x8e,0x90,0xdc,0x6f,0xfd,0x6e, + 0xfe,0x13,0x32,0xab,0xf0,0x81,0x5f,0x03,0x90, + 0xee,0x73,0xf5,0x6c,0x7f,0x91,0x6c,0xd7,0x0c, + 0xc0,0x9f,0x3d,0x23,0xe4,0x36,0xb3,0x50,0xed, + 0xae,0xd2,0x9b,0x4e,0xfe,0xc6,0x53,0xb0,0x7b, + 0xa2,0x0a,0xe8,0xf9,0xf6,0xe1,0x27,0x33,0xa4, + 0x06,0x71,0x6d,0xef,0x7a,0x51,0x57,0xd5,0x18, + 0xca,0x35,0x9f,0xd3,0x90,0x3d,0xb6,0x3f,0x79, + 0x40,0xb8,0x53,0x2e,0x8d,0xcb,0x6d,0x26,0x13, + 0x32,0x96,0xd5,0xc5,0x1e,0x07,0x20,0x43,0xc6, + 0xed,0x15,0xb6,0xb9,0x6a,0xd9,0xfb,0x73,0xdc, + 0xe1,0x05,0x2f,0x61,0x65,0x7c,0xfd,0x9b,0x12, + 0xaa,0x14,0xb0,0x00,0x98,0x69,0x95,0xe3,0x74, + 0x81,0x8d}, + .data_len = 128, + .mac_len = 12, + .mac = {0x42,0x53,0x7b,0x22,0x52,0x0a,0x08,0x55,0x77, + 0x58,0x76,0x16}, + .chunks = {32, 32, 64}, + .num_chunks = 3, + }, { // 3 (16) + .key = {0x80,0xa0,0xdb,0x49,0xd0,0x39,0xb3,0x16,0xae,0x12}, + .key_len = 10, + .data = {0x91,0xf8,0xec,0x84,0x8d,0x6f,0x81,0x14,0x31, + 0xcb,0xde,0xee,0x15,0x0b,0x93,0xaf,0x6f,0x67, + 0x8b,0xe9,0x9c,0x90,0x3f,0x81,0xfc,0x38,0x29, + 0x55,0x03,0xd5,0x7c,0x22,0x8d,0xa2,0x12,0xa6, + 0x72,0xe7,0xa6,0x01,0x5b,0x7b,0x43,0x61,0xd4, + 0x87,0xfc,0xde,0xa2,0x8c,0xde,0xa3,0x56,0xa8, + 0x23,0x4f,0x22,0x15,0xa8,0x9b,0xec,0xf2,0xa2, + 0x3c,0xa1,0x46,0x8c,0x0b,0xcc,0x42,0x64,0x63, + 0x67,0xc6,0x16,0xca,0xf0,0x27,0x39,0xd4,0xc0, + 0x30,0xf9,0x45,0x99,0x66,0x54,0x76,0x7e,0x90, + 0x8a,0xfa,0xc7,0x77,0xce,0x80,0x74,0xeb,0x42, + 0xfb,0xc2,0x06,0x22,0x01,0xfc,0xb5,0x3f,0x71, + 0x94,0x73,0xb0,0x59,0x72,0x58,0xc4,0x17,0x8c, + 0x53,0x3b,0xbe,0xb7,0xb4,0xb5,0xbb,0xbc,0xed, + 0x6a,0xb8}, + .data_len = 128, + .mac_len = 12, + .mac = {0xec,0xae,0x13,0x83,0x22,0xd2,0xd4,0x08,0x6a, + 0xa2,0xbe,0xc6}, + .chunks = {128}, + .num_chunks = 1, + }, { // 4 (30) + .key = {0xf5,0x73,0x1a,0x6e,0x89,0x25,0xf7,0x43,0x06,0xfa}, + .key_len = 10, + .data = {0x44,0xc7,0xcc,0x06,0xad,0x29,0x0f,0x3a,0x54, + 0xa9,0x70,0xb6,0x40,0x01,0x4c,0xb5,0xd1,0xe6, + 0x18,0x23,0x52,0x45,0x99,0x01,0xcd,0xcd,0x57, + 0x0c,0x23,0xad,0x4f,0x99,0x5b,0x9f,0xe8,0xc4, + 0x3b,0x25,0x28,0xc9,0x15,0x12,0x28,0xb2,0xe4, + 0x4d,0xc5,0x33,0x98,0xd2,0x99,0xd2,0xad,0xf9, + 0x2a,0x4a,0x02,0xfb,0x60,0x32,0xe9,0xb2,0x3d, + 0xda,0x7a,0xa0,0xc8,0x76,0x2e,0x33,0x4a,0x7e, + 0xa9,0x47,0xbd,0x54,0xd6,0xed,0x82,0x28,0x39, + 0x6b,0x52,0x19,0x81,0x84,0x77,0x9c,0x5d,0xf9, + 0x3c,0x22,0x91,0x4f,0xa2,0xf5,0x49,0xd3,0x54, + 0x63,0xad,0xdc,0xdd,0x1f,0xb5,0x50,0x19,0xe4, + 0x3f,0x69,0xe9,0x5b,0x5f,0xb9,0x2b,0x3f,0xf6, + 0x6c,0xea,0xbf,0x86,0xce,0xd1,0x24,0x44,0x0d, + 0xe6,0xb3}, + .data_len = 128, + .mac_len = 16, + .mac = {0x73,0xb0,0x83,0xd8,0xbe,0x0d,0x19,0xee,0x7a, + 0x69,0x7f,0x9e,0x5d,0x76,0x36,0x2f}, + .chunks = {32, 0, 64, 32}, + .num_chunks = 4, + }, { // 5 (31) + .key = {0x29,0x05,0x66,0xd7,0x77,0xb0,0xee,0xe9,0x84,0xfa}, + .key_len = 10, + .data = {0x78,0x7f,0xda,0xa9,0x0a,0x2d,0xe3,0x93,0x7e, + 0x79,0x42,0xe6,0x71,0x1f,0x16,0x5a,0x89,0xb9, + 0xe0,0x77,0xfe,0x32,0x2c,0xab,0x59,0x7d,0x74, + 0x9a,0x7c,0x87,0x41,0xb5,0xe3,0x6a,0x93,0x0e, + 0x29,0xe3,0x83,0x6a,0xce,0x06,0x27,0x98,0x37, + 0x30,0xb6,0x02,0xf6,0x3e,0xec,0x82,0x4c,0xfc, + 0xb0,0x77,0xec,0xe0,0xf5,0x17,0x02,0xf9,0xde, + 0x07,0x74,0x22,0x25,0x29,0x68,0x7b,0xbd,0xb5, + 0x06,0x1a,0xb6,0x8b,0x7f,0xfd,0x62,0xc7,0x4e, + 0x43,0xb6,0x96,0xbe,0x9c,0xf2,0x49,0xac,0xff, + 0x85,0xa8,0x8e,0x9b,0x2a,0x89,0xb4,0x0f,0x58, + 0xa1,0xce,0xdd,0xd9,0x99,0xaf,0x1c,0xb8,0x64, + 0x50,0x6e,0x61,0xd1,0x18,0x32,0x04,0x5c,0x5a, + 0xfb,0x3a,0x4a,0x20,0x40,0xeb,0xf5,0x27,0x55, + 0x6f,0x64}, + .data_len = 128, + .mac_len = 16, + .mac = {0xd7,0x2b,0x37,0x0a,0x1d,0x82,0x90,0x10,0x51, + 0x73,0xc8,0x3a,0xee,0xdb,0x83,0x58 }, + .chunks = {64, -1, 64}, + .num_chunks = 3, + }, { //6 (45) + .key = {0x59,0x78,0x59,0x28,0xd7,0x25,0x16,0xe3,0x12,0x72}, + .key_len = 10, + .data = {0xa3,0xce,0x88,0x99,0xdf,0x10,0x22,0xe8,0xd2, + 0xd5,0x39,0xb4,0x7b,0xf0,0xe3,0x09,0xc6,0x6f, + 0x84,0x09,0x5e,0x21,0x43,0x8e,0xc3,0x55,0xbf, + 0x11,0x9c,0xe5,0xfd,0xcb,0x4e,0x73,0xa6,0x19, + 0xcd,0xf3,0x6f,0x25,0xb3,0x69,0xd8,0xc3,0x8f, + 0xf4,0x19,0x99,0x7f,0x0c,0x59,0x83,0x01,0x08, + 0x22,0x36,0x06,0xe3,0x12,0x23,0x48,0x3f,0xd3, + 0x9e,0xde,0xaa,0x4d,0x3f,0x0d,0x21,0x19,0x88, + 0x62,0xd2,0x39,0xc9,0xfd,0x26,0x07,0x41,0x30, + 0xff,0x6c,0x86,0x49,0x3f,0x52,0x27,0xab,0x89, + 0x5c,0x8f,0x24,0x4b,0xd4,0x2c,0x7a,0xfc,0xe5, + 0xd1,0x47,0xa2,0x0a,0x59,0x07,0x98,0xc6,0x8e, + 0x70,0x8e,0x96,0x49,0x02,0xd1,0x24,0xda,0xde, + 0xcd,0xbd,0xa9,0xdb,0xd0,0x05,0x1e,0xd7,0x10, + 0xe9,0xbf}, + .data_len = 128, + .mac_len = 20, + .mac = {0x3c,0x81,0x62,0x58,0x9a,0xaf,0xae,0xe0,0x24, + 0xfc,0x9a,0x5c,0xa5,0x0d,0xd2,0x33,0x6f,0xe3, + 0xeb,0x28}, + .chunks = {25, 25, 25, 25, 3, 25}, + .num_chunks = 6, + }, { // 7 (46) + .key = {0xc5,0x21,0x09,0xc9,0xd0,0xda,0x92,0x58,0xeb,0x73}, + .key_len = 10, + .data = {0x52,0xb1,0x13,0x61,0x4b,0x80,0xb9,0x70,0x51, + 0x0f,0x65,0xa2,0x5d,0x46,0xed,0xc0,0x23,0xd9, + 0xc7,0xb8,0xe7,0xca,0x7c,0x41,0x92,0x30,0x59, + 0xc2,0x05,0x36,0x68,0x70,0xad,0x66,0x9f,0xb7, + 0x57,0x28,0x56,0xdc,0x46,0x85,0xff,0xe0,0x83, + 0x31,0x11,0xa7,0x75,0xc9,0x45,0x5a,0xb1,0x59, + 0x05,0x09,0x13,0x21,0x21,0x95,0x0e,0x99,0xc5, + 0xcd,0x40,0xb2,0xa8,0xd7,0x4a,0x5f,0x85,0xd2, + 0xde,0x54,0xcf,0xb9,0x1a,0x0d,0xa1,0x8a,0x14, + 0x13,0xf4,0xa8,0xb6,0x7b,0x14,0x7e,0xcc,0xaf, + 0x55,0x66,0x5b,0x71,0x01,0xc9,0x34,0x1c,0x96, + 0x87,0xca,0x2d,0x2e,0x99,0x41,0x03,0x3f,0xf5, + 0xc7,0xe3,0x84,0xb1,0x27,0x3f,0x3b,0x6c,0x9b, + 0x38,0x91,0xea,0xe2,0x61,0x5b,0xfe,0x93,0xc6, + 0x06,0xad}, + .data_len = 128, + .mac_len = 20, + .mac = {0x2f,0xec,0xb4,0x66,0xbc,0x92,0x0f,0x61,0x0e, + 0x3e,0xae,0x99,0x49,0xe0,0x0f,0x45,0x4a,0x71, + 0x4a,0xb5}, + .chunks = {54, 0, 54, -1, 20}, + .num_chunks = 5, + }, { // 8 (60) + .key = {0x19,0x1a,0x70,0x0f,0x3d,0xc5,0x60,0xa5,0x89, + 0xf9,0xc2,0xca,0x78,0x4e,0x97,0x0c,0xb1,0xe5, + 0x52,0xa0,0xe6,0xb3,0xdf,0x54,0xfc,0x1c,0xe3, + 0xc5,0x6c,0xc4,0x46,0xd2}, + .key_len = 32, + .data = {0x19,0x48,0xc7,0x12,0x0a,0x06,0x18,0xc5,0x44, + 0xa3,0x9e,0x59,0x57,0x40,0x8b,0x89,0x22,0x0a, + 0xe3,0x98,0xec,0x05,0x30,0x39,0xb0,0x09,0x78, + 0xad,0xb7,0x0a,0x6c,0x2b,0x6c,0x9c,0xe2,0x84, + 0x6d,0xb5,0x85,0x07,0xde,0xb5,0xcb,0xa2,0x02, + 0xa5,0x28,0x4b,0x0c,0xbc,0x82,0x9e,0x32,0x28, + 0xe4,0xc8,0x04,0x0b,0x76,0xa3,0xfc,0xc3,0xad, + 0x22,0x56,0x6e,0xbf,0xf0,0x21,0xad,0x5a,0x54, + 0x97,0xa9,0x95,0x58,0xaa,0x54,0x27,0x2a,0xdf, + 0xf2,0xd6,0xc2,0x5f,0xd7,0x33,0xc5,0x4c,0x72, + 0x85,0xaa,0x51,0x8a,0x03,0x1b,0x7d,0xc8,0x46, + 0x9e,0x51,0x76,0xfd,0x74,0x17,0x86,0xe3,0xc1, + 0x76,0xd6,0xee,0xee,0x44,0xb2,0xc9,0x4c,0x9b, + 0x9b,0x85,0xfa,0x2f,0x46,0x8c,0x08,0xde,0xe8, + 0xd6,0xdc}, + .data_len = 128, + .mac_len = 10, + .mac = {0x40,0x24,0x93,0xfa,0xc2,0x6c,0x24,0x54,0xd0,0xcb}, + }, { // 9 (61) + .key = {0xdc,0xb4,0x63,0xa1,0x3a,0xe3,0x37,0x41,0x41, + 0x51,0xa3,0x1a,0xa0,0xc3,0xe8,0xba,0xb3,0xee, + 0x78,0x1b,0x9f,0x3a,0xaa,0x86,0x9d,0xc5,0xb1, + 0xb1,0x96,0xab,0xcf,0x2b}, + .key_len = 32, + .data = {0x44,0xc9,0xbf,0x3a,0xe8,0xf1,0x4c,0xc9,0xd6, + 0x93,0x5d,0xed,0xa3,0xc2,0x4d,0xe6,0x9c,0x67, + 0xf0,0x88,0x5a,0x87,0xc8,0x99,0x96,0xc4,0x7c, + 0x7b,0x3e,0x27,0x85,0x0a,0xc7,0x1c,0x2b,0xc8, + 0xc6,0xbe,0xb0,0x38,0xba,0x55,0xcb,0x87,0x2c, + 0x1d,0x58,0x71,0xfb,0x4a,0x4d,0x63,0xf1,0x48, + 0xf0,0xdd,0x99,0x47,0x47,0x1b,0x55,0xf7,0xd0, + 0xf4,0xab,0x90,0x73,0x02,0xe0,0x16,0xb5,0x03, + 0xc8,0xdb,0x2e,0x7f,0xdc,0x45,0x3d,0xac,0x8d, + 0xd1,0xfa,0x8e,0xd8,0x58,0x6c,0x62,0x1b,0x92, + 0xfd,0x3d,0x27,0xd8,0x2a,0xf1,0x96,0x2e,0x7f, + 0x30,0x5f,0x80,0xc3,0xf4,0xa7,0x2c,0x70,0x1d, + 0xda,0xc1,0x66,0x5c,0xfb,0x06,0xdf,0x51,0x38, + 0x3f,0xa6,0xf0,0xc2,0xab,0x84,0x29,0xdb,0x51, + 0xfb,0xc8}, + .data_len = 128, + .mac_len = 10, + .mac = {0xb9,0x6d,0xe3,0xa2,0x19,0xd7,0x66,0x14,0xaa,0xa4}, + }, { // 10 (75) + .key = {0xa1,0x27,0x94,0x05,0x7d,0xe3,0xb3,0xea,0x42, + 0x6f,0xbe,0x01,0x95,0xee,0x17,0xb4,0x87,0x3e, + 0xf7,0xe6,0xba,0x87,0xb2,0x2b,0xc6,0x14,0x3c, + 0x38,0xda,0x62,0xec,0x98}, + .key_len = 32, + .data = {0xd1,0x99,0x87,0x5b,0xb7,0x07,0x1c,0x43,0x4a, + 0xb2,0x36,0xe6,0xd1,0x0f,0x84,0x05,0x97,0x8f, + 0xca,0x25,0x9f,0x7c,0x34,0x93,0x94,0x24,0xea, + 0xa6,0xff,0x3a,0xe4,0x44,0xbd,0x79,0x00,0xa7, + 0xaf,0x8a,0x51,0x61,0xb3,0x28,0xba,0x9e,0xd3, + 0x82,0xbc,0xaa,0xbd,0xe1,0x8d,0xb3,0x73,0x8a, + 0x6a,0xcf,0x44,0xe6,0x2d,0x41,0xfb,0xe0,0x22, + 0xf8,0x56,0x8f,0x17,0x58,0xba,0x15,0xb2,0x3d, + 0x24,0xc7,0x08,0x3d,0x63,0x8e,0x6a,0x2e,0x85, + 0x8c,0x82,0xe8,0x8f,0x03,0xa0,0x4c,0x71,0x73, + 0x4e,0x86,0x38,0x03,0x2a,0x8e,0x86,0x22,0xf5, + 0xf5,0x3f,0x6e,0xe7,0xde,0x86,0xd5,0x45,0x4b, + 0xe8,0xfa,0x36,0x9a,0xd6,0xda,0xd3,0x4f,0x59, + 0xaf,0x7d,0x13,0x01,0x15,0x73,0xfd,0x1f,0x6b, + 0xa3,0x11}, + .data_len = 128, + .mac_len = 12, + .mac = {0x44,0x5a,0xa9,0x2b,0x03,0x2c,0x6b,0x65,0xb2, + 0x8a,0x65,0x41}, + }, { // 11 (76) + .key = {0x2a,0x43,0x2b,0x46,0x2e,0xbb,0x78,0x83,0x50, + 0x08,0xb4,0xaa,0x8a,0x92,0xb4,0x0f,0x6f,0xe9, + 0xdc,0x53,0xa9,0x63,0x35,0x2e,0xa5,0x07,0xc0, + 0x6c,0x8d,0xa9,0x0a,0x36}, + .key_len = 32, + .data = {0xac,0x76,0xa7,0xdb,0x96,0x4e,0x9f,0xad,0x2f, + 0x98,0xc1,0x8c,0x06,0xf9,0x29,0xf2,0x3b,0x62, + 0x17,0xee,0x35,0xef,0x45,0x25,0x92,0x0f,0x77, + 0x17,0x64,0xe6,0x53,0xa3,0x9a,0xef,0x73,0xcd, + 0xbc,0xe6,0xb9,0xc0,0xdc,0xe5,0xe2,0x0f,0xc9, + 0xcd,0x5e,0x40,0x85,0xe7,0x5f,0x8b,0xf9,0xcb, + 0x31,0xdf,0xe8,0x81,0xc9,0x26,0x22,0xe7,0xa0, + 0xca,0xfa,0x52,0xc2,0x78,0xf9,0x78,0x21,0x24, + 0xd4,0x8e,0x30,0x4d,0x9c,0xad,0xad,0x82,0x35, + 0x7a,0xbe,0x25,0x09,0x06,0x40,0x6f,0xfd,0xf3, + 0x5c,0xb4,0xa5,0xd9,0x5b,0xe8,0xb3,0xe7,0xbb, + 0x63,0xb6,0xce,0x82,0xe1,0x01,0xda,0xd2,0xcd, + 0xe8,0x62,0xbe,0xbf,0x33,0x63,0x5c,0x43,0xcc, + 0x68,0x1b,0xdc,0xbb,0xad,0x57,0x48,0x54,0x83, + 0x2b,0x06}, + .data_len = 128, + .mac_len = 12, + .mac = {0x2f,0x8e,0x18,0xb7,0x5c,0xb3,0x74,0x02,0xd6, + 0xe8,0x73,0x55}, + }, { // 12 (90) + .key = {0x58,0x10,0x24,0x23,0xa4,0x16,0x8f,0xa6,0x0a, + 0x5a,0xa7,0xf7,0x90,0x92,0xd5,0x23,0x26,0xc9, + 0x8e,0x22,0xee,0x5f,0x3d,0xff,0xdb,0x52,0x7d, + 0x39,0x7d,0xbb,0x8c,0x68}, + .key_len = 32, + .data = {0x48,0x0b,0xe7,0x58,0xa9,0xb7,0xba,0x9a,0xf0, + 0x01,0xbf,0x21,0xdb,0x00,0xc4,0x51,0xcf,0xd6, + 0x6f,0x06,0xc9,0xd8,0xd5,0xd6,0x98,0xef,0x47, + 0x97,0x4a,0x3d,0x6f,0x21,0xe4,0x04,0x9d,0x55, + 0x56,0xc4,0x5b,0x5f,0xad,0xa4,0x47,0x37,0x8b, + 0x13,0x22,0x6e,0xd4,0xaf,0x24,0x27,0xab,0x66, + 0x92,0x64,0x9d,0xdb,0x93,0x83,0x1b,0x0b,0x40, + 0x08,0x2e,0x30,0xfa,0x9c,0x66,0xe6,0x00,0x56, + 0x14,0x8c,0x40,0x3a,0xb8,0xed,0x6e,0xff,0xbd, + 0x1f,0x54,0x16,0x64,0xac,0x69,0xe7,0xff,0xf0, + 0xa4,0x5e,0x5f,0xc2,0x92,0xa6,0x8f,0x57,0xa7, + 0x34,0xc3,0x62,0xd2,0x08,0x8b,0x80,0x53,0x2f, + 0x4c,0xd4,0xd1,0x8d,0xf1,0xee,0xa7,0xd9,0xde, + 0xf2,0x80,0xe9,0x25,0xf6,0x23,0x30,0xfd,0xab, + 0x90,0x85}, + .data_len = 128, + .mac_len = 16, + .mac = {0x4c,0x41,0xbe,0xa8,0x23,0xee,0x67,0x91,0xe8, + 0x36,0x36,0xbf,0x75,0x2c,0x12,0x40}, + }, { // 13 (91) + .key = {0x81,0x6a,0xa4,0xc3,0xee,0x06,0x63,0x10,0xac, + 0x1e,0x66,0x66,0xcf,0x83,0x0c,0x37,0x53,0x55, + 0xc3,0xc8,0xba,0x18,0xcf,0xe1,0xf5,0x0a,0x48, + 0xc9,0x88,0xb4,0x62,0x72}, + .key_len = 32, + .data = {0x22,0x02,0x48,0xf5,0xe6,0xd7,0xa4,0x93,0x35, + 0xb3,0xf9,0x13,0x74,0xf1,0x8b,0xb8,0xb0,0xff, + 0x5e,0x8b,0x9a,0x58,0x53,0xf3,0xcf,0xb2,0x93, + 0x85,0x5d,0x78,0x30,0x1d,0x83,0x7a,0x0a,0x2e, + 0xb9,0xe4,0xf0,0x56,0xf0,0x6c,0x08,0x36,0x1b, + 0xd0,0x71,0x80,0xee,0x80,0x26,0x51,0xe6,0x97, + 0x26,0xc2,0x89,0x10,0xd2,0xba,0xef,0x37,0x96, + 0x06,0x81,0x5d,0xcb,0xab,0x01,0xd0,0xdc,0x7a, + 0xcb,0x0b,0xa8,0xe6,0x5a,0x29,0x28,0x13,0x0d, + 0xa0,0x52,0x2f,0x2b,0x2b,0x3d,0x05,0x26,0x08, + 0x85,0xcf,0x1c,0x64,0xf1,0x4c,0xa3,0x14,0x53, + 0x13,0xc6,0x85,0xb0,0x27,0x4b,0xf6,0xa1,0xcb, + 0x38,0xe4,0xf9,0x98,0x95,0xc6,0xa8,0xcc,0x72, + 0xfb,0xe0,0xe5,0x2c,0x01,0x76,0x6f,0xed,0xe7, + 0x8a,0x1a}, + .data_len = 128, + .mac_len = 16, + .mac = {0x17,0xcb,0x2e,0x9e,0x98,0xb7,0x48,0xb5,0xae, + 0x0f,0x70,0x78,0xea,0x55,0x19,0xe5}, + }, { // 14 (105) + .key = {0x89,0x58,0x68,0xf1,0x96,0x95,0xc1,0xf5,0xa2, + 0x6d,0x8a,0xe3,0x39,0xc5,0x67,0xe5,0xab,0x43, + 0xb0,0xfc,0xc8,0x05,0x60,0x50,0xe9,0x92,0x2e, + 0xc5,0x30,0x10,0xf9,0xce}, + .key_len = 32, + .data = {0x88,0x3e,0x6c,0xa2,0xb1,0x9e,0xf5,0x46,0x40, + 0xbb,0x83,0x33,0xf8,0x5a,0x93,0x80,0xe1,0x72, + 0x11,0xf6,0xee,0x3d,0x1d,0xc7,0xdc,0x8f,0x0e, + 0x7c,0x5d,0x67,0xb7,0x30,0x76,0xc3,0xea,0xfc, + 0x26,0xb9,0x3b,0xb2,0x48,0xc4,0x06,0xce,0xba, + 0x5c,0xb4,0xa9,0xbf,0xc9,0x39,0xf0,0xa2,0x38, + 0xe1,0x55,0x9d,0x0f,0x4d,0x84,0xf8,0x7e,0xb8, + 0x59,0x75,0x56,0x80,0x50,0xec,0x1f,0xe1,0x3d, + 0x33,0x65,0x03,0x3d,0x40,0x52,0x37,0xec,0x92, + 0x82,0x7d,0xd8,0xcd,0x12,0x4b,0x36,0xa4,0xfa, + 0x89,0xd4,0xfb,0x9d,0xe0,0x4f,0x4d,0x9f,0x34, + 0x86,0x4c,0xf7,0x6f,0x4e,0xc8,0x45,0x81,0x68, + 0xd2,0x65,0xa5,0xb0,0x21,0x44,0xe5,0x96,0xb5, + 0xf2,0xe0,0xd2,0xb9,0xf9,0xcb,0x54,0xae,0xee, + 0xb6,0x7a}, + .data_len = 128, + .mac_len = 20, + .mac = {0x37,0x4c,0x88,0xf4,0x48,0x0f,0x5e,0x8a,0xaa, + 0x9f,0x44,0x8b,0x77,0x75,0x57,0xc5,0x00,0x65, + 0xe9,0xac}, + }, { // 15 (106) + .key = {0x95,0x0f,0xb0,0xcd,0xe3,0x0f,0x34,0xf5,0x97, + 0xaf,0x5c,0xaa,0x2b,0x16,0xfc,0x86,0xa5,0xc3, + 0xef,0x06,0x5d,0x36,0xff,0xdd,0x06,0xec,0x04, + 0x8e,0xec,0x91,0x50,0x39}, + .key_len = 32, + .data = {0xe4,0x63,0x62,0x65,0x06,0x14,0x4c,0xec,0xe5, + 0x5d,0xfb,0x7a,0xa2,0x2e,0xb2,0x1e,0xa3,0xa4, + 0x27,0x7d,0x89,0x2c,0x21,0x17,0x62,0xea,0x45, + 0xcc,0x20,0x5c,0x2d,0x9e,0x4b,0x3a,0xbb,0xb8, + 0xf2,0xa1,0xad,0xb0,0xe7,0x71,0x71,0x09,0x2c, + 0xf4,0x3a,0xfc,0xa8,0xc0,0x53,0x77,0x1e,0xde, + 0xb4,0x67,0x60,0x2b,0xd3,0x33,0xc0,0xff,0xbc, + 0x88,0xc8,0x0d,0x64,0x5c,0x2b,0x8a,0x3a,0x2d, + 0xfa,0x92,0x00,0x8a,0x1b,0xc7,0xd9,0xd5,0xf8, + 0x3b,0xa3,0x47,0x74,0x90,0x86,0x34,0x23,0x5d, + 0xcd,0x91,0xba,0xd4,0xf5,0xb3,0xc4,0xa2,0x04, + 0x59,0x97,0x17,0x1d,0xed,0x87,0x87,0x50,0x07, + 0x59,0xf0,0xb6,0x33,0xfb,0xdc,0xbe,0xf4,0x72, + 0x89,0xc2,0x09,0x13,0x48,0xde,0xee,0xf6,0x23, + 0x01,0xa6}, + .data_len = 128, + .mac_len = 20, + .mac = {0x8c,0x90,0x48,0x0e,0xa6,0x41,0x45,0x53,0xdf, + 0x17,0xe5,0x3c,0xf9,0x6d,0xcb,0x16,0x6b,0x94, + 0xbe,0x35}, + }, { // 16 (120) + .key = {0x26,0x8b,0x0e,0x1f,0x11,0x00,0x52,0xaa,0xa2, + 0xee,0xe3,0x27,0xe3,0x4a,0xb3,0x49,0x02,0x98, + 0x06,0xda,0xf7,0x02,0x30,0x68,0x67,0xa7,0xa0, + 0x3b,0xc8,0x35,0x1d,0x8a,0xc7,0xba,0x50,0xee, + 0xe6,0xb7,0x83,0x16,0x6a,0x77,0xa8,0xbd,0x74, + 0x9e,0x9d,0xd9,0x6e,0x05,0xae,0x15,0xa8,0xc5, + 0x5c,0x82,0x43,0x92,0x5c,0x89,0x4f,0x4b,0xe3, + 0x25}, + .key_len = 64, + .data = {0x7c,0x88,0x1d,0xe0,0x03,0x88,0xa0,0x0f,0x8c, + 0xee,0xa8,0x87,0xb8,0xe8,0x7e,0xf7,0xce,0xb2, + 0x3e,0xa0,0x5d,0xad,0x95,0x06,0x23,0xb0,0xca, + 0xeb,0x2e,0xa2,0xfb,0x7d,0x41,0x49,0xaa,0xcf, + 0x79,0x5d,0x78,0x86,0x30,0xe1,0x2f,0xd5,0x22, + 0xb3,0x06,0xab,0xce,0x61,0x21,0x2a,0x20,0x3e, + 0x58,0x5c,0x4c,0xb5,0x39,0x21,0xfd,0xde,0x50, + 0x6c,0xaf,0x4f,0xa6,0xaf,0x59,0x35,0x87,0x94, + 0x50,0xa3,0x88,0xee,0x68,0x29,0xc9,0xef,0x5c, + 0xa9,0x78,0x9b,0x70,0x66,0x96,0x7c,0x54,0x5e, + 0xfe,0x98,0x4c,0xda,0xa3,0xa0,0x8e,0x43,0x19, + 0x6a,0xeb,0x37,0x57,0xa1,0xb2,0xdc,0xbb,0xbc, + 0xd2,0x74,0x4e,0x2c,0x3e,0x32,0x4a,0xda,0x96, + 0x4c,0xd9,0xd0,0x03,0x52,0x20,0x36,0x63,0xbe, + 0x7c,0x81}, + .data_len = 128, + .mac_len = 10, + .mac = {0xe0,0x6c,0x08,0x6d,0x34,0x34,0xd7,0x95,0x95,0xd3}, + }, { // 17 (121) + .key = {0x77,0xc1,0x92,0x47,0x22,0x53,0x68,0x5d,0x52, + 0xa6,0xfc,0x39,0x3b,0xb7,0xa9,0xd5,0xbd,0x73, + 0xf5,0xaf,0x2b,0x6e,0x74,0x20,0x50,0xd7,0xea, + 0xe9,0xb4,0xac,0xb0,0x0f,0x1b,0x2a,0x59,0xea, + 0x4f,0x88,0x94,0x78,0x1f,0xe4,0x54,0xf7,0xa8, + 0x7e,0x2f,0xb2,0xd3,0x24,0x04,0x1b,0x1f,0xed, + 0xe1,0x1a,0xa1,0x2a,0x24,0xa5,0x49,0x9a,0xe0, + 0x91}, + .key_len = 64, + .data = {0x83,0x7d,0xc1,0x90,0xbf,0x0a,0x96,0xd9,0xc7, + 0x87,0x9d,0x8d,0x99,0x8c,0x5c,0x21,0xa2,0x63, + 0x47,0x51,0x80,0xbc,0x9c,0x70,0x0c,0xa2,0x8c, + 0xfc,0x98,0xae,0x9b,0x75,0x75,0x7b,0x49,0x6f, + 0xb9,0x59,0xf2,0xe7,0x3e,0x46,0xf3,0xd3,0xee, + 0x1a,0x0e,0xfc,0x3e,0x01,0x10,0x10,0xf9,0x2e, + 0xb0,0xf3,0x3f,0xce,0xbb,0x57,0xcd,0x3b,0x6e, + 0x8c,0x7f,0x73,0x23,0x99,0x12,0xc8,0x31,0x8b, + 0x2f,0xd9,0x0d,0x0d,0xa5,0xc0,0xb5,0x39,0xf7, + 0x8d,0x4e,0xae,0x16,0xf4,0x0b,0xe3,0x6f,0x42, + 0x52,0xbb,0x28,0x95,0x1a,0x59,0xa7,0x4d,0x98, + 0x35,0x55,0xbe,0x1a,0x6f,0xa1,0x27,0x33,0x64, + 0x47,0xe8,0x18,0x80,0xd2,0xef,0x4a,0x53,0x5f, + 0x74,0x75,0xe6,0xa5,0xe6,0x98,0x4f,0x32,0x25, + 0x67,0x83}, + .data_len = 128, + .mac_len = 10, + .mac = {0x2d,0x0f,0x6c,0x93,0x5a,0x06,0xd9,0xd4,0x8e,0x10}, + }, { // 18 (135) + .key = {0xb2,0x44,0xd3,0x05,0xbf,0xd5,0x34,0xde,0x7b, + 0x05,0xb6,0x6c,0xda,0x0b,0x7b,0xd3,0xc2,0x41, + 0x49,0x56,0xb5,0x36,0x46,0x11,0xb0,0xfe,0xff, + 0xea,0x53,0xcd,0xaf,0xc5,0x41,0xc5,0xbf,0xf7, + 0xca,0x0b,0x89,0xfd,0xc8,0x20,0x61,0x6f,0xc6, + 0x6f,0xd6,0x2f,0x68,0x22,0x35,0xe6,0x07,0x3a, + 0x4f,0xb1,0x9b,0xdf,0x7c,0x17,0xde,0xf4,0xe0, + 0x3f}, + .key_len = 64, + .data = {0xf5,0x4c,0x5e,0x14,0xa2,0x9a,0xbb,0x69,0x9f, + 0xea,0x35,0x04,0xf4,0xb9,0xa0,0x77,0xbd,0x40, + 0xa4,0xdd,0x72,0xa6,0x1c,0xb5,0x6c,0x75,0xbd, + 0xf0,0xa5,0x4b,0xf8,0x48,0xc0,0xd2,0x21,0xd4, + 0x49,0xf1,0xd0,0xd9,0x3d,0x44,0x88,0xe4,0xcd, + 0xca,0x96,0x15,0x5f,0xde,0x3c,0xbe,0xd6,0x69, + 0x0f,0x2d,0x13,0x55,0x9e,0xc5,0xbb,0x45,0x54, + 0x54,0x3b,0x83,0xa0,0xa0,0x0a,0x39,0x52,0x43, + 0x2e,0xe5,0x49,0xb9,0x02,0x07,0x4b,0xb8,0x36, + 0x1c,0x34,0xbf,0x17,0xd0,0x53,0xf2,0x11,0x70, + 0x11,0x25,0x72,0x9e,0xd3,0x37,0x70,0x48,0x22, + 0xa1,0x6e,0xdb,0x0a,0x4e,0x7b,0xb3,0xbf,0xae, + 0x1c,0xd7,0x87,0x06,0x4b,0xe3,0xd3,0x0a,0xbf, + 0x45,0xaf,0xad,0x6e,0xac,0x5d,0x38,0x51,0xbe, + 0x3d,0x99}, + .data_len = 128, + .mac_len = 12, + .mac = {0xe6,0x85,0xc2,0x6a,0x4e,0xf7,0x66,0xa1,0xac, + 0x24,0x4b,0xf7}, + }, { // 19 (136) + .key = {0xf3,0xcb,0x2c,0xba,0xaf,0xe6,0x28,0x1e,0xbb, + 0x54,0x6a,0xf8,0x8c,0x05,0x2e,0x66,0x58,0xa5, + 0x84,0x07,0xcd,0x7b,0xa3,0x05,0x02,0x91,0x80, + 0x52,0xae,0x15,0x9f,0x31,0x98,0xff,0x29,0xf9, + 0x4e,0xf4,0x40,0x15,0x1a,0x6a,0x8f,0x50,0x32, + 0x0e,0x25,0x50,0x2f,0x62,0x83,0x5f,0xc0,0xab, + 0xf3,0x72,0xa0,0x0a,0x1c,0x63,0xc5,0xe9,0xd4, + 0x82}, + .key_len = 64, + .data = {0x8f,0x63,0x60,0x70,0xd8,0xc5,0xc1,0xf9,0x79, + 0x73,0x4a,0xe3,0x6a,0xcf,0xe6,0x3f,0x0c,0x08, + 0x17,0x53,0x1a,0x3f,0x8d,0xe1,0xdd,0xe9,0xf7, + 0xad,0xa0,0x75,0x19,0x39,0x64,0x2e,0x1e,0xd3, + 0xd5,0x62,0x30,0xd1,0x7c,0xc4,0x47,0x1c,0x35, + 0x0f,0x3e,0xeb,0xe4,0xec,0x2c,0xd1,0x64,0x16, + 0xf1,0xfa,0xc0,0xbc,0x0f,0xb2,0xa6,0x27,0xbc, + 0x26,0x18,0x9c,0x35,0x6f,0x65,0x84,0x54,0xcc, + 0x58,0xca,0x65,0x2f,0xaf,0x85,0x36,0xfc,0xce, + 0xd7,0x6d,0x0d,0xb5,0x14,0x1e,0xf9,0x30,0x27, + 0x9d,0x96,0x4d,0x32,0x91,0xbc,0x13,0x75,0x4a, + 0x4c,0x71,0x71,0x55,0x71,0x75,0x4d,0x4d,0x26, + 0xbf,0x78,0xf3,0xf9,0x34,0x90,0x81,0x0e,0xf7, + 0x83,0x3c,0x66,0x95,0xf4,0x49,0x61,0x7f,0xe0, + 0xc1,0x82}, + .data_len = 128, + .mac_len = 12, + .mac = {0x3b,0xf0,0xf6,0xf4,0xac,0x75,0x7a,0xfb,0x9d, + 0xea,0xfd,0xb3}, + }, { // 20 (150) + .key = {0x8e,0xcc,0xd4,0x67,0xd8,0x75,0x83,0x9c,0xb4, + 0xb0,0xa0,0x17,0x0a,0x97,0x6f,0x60,0x56,0x87, + 0x68,0x59,0xfb,0x24,0x2f,0x69,0xd9,0x9d,0xc6, + 0xda,0x21,0x32,0x02,0x80,0x68,0xf3,0x3b,0x9c, + 0xfb,0xca,0x48,0xff,0x73,0xbb,0xaa,0x73,0x89, + 0x6b,0x08,0x56,0x2b,0xdf,0xdc,0x88,0xcf,0x87, + 0x6b,0x88,0x07,0x7b,0xfa,0xd9,0x55,0x04,0x3f, + 0xab}, + .key_len = 64, + .data = {0xa6,0x7b,0x1d,0xc3,0x63,0x3d,0x30,0xc4,0xef, + 0x2b,0xf3,0x18,0x5f,0xd4,0x48,0x65,0xd2,0xaf, + 0x5e,0x72,0x01,0x5c,0xdf,0x8c,0x18,0x2e,0x6b, + 0x28,0xc5,0xe7,0x46,0xc9,0x8e,0xc2,0x4d,0x24, + 0x67,0xb7,0x2f,0x82,0x84,0xfa,0xd9,0x67,0x6c, + 0xc5,0x32,0x71,0x4f,0x57,0x09,0x82,0x99,0x3d, + 0x4b,0x22,0xc7,0xd0,0x7a,0x1e,0x79,0xff,0x5a, + 0x75,0xc9,0x4e,0xee,0x75,0xdc,0x1f,0xa2,0x22, + 0xb6,0x30,0xca,0xd7,0x53,0x66,0x4b,0x30,0xf3, + 0xc9,0x98,0x26,0xb5,0xcf,0xe1,0x7c,0x67,0xdd, + 0x87,0x5b,0x9d,0x0b,0xd2,0x39,0x00,0x28,0xe6, + 0xff,0xe9,0xfe,0xf3,0x6a,0x2f,0xd6,0xad,0xb1, + 0x3d,0x3f,0xfc,0x69,0x67,0x0c,0xf4,0xa6,0x7e, + 0x9c,0x07,0x64,0xa1,0x5e,0x79,0x25,0x57,0x93, + 0x15,0xdb}, + .data_len = 128, + .mac_len = 16, + .mac = {0xf3,0x5a,0x43,0x23,0xca,0xb7,0xad,0xe7,0x16, + 0x8c,0x8b,0x9f,0x72,0x76,0x74,0x4e }, + }, { // 21 (151) + .key = {0xb4,0x88,0x33,0x2a,0x10,0xf2,0xbc,0x7d,0x90, + 0x42,0xa1,0x93,0x3d,0xa8,0x5d,0xcc,0x89,0x25, + 0x04,0xbe,0x3e,0xa8,0xd5,0x7b,0xb5,0x78,0x0f, + 0x16,0x48,0xd1,0x07,0x63,0x09,0xd2,0x76,0xff, + 0xb5,0x97,0x17,0x90,0xe3,0xa2,0x72,0x4e,0x81, + 0x7f,0xf2,0xc3,0x81,0xa7,0x3e,0xce,0xd0,0xa6, + 0xc6,0xee,0x88,0x79,0x9c,0xbd,0x66,0x3a,0x86, + 0xbb}, + .key_len = 64, + .data = {0xa9,0x17,0x4a,0x67,0x60,0x3a,0x4d,0x5f,0xba, + 0xa8,0xcf,0xb5,0x62,0xf0,0x73,0x93,0xab,0xad, + 0xbc,0x80,0xd1,0xb5,0x72,0x31,0x82,0x93,0x47, + 0xa2,0x9c,0x38,0xba,0x66,0x39,0xed,0x3c,0x3c, + 0xe9,0x8c,0x91,0xe2,0x3e,0xf0,0x7a,0x2e,0x8e, + 0xaa,0x91,0x5a,0xf4,0xf5,0x74,0xa0,0x98,0xed, + 0x25,0x06,0x30,0xfb,0xb1,0x7c,0xc7,0x94,0x10, + 0x24,0xbd,0x23,0x4d,0xf1,0x10,0x43,0xe7,0x73, + 0xd9,0x32,0x76,0xf1,0x1a,0x82,0x91,0xb9,0xb6, + 0x12,0xf0,0xb4,0xc1,0x3d,0xce,0x3d,0xfa,0x51, + 0x91,0x33,0x96,0x43,0xad,0x4d,0x40,0xa1,0xc6, + 0xae,0x5d,0xc7,0x15,0xba,0x94,0x56,0x0c,0x27, + 0x8e,0xe2,0x3d,0x57,0xfa,0xeb,0x78,0xe5,0xd5, + 0x0f,0x33,0x7e,0xe8,0x7d,0x2f,0xf2,0x92,0xad, + 0x59,0x8a}, + .data_len = 128, + .mac_len = 16, + .mac = {0x59,0xa1,0x16,0xa2,0x49,0xea,0xca,0xff,0xc5, + 0x44,0x98,0x95,0x77,0x87,0xf8,0xf4}, + }, { // 22 (165) + .key = {0xb9,0x57,0x5f,0x4d,0x5e,0xcc,0x0f,0x4f,0x62, + 0xe4,0xa0,0x55,0x6b,0xb8,0x94,0x64,0xba,0x97, + 0xd4,0x57,0x0e,0x55,0xac,0xd4,0xc5,0xe5,0x17, + 0x7e,0x45,0x2a,0x3d,0x6c,0x9a,0x0b,0x3a,0xdb, + 0x60,0xc6,0x21,0x1f,0xe4,0x86,0x40,0xe0,0x86, + 0x37,0xa6,0x82,0x62,0x99,0xe3,0xe5,0x2f,0x93, + 0x0f,0x4f,0x66,0xcb,0x0e,0xa6,0xa7,0x73,0x11, + 0xe3}, + .key_len = 64, + .data = {0x8c,0x83,0x87,0xf4,0xae,0x2c,0xa1,0xa6,0xdd, + 0x13,0xd2,0x9e,0x93,0x58,0x0b,0x1c,0xdf,0x62, + 0x68,0xda,0x66,0xcf,0x58,0x9c,0xa8,0xb1,0xff, + 0x08,0x84,0xf7,0xd8,0xb8,0xfe,0x29,0x9f,0x8e, + 0x41,0x59,0x6e,0x47,0xe0,0x56,0x26,0x53,0x61, + 0x22,0x10,0xe4,0xfc,0xa6,0xc4,0x46,0xa0,0xa5, + 0x4a,0x6e,0x37,0xef,0x80,0xd5,0x2b,0xd7,0xbb, + 0x87,0x29,0xe6,0xb1,0x76,0x25,0xd1,0x97,0x15, + 0x9e,0xa9,0x86,0x22,0x23,0x52,0x23,0xc3,0x16, + 0x36,0x7f,0xd5,0xb0,0x3a,0x3c,0x81,0x45,0xf2, + 0xf2,0x10,0xc9,0x10,0xd0,0x00,0x94,0x23,0x87, + 0x57,0x62,0x7e,0x63,0x37,0x9e,0x75,0xbb,0xb3, + 0xe0,0xd0,0x8c,0xe1,0xb4,0x79,0x61,0x30,0x9d, + 0x78,0x76,0xfc,0x59,0x21,0x1c,0x60,0x67,0x8c, + 0x5f,0x4c}, + .data_len = 128, + .mac_len = 20, + .mac = {0x15,0xaf,0x23,0x33,0x16,0x48,0x17,0x14,0x99, + 0xb5,0x80,0x42,0xdb,0xe7,0xb2,0xd5,0xdf,0x72, + 0xd1,0x52}, + }, { // 23 (166) + .key = {0xd2,0x91,0xad,0xbf,0x05,0xb0,0x65,0x96,0xc2, + 0xf3,0x6f,0x41,0xa8,0xcd,0x80,0x70,0x37,0x0c, + 0x42,0xf6,0x87,0xb8,0xa6,0xcc,0x3a,0x3e,0x7b, + 0x59,0xaf,0xcd,0x40,0xf0,0x78,0x01,0x36,0x9b, + 0x0f,0xbf,0xba,0x17,0xc4,0x60,0xd2,0x1f,0xfa, + 0x11,0x06,0xee,0x93,0x79,0x71,0xff,0xa9,0x9d, + 0x17,0x17,0x7f,0x01,0x79,0x85,0xb7,0x10,0x67, + 0xa8}, + .key_len = 64, + .data = {0x50,0xbc,0xdf,0x31,0x38,0x9e,0xad,0xac,0x5b, + 0xb8,0x19,0x7e,0xe9,0x49,0xf2,0x86,0x4e,0xde, + 0x28,0x4c,0x07,0xd0,0x39,0xa0,0xb4,0x0e,0xed, + 0x7e,0x6f,0x1c,0x43,0x35,0x5d,0x5c,0xab,0xc8, + 0x82,0x8d,0x75,0x95,0xda,0x91,0x8a,0x34,0xa5, + 0x73,0x5a,0xa2,0x02,0xa8,0x15,0x9f,0xbf,0x95, + 0x1e,0x54,0x70,0x52,0xbd,0x39,0xbe,0xae,0x14, + 0x36,0x02,0x73,0x54,0x09,0x13,0xeb,0x30,0xe7, + 0x5b,0xa2,0x92,0x66,0x31,0x6e,0x8d,0x9a,0x63, + 0xad,0x94,0x7e,0x11,0xce,0xe9,0x96,0xc2,0x13, + 0x57,0xd3,0xb1,0x94,0x24,0xb7,0x68,0x88,0x42, + 0xb9,0x90,0xc0,0xc5,0xeb,0x08,0x74,0x9a,0xda, + 0x34,0x42,0x75,0xb6,0x98,0x74,0x0b,0xb3,0xa5, + 0x82,0x82,0xae,0xd2,0xd7,0x25,0x14,0xef,0xd8, + 0x5d,0x00}, + .data_len = 128, + .mac_len = 20, + .mac = {0x5f,0x7a,0x57,0xd4,0x2e,0x3e,0xbb,0xcb,0x85, + 0xb0,0x85,0x65,0x30,0x4d,0xab,0x94,0x1d,0x62, + 0x34,0xf3}, + }, { // 24 (180) + .key = {0x15,0x0d,0x3a,0xa3,0x09,0xa3,0x66,0x9a,0xf9, + 0x9a,0x70,0xf2,0xce,0xc5,0x2d,0x3d,0xa1,0x6b, + 0x1c,0x13,0x7f,0xf7,0x46,0x62,0x69,0xf2,0x68, + 0x05,0x9f,0x2f,0x54,0x98,0x1f,0x45,0x95,0x8b, + 0x68,0x42,0x52,0x76,0x83,0x9e,0x75,0xac,0x44, + 0x6e,0x0b,0x13,0xce,0xda,0xee,0x33,0x55,0xd1, + 0xa2,0x8c,0x28,0xfc,0x7e,0x2d,0xee,0xf0,0x0c, + 0x82,0x2f,0xa7,0xb2,0x6e,0x17,0x31}, + .key_len = 70, + .data = {0x07,0x35,0x5a,0xc8,0x18,0xce,0x6b,0x46,0xd3, + 0x41,0x63,0xae,0xec,0x45,0xab,0x17,0x2d,0x4b, + 0x85,0x0b,0x0d,0xbb,0x42,0xe6,0x83,0x81,0xb6, + 0x7f,0x1c,0xc8,0xe9,0x0a,0x4c,0x05,0x0f,0x3d, + 0x01,0x38,0xba,0xb2,0x7e,0x6f,0x4f,0x8d,0x67, + 0x8b,0xb6,0x5e,0x18,0x46,0x56,0x49,0x3b,0x75, + 0x41,0x64,0x9a,0x8b,0xab,0x60,0x31,0x5f,0xa1, + 0x6c,0x88,0x2f,0xf8,0x56,0x40,0xe4,0x83,0xf3, + 0xeb,0x97,0x89,0xc2,0x21,0x55,0x75,0xcc,0xd0, + 0x1f,0xd0,0xce,0xd3,0x35,0x6d,0x9a,0xc6,0x95, + 0xe3,0xbb,0x19,0xbe,0x40,0x58,0x64,0xb9,0xfc, + 0x5b,0xfa,0x5a,0x2c,0xd1,0xc1,0xc4,0xf8,0x94, + 0x41,0x2b,0x4f,0x28,0xfa,0xde,0xda,0xe4,0xfb, + 0x84,0x2e,0x52,0xb0,0xa5,0x45,0xd8,0xfc,0x6d, + 0x2f,0x97}, + .data_len = 128, + .mac_len = 10, + .mac = {0xc7,0x3d,0x3c,0xf2,0xbd,0x6c,0x5c,0x9d,0xcb,0x91}, + }, { // 25 (181) + .key = {0xc9,0xc8,0xb8,0x91,0xb8,0x25,0x67,0x75,0x7d, + 0xbf,0x1a,0x15,0xb3,0x17,0x62,0x8d,0x98,0xc4, + 0x86,0xdb,0xbe,0x5e,0xd4,0xe6,0x04,0x9a,0x35, + 0xbf,0xc5,0xb6,0x04,0x26,0x4f,0x18,0x20,0x50, + 0x97,0x32,0x40,0xe7,0x2b,0xa8,0x87,0x53,0x67, + 0xb5,0x59,0x38,0xec,0xcb,0x6c,0x3f,0x4e,0x79, + 0x22,0x1a,0x0d,0x92,0x16,0xc2,0xc7,0x8c,0xf4, + 0x03,0xab,0x26,0x8f,0x3b,0x31,0x4d}, + .key_len = 70, + .data = {0x17,0x92,0x59,0x52,0xaf,0x30,0x95,0x9b,0x1a, + 0x5a,0x13,0x6f,0xf1,0x1b,0x3d,0xe1,0x0d,0xb6, + 0xe4,0xce,0xe1,0x9f,0x31,0x08,0x0d,0xcb,0xde, + 0xb4,0x31,0x29,0xa5,0xf1,0xff,0x71,0xf9,0xbb, + 0x95,0x1c,0xf5,0x0e,0x09,0xb3,0x92,0x4e,0x45, + 0x4d,0x1c,0xe6,0x15,0x54,0xe7,0x30,0x7e,0x87, + 0x3e,0x95,0x52,0x45,0x9c,0xf5,0x01,0x08,0x1f, + 0x48,0xb2,0x30,0x39,0x86,0x92,0x02,0xa9,0xc5, + 0x6c,0xf0,0xa9,0xa1,0x7b,0x1a,0x69,0xe1,0x7c, + 0x16,0xbd,0x58,0x06,0xec,0x12,0x08,0x1e,0x65, + 0xa7,0x8e,0x07,0x86,0xfa,0xba,0x57,0x57,0x80, + 0x7d,0x50,0xe9,0x98,0x08,0x6c,0x96,0xc2,0x32, + 0x3a,0x8b,0x0c,0x1a,0x69,0x84,0xce,0x0e,0x22, + 0xd7,0x97,0xac,0x9c,0xb4,0x67,0x47,0xea,0xab, + 0x1f,0x8d}, + .data_len = 128, + .mac_len = 10, + .mac = {0x3b,0x89,0xbc,0x8d,0x9f,0x3f,0xbe,0xdb,0x86,0xa8}, + }, { // 26 (195) + .key = {0x08,0x6d,0x40,0xb5,0xbb,0xe7,0x5d,0xfa,0x59, + 0x05,0x54,0x5f,0x83,0xbc,0xd5,0x2d,0x71,0x2f, + 0x09,0x2f,0xce,0x2c,0x0f,0x5c,0xc9,0xfa,0xac, + 0xb5,0x69,0x52,0x3e,0x71,0x20,0xab,0xf2,0x58, + 0xa4,0xbb,0x37,0x6d,0xfa,0x3a,0x73,0xcf,0xd3, + 0xe9,0xf4,0xe1,0x1c,0xd3,0x29,0xa9,0xd1,0xd2, + 0x12,0x76,0x12,0x56,0xf5,0xc6,0x78,0x62,0x53, + 0x66,0xa9,0xd7,0x1a,0xdb,0x2a,0xf5}, + .key_len = 70, + .data = {0x33,0xfc,0xb8,0xef,0xf4,0x17,0x86,0x63,0x44, + 0x63,0x2d,0x0f,0x9e,0x81,0x98,0xc4,0xdb,0xee, + 0x1c,0x13,0x9e,0xda,0xfe,0xbd,0xef,0x37,0x35, + 0x6b,0x26,0x10,0x72,0x9f,0x0b,0x1c,0x5e,0xeb, + 0x3b,0x93,0x22,0x61,0xce,0x40,0x2d,0x4a,0x36, + 0xd8,0x31,0x1b,0x6a,0x8a,0x6f,0xa4,0x45,0xd7, + 0x35,0x8b,0x28,0xa4,0xa5,0xf9,0xe7,0x8d,0xb7, + 0x93,0xe3,0x7d,0x82,0xac,0x73,0x7b,0xb7,0xb8, + 0x89,0xc7,0x6e,0x04,0x92,0x26,0x25,0xa5,0x9d, + 0x7a,0x05,0xaf,0xc0,0x95,0x68,0xa7,0xb7,0x4f, + 0x99,0x3a,0xcf,0xd6,0xda,0x2e,0x03,0x46,0xac, + 0x9a,0x64,0x7a,0x4a,0x52,0xbe,0x21,0x77,0xa6, + 0x78,0x14,0x79,0x4c,0xbc,0xe7,0x66,0x9a,0xd8, + 0xbd,0x9e,0xf8,0xe4,0x61,0x99,0x96,0xa5,0x93, + 0xe3,0x5a}, + .data_len = 128, + .mac_len = 12, + .mac = {0x14,0xad,0x91,0x5c,0x81,0x90,0x56,0x7f,0x88, + 0x91,0x60,0xf9}, + }, { // 27 (196) + .key = {0x57,0x44,0x61,0x8f,0xe8,0xe5,0xc1,0xe4,0xca, + 0xd9,0x5c,0xf4,0x35,0x05,0xcc,0x03,0x2d,0xf1, + 0xcf,0xe5,0x04,0x34,0xed,0x13,0x20,0x2d,0x5b, + 0xfe,0xfe,0xf4,0x20,0xa3,0x77,0x90,0x76,0x60, + 0x42,0x6b,0x73,0x06,0xbb,0x03,0xe8,0x2f,0xe2, + 0xe1,0x8a,0xd2,0xa7,0xcf,0x4f,0x14,0x65,0x46, + 0x1b,0x61,0xac,0x26,0x9c,0xbc,0x43,0xa9,0x72, + 0x53,0x6d,0x9a,0x94,0x57,0x6c,0xc2}, + .key_len = 70, + .data = {0x90,0xa0,0x2b,0xc5,0xf2,0x6d,0x2c,0xcc,0x03, + 0x0b,0x15,0x03,0xc6,0xc7,0x12,0xb8,0xe6,0xef, + 0x4b,0x41,0xec,0x33,0xb8,0x87,0xb4,0x51,0x37, + 0xc1,0x22,0xf2,0xdc,0x82,0x11,0xce,0x88,0xf6, + 0x8c,0x17,0xbd,0x68,0x41,0x15,0xb0,0x08,0x32, + 0x0e,0xa0,0xec,0xae,0x68,0x67,0x54,0x80,0x11, + 0x4f,0x32,0x66,0x1f,0x26,0xea,0xc5,0xb4,0x95, + 0x56,0x9a,0x25,0xad,0x0d,0xb4,0x5b,0xc3,0xe5, + 0x21,0x79,0x7e,0xb6,0xe6,0xbe,0x2e,0x61,0xf3, + 0xae,0x5f,0x11,0x55,0x6c,0xaf,0xc1,0xae,0x6b, + 0xdc,0xff,0xe2,0x45,0x21,0xef,0x14,0xeb,0xc3, + 0x92,0xd1,0xff,0xe7,0x48,0x8a,0x7e,0xa6,0x94, + 0x48,0xa2,0x63,0x20,0x9b,0x07,0x5c,0x01,0xd3, + 0x0c,0x80,0x3b,0x73,0x7c,0x81,0x88,0xe3,0x6e, + 0x29,0x55}, + .data_len = 128, + .mac_len = 12, + .mac = {0x43,0xbf,0x10,0x01,0xad,0x1f,0x5c,0x5a,0xdf, + 0x0f,0x59,0xc2}, + }, { // 28 (211) + .key = {0x4a,0x25,0xe3,0xa8,0x8e,0xae,0x86,0x48,0x51, + 0xb4,0xc6,0xd0,0x1c,0x6b,0x98,0xb7,0x99,0xa7, + 0x0f,0x0c,0xa4,0x9f,0x18,0x60,0xa4,0xf1,0x67, + 0xdf,0x1c,0xe7,0xb1,0xc0,0x7d,0xf9,0x1c,0xe0, + 0x3f,0x93,0xf4,0xa9,0x2f,0x18,0x9f,0x39,0x0b, + 0x26,0xd3,0xc0,0x4c,0x1c,0x06,0x2a,0x43,0xd9, + 0x26,0xff,0x67,0xc7,0x8b,0x87,0xee,0x19,0x2a, + 0x31,0x9a,0x50,0x0b,0x35,0xd6,0x04}, + .key_len = 70, + .data = {0x72,0x72,0xef,0xf0,0xb2,0x89,0x64,0xa1,0xaa, + 0xbf,0xa0,0x8f,0x37,0x52,0x7a,0x86,0x07,0x04, + 0x3f,0xed,0xf3,0x1b,0xa6,0xee,0x8f,0xad,0x05, + 0xd8,0xff,0x1a,0xc4,0xc1,0x0c,0xda,0x12,0x6f, + 0x77,0x79,0xd8,0x79,0x8c,0xdf,0xeb,0xa9,0xfb, + 0xd5,0x86,0xa5,0xe4,0xc5,0xf7,0xce,0x31,0xc1, + 0x98,0x69,0x28,0xc7,0x01,0xfd,0x40,0x44,0x7c, + 0xfb,0x34,0xd6,0xba,0xa4,0x57,0x56,0xc4,0x28, + 0x27,0x16,0x33,0x0b,0x24,0x67,0xa4,0xcd,0xe3, + 0x5f,0x67,0xca,0x5e,0xd9,0x77,0x5f,0x8e,0xbc, + 0xaf,0x4e,0x3c,0x81,0x3a,0x64,0x14,0xef,0x4c, + 0x59,0xfb,0x29,0x0f,0xf7,0xa2,0xeb,0xe1,0x7e, + 0x5b,0x11,0xbc,0x48,0x2c,0x59,0xf5,0xa9,0x22, + 0x69,0x2a,0x19,0xe8,0x14,0x76,0x95,0x98,0xd9, + 0xe6,0x42}, + .data_len = 128, + .mac_len = 16, + .mac = {0x76,0x12,0x2c,0x55,0x82,0xfe,0xa3,0xb4,0xf5, + 0x91,0x81,0xcb,0x1d,0x83,0xa5,0xee}, + }, { // 29 (212) + .key = {0x13,0xe8,0xb6,0x56,0x8b,0x1d,0x83,0xee,0x06, + 0x23,0x52,0x23,0xca,0xf6,0xbe,0x6e,0x76,0x89, + 0x7f,0xfc,0x95,0x0a,0x9a,0x0f,0x74,0x68,0xd5, + 0xa2,0x31,0x13,0x6e,0x4c,0x15,0x03,0x0c,0x66, + 0x23,0xfb,0xf6,0x70,0xf1,0x0f,0x83,0xb1,0xb7, + 0x64,0xd2,0x1e,0xa6,0x37,0xba,0x7d,0x7b,0x20, + 0x04,0xca,0x53,0x98,0xd8,0xda,0xc1,0xba,0x76, + 0x3e,0x1e,0x46,0x27,0x6a,0x20,0xeb}, + .key_len = 70, + .data = {0xc2,0xc1,0xad,0x60,0x4e,0x21,0xc2,0xc8,0x69, + 0x19,0x3d,0x67,0x97,0xae,0x65,0x7e,0xe7,0x40, + 0x64,0x9c,0x78,0x05,0xee,0xb8,0x3c,0xb6,0x23, + 0x7d,0xfc,0x88,0xb7,0xe5,0x9d,0x5e,0x50,0x09, + 0xa1,0x3d,0x2f,0x38,0xf1,0x00,0x13,0x46,0xd9, + 0x4d,0x5a,0x26,0x54,0xc7,0x6a,0xbb,0x8a,0x85, + 0x4f,0xec,0x97,0xc4,0xa5,0xf7,0x8e,0xd8,0xb9, + 0x07,0xbd,0x69,0xeb,0x08,0x33,0xdb,0x57,0xba, + 0x80,0x0e,0xb4,0x04,0xbc,0x48,0x7b,0x8c,0xcb, + 0x6f,0x4c,0x84,0xde,0x7c,0x8f,0xc7,0x3d,0x2c, + 0x57,0x24,0x45,0xf8,0x8b,0xf9,0xac,0x48,0x47, + 0x04,0x0d,0xe4,0x80,0x77,0xa0,0xab,0xe7,0x4a, + 0x48,0x87,0x10,0xd5,0xd4,0xa0,0xd4,0x9e,0x7e, + 0xd0,0xf4,0x70,0xb8,0x58,0xfe,0xad,0x29,0xd1, + 0x75,0xe4}, + .data_len = 128, + .mac_len = 16, + .mac = {0x87,0xae,0x09,0x52,0x13,0x2a,0x3b,0x05,0x83, + 0x31,0x79,0x97,0xe5,0x90,0x7a,0xe4}, + }, { // 30 (225) + .key = {0xf0,0xda,0xe6,0xd8,0x75,0x30,0x76,0xb1,0x89, + 0x5c,0x01,0x26,0x2c,0xa9,0xb5,0x76,0x33,0xeb, + 0x28,0xb3,0xf9,0x63,0xa7,0xc7,0x52,0xe2,0xcb, + 0xb4,0xc0,0x31,0x4c,0x20,0xea,0xb1,0x1a,0x10, + 0x49,0x3f,0xaa,0xf4,0x25,0x5a,0x8e,0xe4,0xc0, + 0x88,0x49,0x29,0xd1,0xf5,0x61,0xff,0x33,0x5e, + 0xb6,0x99,0xdf,0x2d,0x11,0x66,0x18,0xe6,0x00, + 0x93,0xe5,0xc1,0xe2,0xd1,0xc4,0x99}, + .key_len = 70, + .data = {0x61,0xcb,0x9e,0x1f,0x1e,0x4b,0x3a,0x3b,0x3b, + 0xdf,0xf8,0xcd,0x5f,0x24,0x56,0x6b,0x98,0x7f, + 0x75,0xc8,0xa0,0x53,0x77,0x85,0x5f,0x77,0x2b, + 0x49,0xb0,0xe7,0xec,0x13,0x68,0xb9,0xc6,0xcf, + 0x95,0x53,0xdb,0x28,0x03,0xdc,0x05,0x9e,0x05, + 0xf0,0xbd,0xd8,0x71,0x98,0x3c,0x3b,0xed,0x79, + 0xdf,0xbb,0x69,0x4b,0xd0,0xf1,0xed,0x8d,0xe3, + 0x6e,0x95,0x77,0xbe,0x50,0xda,0x31,0x3d,0x13, + 0x12,0x42,0x15,0xa9,0x3a,0x4b,0xb7,0xcc,0xf4, + 0xf5,0x77,0x93,0xcc,0x28,0xed,0x43,0xbf,0x7e, + 0x9b,0x68,0xfe,0xf7,0xd1,0x25,0xef,0xee,0xce, + 0xc9,0x75,0x4b,0x28,0xa2,0x71,0xfb,0x6e,0x16, + 0x89,0x9d,0x0b,0xef,0x28,0x7e,0x6d,0xf7,0xc5, + 0xc8,0x67,0xc5,0x69,0xf6,0xd4,0xd6,0x6b,0x8b, + 0x7e,0xe0}, + .data_len = 128, + .mac_len = 20, + .mac = {0x62,0xac,0x95,0x6a,0xda,0x19,0xf0,0x4b,0xe5, + 0x0c,0x23,0xf2,0x32,0x8a,0x32,0x47,0x7c,0xd5, + 0x8f,0xb9}, + }, { // 31 (226) + .key = {0x65,0xaf,0x1f,0x17,0xcd,0x7f,0xda,0xa5,0x23, + 0xb9,0xb7,0xa9,0x82,0x9d,0x49,0x7c,0xac,0x73, + 0x03,0xd4,0x50,0xc5,0x9e,0x98,0x88,0xcb,0xba, + 0xf3,0xa6,0x27,0xc8,0xa8,0x30,0xd3,0x27,0xa5, + 0x29,0x57,0x8d,0xda,0x92,0x3f,0xa9,0x4b,0x31, + 0xcc,0x07,0x64,0x91,0xea,0x33,0x8d,0x4a,0x62, + 0x21,0xff,0x82,0x51,0xcc,0xd6,0xb4,0xd9,0x1e, + 0x67,0xb1,0x16,0x10,0xd3,0xe4,0x53}, + .key_len = 70, + .data = {0x9a,0xb4,0x66,0x7b,0x2d,0xf7,0xeb,0x4b,0xe8, + 0x86,0x3a,0xa5,0x3e,0x9b,0xf9,0xaf,0x8b,0xae, + 0x0f,0xc0,0x9d,0xe9,0x4f,0x73,0x73,0xdc,0x56, + 0xfa,0x44,0x72,0xb6,0xb5,0xc4,0x23,0x54,0x03, + 0xa2,0x6c,0x0e,0x59,0x55,0x7c,0xa1,0x91,0x18, + 0x31,0xca,0x84,0x33,0x42,0xac,0xda,0x7d,0xbe, + 0x72,0x21,0x1f,0xb5,0x35,0x1d,0x9a,0x34,0x20, + 0x5f,0x0c,0x77,0xd2,0x19,0xaf,0x5b,0x03,0x31, + 0xa2,0x12,0x6b,0x94,0xec,0x1a,0xdf,0xcd,0xbe, + 0x70,0xbe,0xd6,0xf8,0x01,0x8b,0x2e,0xef,0x61, + 0xdb,0x2b,0x6d,0xbf,0x72,0x92,0xfa,0x19,0xa9, + 0x65,0x5a,0xac,0x13,0xfc,0x57,0xaf,0x5f,0x57, + 0xc1,0x40,0x80,0xb3,0xb2,0x9f,0x0c,0x5b,0x16, + 0x9a,0xe2,0xc1,0x6b,0x48,0x10,0xcd,0xc6,0xfa, + 0xf4,0x75}, + .data_len = 128, + .mac_len = 20, + .mac = {0xa2,0x79,0xd0,0x55,0xe2,0xd7,0x33,0x06,0xa8, + 0x18,0x73,0x44,0xfc,0x32,0xcb,0x0b,0x5b,0x80, + 0xcd,0x35}, + }, { // 32 (240) + .key = {0x13,0xfb,0x1e,0xd6,0x38,0x9f,0x32,0xd1,0xde, + 0x31,0x39,0xcb,0x04,0xbc,0xdd,0x53,0x52,0x5c, + 0x98,0x89,0xb8,0x53,0x79,0xd3,0x53,0x5a,0x25, + 0xd2,0x90,0x35,0x1c,0x95,0x93,0x8a,0x3d,0x0c, + 0xda,0xf3,0x8d,0xbf,0x1d,0x52,0x34,0xbf,0x79, + 0x65,0xc8,0xdd,0xce,0x9a,0xce,0x1b,0x66,0x24, + 0x7e,0x60,0xd7,0x4e,0xc7,0x70,0x2a,0x0f,0x93, + 0x1a,0x3c,0xdf,0x4c,0xb4,0x65,0xca,0x9f,0xc4, + 0x58,0xc3,0x80,0x00,0x4a,0x3a,0x6e,0x79}, + .key_len = 80, + .data = {0x0c,0x36,0xca,0x43,0xe7,0xc1,0x13,0xed,0x9f, + 0xb7,0x16,0x70,0xb3,0xea,0x73,0xbf,0xd6,0x92, + 0x8c,0x83,0x9f,0x36,0xdb,0x1a,0x82,0xd0,0x8a, + 0xe0,0xff,0x2c,0x3d,0xae,0x19,0x91,0x33,0xa1, + 0x0a,0xa3,0x8d,0x1d,0x35,0x88,0xed,0x11,0x5c, + 0x4a,0x43,0x7c,0x13,0x7c,0xe4,0x30,0x74,0x21, + 0xdd,0xd6,0x15,0xc9,0x86,0x32,0x37,0xfd,0x5a, + 0xa8,0x40,0xdd,0x05,0xff,0x6c,0x08,0xbf,0x66, + 0xbf,0xbc,0xd9,0xb4,0x3e,0x3f,0x95,0xf4,0x5e, + 0x7d,0x3b,0x21,0xbd,0xf2,0x69,0x2e,0x10,0xca, + 0xab,0x49,0x5c,0x47,0x4b,0x61,0x6a,0x64,0x6b, + 0xe6,0x75,0xb8,0x50,0xd0,0x25,0x9c,0x01,0xe2, + 0xc1,0x90,0x11,0x30,0xa0,0xdb,0xb9,0xdf,0xe0, + 0x72,0x2a,0x2c,0x5b,0x1b,0x20,0xaf,0xd7,0xd2, + 0xbb,0xe1}, + .data_len = 128, + .mac_len = 10, + .mac = {0x76,0x53,0xdc,0x1c,0xa2,0xb7,0x0f,0x05,0x86,0x14}, + }, { // 33 (241) + .key = {0x5c,0xf5,0x9e,0x34,0xf1,0xae,0x4e,0xd7,0x32, + 0xa9,0x5c,0xee,0x65,0xeb,0x49,0x4c,0x1f,0x7e, + 0x89,0xe1,0xa2,0x72,0x7c,0xde,0x68,0x22,0x9f, + 0x1a,0x00,0xb9,0x04,0xb5,0x19,0xf4,0xff,0xfb, + 0xdd,0x29,0x23,0x8b,0x80,0x88,0x6c,0xb8,0x18, + 0xa1,0xbe,0x2f,0xaf,0x26,0x8e,0xda,0x96,0xf2, + 0xdf,0x05,0xfd,0x4b,0x71,0xc0,0xc1,0x64,0x35, + 0x84,0x85,0x26,0x03,0x19,0x04,0x30,0x8f,0xb6, + 0xa5,0x1d,0x9a,0x6b,0x51,0x05,0x65,0xbc }, + .key_len = 80, + .data = {0xab,0x5d,0xa4,0xa6,0x4f,0xbb,0xf3,0xc6,0x0f, + 0x5a,0xb1,0xf7,0x77,0x6e,0xd6,0xa5,0x57,0x51, + 0xe3,0x9a,0x5e,0xc8,0x19,0x67,0xea,0x88,0xe9, + 0x06,0x1f,0xf9,0xad,0xbd,0x37,0x39,0x95,0x45, + 0x18,0x64,0xe4,0x2c,0x2c,0x13,0x5c,0x78,0x6d, + 0x22,0xf6,0x8d,0xbf,0xb7,0xd7,0x51,0x83,0x7f, + 0x80,0x8d,0x69,0x3b,0x45,0x97,0x85,0x7c,0x00, + 0x2e,0xa6,0xaa,0x06,0xa5,0xe3,0x4b,0x5a,0x44, + 0x76,0x82,0x21,0xeb,0xce,0xd6,0x56,0xf8,0xdf, + 0x35,0xbf,0x6b,0xbd,0x39,0x20,0x48,0x69,0xaa, + 0xae,0x3d,0xea,0x43,0xc6,0x85,0xa0,0xb9,0xdf, + 0x0c,0xd6,0xf9,0xbe,0xd4,0x96,0xb1,0xe9,0x97, + 0xc1,0x13,0x5d,0xae,0x5f,0xd6,0x83,0x31,0x33, + 0x7d,0x61,0x60,0x92,0xdb,0x0d,0x41,0x76,0xd7, + 0x68,0x8b}, + .data_len = 128, + .mac_len = 10, + .mac = {0x8d,0xb9,0x4b,0xaa,0xaf,0x03,0xa5,0x1a,0xcc,0x87}, + }, { // 34 (255) + .key = {0x24,0xd8,0x93,0x8c,0x16,0x44,0xcb,0xb0,0x80, + 0xc4,0x50,0x55,0x39,0xe4,0x4c,0x8a,0x61,0x56, + 0x7c,0xa7,0x44,0x43,0x36,0x3b,0x80,0xdf,0xaa, + 0x46,0x6b,0x40,0x68,0xa9,0xaf,0x70,0x22,0xda, + 0x37,0xc1,0xb3,0xdc,0x4f,0x60,0x61,0x6f,0x06, + 0x2d,0x5f,0x84,0xd7,0xca,0x96,0xf3,0x89,0xf2, + 0xa6,0x70,0x54,0x0d,0x27,0xbc,0x45,0x01,0x34, + 0x18,0xe4,0x4a,0x2a,0xff,0x13,0x4d,0xad,0x14, + 0x39,0xe9,0xec,0x5a,0xa0,0x50,0x26,0xa3}, + .key_len = 80, + .data = {0xc0,0xb1,0x84,0xc7,0xb9,0xe4,0xcb,0x8d,0xd1, + 0x9a,0xf3,0x77,0x30,0x65,0x16,0xc5,0x63,0xb3, + 0xb8,0x78,0xba,0xa2,0x50,0xc1,0xee,0x16,0x05, + 0xb9,0x07,0x08,0xb5,0x52,0x7d,0x21,0x3b,0x8e, + 0x9e,0x87,0xf2,0xef,0x2f,0xf7,0x75,0x2e,0x56, + 0x14,0xa9,0x30,0xb8,0xfe,0xfe,0x35,0xde,0x27, + 0xf1,0x53,0xdd,0x62,0xd6,0x23,0x36,0x3d,0xd4, + 0xba,0xfb,0x91,0x31,0xda,0x33,0x57,0xcf,0x6a, + 0x80,0xbd,0xf7,0x24,0xff,0x7a,0x56,0x8e,0x70, + 0x5e,0x45,0x2b,0x97,0x2d,0x4e,0xf2,0xe1,0xad, + 0xeb,0xff,0x4b,0xfe,0x90,0x89,0x80,0x2a,0xec, + 0x14,0x41,0xfd,0x6d,0xe7,0x0a,0x17,0x02,0xc1, + 0xf3,0x3f,0x24,0xc8,0xd4,0xfa,0x17,0xc2,0xac, + 0x5c,0x6d,0x87,0x44,0x1f,0xcd,0xb6,0x0f,0xf2, + 0xf2,0xa8}, + .data_len = 128, + .mac_len = 12, + .mac = {0x1d,0x1d,0x12,0xf4,0xff,0x4e,0x0d,0xeb,0xb7, + 0x15,0xb9,0xcb}, + }, { // 35 (256) + .key = {0x4b,0xdc,0x4b,0x88,0x62,0x95,0x68,0x99,0x37, + 0x3d,0x3d,0xf4,0xda,0x72,0x81,0xc0,0xea,0x2b, + 0xdd,0x57,0x63,0x40,0x59,0xef,0xb8,0x2d,0x15, + 0x7a,0x22,0x13,0x39,0xcb,0x37,0xff,0x2e,0xf9, + 0xbe,0x6f,0x0f,0x08,0xc2,0x12,0x5a,0xc6,0xe5, + 0xd0,0xec,0xf4,0xf7,0x0a,0x2c,0xa6,0xc7,0x23, + 0x86,0xed,0x39,0x3f,0x1b,0xb2,0x99,0x4a,0xb6, + 0xe5,0x2f,0x3d,0x02,0xd8,0x14,0x9c,0xfb,0xe5, + 0x44,0x43,0xa3,0x57,0xf3,0x63,0xf6,0x88}, + .key_len = 80, + .data = {0x28,0xaa,0xb2,0xe4,0xa0,0xe5,0x5c,0x11,0xd5, + 0x50,0x3c,0x4d,0xca,0xb5,0x84,0x54,0x5c,0x49, + 0x23,0xa6,0x1b,0x31,0x3c,0x2c,0x5a,0x44,0xd6, + 0x1d,0x82,0x13,0xd5,0x23,0xac,0x26,0x29,0xba, + 0x6e,0x89,0x45,0xd9,0xf4,0x88,0xd2,0xd5,0x53, + 0xb6,0xa5,0x82,0x1b,0x34,0xef,0x9b,0x2b,0x2f, + 0xb4,0x64,0xca,0xab,0x7f,0x8d,0xf3,0x7f,0x53, + 0x5a,0xef,0xa1,0xe4,0x01,0x2a,0xa4,0x07,0x54, + 0x3f,0x7f,0x68,0x9f,0x55,0x90,0x7b,0xd4,0xae, + 0xe1,0xb5,0xe5,0x7d,0xa9,0xfb,0x72,0xf8,0x16, + 0x5b,0xa4,0xaf,0x49,0xfa,0x59,0x1c,0xa3,0x4d, + 0x81,0x7b,0x3f,0x8c,0xc7,0xdc,0xbf,0x64,0x75, + 0x76,0x4c,0xed,0x91,0x3e,0xd8,0xdb,0x4c,0xb8, + 0xa6,0xf8,0x9e,0x0d,0x0d,0xd2,0x2a,0x5f,0x79, + 0xb0,0x67}, + .data_len = 128, + .mac_len = 12, + .mac = {0xb3,0xeb,0xb5,0x67,0xbe,0xf1,0xfe,0xa5,0xd4, + 0xf9,0x54,0xbb}, + }, { // 36 (270) + .key = {0xb5,0x43,0x8e,0x38,0x45,0xf3,0x9a,0xfe,0x7d, + 0xeb,0x0f,0xcf,0xb8,0x6e,0x2d,0xbe,0x4f,0xbc, + 0x48,0x9f,0x55,0xf0,0x1c,0x0f,0x84,0x29,0x61, + 0xb5,0x76,0xe8,0x9f,0xc7,0x19,0xb9,0x44,0xcf, + 0x5d,0x16,0xf4,0xaf,0x2f,0x88,0x20,0xe2,0xab, + 0x0f,0xda,0x06,0x8d,0xc4,0xe7,0x97,0xe9,0xbd, + 0x16,0xfe,0x1d,0x31,0xd1,0xca,0x03,0xdc,0xf2, + 0x3d,0x6b,0xa5,0xd8,0x0a,0xc8,0x7f,0xb9,0x5d, + 0x29,0x8d,0x39,0x1c,0x6b,0x89,0x3c,0x6c}, + .key_len = 80, + .data = {0x8e,0xcd,0xcd,0x81,0x76,0xd8,0xa1,0x64,0xf6, + 0x25,0x97,0x33,0xbc,0x77,0xef,0x78,0x3b,0x48, + 0xd4,0x0c,0xff,0xc5,0x47,0x35,0x3d,0x19,0x59, + 0x12,0xaf,0xee,0x9d,0x39,0x9e,0x31,0xdd,0x9e, + 0x41,0x16,0x0c,0xb7,0x45,0x5d,0x7c,0xdd,0xad, + 0xd3,0x51,0xf6,0xdc,0x1b,0x36,0x51,0xf0,0xae, + 0x4e,0xd1,0x52,0x21,0x6d,0x4e,0x8b,0xa7,0x89, + 0x38,0x5a,0xd6,0x6b,0x7d,0x03,0xae,0xaa,0xad, + 0xe9,0xd7,0xda,0x5d,0x5f,0x2a,0x01,0xc9,0xbc, + 0x73,0x4a,0xbd,0xad,0x75,0xfe,0xb5,0xd0,0x2f, + 0xaf,0x43,0x7e,0x5e,0xb7,0xb1,0xe8,0x43,0xe1, + 0xe7,0x65,0xa6,0x65,0x90,0x0a,0x1b,0x1a,0x79, + 0x7c,0x84,0xe7,0x39,0x02,0xd7,0x7a,0x17,0xde, + 0x22,0x3d,0x28,0xde,0xcc,0x86,0xb8,0x2e,0x1d, + 0x0f,0xeb}, + .data_len = 128, + .mac_len = 16, + .mac = {0xa9,0x5c,0xf7,0xbb,0x2f,0x67,0x98,0x34,0x69, + 0xd4,0xfc,0x48,0x9e,0x31,0x92,0xd3}, + }, { // 37 (271) + .key = {0x95,0xf2,0xc1,0x50,0x9d,0xff,0x6d,0x16,0x2e, + 0xdd,0x5d,0xe3,0x2d,0xed,0x42,0x38,0x66,0xdf, + 0xda,0x68,0x2b,0xc7,0xb7,0x50,0x3e,0x73,0x41, + 0x42,0xf2,0xfc,0xfe,0x42,0x8c,0x9c,0x11,0x75, + 0xef,0xbf,0x01,0xd6,0x79,0x5d,0xbc,0x2b,0x28, + 0x86,0xdc,0x38,0x01,0x3f,0x28,0x32,0xb2,0x8c, + 0x5e,0x76,0x76,0xce,0x30,0x7b,0x39,0x4f,0x8c, + 0x05,0xfd,0x1c,0x20,0x9c,0x7c,0x13,0x1e,0x3d, + 0x0e,0x3c,0x3c,0x4f,0xce,0x5d,0x00,0xd8}, + .key_len = 80, + .data = {0x1c,0x43,0x96,0xf7,0xb7,0xf9,0x22,0x8e,0x83, + 0x2a,0x13,0x69,0x20,0x02,0xba,0x2a,0xff,0x43, + 0x9d,0xcb,0x7f,0xdd,0xbf,0xd4,0x56,0xc0,0x22, + 0xd1,0x33,0xee,0x89,0x03,0xa2,0xd4,0x82,0x56, + 0x2f,0xda,0xa4,0x93,0xce,0x39,0x16,0xd7,0x7a, + 0x0c,0x51,0x44,0x1d,0xab,0x26,0xf6,0xb0,0x34, + 0x02,0x38,0xa3,0x6a,0x71,0xf8,0x7f,0xc3,0xe1, + 0x79,0xca,0xbc,0xa9,0x48,0x2b,0x70,0x49,0x71, + 0xce,0x69,0xf3,0xf2,0x0a,0xb6,0x4b,0x70,0x41, + 0x3d,0x6c,0x29,0x08,0x53,0x2b,0x2a,0x88,0x8a, + 0x9f,0xc2,0x24,0xca,0xe1,0x36,0x5d,0xa4,0x10, + 0xb6,0xf2,0xe2,0x98,0x90,0x4b,0x63,0xb4,0xa4, + 0x17,0x26,0x32,0x18,0x35,0xa4,0x77,0x4d,0xd0, + 0x63,0xc2,0x11,0xcf,0xc8,0xb5,0x16,0x6c,0x2d, + 0x11,0xa2}, + .data_len = 128, + .mac_len = 16, + .mac = {0x0a,0x06,0x07,0x35,0xb4,0x79,0x9e,0xeb,0x20, + 0x4c,0x52,0x03,0xe6,0x17,0xa7,0x76}, + }, { // 38 (285) + .key = {0x4d,0xdd,0x00,0xd0,0xab,0x6a,0xab,0x21,0x00, + 0xce,0x97,0x54,0xc3,0xb3,0x98,0x7c,0x06,0xf7, + 0xe5,0x86,0x56,0x01,0x1d,0x26,0xe3,0x51,0x87, + 0x11,0xe1,0x5b,0x9e,0x6d,0x2d,0x96,0xcd,0x85, + 0x34,0xd0,0x77,0xc2,0x11,0xc4,0x3a,0xd7,0xf5, + 0xee,0x75,0x3b,0xcc,0x9e,0x07,0xdc,0x1d,0x4c, + 0x5a,0x12,0x32,0x2b,0xa1,0xd1,0x7a,0x00,0x5d, + 0x24,0x2b,0x35,0x26,0xd6,0x2b,0x29,0xa8,0x72, + 0x31,0xcb,0xec,0x6f,0x28,0x67,0xd9,0xa4}, + .key_len = 80, + .data = {0x28,0xbe,0x0d,0x9e,0x62,0xdc,0x89,0xe2,0xa9, + 0x13,0x06,0x4c,0x0d,0x3d,0xbf,0xb3,0x5a,0x0c, + 0x77,0x66,0xf7,0x56,0x74,0x1b,0x0e,0xaf,0xcc, + 0x28,0xed,0x3d,0xdf,0xf6,0xad,0xc8,0x25,0xb2, + 0x11,0x11,0x2a,0x45,0xb0,0x65,0xd6,0x87,0x57, + 0x71,0xf2,0xaf,0xa9,0x58,0xe8,0x0f,0x08,0x03, + 0xca,0xfe,0xb9,0xb9,0x96,0x15,0x42,0xef,0xb9, + 0x9e,0x17,0x61,0xd1,0x49,0x76,0x61,0xb7,0x21, + 0x90,0x6f,0xbd,0xbf,0xe9,0x0b,0x34,0xbd,0x01, + 0xc7,0x32,0x6e,0x34,0xa0,0x92,0xcc,0xdf,0x8e, + 0x3b,0xb2,0xc4,0x5a,0xa6,0x4c,0xb0,0xb0,0x9a, + 0xcb,0x5b,0x75,0x3a,0x5d,0x8f,0x5a,0x42,0x5c, + 0x8c,0xb2,0x8e,0xc5,0xac,0x81,0xdc,0xed,0x43, + 0xd5,0xd2,0x6f,0xc9,0x59,0x43,0x69,0x3b,0x27, + 0xae,0xe8}, + .data_len = 128, + .mac_len = 20, + .mac = {0x39,0x32,0x38,0xd3,0xaf,0xdb,0x7d,0x97,0x0b, + 0x96,0x6d,0x37,0x4f,0xe0,0x97,0xec,0x87,0x97, + 0xa8,0x70}, + }, { // 39 (286) + .key = {0x7a,0x31,0x55,0x3b,0x05,0xe9,0x6a,0x8d,0xa0, + 0xa4,0xd5,0xb8,0x1a,0x85,0x7d,0x19,0x2a,0xfb, + 0x6a,0xab,0xb1,0xf1,0x27,0xd7,0x40,0x45,0x6a, + 0x8e,0xda,0x7c,0xf6,0x96,0xfb,0xb4,0xc1,0x21, + 0xd8,0xd9,0x52,0xa4,0xe9,0x1c,0x6e,0xe6,0xa5, + 0xa1,0xf3,0x58,0x8d,0x78,0x04,0xa4,0x6b,0xcf, + 0x66,0x88,0xdc,0x66,0x2a,0xe5,0x0c,0x43,0x8d, + 0x13,0xc1,0xa6,0x1c,0x78,0x9b,0x3f,0x1c,0x59, + 0x9a,0x9f,0x28,0xef,0xe0,0xed,0x1c,0xbe}, + .key_len = 80, + .data = {0xfb,0x09,0x1d,0xdd,0x95,0xb1,0x00,0xdf,0xcf, + 0x89,0x2d,0x78,0xe5,0xe7,0x70,0xd3,0xa3,0x7b, + 0x8c,0x38,0x85,0xdf,0x80,0x3c,0x1d,0x6f,0x09, + 0x35,0xb5,0x5b,0x68,0xf1,0x36,0xfb,0x65,0xa8, + 0x48,0x62,0x94,0x2e,0xbb,0x35,0xd7,0x6d,0x26, + 0xbe,0x24,0x13,0xcd,0x3c,0x89,0x88,0xc8,0x7d, + 0x6d,0x23,0x62,0xaf,0x18,0x9d,0xc0,0x74,0x76, + 0xc6,0xc3,0x34,0x17,0x76,0x2e,0xb7,0x7b,0xc7, + 0x0c,0xf3,0x8d,0x81,0x4c,0x22,0x6d,0xd6,0xaf, + 0x18,0x72,0x50,0xe4,0xd4,0x70,0x07,0xf1,0x55, + 0x36,0x17,0xd4,0xaf,0x5b,0x51,0x6a,0x5d,0x3b, + 0x31,0x91,0xd9,0x3c,0x10,0x89,0x6a,0x56,0x9b, + 0xa1,0x3d,0xd2,0x84,0x0f,0xb8,0x51,0x78,0x1f, + 0x0b,0x11,0x50,0x90,0x08,0x6c,0x8b,0x3a,0x34, + 0xa1,0xfc}, + .data_len = 128, + .mac_len = 20, + .mac = {0x0f,0xdd,0x3f,0x83,0x6d,0xd7,0xe5,0xc5,0x06, + 0xab,0x21,0xad,0xde,0x9a,0xe5,0xdc,0x09,0xcb, + 0x35,0x9d}, + } +}; + +struct HMAC_TEST_VECTOR fips_sha224_hmac_general_test_vector[] = { + { // 0 (0) + .key = {0x37,0x14,0x70,0x78,0x39,0xda,0xf7,0x91,0x22, + 0xc7,0x82,0x41,0x63,0x51,0x38,0x5e,0x88,0xa8, + 0x1d,0x31,0xc9,0xf6,0x41,0xd8,0xdc,0xe5,0x38, + 0xe9,0x0e,0x63,0xc9,0x58,0x92,0xa2,0xea,0x9b, + 0x19,0x62,0xed,0x0b,0xa3,0x72,0xf4,0x8e,0x94, + 0x74,0xaa,0x73,0x0a,0xe2}, + .key_len = 50, + .data = {0x41,0x18,0x43,0xa2,0x13,0x87,0x84,0x6f,0x3b, + 0x9e,0xd5,0xfc,0x54,0x5a,0xca,0xdf,0xa5,0xb7, + 0x03,0x86,0xf6,0x2d,0xa4,0xd9,0xa2,0x7b,0x04, + 0x1b,0xee,0xa3,0xaa,0x11,0x99,0x36,0x75,0x67, + 0xb4,0xd1,0x1a,0x4f,0xb4,0xe8,0xd4,0x6b,0xc6, + 0xc2,0x56,0xed,0x62,0xc5,0x05,0xfd,0x23,0xf4, + 0x64,0x5b,0xd6,0xb6,0xcf,0x45,0xd1,0xd9,0x6d, + 0x9b,0x86,0xd6,0x60,0x41,0x57,0x57,0x3e,0xc5, + 0xac,0xf6,0xc5,0x41,0x43,0x48,0xca,0x83,0xc8, + 0x1a,0x73,0x6c,0xa6,0xfa,0xa6,0x96,0x1c,0xfa, + 0xc1,0x39,0x93,0xb0,0x8c,0x50,0x2f,0x81,0x6c, + 0xf7,0xa4,0x20,0xd9,0x18,0x4b,0x51,0x11,0x46, + 0x75,0xf3,0x0e,0xe9,0xff,0x3d,0xb6,0x9c,0x26, + 0x48,0x53,0xd3,0x9d,0xcd,0x42,0xc1,0xdd,0x31, + 0xef,0x79}, + .data_len = 128, + .mac_len = 14, + .mac = {0x33,0xf1,0x7a,0xc8,0xa5,0xc6,0xb5,0x25,0xdb, + 0x8b,0x86,0x44,0xb6,0xab}, + .chunks = {64, 64}, + .num_chunks = 2, + }, { // 1 (1) + .key = {0xce,0x4c,0x92,0x6c,0x09,0x22,0xba,0x36,0x26, + 0x9a,0x20,0xd6,0x0d,0xcf,0x08,0xd4,0x3a,0x1c, + 0xea,0x12,0x0f,0x26,0x6a,0xf7,0x6f,0x1c,0x8a, + 0xcd,0x88,0x3d,0x1f,0x68,0xf0,0x9b,0x82,0x09, + 0xf4,0x1f,0x87,0x82,0x2d,0xce,0xb3,0x9a,0x54, + 0x4a,0xa9,0xb2,0x56,0x9c}, + .key_len = 50, + .data = {0x41,0x0a,0xc8,0x70,0x3f,0x31,0x2f,0xe4,0x26, + 0xf0,0xd1,0xa6,0x2d,0x36,0x2d,0x44,0x78,0x25, + 0x2f,0x11,0xdf,0xc7,0x0b,0x78,0xf0,0xfc,0x6c, + 0x91,0x37,0xb7,0xce,0xf2,0xbd,0x6a,0x28,0xc8, + 0xce,0xbf,0xcf,0x26,0xff,0x89,0x97,0x9c,0x70, + 0xfa,0x3b,0x0c,0x4f,0x16,0xff,0xb9,0x9d,0x67, + 0x93,0xa1,0x35,0xf3,0x3b,0x0d,0x0a,0x6b,0x2d, + 0x66,0xb0,0xa5,0x3a,0x4a,0x1e,0x4c,0xb1,0xdf, + 0xb2,0xd7,0x81,0x67,0x75,0xb7,0x9d,0x15,0xa1, + 0xd5,0xa5,0x1f,0x60,0x3b,0xc2,0x15,0xd7,0x11, + 0xd2,0x71,0x63,0xcc,0xc5,0x6f,0x22,0xa2,0x46, + 0x1f,0xb6,0x41,0x9e,0xb8,0x45,0xc0,0xd6,0x2f, + 0xc4,0xd6,0x1c,0x08,0x76,0x4a,0x69,0x6d,0xaf, + 0xaa,0x60,0x7d,0xde,0x40,0x78,0xe6,0xca,0x42, + 0x5d,0xb6}, + .data_len = 128, + .mac_len = 14, + .mac = {0x90,0x08,0x42,0xbb,0x91,0x6f,0xb0,0xdf,0xf7, + 0xab,0xe3,0x7e,0xd8,0xf6}, + .chunks = {32, 32, 32, 32}, + .num_chunks = 4, + }, { // 2 (15) + .key = {0x49,0x55,0x39,0xa6,0x81,0x41,0xfc,0x09,0x93, + 0x93,0xad,0x40,0x55,0x5a,0x70,0xeb,0xb4,0x5e, + 0x3d,0x37,0xf9,0x57,0x3f,0xb1,0x4b,0x5c,0x7a, + 0x5c,0x75,0x9e,0xb1,0x00,0xea,0x56,0x87,0xc6, + 0x06,0xfc,0xe4,0x02,0x97,0xba,0x9a,0x50,0x9c, + 0x20,0x49,0xe2,0x4d,0x19}, + .key_len = 50, + .data = {0xf2,0xc2,0x98,0xf6,0x2c,0xcd,0x8e,0x10,0x26, + 0x45,0x35,0x2f,0xd2,0x64,0xaf,0x76,0x17,0x84, + 0xc2,0x2a,0x77,0x31,0x94,0x67,0xef,0x83,0xb2, + 0x11,0x1e,0xaa,0x57,0x0c,0xaa,0xcb,0xec,0xb0, + 0xe0,0x0b,0xcb,0x77,0x9a,0xe9,0x48,0xf9,0x66, + 0xd0,0xf2,0x1b,0xe4,0xec,0x16,0x83,0x70,0x3e, + 0x85,0x4f,0x01,0xeb,0x97,0x06,0x51,0xda,0x70, + 0xce,0x3f,0x7d,0x82,0xe0,0x71,0xef,0x53,0x3a, + 0x3d,0x40,0x81,0x93,0xca,0x0d,0x03,0x94,0x72, + 0x53,0xb1,0x45,0x6b,0x84,0x07,0xc6,0xa7,0xdb, + 0x26,0x3f,0xf8,0xed,0x1b,0x19,0x78,0x82,0x64, + 0x6f,0x28,0xa2,0xb0,0xbf,0xd7,0xf3,0xe7,0xe6, + 0x46,0x42,0x6a,0x4b,0x89,0x5f,0x9c,0x5a,0xb0, + 0x2e,0xa1,0x34,0xa7,0xfb,0x66,0xa4,0x5b,0x0e, + 0xe1,0x56}, + .data_len = 128, + .mac_len = 16, + .mac = {0x04,0x40,0xb3,0xfc,0xd0,0xdd,0xf5,0x07,0x71, + 0x7e,0xae,0x86,0xbe,0x2b,0x0a,0x69}, + .chunks = {32, 32, 64}, + .num_chunks = 3, + }, { // 3 (16) + .key = {0x60,0xcb,0xa4,0xff,0xa6,0x39,0xda,0x15,0x80, + 0x9f,0x0c,0x93,0x07,0x42,0xba,0x0a,0x5d,0x50, + 0xa6,0x47,0xeb,0x18,0x35,0x25,0xed,0x79,0x17, + 0xa6,0x31,0x9b,0x2a,0x42,0x1b,0xde,0x9c,0x7f, + 0xed,0x10,0x51,0xc2,0x45,0xe3,0x84,0x65,0xe8, + 0x9e,0xb0,0x09,0xbd,0x12}, + .key_len = 50, + .data = {0x1a,0xc2,0x64,0x9d,0xc5,0x45,0x8f,0x43,0x9f, + 0x94,0x49,0x5d,0xb8,0x4e,0x48,0x19,0x9a,0xa8, + 0x7c,0xf5,0xda,0xb2,0x46,0x24,0xec,0xdc,0xe5, + 0x33,0x3b,0xb8,0x31,0xec,0x79,0x01,0x8b,0x7b, + 0x34,0xdd,0x14,0xcf,0xab,0x5f,0x1d,0x43,0xdf, + 0x50,0xdf,0x7e,0xed,0x2f,0x6c,0x97,0x9a,0x76, + 0xe6,0x7d,0x30,0x1f,0xef,0x97,0x89,0x67,0x60, + 0xa7,0x69,0xd2,0x3e,0xf4,0x11,0x6f,0xea,0xa8, + 0x10,0x5d,0x97,0x77,0x5d,0x8e,0x01,0x81,0xa3, + 0xcb,0x5d,0x7a,0xdc,0xf8,0x8b,0x08,0x21,0x9a, + 0x93,0x6c,0xc0,0x96,0x4f,0x65,0x90,0x3b,0x65, + 0x51,0x81,0x83,0x79,0x96,0x77,0x96,0xa0,0x40, + 0x59,0x90,0x17,0xec,0x64,0x84,0x35,0xe4,0xc6, + 0xc1,0x9e,0x8b,0x68,0x54,0xba,0xfc,0x0b,0xce, + 0x65,0xee}, + .data_len = 128, + .mac_len = 16, + .mac = {0x48,0x9b,0x50,0xad,0x20,0x00,0x2f,0xdc,0x27, + 0x65,0xad,0xa1,0x13,0x4b,0xad,0xda}, + .chunks = {128}, + .num_chunks = 1, + }, { // 4 (30) + .key = {0x76,0xcc,0x58,0x37,0x87,0x82,0xbb,0xc0,0x17, + 0x8f,0x9b,0x4f,0x1f,0x9c,0x4a,0xfc,0x23,0xa6, + 0x25,0xc5,0x00,0xaf,0x74,0xde,0xe4,0xb3,0x91, + 0x48,0x9e,0xdd,0x4d,0xa5,0x18,0xfb,0x8f,0x4b, + 0x21,0x30,0x3e,0x97,0x70,0xe8,0x61,0x83,0xe6, + 0x11,0x85,0x7b,0x14,0x89}, + .key_len = 50, + .data = {0xba,0xa0,0xac,0xc0,0x88,0x14,0xf2,0x45,0x3a, + 0x81,0x6e,0xce,0xe2,0xf7,0xf8,0xa8,0x31,0xbc, + 0xd3,0xd7,0xa3,0xaa,0x83,0xa1,0xf7,0xd2,0xde, + 0x51,0xe2,0x65,0x66,0x35,0x04,0xd5,0xd6,0xe9, + 0x1b,0x37,0xfb,0xd7,0x77,0xec,0xc5,0xff,0xae, + 0x80,0x9e,0xf4,0x90,0xd2,0xfa,0x27,0x5d,0x75, + 0x30,0x68,0x36,0x57,0x88,0xaa,0xd2,0xa0,0x95, + 0x07,0x72,0xdd,0xc5,0x04,0x17,0x5e,0x36,0x15, + 0xf2,0xdc,0xcb,0x64,0x1c,0x60,0x80,0xce,0x87, + 0x5f,0xfa,0x2e,0x35,0x2a,0x63,0xdf,0xa7,0x86, + 0x74,0x7c,0x99,0x96,0xd3,0xea,0xec,0x02,0xa0, + 0x99,0xe4,0x52,0x4a,0x06,0x93,0x9b,0xa8,0x85, + 0x95,0x5e,0x45,0x3d,0xfe,0xad,0xfb,0x74,0x91, + 0x8f,0xc3,0x0d,0x33,0xa6,0xcb,0x4e,0x9f,0x0f, + 0xc9,0xe7}, + .data_len = 128, + .mac_len = 20, + .mac = {0xf2,0x55,0xc7,0x06,0x5a,0x6a,0xd7,0xac,0x49, + 0xaa,0x68,0x31,0xe5,0xe0,0xfa,0x8b,0x12,0x8a, + 0x5f,0xf7}, + .chunks = {32, 0, 64, 32}, + .num_chunks = 4, + }, { // 5 (31) + .key = {0x49,0x18,0x62,0x90,0x58,0xbb,0x50,0x84,0x7e, + 0x7a,0xb9,0x96,0xa8,0x27,0x7c,0x35,0x51,0xd6, + 0xa7,0x4a,0x91,0xd9,0x97,0xcb,0x57,0xef,0x61, + 0x8c,0xf2,0xb8,0x71,0x59,0xd7,0x6c,0x71,0x43, + 0x9e,0xcd,0x6d,0x37,0x4d,0x5a,0x34,0xd5,0xd9, + 0xc6,0x01,0x7e,0xea,0xa8}, + .key_len = 50, + .data = {0x38,0x7b,0xac,0x63,0xcf,0x86,0x5f,0x06,0xe9, + 0x6a,0x5a,0x62,0x32,0xb7,0x3b,0xa8,0xe8,0x43, + 0xcf,0x80,0xdf,0x1f,0x36,0x9f,0xc9,0xc9,0x41, + 0x9c,0xb4,0xa3,0x1f,0xff,0xd4,0xa4,0x39,0x9c, + 0x83,0x4e,0x5a,0x1f,0x86,0xe0,0x13,0xe7,0x92, + 0xcc,0x5e,0x18,0x0e,0x6b,0x81,0xeb,0x1b,0xf0, + 0x35,0x49,0xd2,0x9b,0x08,0x99,0xcc,0x2f,0x00, + 0xd6,0xe8,0xa5,0x81,0xe4,0x48,0x22,0x70,0x24, + 0x9d,0x27,0x99,0x46,0xa5,0x07,0x4e,0x5e,0xf2, + 0x9f,0x51,0x3a,0xec,0x41,0xf5,0xf3,0x19,0xf1, + 0x7f,0xc3,0x9c,0xd4,0xd2,0x16,0xfc,0xe5,0x4c, + 0xe4,0x27,0xea,0xeb,0x3d,0xb7,0xa7,0xb4,0x26, + 0x73,0x51,0x55,0xa3,0x19,0x45,0x09,0x15,0x5b, + 0xfa,0xbc,0xc6,0x27,0x34,0x70,0xc3,0x2b,0x7b, + 0xdf,0xea}, + .data_len = 128, + .mac_len = 20, + .mac = {0xb1,0x75,0x6c,0x19,0x6d,0xc4,0x40,0x75,0x21, + 0xf3,0xc2,0x1d,0xe5,0x53,0xec,0xc2,0x1c,0x50, + 0x76,0xf5}, + .chunks = {64, -1, 64}, + .num_chunks = 3, + }, { // 6 (45) + .key = {0xff,0x91,0xe9,0xe7,0x48,0xc9,0x4f,0xd0,0x81, + 0x84,0x2c,0x50,0xfc,0x5e,0xfc,0x03,0xb9,0xe5, + 0x66,0x06,0x2d,0x4e,0x1c,0x52,0x43,0x67,0x03, + 0x48,0xa1,0xcd,0x94,0x8c,0x2c,0x5f,0x82,0x17, + 0xce,0xf2,0x9c,0x88,0x77,0x47,0xf6,0xbb,0x61, + 0x3a,0x43,0x9d,0x99,0x3b}, + .key_len = 50, + .data = {0x9c,0xe6,0x6b,0xe0,0xe1,0x6f,0x03,0xba,0xae, + 0x35,0x67,0xae,0xb7,0xae,0x84,0x00,0xfe,0x60, + 0x14,0x99,0x99,0x9c,0x7b,0x5a,0xb6,0x68,0xef, + 0xb0,0xdc,0xbd,0xdc,0x69,0x74,0xf3,0x87,0xc6, + 0x87,0x79,0xf1,0xd1,0xc9,0xc9,0xfe,0xf0,0xd7, + 0x9b,0xd6,0xbb,0xbd,0x59,0x8c,0x0b,0xbb,0xd4, + 0xfe,0x53,0x49,0x35,0xfc,0x34,0x58,0x36,0xac, + 0x4b,0xdb,0x92,0x2c,0x4e,0x86,0xb9,0x7a,0x57, + 0xd5,0xc9,0x91,0x7f,0x51,0xba,0xd5,0xaf,0x0f, + 0xd8,0xb1,0xb3,0x79,0x77,0x7f,0x90,0x50,0xe2, + 0xa8,0x18,0xf2,0x94,0x0c,0xbb,0xd9,0xab,0xa4, + 0xa0,0x65,0x99,0x65,0xf5,0xdb,0x1d,0x68,0x83, + 0xad,0x72,0x49,0x85,0xfc,0xc6,0xcd,0xba,0x5b, + 0xed,0xc7,0xb9,0xd6,0x57,0x3c,0x85,0x33,0x3f, + 0xc5,0x61}, + .data_len = 128, + .mac_len = 24, + .mac = {0x77,0xee,0x73,0x67,0x64,0x7f,0xa4,0x10,0xa0, + 0x9e,0x96,0x59,0xb6,0x88,0xcb,0xb9,0x2a,0x51, + 0xb4,0x79,0xfd,0xa8,0x95,0xc6}, + .chunks = {54, 0, 54, -1, 20}, + .num_chunks = 5, + }, { // 7 (46) + .key = {0x3c,0x17,0xd3,0x27,0x44,0x95,0xdc,0xc8,0x6f, + 0x27,0x22,0x39,0x8d,0xb6,0x02,0x37,0xfc,0x70, + 0xfc,0x0e,0x63,0xb3,0x0a,0xa4,0xa3,0x2c,0x30, + 0xb9,0x0b,0x40,0x55,0x6d,0xcc,0xaa,0x51,0x03, + 0xac,0x66,0x47,0xe4,0xfe,0xce,0x35,0xe7,0xd1, + 0x04,0xc9,0xcf,0x68,0x8f}, + .key_len = 50, + .data = {0x1b,0xd9,0x6d,0xb9,0x6e,0x74,0x1d,0x63,0x7e, + 0x5c,0x63,0xd6,0x97,0xf8,0x1a,0x4d,0x99,0xf8, + 0x44,0x96,0xac,0x38,0x5a,0x15,0x30,0xe7,0xe0, + 0x0c,0xf3,0xe8,0x3b,0x1a,0xa7,0x78,0xc7,0x01, + 0x93,0x12,0x25,0xac,0x88,0x8f,0xd2,0x70,0x17, + 0x92,0xfe,0x92,0x01,0x23,0x9b,0x09,0xef,0x9a, + 0xb4,0x86,0x63,0xbf,0x00,0xb2,0xef,0x2f,0xb7, + 0xb6,0xa5,0x02,0xa4,0x01,0xce,0xaa,0x7c,0x45, + 0xdf,0x1e,0x6e,0xc3,0xa8,0x39,0xfb,0xc9,0xcf, + 0x5c,0x08,0x79,0x7d,0x5b,0x31,0xcb,0x57,0x97, + 0x61,0xd6,0xb0,0x67,0x9f,0x4b,0xfc,0xbd,0x2b, + 0x42,0x88,0x06,0xca,0x39,0x69,0x51,0x5e,0x59, + 0xb3,0xb4,0xb9,0xfc,0xeb,0xeb,0xb3,0x6d,0xbe, + 0x43,0x7a,0xee,0xf2,0xb7,0x2a,0x00,0x9e,0x58, + 0x9e,0xde}, + .data_len = 128, + .mac_len = 24, + .mac = {0xcd,0xf3,0x67,0xa1,0xb5,0x73,0x71,0x3f,0x1f, + 0xb0,0xea,0xb4,0xfa,0x6d,0xbc,0x13,0x4e,0x1d, + 0x3b,0x90,0x14,0xec,0xe5,0x10}, + .chunks = {0, 128}, + .num_chunks = 2, + }, { // 8 (59) + .key = {0x10,0x9f,0xaf,0xbb,0x90,0x12,0xbe,0x97,0x20, + 0x36,0x15,0x85,0xc1,0x58,0xdf,0xd0,0x1e,0xc6, + 0x46,0xcf,0xc2,0x30,0x42,0x6a,0x89,0x54,0xae, + 0xdb,0x54,0xdb,0xa1,0xb2,0x01,0x7d,0xfb,0x1c, + 0x9b,0x6c,0x3e,0x64,0xcd,0xf0,0xa0,0xba,0x9d, + 0x4e,0x5e,0x34,0x57,0xef}, + .key_len = 50, + .data = {0xf2,0xa1,0xc2,0x04,0xbb,0xd1,0xcc,0x55,0xc3, + 0x09,0x72,0xbc,0xc2,0xb5,0xbc,0x33,0x97,0xc1, + 0x37,0x26,0xd3,0x0b,0x98,0x83,0x7b,0x18,0xa3, + 0x11,0x0a,0x06,0x4b,0x02,0xb6,0xc1,0x1b,0xcb, + 0xf4,0x7a,0xd4,0x33,0x3e,0x55,0x58,0xaa,0x14, + 0x62,0xc6,0xdd,0x41,0xcf,0xe7,0x87,0x5f,0x5c, + 0xc9,0x8a,0x9d,0x0e,0xa9,0x3e,0xc0,0x28,0x16, + 0x09,0x68,0x57,0x54,0x30,0x95,0x2d,0xff,0xec, + 0x69,0xd0,0xf0,0xc1,0x30,0xf4,0x65,0x0b,0x9d, + 0x06,0x5b,0xda,0x56,0xaa,0x3f,0xff,0xb4,0x68, + 0xc6,0x67,0xc3,0xa2,0x1a,0xa8,0x91,0xca,0x36, + 0xda,0xa5,0xd2,0x93,0xa8,0xcd,0xe3,0x04,0xa6, + 0x1d,0x51,0xde,0xe6,0x34,0xcf,0x5d,0xc6,0xc1, + 0xdf,0x43,0x0b,0x46,0x8d,0xc2,0x34,0x1c,0x5d, + 0x9c,0x08}, + .data_len = 128, + .mac_len = 24, + .mac = {0xab,0xfb,0x36,0xe5,0xd7,0x72,0x30,0x9a,0xdf, + 0x06,0x08,0x36,0x72,0x69,0x58,0x20,0x67,0xa3, + 0x0f,0x8d,0xb7,0x10,0xd3,0xb2}, + }, { // 9 (60) + .key = {0xcf,0x12,0x75,0x79,0xd6,0xb2,0xb0,0xb3,0xa6, + 0x07,0xa6,0x31,0x4b,0xf8,0x73,0x30,0x61,0xc3, + 0x2a,0x04,0x35,0x93,0x19,0x55,0x27,0x54,0x4f, + 0x87,0x53,0xc6,0x5c,0x7a,0x70,0xd0,0x58,0x74, + 0xf7,0x18,0x27,0x5b,0x88,0xd0,0xfa,0x28,0x8b, + 0xd3,0x19,0x98,0x13,0xf0}, + .key_len = 50, + .data = {0xfa,0x7e,0x18,0xcc,0x54,0x43,0x98,0x1f,0x22, + 0xc0,0xa5,0xab,0xa2,0x11,0x79,0x15,0xf8,0x9c, + 0x77,0x81,0xc3,0x4f,0x61,0xf9,0xf4,0x29,0xcb, + 0x13,0xe0,0xfc,0xd0,0xce,0x94,0x71,0x03,0xbe, + 0x68,0x4c,0xa8,0x69,0xd7,0xf1,0x25,0xf0,0x8d, + 0x27,0xb3,0xf2,0xc2,0x1d,0x59,0xad,0xc7,0xab, + 0x1b,0x66,0xde,0xd9,0x6f,0x0b,0x4f,0xa5,0xf0, + 0x18,0xb8,0x01,0x56,0xb7,0xa5,0x1c,0xa6,0x2b, + 0x60,0xe2,0xa6,0x6e,0x0b,0xc6,0x94,0x19,0xeb, + 0xbf,0x17,0x85,0x07,0x90,0x76,0x30,0xf2,0x4d, + 0x08,0x62,0xe5,0x1b,0xec,0x10,0x10,0x37,0xf9, + 0x00,0x32,0x3a,0xf8,0x2e,0x68,0x9b,0x11,0x6f, + 0x42,0x75,0x84,0x54,0x1c,0x8a,0x9a,0x51,0xac, + 0x89,0xda,0x1e,0xd7,0x8c,0x7f,0x5e,0xc9,0xe5, + 0x2a,0x7f}, + .data_len = 128, + .mac_len = 28, + .mac = {0x35,0x4f,0x87,0xe9,0x8d,0x27,0x64,0x46,0x83, + 0x6e,0xa0,0x43,0x0c,0xe4,0x52,0x92,0x72,0xa0, + 0x17,0xc2,0x90,0x03,0x9a,0x9d,0xfe,0xa4,0x34, + 0x9b}, + }, { // 10 (75) + .key = {0xb2,0xff,0x28,0x2d,0x91,0x3a,0x31,0x26,0xaa, + 0x23,0x1a,0xc4,0x06,0xb1,0xcb,0xde,0x6e,0x98, + 0xf8,0xea,0xd0,0x1e,0xa3,0x71,0xe4,0x2b,0xe3, + 0xc0,0x0e,0xa0,0xe3,0xe1,0x87,0xea,0x2d,0xc9, + 0xb8,0xd7,0x29,0xd3,0xe6,0xa8,0xe0,0x6d,0x14, + 0x67,0x06,0x11,0x25,0x7b,0x38,0x78,0x42,0x79, + 0x82}, + .key_len = 55, + .data = {0xbc,0x68,0x7c,0x26,0xe4,0x2b,0xc5,0xd7,0x71, + 0xe3,0xc1,0xba,0x81,0xc6,0x1c,0xdf,0xb5,0x81, + 0x1d,0x7d,0x36,0x2e,0xce,0x89,0xf6,0x80,0x5d, + 0x87,0x39,0x41,0xc2,0xa1,0x53,0xff,0xa2,0xf6, + 0xb3,0x02,0x73,0x34,0x20,0x81,0xe2,0x69,0x43, + 0x15,0x71,0x16,0x66,0x6d,0x65,0x86,0x7b,0x44, + 0xdf,0x5d,0x60,0x90,0x49,0x74,0x61,0xfc,0xf3, + 0xe4,0xff,0x99,0xfe,0x61,0xef,0xd0,0x7a,0xca, + 0x66,0x9c,0xcb,0xfd,0x94,0xf6,0x51,0xf0,0x6e, + 0x90,0x48,0xfe,0xb1,0xc5,0xec,0x7e,0x24,0xd0, + 0xe1,0x9a,0x1d,0x3d,0xd3,0x5f,0x46,0x9e,0x5a, + 0x10,0xa1,0x7f,0x20,0xc0,0xca,0x9c,0x45,0x1f, + 0x7d,0x51,0x02,0x95,0x57,0x51,0x8d,0x8d,0xe1, + 0x9b,0x3d,0x14,0xca,0xaa,0xef,0xa2,0x74,0xec, + 0xa8,0x37}, + .data_len = 128, + .mac_len = 14, + .mac = {0xe5,0x01,0xec,0x9c,0x4f,0x64,0xa8,0xbd,0x00, + 0x45,0xec,0x1f,0x5d,0x1a}, + }, { // 11 (76) + .key = {0xac,0x37,0xe2,0x6c,0xdf,0x42,0x16,0x13,0x63, + 0x8a,0x00,0x51,0xf8,0x20,0x7c,0x60,0x7c,0xbb, + 0x77,0x4d,0x5f,0x5a,0x01,0xb4,0x57,0x2b,0xa4, + 0xcb,0x55,0xac,0xf4,0xa1,0xb7,0x10,0x68,0xa8, + 0xbf,0xe4,0x68,0x72,0x44,0xf2,0xa7,0xb8,0xa7, + 0x66,0xb3,0xa0,0x09,0x2f,0xcb,0x3f,0xbb,0xa8, + 0xf0}, + .key_len = 55, + .data = {0x31,0xf7,0x10,0x73,0x70,0x7b,0x06,0x4c,0xf9, + 0xe9,0xe5,0x79,0x52,0x7f,0x7f,0xd7,0xf5,0xa0, + 0x3b,0x80,0xa3,0xd8,0x0b,0xef,0xfc,0x1b,0x9e, + 0x65,0x4d,0x4d,0xd6,0x8c,0xa9,0x08,0x7c,0x5a, + 0x3b,0x99,0x33,0x39,0xda,0x4b,0xaa,0x65,0xde, + 0xe9,0x16,0x95,0x32,0x7e,0xe0,0xdd,0xab,0x5f, + 0x9a,0xd3,0x98,0x6b,0x38,0xf1,0x9b,0x92,0x7d, + 0x3a,0xb7,0x94,0xb3,0x20,0xa9,0x0b,0x9f,0xa6, + 0x7c,0xac,0xb4,0xc2,0x58,0xca,0x87,0x05,0x9b, + 0x1b,0x83,0x7d,0x2a,0xbf,0xde,0xdb,0x0a,0x7e, + 0xcb,0xd1,0x2a,0x52,0xf2,0xbe,0x83,0x25,0x1d, + 0x8d,0x63,0xdb,0x34,0xda,0x06,0x93,0x6b,0x57, + 0x67,0x2a,0xba,0x6f,0x55,0x01,0x8e,0x29,0xc9, + 0x01,0xbe,0x4e,0x77,0xdc,0xc0,0xce,0xa3,0x95, + 0x1d,0x60}, + .data_len = 128, + .mac_len = 14, + .mac = {0x98,0x19,0x5b,0x20,0x59,0xde,0x04,0x57,0xa5, + 0x3c,0x81,0xc4,0x87,0x86}, + }, { // 12 (90) + .key = {0x21,0xb7,0x02,0x6d,0xf9,0xd8,0xe4,0x35,0x96, + 0x6d,0x29,0x9e,0xf1,0xd4,0xc2,0xa4,0xa9,0x88, + 0x55,0x27,0xb1,0xfd,0x8f,0xed,0x46,0xcb,0xba, + 0xe7,0x25,0x0f,0x92,0xb5,0xfa,0x0e,0x54,0x6b, + 0x1b,0x1c,0x19,0x96,0x76,0xbd,0x62,0x7a,0xc9, + 0x09,0xf4,0x9e,0x11,0x55,0xe6,0x8b,0x44,0x0f, + 0xf8}, + .key_len = 55, + .data = {0x6f,0xd5,0xc7,0x32,0x17,0x27,0x29,0x3f,0x9e, + 0xcc,0xcd,0xd7,0x83,0x55,0xce,0x3f,0x49,0x45, + 0x75,0x2d,0x20,0x22,0xfc,0x7d,0xc1,0xcc,0x97, + 0x25,0x9a,0x0d,0xb5,0x6b,0x2b,0x70,0x82,0x56, + 0xb0,0x57,0xb1,0x62,0x00,0x48,0x7a,0x77,0xb5, + 0x88,0xde,0x1c,0x8d,0xeb,0x32,0xe9,0x10,0xea, + 0xdb,0x3a,0x73,0xf6,0x57,0x2b,0xbd,0x0c,0x7d, + 0xc0,0x28,0x8a,0x05,0x63,0xca,0x41,0x4a,0x94, + 0x74,0xcb,0x4f,0xdc,0xdb,0x1e,0x00,0x02,0xf5, + 0x62,0xbb,0x82,0xa6,0x00,0x0f,0x3b,0x9c,0xfc, + 0xc4,0x68,0x78,0x84,0x1b,0xd1,0x2e,0xc9,0x56, + 0x43,0xae,0x0d,0x7b,0x3d,0xc4,0xfd,0x56,0xec, + 0x3c,0x42,0xbd,0x59,0x4b,0x53,0x18,0xe2,0x2a, + 0x8d,0x20,0xe7,0x04,0x85,0xe6,0xc5,0x12,0x9d, + 0x17,0x08}, + .data_len = 128, + .mac_len = 16, + .mac = {0xb7,0xdf,0x20,0xfb,0x02,0xdc,0x06,0x3c,0x82, + 0x50,0xc1,0x0f,0x2e,0x0f,0x0a,0x91}, + }, { // 13 (91) + .key = {0x75,0xde,0xc6,0x97,0xbc,0xf3,0x0b,0x7b,0x34, + 0x5d,0x97,0xbc,0x02,0x7f,0xcd,0x80,0xc5,0x4a, + 0x6f,0xd1,0x6e,0xbc,0x11,0x43,0x52,0xa7,0xcd, + 0xd6,0x7d,0xb4,0x39,0x1d,0x49,0xa7,0x96,0xa0, + 0x30,0xe5,0x4a,0x80,0xdf,0x33,0x91,0x59,0x8b, + 0xc0,0x6f,0x6c,0x88,0x66,0xe9,0xfe,0x18,0x2d, + 0x74}, + .key_len = 55, + .data = {0x7f,0xc3,0xaa,0x4f,0x04,0xea,0x53,0x39,0xd7, + 0xf8,0xd6,0xee,0x41,0x64,0xdb,0x43,0x4f,0x52, + 0x05,0x25,0xca,0xba,0x80,0xdd,0x69,0xc7,0xd9, + 0x92,0x46,0x7d,0x13,0x10,0x8f,0x9f,0xf7,0xc8, + 0x7e,0xd0,0xab,0x17,0x8b,0xf8,0x86,0xcb,0xe0, + 0xe9,0x23,0xe3,0x0d,0x43,0xb4,0x96,0xfd,0x94, + 0x99,0x97,0x28,0xc4,0x32,0x98,0x0b,0xb1,0xf1, + 0x0d,0xd5,0x16,0xb3,0x32,0x64,0xb1,0x50,0x4f, + 0x6f,0xa5,0x70,0x3a,0x05,0x1d,0xa1,0x1e,0x36, + 0x32,0xa7,0x7c,0x10,0x0f,0x13,0x6f,0xcd,0x52, + 0x18,0x34,0x4a,0xb6,0x99,0xe9,0xbb,0xef,0x86, + 0x95,0x9e,0xd6,0x69,0x69,0xed,0xc6,0x3c,0x46, + 0x98,0x46,0x7e,0x7f,0x32,0xe8,0x86,0xdf,0xea, + 0x71,0x16,0xee,0xbe,0x39,0x33,0x70,0xeb,0xd5, + 0x34,0x2f}, + .data_len = 128, + .mac_len = 16, + .mac = {0x12,0x2a,0x00,0xcc,0xa9,0x91,0xda,0x9c,0x55, + 0xa5,0xe0,0x33,0x15,0x61,0x34,0x60}, + }, { // 14 (105) + .key = {0xb9,0x08,0x26,0x98,0x10,0xb3,0x54,0xc1,0xba, + 0x7e,0xd9,0xc8,0x2b,0xdd,0xe5,0x67,0x3f,0x0c, + 0x55,0x5c,0xce,0x53,0xe3,0xca,0x81,0x89,0x9a, + 0xdc,0xe4,0xd7,0x8e,0xab,0xbc,0xbe,0xc9,0x62, + 0x9a,0x5b,0x88,0xa0,0xb0,0xea,0xa8,0x1d,0xe4, + 0x8a,0x5b,0x91,0x23,0x3f,0x1f,0xd1,0xf8,0x3d, + 0xf1}, + .key_len = 55, + .data = {0xeb,0x39,0x1d,0x78,0x04,0x74,0x1b,0xb2,0xfc, + 0xe4,0x06,0x7e,0x2e,0xc6,0x3a,0x98,0xfd,0x41, + 0x4c,0x11,0xc5,0x92,0x9e,0x94,0x12,0x66,0x30, + 0xee,0x10,0x87,0xb9,0xcd,0x43,0xbb,0xf7,0xc8, + 0x78,0xea,0x43,0xa0,0xfc,0x7e,0x68,0xc6,0x0b, + 0x0f,0xb5,0x1d,0x8b,0x40,0x51,0x00,0xfb,0xe4, + 0xcf,0x87,0xa6,0x66,0x02,0x06,0x1c,0x67,0x13, + 0xd7,0xe2,0xa8,0xd0,0x5a,0x69,0x2b,0x47,0x39, + 0x3d,0x95,0x94,0xf1,0x7f,0xd7,0xf7,0x8e,0x95, + 0x0d,0x2a,0xb5,0x20,0xa6,0xf1,0xe8,0x2e,0xc6, + 0xf2,0x06,0xb2,0xe8,0xc7,0x11,0x31,0xc8,0x52, + 0x34,0xbd,0x80,0x50,0x05,0x27,0xf1,0x31,0x07, + 0x71,0x64,0x28,0x73,0x82,0x71,0x7e,0x38,0x1d, + 0x21,0x2b,0x40,0x14,0x4f,0xa7,0xf5,0xb9,0x54, + 0xfe,0x04}, + .data_len = 128, + .mac_len = 20, + .mac = {0xaf,0x9d,0x53,0xa7,0x6a,0xfb,0x25,0x04,0xb7, + 0x6b,0x96,0x59,0xd4,0x04,0x11,0x24,0xcc,0xa9, + 0x05,0x6d}, + }, { // 15 (106) + .key = {0xc5,0xf1,0xb3,0xcb,0xdd,0x47,0x1b,0x97,0xa9, + 0x94,0x5f,0x90,0xb7,0xc3,0x0c,0x18,0xb0,0x61, + 0xcc,0x44,0x26,0x53,0x45,0x33,0x8c,0xc4,0x3e, + 0x9e,0x86,0x62,0x03,0xb1,0x64,0xca,0x0b,0x19, + 0xe8,0x40,0xd9,0x5f,0x50,0xa4,0x20,0x74,0x90, + 0xa1,0x2a,0x8d,0xe0,0x28,0x7a,0x30,0x76,0x1d, + 0xb1}, + .key_len = 55, + .data = {0x4f,0x24,0x59,0x09,0xbf,0x3d,0x0f,0x29,0xdb, + 0xb5,0x83,0x77,0x32,0x2f,0xdf,0x46,0x5c,0x2d, + 0xaa,0xd2,0x32,0x79,0x9a,0xc8,0x3f,0xc5,0xa9, + 0x09,0x71,0x8e,0x6a,0xab,0x14,0x46,0x9e,0x41, + 0x01,0xb1,0x03,0x5d,0x13,0x90,0x6c,0x53,0xdb, + 0x7d,0x16,0x3f,0x95,0x16,0x3a,0x49,0x5a,0x5d, + 0xdf,0x27,0x97,0x5f,0xf2,0xe4,0xbd,0x14,0x98, + 0xe0,0x3a,0x87,0xc3,0x19,0xa9,0x36,0x04,0xa8, + 0x45,0xbc,0xa0,0x8f,0xa4,0xad,0xe5,0xb1,0xa2, + 0xc2,0xbe,0x22,0x9b,0x36,0x86,0xa1,0xdd,0x6f, + 0x1a,0x63,0x5c,0xe1,0x32,0x13,0xa8,0x30,0xf1, + 0x16,0x1d,0x94,0xba,0x13,0x59,0x82,0x46,0xb3, + 0xf4,0x89,0xf3,0xa5,0x6b,0x7a,0x5f,0xe6,0x5c, + 0xcb,0x36,0x3f,0xf9,0x3d,0x48,0x0f,0xb7,0xbd, + 0xdf,0x4a}, + .data_len = 128, + .mac_len = 20, + .mac = {0x6b,0x30,0x31,0x24,0x13,0x75,0x7c,0x67,0xa1, + 0xa1,0x7e,0xc1,0x58,0x35,0xe1,0xb7,0xe6,0x58, + 0x65,0x77}, + }, { // 16 (120) + .key = {0x0d,0xf4,0x0c,0xc5,0x47,0xac,0xed,0x4a,0x85, + 0xca,0x48,0x57,0x40,0x35,0x7c,0xa5,0xdd,0x07, + 0x45,0xcb,0x27,0x36,0xd5,0x05,0xfc,0x73,0x27, + 0x33,0x46,0x52,0x90,0x25,0x2e,0xac,0x97,0x15, + 0x8c,0x42,0x06,0x75,0xa1,0xa2,0x41,0xec,0x08, + 0x4f,0xd7,0x9b,0xea,0x1c,0x57,0xa4,0x72,0xd9, + 0x65}, + .key_len = 55, + .data = {0x95,0x9b,0xb5,0xd8,0x4a,0xd0,0x5a,0x55,0xca, + 0xad,0xef,0x57,0xc7,0xea,0xd8,0xfc,0xf9,0x33, + 0xa2,0xef,0x6e,0x2c,0xf3,0x8c,0x22,0xb1,0xc1, + 0x45,0xcf,0x62,0xc3,0x44,0x06,0x5f,0x25,0x51, + 0x7f,0x50,0x80,0xf7,0xae,0xa9,0x09,0xe2,0x96, + 0x2c,0x09,0x8c,0xe2,0xaf,0x8d,0x19,0x32,0x1f, + 0x5e,0x7f,0xb3,0xc5,0x33,0xe9,0xf2,0xc8,0x26, + 0x5e,0xf2,0xf3,0x65,0x9d,0x7c,0xb9,0x2a,0x4c, + 0xb6,0x76,0xed,0x52,0xf7,0xf8,0xd8,0x82,0xda, + 0x3e,0x7b,0x79,0x91,0x7f,0xc1,0xc9,0x7c,0x6f, + 0x22,0x57,0xfa,0xbd,0x1b,0x01,0x80,0xe0,0xdb, + 0x84,0xe8,0x13,0x40,0x9d,0x0b,0x9e,0x01,0x6f, + 0x91,0x58,0x2d,0x25,0x08,0x6a,0xd4,0xd8,0x34, + 0x55,0x03,0xb3,0xa6,0x37,0xf6,0x55,0x90,0x4a, + 0x8a,0x76}, + .data_len = 128, + .mac_len = 24, + .mac = {0x3b,0x47,0xb7,0x8b,0x7d,0xd5,0xe4,0xc0,0x09, + 0xa8,0x21,0x67,0x9e,0x8f,0x7d,0x84,0xd2,0x04, + 0x07,0x40,0x41,0xbd,0xa9,0xe4}, + }, { // 17 (121) + .key = {0x5a,0xd5,0x01,0x55,0xc4,0x65,0x26,0xa9,0xbe, + 0xd2,0x0d,0xac,0xcc,0xa0,0xf7,0x29,0xdf,0x0d, + 0xff,0x63,0x79,0xa2,0x58,0x4f,0x11,0x09,0xd7, + 0x00,0xb9,0x1e,0xb1,0x63,0xfe,0x48,0x85,0x2c, + 0x10,0x0a,0x9d,0x10,0x23,0xd5,0x71,0x35,0x14, + 0x21,0x6c,0xe7,0x50,0xbc,0xf3,0x8c,0xf2,0x61, + 0xa4}, + .key_len = 55, + .data = {0xc3,0x3d,0x3d,0x1f,0x44,0x27,0x76,0xd5,0x46, + 0xf4,0xd5,0xa2,0x5b,0x7d,0x23,0x40,0x2a,0x5f, + 0xd6,0x5e,0x6e,0xf3,0x33,0x3a,0x42,0x81,0xb5, + 0x72,0x9b,0xb0,0xb2,0x18,0x16,0x41,0x3c,0x04, + 0xf4,0xfd,0x46,0x6e,0x62,0xec,0x07,0xbc,0xfe, + 0xc8,0xa4,0x98,0x98,0xb1,0x09,0x46,0x35,0x22, + 0x17,0x34,0x5a,0x24,0x05,0xd3,0x87,0xc2,0x00, + 0xa6,0x01,0xbc,0x15,0x99,0xd4,0x80,0x51,0x93, + 0x19,0x55,0x27,0x4e,0x75,0xda,0x11,0x67,0xe2, + 0xaf,0x7a,0xb1,0xb2,0x72,0xdc,0xcf,0xd1,0xed, + 0x26,0x02,0x4a,0x8d,0x60,0x3f,0x0c,0x16,0x91, + 0x85,0xef,0x96,0xe1,0x6d,0xf2,0x98,0xfb,0x03, + 0xc6,0x99,0xb5,0xd4,0x91,0xc0,0xf3,0x48,0xec, + 0xc9,0xc8,0x32,0x2d,0x43,0xdf,0xa6,0xec,0xfb, + 0x1a,0x0b}, + .data_len = 128, + .mac_len = 24, + .mac = {0xc6,0x05,0xa8,0x4b,0x7f,0x4d,0x75,0x71,0xc4, + 0xf3,0xbc,0xee,0x28,0x3d,0x45,0xe2,0x7a,0x58, + 0x13,0xd8,0x00,0xfa,0x9d,0xc9}, + }, { // 18 (135) + .key = {0xb3,0x4a,0x6e,0xba,0x59,0xe6,0x32,0xe3,0xc3, + 0x34,0xdf,0x58,0x2f,0xd0,0xb0,0x3a,0xca,0x7f, + 0x64,0x1c,0x69,0x14,0x92,0x0a,0x79,0x94,0x3d, + 0xca,0x39,0x98,0xa8,0x61,0x27,0xf3,0x6b,0xda, + 0xb7,0x95,0xc7,0x42,0x4b,0xaf,0x37,0xf7,0x60, + 0x18,0x47,0x23,0x05,0xf0,0xa9,0x83,0x92,0x83, + 0x86}, + .key_len = 55, + .data = {0xd0,0x3d,0xd9,0x4e,0x43,0xd9,0x6c,0xa4,0x59, + 0x92,0x8a,0xa9,0x6d,0x2b,0x81,0xc3,0x5e,0xd5, + 0x45,0x66,0xe3,0x3e,0x66,0x35,0x1f,0xca,0x40, + 0x6b,0x76,0x20,0x72,0x7a,0x9e,0xe9,0x91,0xf2, + 0xf9,0xd4,0x1d,0xa3,0x22,0xde,0xb3,0x06,0xc6, + 0xd0,0x85,0xd9,0xb5,0x09,0x08,0x0a,0x38,0x7d, + 0xec,0xd6,0xa6,0xfe,0x51,0x32,0x32,0xbb,0x38, + 0x6a,0x07,0x06,0x37,0x08,0x97,0x5a,0x72,0xf7, + 0x2f,0x9c,0xc6,0xe8,0xcf,0xa1,0x47,0xf5,0x3a, + 0xf1,0xed,0x84,0x49,0xca,0x8a,0x6f,0x84,0x68, + 0xff,0x62,0xf3,0x84,0xb0,0x84,0x32,0x1b,0x35, + 0x59,0xc4,0x70,0x53,0xe7,0xa9,0x54,0x2a,0x17, + 0x33,0xa5,0xaf,0x5f,0x15,0x15,0x5d,0x9e,0xbd, + 0x2c,0x28,0x47,0xe4,0x91,0xb3,0xc2,0x63,0x85, + 0xc2,0x0f}, + .data_len = 128, + .mac_len = 28, + .mac = {0x1c,0x49,0x44,0x84,0x3c,0x3e,0xe7,0xf9,0x8a, + 0xb5,0x29,0x87,0xe0,0xd2,0xd4,0x49,0x4a,0xa7, + 0x25,0x48,0xbf,0xdc,0x36,0x02,0xdb,0x45,0xb5, + 0xf4}, + }, { // 19 (136) + .key = {0x2f,0xd5,0x86,0x3a,0xb5,0xac,0x01,0x09,0xcd, + 0x1c,0xc8,0xa6,0x59,0x8e,0x75,0xd8,0x58,0x11, + 0xa8,0x4d,0x0d,0xf1,0x4c,0xd5,0x5e,0x8b,0x1c, + 0xce,0x7a,0x5f,0x65,0xdf,0xbe,0x67,0x0d,0xea, + 0xda,0xa8,0xd4,0x3b,0x2f,0x06,0xda,0x06,0x7c, + 0x5c,0x62,0x10,0xba,0xcc,0xd5,0xac,0x44,0x54, + 0x0a}, + .key_len = 55, + .data = {0x85,0xc0,0x2d,0x7c,0xfa,0xb2,0x9f,0x8a,0xdf, + 0x0f,0xa5,0x5e,0xf3,0x67,0x22,0xa0,0x47,0x57, + 0xc8,0x86,0x50,0x53,0xd2,0xaf,0x3b,0xa2,0xf6, + 0x4e,0x80,0xaa,0x95,0x8a,0xba,0x6e,0x36,0x25, + 0xb6,0x55,0x32,0x5c,0xca,0x2d,0xb0,0x0f,0x68, + 0x6f,0xd4,0x22,0xf2,0xc5,0x34,0x23,0xd0,0xc9, + 0x8c,0x2d,0xc1,0x10,0xb2,0x0c,0x6e,0x67,0xcc, + 0xa1,0x45,0x5c,0xc0,0x88,0x84,0x01,0xec,0xf9, + 0x94,0xec,0x18,0xec,0x99,0x82,0xa8,0x81,0x47, + 0x76,0x16,0x9e,0xf7,0x8c,0xa0,0xda,0xfa,0xa3, + 0x3e,0x9a,0x2d,0xf2,0xd7,0x79,0xcd,0x92,0xb4, + 0xee,0x8d,0x3c,0x35,0x29,0xe6,0x55,0xc3,0x3d, + 0xaf,0x27,0x05,0x84,0xed,0x72,0x57,0x3f,0xec, + 0x23,0x78,0x7e,0x8f,0x63,0x82,0x40,0xe4,0xd3, + 0x20,0xda}, + .data_len = 128, + .mac_len = 28, + .mac = {0xea,0xbb,0xa9,0xf3,0x5b,0xa3,0x9c,0xfb,0x92, + 0x83,0x39,0x0d,0x54,0x25,0x68,0x7c,0xdd,0x70, + 0xd4,0xcb,0x1f,0xea,0x43,0x39,0x25,0x64,0x7c, + 0x79}, + }, { // 20 (150) + .key = {0xf4,0x29,0xce,0x00,0x3a,0x8a,0x56,0xac,0xa9, + 0x28,0xf8,0x8b,0xf9,0xad,0x4e,0x22,0xb2,0x4e, + 0x43,0xfa,0x42,0x95,0xca,0x8d,0x4c,0x64,0xd0, + 0x67,0x44,0x37,0x6e,0x85,0x39,0xa9,0x64,0x01, + 0xf1,0x3a,0xc3,0xf1,0x3b,0x4f,0xe9,0x8c,0x81, + 0x7a,0xb2,0x8e,0x9d,0xfc,0xed,0xde,0xed,0x88, + 0x0d,0x6e,0xaa,0x4a,0x21,0x63,0x75,0x28,0x07, + 0x77}, + .key_len = 64, + .data = {0x71,0x95,0xbe,0xf6,0xe6,0x3a,0x04,0xc5,0xd4, + 0xa5,0x65,0xff,0x52,0xe0,0xd3,0x99,0x17,0x19, + 0xd3,0xd6,0xea,0x48,0x8e,0x0a,0x59,0x12,0x25, + 0xa4,0xae,0xed,0x46,0x6b,0x1f,0x86,0xfd,0x08, + 0x45,0x60,0xcc,0xc5,0xd0,0xbd,0xfd,0x94,0x78, + 0xc1,0x37,0x53,0x37,0xd5,0x50,0x4e,0xb5,0x4a, + 0x62,0x06,0x04,0x3e,0x21,0x31,0x8d,0xc4,0x6b, + 0x01,0x4a,0x3f,0x21,0xa9,0x36,0x0f,0x36,0x1e, + 0x02,0x70,0x05,0x1a,0x0a,0x9e,0xe8,0x67,0x87, + 0x3e,0x06,0x5a,0x06,0xf9,0x6c,0x9e,0x19,0x6a, + 0x60,0x32,0x4c,0x3a,0xf1,0xb5,0x5a,0x89,0xd3, + 0xe2,0xa1,0x90,0x6a,0x57,0xd4,0x85,0x25,0x9a, + 0xf0,0xbf,0x0d,0x5d,0x71,0x1b,0x9e,0x01,0xc5, + 0x9e,0xd5,0x5a,0x01,0x5c,0x8a,0xb2,0xd3,0x98, + 0x00,0x10}, + .data_len = 128, + .mac_len = 14, + .mac = {0xf5,0xe7,0xc5,0x7d,0x68,0xeb,0x37,0x62,0x6c, + 0x4d,0x14,0xe9,0x14,0xc7}, + }, { // 21 (151) + .key = {0x99,0xe9,0xa3,0xe7,0x71,0xc6,0x1c,0x89,0xa9, + 0x04,0xf0,0xa1,0xe2,0x0e,0xf0,0x8f,0x92,0xd6, + 0x50,0x83,0xb3,0xbd,0xff,0x87,0xb8,0xb7,0x34, + 0xc0,0xc5,0xaa,0x4a,0xf0,0x1f,0x18,0xcd,0x40, + 0xe2,0xfe,0xd5,0x3d,0xf2,0xfc,0x92,0x20,0x33, + 0xb5,0x29,0x52,0xfd,0x79,0xbe,0x2f,0xca,0x22, + 0xd2,0x0b,0x32,0x3b,0xd0,0x72,0x1a,0x68,0xe2, + 0xb4}, + .key_len = 64, + .data = {0xea,0x75,0x33,0x86,0xd4,0x48,0x44,0xfc,0xbd, + 0xec,0x77,0x3f,0xa1,0x7d,0x50,0x55,0xba,0x5b, + 0x78,0xd1,0xa4,0xc5,0x06,0x03,0xbe,0xaa,0xfe, + 0x6c,0xd3,0xbb,0x17,0x74,0xfa,0xc5,0xc2,0x60, + 0xba,0x3e,0x67,0x7e,0x72,0x1e,0xf2,0xa2,0xf8, + 0xf0,0x8e,0xd6,0x81,0x28,0xb0,0x4e,0xc1,0xb7, + 0x58,0x9a,0x53,0xdd,0x94,0x1f,0x5a,0x3e,0x45, + 0xc8,0x69,0x39,0x25,0xf9,0xa0,0x75,0x09,0xc5, + 0x18,0xbc,0x64,0x60,0x82,0x0d,0x0d,0xd7,0x0a, + 0xec,0x42,0xfe,0x82,0xfd,0xec,0xaa,0xbc,0xd1, + 0x24,0x21,0x37,0x00,0xf7,0xcf,0xfe,0x78,0x66, + 0x3b,0xce,0x14,0xb1,0x39,0x77,0x71,0xd6,0x60, + 0x84,0xfd,0x54,0xbe,0x1e,0x50,0x34,0xcb,0x2e, + 0xc0,0x4a,0x9c,0xc2,0x2f,0xb9,0x59,0xb2,0x28, + 0xb5,0xf1}, + .data_len = 128, + .mac_len = 14, + .mac = {0x12,0x51,0x02,0x95,0xbb,0x35,0x34,0x36,0x9b, + 0xf5,0xd8,0x30,0xb1,0xad}, + }, { // 22 (165) + .key = {0xf0,0x0f,0x23,0x44,0xb9,0xff,0xa8,0xef,0x49, + 0xdb,0xb6,0x23,0xd0,0x1c,0xac,0x56,0x3a,0x13, + 0x69,0x76,0x0f,0x37,0x57,0xdb,0x97,0xbe,0xa9, + 0x7a,0x41,0x6a,0xe0,0x5b,0x45,0xa6,0x94,0x4d, + 0x89,0xd1,0x71,0xd8,0xc2,0xda,0x80,0x73,0xdb, + 0x0d,0xa7,0xf7,0x9a,0x2c,0x74,0x54,0x81,0xc2, + 0x16,0x82,0xf2,0xb4,0xac,0xbb,0x97,0x19,0xc3, + 0xe8}, + .key_len = 64, + .data = {0x88,0x2d,0x04,0x1c,0x2a,0x6f,0x05,0x05,0xef, + 0xe2,0xa6,0x6c,0x17,0x92,0x59,0x52,0xaf,0x30, + 0x95,0x9b,0x1a,0x5a,0x13,0x6f,0xf1,0x1b,0x3d, + 0xe1,0x0d,0xb6,0xe4,0xce,0xe1,0x9f,0x31,0x08, + 0x0d,0xcb,0xde,0xb4,0x31,0x29,0xa5,0xf1,0xff, + 0x71,0xf9,0xbb,0x95,0x1c,0xf5,0x0e,0x09,0xb3, + 0x92,0x4e,0x45,0x4d,0x1c,0xe6,0x15,0x54,0xe7, + 0x30,0x7e,0x87,0x3e,0x95,0x52,0x45,0x9c,0xf5, + 0x01,0x08,0x1f,0x48,0xb2,0x30,0x39,0x86,0x92, + 0x02,0xa9,0xc5,0x6c,0xf0,0xa9,0xa1,0x7b,0x1a, + 0x69,0xe1,0x7c,0x16,0xbd,0x58,0x06,0xec,0x12, + 0x08,0x1e,0x65,0xa7,0x8e,0x07,0x86,0xfa,0xba, + 0x57,0x57,0x80,0x7d,0x50,0xe9,0x98,0x08,0x6c, + 0x96,0xc2,0x32,0x3a,0x8b,0x0c,0x1a,0x69,0x84, + 0xce,0x0e}, + .data_len = 128, + .mac_len = 16, + .mac = {0xab,0x15,0x00,0x58,0x48,0x0e,0xfe,0x9b,0x92, + 0x43,0xbf,0x6d,0x59,0xb1,0xea,0x0f}, + }, { // 23 (166) + .key = {0x41,0xc9,0x0a,0xec,0xc4,0x6f,0xc8,0xe1,0x93, + 0x38,0x0e,0x6e,0x14,0x7f,0x1b,0xe2,0x2a,0x2c, + 0x85,0x8b,0xb6,0x2c,0xdb,0xcf,0x5e,0x1e,0x88, + 0x78,0x8d,0x4f,0xfa,0x50,0xba,0xe9,0x04,0xee, + 0xee,0x67,0x81,0xcf,0x80,0x4c,0x3b,0xa9,0x23, + 0x15,0x0b,0xfb,0x24,0x6c,0x41,0xe9,0xec,0x9e, + 0x45,0x47,0xcc,0x4f,0x7f,0xf4,0xfa,0x6d,0x75, + 0x69}, + .key_len = 64, + .data = {0x92,0x24,0x50,0x54,0x1f,0xe8,0xfc,0xa6,0x6a, + 0x8b,0xcd,0x46,0x91,0x3c,0x86,0xfa,0x15,0x0b, + 0x44,0x7c,0x99,0xa0,0x61,0xce,0xe7,0x2d,0x99, + 0xce,0x34,0xa1,0x6b,0x0a,0xa5,0x1f,0xc2,0xd5, + 0x12,0xae,0xd5,0x9b,0x09,0x32,0x4c,0x71,0x16, + 0x9b,0xa4,0xf0,0x41,0x5c,0xd4,0x44,0xd9,0x1e, + 0x31,0x80,0x70,0xb6,0x8f,0x34,0x27,0x55,0xa9, + 0x42,0x2c,0xff,0xc3,0xed,0x80,0x3f,0x8d,0x33, + 0xfe,0x18,0x4b,0x5d,0x99,0x3e,0x33,0xd4,0xe5, + 0x87,0x16,0x36,0xd9,0x9c,0x43,0xa9,0xd3,0xf4, + 0xa9,0x70,0xdc,0x03,0x3b,0xbc,0x2d,0xae,0x99, + 0xc4,0xf3,0x03,0xec,0x17,0x50,0x27,0x11,0x31, + 0xa2,0x8f,0xfb,0x4d,0x07,0x73,0x52,0x7b,0x21, + 0x80,0x60,0xf2,0x16,0xce,0x2e,0xa7,0xdb,0x11, + 0xea,0x1f}, + .data_len = 128, + .mac_len = 16, + .mac = {0xf8,0x4d,0x32,0x38,0x59,0x67,0x0d,0x90,0x05, + 0xe2,0x83,0x06,0x5a,0x76,0xae,0xfc}, + }, { // 24 (180) + .key = {0x0a,0xd0,0x88,0x72,0xef,0x79,0xc9,0x40,0x18, + 0x89,0x35,0x69,0x95,0x64,0xf1,0x8e,0x5c,0xb7, + 0x46,0xe7,0x8d,0xae,0xff,0x1f,0xfa,0x68,0x12, + 0x65,0xe6,0xa8,0x83,0xc0,0x0d,0xcd,0x86,0xa2, + 0xe5,0x04,0xe4,0xc1,0x24,0xbc,0x9f,0x22,0x82, + 0x5a,0xd9,0x76,0xc0,0x2e,0xf2,0xaa,0xe9,0xa6, + 0xf1,0xba,0xd8,0xc2,0x25,0xc6,0xfa,0xc8,0x0c, + 0x67}, + .key_len = 64, + .data = {0xca,0xdf,0xc1,0xa6,0x87,0xa6,0xb4,0x36,0xe1, + 0xbd,0x3f,0x6f,0xeb,0xbf,0x19,0x78,0x41,0xa6, + 0xeb,0xae,0xe0,0x49,0xbd,0x44,0x3b,0x24,0xae, + 0x2c,0x8b,0x58,0xe9,0x3b,0x66,0xf2,0xd4,0x88, + 0x93,0x70,0x8b,0x15,0x1d,0x82,0x8c,0xb1,0xa6, + 0x0d,0xb4,0x1c,0xfe,0x75,0x6a,0x6d,0xf4,0x1c, + 0x1a,0xb1,0x6c,0x26,0xe5,0xd5,0xb2,0x80,0x96, + 0xc6,0x0e,0x20,0xd8,0xd6,0x99,0x8e,0xa7,0x62, + 0x4e,0xa3,0x05,0xb1,0x64,0x90,0xee,0x20,0xdc, + 0x23,0x8d,0x7c,0x56,0x46,0xb0,0xb0,0x28,0xc9, + 0x7a,0xa0,0xb1,0x61,0x57,0x54,0xeb,0xf0,0x35, + 0x59,0x40,0x06,0xf2,0x64,0x9f,0xa8,0x10,0x39, + 0xce,0x51,0xb0,0xcb,0x02,0x37,0xbe,0xa5,0xad, + 0xcf,0x69,0x88,0x97,0x93,0xd6,0x56,0x30,0x03, + 0x15,0x2e}, + .data_len = 128, + .mac_len = 20, + .mac = {0x1f,0x60,0xfc,0xa9,0x69,0x4f,0x82,0x54,0x77, + 0x8f,0x18,0xca,0xb6,0xc2,0x86,0xa0,0x4f,0x89, + 0xb3,0x71}, + }, { // 25 (181) + .key = {0x59,0x88,0xc7,0x94,0xc1,0xf1,0xe8,0x5d,0x23, + 0xd6,0x5b,0xe0,0x40,0xc0,0x12,0x9b,0xb8,0xa6, + 0xbb,0xcc,0xd8,0x6c,0x3b,0x1e,0xb3,0xa9,0x58, + 0x87,0x74,0xad,0xb5,0x71,0xf2,0xc3,0x04,0x18, + 0x85,0xb3,0x77,0x33,0x19,0x8b,0x77,0xd6,0x80, + 0x9f,0x99,0x97,0x0d,0xcf,0xce,0xf0,0x5e,0x08, + 0xda,0xe4,0x79,0x0e,0x07,0xe5,0x1b,0x78,0x1a, + 0xf6}, + .key_len = 64, + .data = {0x40,0xae,0x14,0x83,0x42,0x14,0xdf,0x6b,0xf1, + 0x10,0x10,0xa3,0x21,0x33,0xc6,0x63,0x7b,0x9b, + 0x79,0xd3,0xd7,0xc3,0x80,0x7a,0xed,0x9f,0xd6, + 0xf9,0x2d,0xe9,0x1d,0xf9,0xeb,0xb6,0xe3,0x62, + 0xbf,0x4c,0x25,0xcd,0x2c,0x37,0x11,0x3d,0x7f, + 0x9a,0x10,0x09,0xfa,0xc4,0x04,0x1d,0x32,0x03, + 0xce,0x63,0xb6,0xbd,0x14,0x7b,0xf1,0xbc,0x41, + 0xb2,0x52,0xca,0xcd,0x32,0xaa,0x7e,0xbe,0x76, + 0xd5,0x55,0x6f,0x01,0x9c,0x04,0x90,0x50,0xda, + 0x0d,0x6e,0x0d,0xde,0x91,0x74,0x85,0x11,0x65, + 0xf2,0x5c,0xd8,0x68,0x1e,0x7f,0xbc,0x13,0x59, + 0x5b,0xc9,0x51,0xb3,0x4d,0x33,0x91,0xb0,0x59, + 0x40,0x1a,0x4d,0x1e,0x61,0x9f,0x3e,0x09,0xa2, + 0x14,0x7a,0xca,0x45,0xc0,0xf9,0x04,0xaa,0x92, + 0xbc,0x49}, + .data_len = 128, + .mac_len = 20, + .mac = {0x25,0xc4,0xde,0x6c,0x4e,0x70,0x53,0xec,0x00, + 0xc2,0x9d,0x0e,0x95,0xb5,0x1c,0xcc,0x78,0xc1, + 0xf1,0x10}, + }, { // 26 (195) + .key = {0xc7,0x34,0x1f,0xb6,0x18,0xef,0x24,0x48,0xc1, + 0x1c,0x67,0x61,0x11,0x9e,0xd1,0x97,0x56,0x56, + 0x4c,0x78,0xf6,0xe9,0x7b,0x72,0xbb,0xc4,0xa8, + 0xf0,0x6f,0x5e,0xfe,0xc6,0xa9,0xbd,0xf8,0xcf, + 0xe6,0x3c,0x19,0xd4,0xdb,0x8b,0xde,0xb0,0x0a, + 0xf7,0xf1,0xb2,0x94,0xec,0x9f,0x43,0x4e,0xb8, + 0x8c,0xc9,0x16,0x91,0xa5,0xcb,0x68,0xda,0x57, + 0x55}, + .key_len = 64, + .data = {0xe2,0xdf,0x37,0xf7,0x50,0xaa,0xdc,0x39,0x3a, + 0x1d,0x30,0x72,0x2f,0x9c,0xda,0x3d,0xaf,0xb6, + 0xfd,0xc3,0x90,0xfa,0xba,0x2f,0xa1,0x0c,0xf7, + 0x62,0x8e,0xf8,0x5f,0xe7,0x03,0xc5,0xaa,0x29, + 0x14,0x4e,0x1f,0xe3,0xdd,0x4d,0x57,0xd9,0x65, + 0xb9,0x43,0xc6,0xc9,0x52,0x71,0x95,0x96,0x7a, + 0x8a,0xd3,0x76,0x46,0x20,0x65,0x0f,0xd5,0xa6, + 0x76,0x28,0xe0,0xc0,0xb4,0x0d,0x93,0xbe,0xbc, + 0x35,0x9b,0x62,0xd2,0x23,0x81,0xea,0xd6,0x8a, + 0x36,0x4a,0x73,0xb4,0xef,0xba,0x9a,0x24,0x32, + 0x70,0x2f,0x7b,0x31,0xaf,0x02,0x98,0x58,0x00, + 0x00,0x03,0x22,0xc0,0xab,0x8c,0x30,0xda,0xc7, + 0x2f,0x9c,0xd6,0x56,0x3b,0x8b,0x13,0xc7,0xb4, + 0x01,0x50,0x6b,0xf5,0xfa,0x71,0x28,0x99,0xb6, + 0x80,0x71}, + .data_len = 128, + .mac_len = 24, + .mac = {0x0a,0x94,0xe0,0x61,0xe9,0x65,0xf1,0x09,0x81, + 0x02,0x96,0x6f,0x5e,0xf8,0xf0,0x31,0x07,0x6b, + 0x13,0xd8,0xb5,0xb3,0x62,0xd0}, + }, { // 27 (196) + .key = {0x7d,0x40,0x85,0xba,0xfc,0xc1,0x42,0x00,0xf7, + 0xad,0x29,0x8c,0xd0,0xed,0x4c,0xb8,0xc9,0xc8, + 0xa9,0x1c,0x6c,0xb3,0xac,0x02,0x2a,0x6a,0xf6, + 0x1a,0x42,0x3f,0x5d,0x70,0xe4,0xb2,0x34,0x9a, + 0x96,0x43,0xcc,0x36,0xd8,0x84,0x3a,0x94,0x03, + 0x72,0x5b,0xaf,0x77,0x05,0x16,0x62,0xf5,0x06, + 0xe1,0xd8,0x4a,0x21,0x87,0x45,0x2e,0x3b,0x28, + 0xd3}, + .key_len = 64, + .data = {0x19,0x2a,0xdf,0x7a,0x27,0x91,0x33,0x1e,0x99, + 0x5c,0xa9,0x76,0xa8,0x36,0x50,0x21,0xfe,0x66, + 0x61,0x49,0xb6,0xf6,0xd0,0xe0,0x83,0x14,0x22, + 0x29,0x2f,0xb8,0x7e,0x7b,0x48,0x87,0x06,0x42, + 0x16,0xf8,0x68,0x46,0xcf,0xb5,0xaf,0x30,0x0e, + 0x44,0x60,0x4a,0x82,0xe6,0xc2,0x86,0xe3,0xbf, + 0x7d,0xc2,0x2b,0x38,0x66,0x4a,0x02,0xa2,0x9a, + 0x9e,0x7a,0x1c,0xca,0x76,0xfc,0xb6,0xd5,0x04, + 0x83,0xd6,0x9c,0x79,0x07,0xdb,0x12,0xca,0x3d, + 0x01,0x92,0xb4,0x7d,0x84,0x76,0xfe,0x03,0x09, + 0xe5,0xfe,0x5b,0x39,0xec,0x5e,0x17,0xaf,0xd0, + 0x20,0xc3,0x14,0xa3,0xe0,0x1b,0x88,0x16,0x59, + 0x7b,0x44,0x8e,0x2b,0x96,0x7e,0x7a,0xdc,0x6b, + 0x8d,0xe3,0x1c,0x75,0x4e,0x44,0x4d,0x22,0xc6, + 0x9d,0x42}, + .data_len = 128, + .mac_len = 24, + .mac = {0x0d,0x47,0xd7,0x80,0x8c,0x1f,0xc2,0xd4,0x0a, + 0x5f,0xb6,0x7f,0x75,0xb0,0xd5,0x54,0x92,0x9e, + 0x40,0x94,0xfc,0x45,0xee,0x88}, + }, { // 28 (210) + .key = {0xf3,0xaa,0x51,0xee,0x90,0xaa,0x06,0xe9,0x8e, + 0x23,0x88,0xdf,0x7a,0x3a,0xf2,0xcd,0x69,0x7f, + 0x2a,0x52,0x8f,0x2a,0x14,0x14,0x0d,0xa4,0x05, + 0x60,0x0b,0x4a,0x7b,0x10,0x07,0x6d,0x0b,0xb2, + 0x6c,0x9d,0x9a,0xe6,0x67,0x27,0xd0,0x08,0xf6, + 0xdc,0xca,0x0f,0x42,0x14,0x0f,0xb5,0x2e,0xf3, + 0xc6,0xd9,0x30,0xeb,0x26,0x21,0x60,0x82,0x2d, + 0xe3}, + .key_len = 64, + .data = {0x2c,0x07,0x0e,0x5e,0xb0,0xa7,0xef,0xbf,0xc4, + 0x0b,0x23,0x43,0x14,0xc0,0x55,0xfc,0x43,0x6c, + 0xe1,0xe2,0x30,0x05,0x39,0xb3,0x78,0x42,0x87, + 0xfd,0x3c,0x4f,0x94,0x78,0x24,0xc5,0xe8,0x9a, + 0xa3,0xd9,0x33,0x66,0x7d,0xd4,0xeb,0x85,0x87, + 0xc3,0x37,0x97,0xae,0x6f,0x0c,0xcb,0x3b,0x8f, + 0x95,0xad,0x56,0x3d,0xd9,0x40,0xc8,0xa7,0x98, + 0x4d,0x05,0x07,0x75,0xfa,0x69,0xd5,0x5b,0x9e, + 0xc2,0x3a,0x19,0xd4,0x0f,0xc9,0x4f,0xcf,0x87, + 0x6a,0x8e,0xed,0xdd,0x96,0xbb,0x8e,0xc3,0xca, + 0xb4,0x26,0xad,0x35,0x36,0x91,0xd7,0xb4,0xff, + 0xa7,0x89,0x01,0x2f,0x11,0x9a,0x28,0xf4,0x5b, + 0x33,0x3a,0x66,0x49,0xd5,0x44,0xb0,0x6f,0x9d, + 0x82,0x71,0xfc,0xc7,0xd1,0x62,0xd7,0x72,0x63, + 0x38,0xed}, + .data_len = 128, + .mac_len = 28, + .mac = {0x69,0x5c,0x32,0x8d,0xc8,0x58,0xa4,0x6b,0xe7, + 0xac,0x8b,0x8d,0xeb,0xf5,0x8d,0xd9,0xa9,0xbd, + 0x72,0xd7,0xa4,0x08,0xa4,0x3e,0x6b,0xbc,0x69, + 0xa3}, + }, { // 29 (211) + .key = {0xa2,0x7f,0x5b,0xa4,0xa0,0xd5,0xa8,0x0c,0xb4, + 0xef,0x9b,0xb1,0x8d,0x4f,0xfc,0x4a,0xd4,0x87, + 0x68,0x0c,0xb5,0xa8,0xf6,0xc6,0x9c,0xfe,0x1b, + 0x29,0x3c,0xfa,0xcb,0x67,0xd6,0x70,0xe1,0x01, + 0xb8,0x03,0xc1,0xd9,0x04,0xdd,0x3c,0x8f,0xb2, + 0xa3,0xb4,0x0a,0xd8,0xa7,0x80,0x55,0x29,0x60, + 0x91,0xad,0xbc,0x18,0x56,0xd8,0x10,0xe5,0xde, + 0xb8}, + .key_len = 64, + .data = {0x80,0x2e,0xd2,0x88,0x73,0xc2,0x16,0x05,0x62, + 0xfb,0x91,0x62,0x24,0x6b,0x60,0xd7,0x5e,0x2f, + 0xfb,0x8c,0xec,0xc5,0xbb,0x08,0x83,0x1e,0x9a, + 0xec,0x94,0xf4,0x3b,0xe1,0x73,0x5e,0x2a,0xcf, + 0xb8,0xa2,0x64,0x50,0xe6,0x4a,0x1a,0x64,0x4a, + 0x7a,0xb2,0x66,0x26,0x80,0x0f,0x3e,0x0f,0xad, + 0x12,0xd9,0x94,0x63,0x60,0xd6,0x20,0x70,0x66, + 0x82,0x22,0x9a,0x9b,0x07,0x6a,0x7b,0x05,0xe0, + 0xd6,0x90,0xff,0x90,0x2f,0x8c,0x39,0x94,0x4e, + 0xf2,0x00,0x96,0x83,0xe2,0xc0,0xe3,0x37,0x33, + 0xc7,0x1f,0xcf,0xc3,0x4b,0x38,0xd4,0x0b,0xaf, + 0x98,0x51,0xf7,0x02,0x9f,0x7d,0xf4,0xc9,0x50, + 0x9a,0x4a,0xfe,0x4a,0x1d,0xac,0x58,0xfa,0x0f, + 0x0d,0xcd,0x10,0xb3,0xb6,0x56,0x2f,0x69,0x96, + 0xf2,0xe9}, + .data_len = 128, + .mac_len = 28, + .mac = {0xee,0x63,0xe8,0x6a,0xac,0x85,0xf3,0x69,0x61, + 0xd6,0x97,0x45,0x12,0x88,0xcf,0x78,0x00,0x41, + 0xea,0xfe,0x46,0x2c,0xa6,0x55,0x70,0x35,0xd9, + 0x2a}, + } +}; + + +struct HMAC_TEST_VECTOR fips_sha256_hmac_general_test_vector[] = { + { // 0 (0) + .key = {0x6f,0x35,0x62,0x8d,0x65,0x81,0x34,0x35,0x53, + 0x4b,0x5d,0x67,0xfb,0xdb,0x54,0xcb,0x33,0x40, + 0x3d,0x04,0xe8,0x43,0x10,0x3e,0x63,0x99,0xf8, + 0x06,0xcb,0x5d,0xf9,0x5f,0xeb,0xbd,0xd6,0x12, + 0x36,0xf3,0x32,0x45}, + .key_len = 40, + .data = {0x75,0x2c,0xff,0x52,0xe4,0xb9,0x07,0x68,0x55, + 0x8e,0x53,0x69,0xe7,0x5d,0x97,0xc6,0x96,0x43, + 0x50,0x9a,0x5e,0x59,0x04,0xe0,0xa3,0x86,0xcb, + 0xe4,0xd0,0x97,0x0e,0xf7,0x3f,0x91,0x8f,0x67, + 0x59,0x45,0xa9,0xae,0xfe,0x26,0xda,0xea,0x27, + 0x58,0x7e,0x8d,0xc9,0x09,0xdd,0x56,0xfd,0x04, + 0x68,0x80,0x5f,0x83,0x40,0x39,0xb3,0x45,0xf8, + 0x55,0xcf,0xe1,0x9c,0x44,0xb5,0x5a,0xf2,0x41, + 0xff,0xf3,0xff,0xcd,0x80,0x45,0xcd,0x5c,0x28, + 0x8e,0x6c,0x4e,0x28,0x4c,0x37,0x20,0x57,0x0b, + 0x58,0xe4,0xd4,0x7b,0x8f,0xee,0xed,0xc5,0x2f, + 0xd1,0x40,0x1f,0x69,0x8a,0x20,0x9f,0xcc,0xfa, + 0x3b,0x4c,0x0d,0x9a,0x79,0x7b,0x04,0x6a,0x27, + 0x59,0xf8,0x2a,0x54,0xc4,0x1c,0xcd,0x7b,0x5f, + 0x59,0x2b}, + .data_len = 128, + .mac_len = 16, + .mac = {0x05,0xd1,0x24,0x3e,0x64,0x65,0xed,0x96,0x20, + 0xc9,0xae,0xc1,0xc3,0x51,0xa1,0x86}, + .chunks = {64, 64}, + .num_chunks = 2, + }, { // 1 (1) + .key = {0x17,0xb5,0x28,0x58,0xe3,0xe1,0x35,0xbe,0x44, + 0x40,0xd7,0xdf,0x0c,0xa9,0x96,0xf4,0x1c,0xcb, + 0x78,0xb7,0xd8,0xcc,0x19,0x24,0xd8,0x30,0xfe, + 0x81,0xe0,0xfd,0x27,0x9c,0x13,0x1c,0xe3,0x54, + 0x63,0x03,0xe9,0x5a}, + .key_len = 40, + .data = {0xe0,0xef,0xf0,0x0f,0x3c,0x46,0xe9,0x6c,0x8d, + 0x5b,0xd1,0x81,0x28,0x3e,0x46,0x05,0x34,0x8e, + 0x3f,0xa1,0x0b,0x47,0x94,0x5d,0xe3,0xdc,0xc1, + 0x59,0xae,0x86,0xe7,0xbd,0x3f,0xdb,0x13,0xf2, + 0xad,0xa2,0xc3,0x13,0xfc,0xe6,0xa6,0x9e,0xfa, + 0x49,0xa4,0x70,0x68,0x9b,0x1e,0xf0,0x5a,0xab, + 0x77,0x8a,0xe1,0x5d,0xd3,0x5f,0xe6,0xfd,0x1e, + 0x3a,0x59,0xd3,0x51,0xc6,0x8c,0xf8,0xf0,0xff, + 0xd9,0x68,0xd7,0xe7,0x8b,0x57,0x37,0x7a,0xfc, + 0xc9,0xdc,0xe3,0xfa,0x5d,0xb1,0xf0,0x6f,0x69, + 0x85,0xc4,0x41,0x4c,0x0f,0xcc,0x78,0x00,0x30, + 0xf4,0x9f,0xef,0x79,0x1a,0x6c,0x08,0xed,0xc2, + 0xa3,0x11,0x08,0x0c,0x37,0x3f,0x00,0xe4,0xb2, + 0x04,0x4a,0x79,0xd8,0x28,0x60,0xf0,0x87,0x1b, + 0xc2,0x59}, + .data_len = 128, + .mac_len = 16, + .mac = {0xc4,0x06,0x14,0x27,0x76,0x4f,0x97,0x94,0x68, + 0xac,0x42,0x28,0x91,0xde,0xa9,0xca}, + .chunks = {32, 32, 32, 32}, + .num_chunks = 4, + }, { // 2 (15) + .key = {0x14,0xd4,0x5c,0xa2,0xa3,0xd4,0x97,0x7d,0xab, + 0x2b,0x7d,0x44,0x2c,0x6f,0x9e,0x57,0xce,0x34, + 0x8e,0x0a,0x6a,0x80,0x8b,0xb3,0xcc,0x7f,0x60, + 0x02,0xb8,0x77,0x89,0x91,0x2a,0xfd,0x98,0xbc, + 0xe2,0x6a,0xd8,0xb3}, + .key_len = 40, + .data = {0x0c,0x29,0x4a,0x31,0x8b,0x7c,0x1e,0x88,0x46, + 0x49,0xfe,0x54,0xe4,0xa8,0x72,0x85,0xe4,0x2f, + 0x86,0x8e,0x3d,0x0a,0x85,0x19,0x41,0x4e,0x05, + 0xf9,0xc7,0x8b,0x23,0x60,0x89,0xa1,0x10,0x52, + 0xcb,0xd4,0xcd,0x59,0x3e,0x22,0x32,0x7b,0x23, + 0xd3,0x35,0x69,0xb3,0x53,0x69,0xf9,0xbf,0x3d, + 0xc5,0xd6,0x94,0xb8,0xa7,0x76,0x21,0x06,0x18, + 0x4d,0x5c,0x5a,0x52,0x41,0xe1,0xea,0x80,0x5d, + 0xdc,0x46,0xc4,0xc9,0x2a,0xe8,0x7e,0xfa,0xbb, + 0x0c,0xcc,0x26,0x3b,0xc2,0x4d,0xfb,0xf1,0x41, + 0x2b,0x90,0xe7,0x7e,0x58,0x9c,0x4b,0xfd,0x17, + 0xe6,0x15,0xe7,0xbf,0xfc,0xea,0x5e,0xbb,0x28, + 0x40,0x0d,0xd6,0xa0,0xc4,0x03,0xb6,0xfd,0xf8, + 0xc1,0xa5,0xee,0x21,0x91,0x98,0x2e,0x60,0x1a, + 0x69,0xb3}, + .data_len = 128, + .mac_len = 24, + .mac = {0x28,0xf1,0xb6,0x63,0x21,0x30,0x43,0xc4,0xd4, + 0xfb,0x31,0x2b,0xd3,0x6d,0x85,0xfb,0xe6,0x2c, + 0x80,0x08,0xce,0x82,0xaa,0xbc}, + .chunks = {32, 32, 64}, + .num_chunks = 3, + }, { //3 (16) + .key = {0x2a,0x04,0x66,0xdd,0x51,0x5d,0x2f,0x48,0xfe, + 0xc5,0xe7,0x8e,0x22,0xbb,0x22,0xc6,0x06,0xb0, + 0x9e,0x81,0x84,0x69,0x1c,0x51,0x77,0xa4,0x6e, + 0x8c,0x70,0xfe,0xd2,0x4d,0xab,0x14,0x7e,0xbc, + 0x41,0xe9,0x7c,0x8f}, + .key_len = 40, + .data = {0xd6,0x08,0x12,0x43,0x30,0x98,0xc4,0x46,0x23, + 0x15,0x91,0x53,0xde,0x7c,0xd2,0x72,0x1b,0x34, + 0x9f,0x68,0x5c,0x43,0x38,0x8a,0x74,0xc2,0xa3, + 0xd0,0x4a,0x8e,0x97,0x2a,0xda,0x41,0x99,0x17, + 0x7c,0x61,0x65,0x73,0x69,0xd7,0x8f,0x90,0x7b, + 0xa2,0x6a,0x89,0x34,0xcc,0x29,0xd3,0x02,0x9d, + 0x44,0x15,0xc1,0x10,0x1e,0x3a,0x82,0x83,0xe4, + 0xc4,0x8b,0xb2,0xb8,0x63,0x9f,0xe6,0x0f,0xc6, + 0x7f,0x6a,0x57,0xb1,0xb0,0x3f,0xde,0x50,0x7f, + 0x10,0xef,0xcb,0x43,0x68,0x3e,0x1a,0xe2,0x23, + 0x85,0x1b,0x96,0x23,0x70,0xe1,0xf1,0x44,0xb7, + 0x4f,0x1f,0x91,0x89,0xe6,0x6c,0xb8,0x31,0xdc, + 0x05,0xbb,0xf4,0x6e,0x03,0xe9,0x38,0x77,0xa5, + 0x0d,0xec,0x40,0xdd,0xe5,0x23,0x9a,0x0f,0xd5, + 0x02,0x2a}, + .data_len = 128, + .mac_len = 24, + .mac = {0X7c,0x2e,0x5f,0x1f,0xdb,0xda,0x3c,0x15,0x35, + 0x36,0xec,0x71,0x36,0x09,0x1e,0xba,0x0b,0xa5, + 0x25,0xb9,0x50,0xbf,0xc8,0x4f}, + .chunks = {128}, + .num_chunks = 1, + }, { // 4 (30) + .key = {0x97,0x79,0xd9,0x12,0x06,0x42,0x79,0x7f,0x17, + 0x47,0x02,0x5d,0x5b,0x22,0xb7,0xac,0x60,0x7c, + 0xab,0x08,0xe1,0x75,0x8f,0x2f,0x3a,0x46,0xc8, + 0xbe,0x1e,0x25,0xc5,0x3b,0x8c,0x6a,0x8f,0x58, + 0xff,0xef,0xa1,0x76}, + .key_len = 40, + .data = {0xb1,0x68,0x9c,0x25,0x91,0xea,0xf3,0xc9,0xe6, + 0x60,0x70,0xf8,0xa7,0x79,0x54,0xff,0xb8,0x17, + 0x49,0xf1,0xb0,0x03,0x46,0xf9,0xdf,0xe0,0xb2, + 0xee,0x90,0x5d,0xcc,0x28,0x8b,0xaf,0x4a,0x92, + 0xde,0x3f,0x40,0x01,0xdd,0x9f,0x44,0xc4,0x68, + 0xc3,0xd0,0x7d,0x6c,0x6e,0xe8,0x2f,0xac,0xea, + 0xfc,0x97,0xc2,0xfc,0x0f,0xc0,0x60,0x17,0x19, + 0xd2,0xdc,0xd0,0xaa,0x2a,0xec,0x92,0xd1,0xb0, + 0xae,0x93,0x3c,0x65,0xeb,0x06,0xa0,0x3c,0x9c, + 0x93,0x5c,0x2b,0xad,0x04,0x59,0x81,0x02,0x41, + 0x34,0x7a,0xb8,0x7e,0x9f,0x11,0xad,0xb3,0x04, + 0x15,0x42,0x4c,0x6c,0x7f,0x5f,0x22,0xa0,0x03, + 0xb8,0xab,0x8d,0xe5,0x4f,0x6d,0xed,0x0e,0x3a, + 0xb9,0x24,0x5f,0xa7,0x95,0x68,0x45,0x1d,0xfa, + 0x25,0x8e}, + .data_len = 128, + .mac_len = 32, + .mac = {0x76,0x9f,0x00,0xd3,0xe6,0xa6,0xcc,0x1f,0xb4, + 0x26,0xa1,0x4a,0x4f,0x76,0xc6,0x46,0x2e,0x61, + 0x49,0x72,0x6e,0x0d,0xee,0x0e,0xc0,0xcf,0x97, + 0xa1,0x66,0x05,0xac,0x8b}, + .chunks = {32, 0, 64, 32}, + .num_chunks = 4, + }, { // 5 (31) + .key = {0x09,0x67,0x5f,0x2d,0xcc,0x47,0x83,0xb5,0x99, + 0xf1,0x8f,0xb7,0x65,0x58,0x36,0x68,0xa0,0xfd, + 0x8a,0xe4,0x09,0x6f,0x6f,0xcd,0xc6,0x0d,0x4f, + 0x35,0xb4,0x13,0x0f,0xbe,0xfc,0xd5,0x42,0xff, + 0xe7,0x45,0x9d,0x2a}, + .key_len = 40, + .data = {0x0c,0xf2,0x19,0x8c,0x31,0x37,0x6f,0x5c,0x89, + 0x15,0x66,0x01,0x37,0x72,0x5f,0x2b,0xbc,0x18, + 0x0a,0x98,0x6e,0x5a,0x7b,0xda,0x27,0xfa,0x81, + 0x59,0x3a,0x4a,0x33,0x9b,0xab,0x92,0xcb,0xc3, + 0x9f,0xb2,0xb8,0x58,0x11,0x08,0xee,0x48,0xc7, + 0x94,0x81,0x2d,0x84,0x5a,0x72,0xce,0x80,0x08, + 0xc9,0xe9,0x15,0xd9,0xe3,0x30,0xbb,0xb9,0x0e, + 0x91,0x36,0xaa,0x53,0xba,0x0e,0x66,0x93,0xdd, + 0x40,0x46,0xd6,0xb0,0x33,0x62,0xdf,0xb9,0xed, + 0xfa,0x04,0xc8,0x87,0x15,0x3c,0xc5,0xde,0x67, + 0x7a,0xab,0x8c,0x78,0x39,0xd5,0x17,0x03,0x58, + 0x79,0x67,0x9c,0x29,0x72,0x7e,0x96,0xc5,0x42, + 0x63,0x24,0xa2,0x57,0x5f,0xbe,0x67,0x8d,0x6c, + 0xc7,0xfe,0xf5,0xeb,0x6c,0xeb,0xd5,0x95,0xcf, + 0xdd,0xef}, + .data_len = 128, + .mac_len = 32, + .mac = {0x6b,0x14,0x2d,0x4d,0xfe,0x21,0x7f,0x18,0x81, + 0xaa,0x0e,0x64,0x83,0xb2,0x71,0xdd,0x5d,0x43, + 0xf7,0x0b,0x85,0x60,0x59,0x53,0xa0,0xfe,0xf2, + 0x72,0xdd,0xde,0x46,0xca}, + .chunks = {64, -1, 64}, + .num_chunks = 3, + }, { // 6 (45) + .key = {0xf9,0x87,0xeb,0x83,0xa3,0xfd,0x6d,0x94,0xeb, + 0xf3,0x62,0x6b,0x7d,0x34,0xfe,0xc2,0x3e,0xe0, + 0x6c,0x63,0xdf,0xb4,0x07,0x8c,0xb3,0x8b,0xcc, + 0x97,0xbd,0x25,0x0f,0xda,0x0e,0x28,0x6e,0xcd, + 0x4e,0x64,0x04,0x6a,0x98,0x5b,0xdf,0xda,0x8b}, + .key_len = 45, + .data = {0x39,0x0a,0x9d,0xc2,0xea,0x20,0x22,0x1c,0x59, + 0x93,0xc5,0x81,0x89,0x2e,0xb4,0xb0,0x43,0x64, + 0x29,0x4f,0xad,0x91,0x9c,0x45,0x1e,0x83,0x37, + 0x65,0x31,0x39,0x8a,0x4c,0x18,0xea,0x80,0x8c, + 0x33,0x4a,0x91,0x0a,0xe1,0x08,0x3a,0xa4,0x97, + 0x9b,0xaa,0x17,0x2f,0x3e,0xbf,0x20,0x82,0x39, + 0x30,0xe2,0x38,0x63,0x0c,0x88,0xdf,0xe5,0x63, + 0x2b,0x3b,0x40,0x42,0xf6,0xdd,0x92,0xe5,0x88, + 0xf7,0x15,0x29,0x99,0x6f,0xe8,0x40,0xe1,0x32, + 0x12,0xa8,0x35,0xcb,0xc4,0x5e,0xf4,0x34,0xde, + 0x4f,0xa1,0xec,0xb5,0x0f,0xd1,0x49,0x13,0xcd, + 0x48,0x10,0x80,0x87,0x5f,0x43,0xc0,0x7a,0xa9, + 0x3a,0x9d,0xdd,0xd5,0xf5,0xe7,0xce,0xd6,0xb1, + 0xb8,0x8d,0x42,0xb9,0xfc,0xe8,0xf8,0x7f,0x31, + 0xf6,0x06}, + .data_len = 128, + .mac_len = 16, + .mac = {0x0b,0x3b,0x22,0x0e,0xe7,0xa4,0xfd,0xcb,0x0d, + 0x17,0xa5,0xc8,0xb5,0x95,0xb9,0x81}, + .chunks = {54, 0, 54, -1, 20}, + .num_chunks = 5, + }, { // 7 (46) + .key = {0xef,0x25,0x71,0x32,0xb7,0xbe,0x12,0x4e,0xa0, + 0x88,0x6d,0x58,0x77,0x65,0xe8,0xe7,0x03,0x57, + 0x95,0x9c,0xf3,0x9e,0xbf,0x62,0x14,0x20,0xc3, + 0xf3,0xc7,0x0e,0x21,0x9f,0xb3,0xc5,0xd3,0x49, + 0xb7,0xf2,0xde,0xb2,0x22,0xfa,0x26,0xfa,0x27}, + .key_len = 45, + .data = {0xf9,0x07,0x68,0x95,0x4c,0xdc,0xbd,0x57,0x05, + 0xf9,0xd3,0x18,0xfc,0xa6,0x59,0x17,0x87,0xaf, + 0x84,0x0a,0x92,0x1f,0xbd,0x06,0xf2,0x4b,0x97, + 0x9e,0xf6,0x12,0x03,0x4f,0x3f,0x64,0xc7,0x1c, + 0xd2,0x01,0x2c,0x75,0x6c,0x83,0xf7,0x5d,0x16, + 0x9f,0x9b,0xcc,0xf8,0xa8,0xad,0x52,0x72,0x54, + 0x98,0xfe,0x69,0xc3,0x92,0x7e,0xdf,0xbd,0xcf, + 0x87,0xc7,0x3c,0xf4,0x78,0x17,0x2a,0xce,0x3a, + 0x1e,0x6b,0x44,0x6a,0x18,0x1e,0x8a,0xba,0x00, + 0x20,0x98,0x94,0xa5,0xd2,0xdb,0x01,0x00,0x1d, + 0x2a,0xca,0xc5,0xb3,0xfb,0xdd,0x38,0x97,0xd7, + 0xf1,0x42,0xdf,0x0b,0x6d,0xc4,0xb9,0xa1,0x86, + 0x2b,0xac,0x8e,0xa8,0x45,0x20,0x2d,0x18,0x53, + 0x21,0xec,0xd7,0x5f,0x60,0x46,0xc9,0xcf,0x7a, + 0xf1,0x16}, + .data_len = 128, + .mac_len = 16, + .mac = {0xa1,0x7d,0x0e,0x0f,0x02,0x11,0x84,0xa3,0x93, + 0x72,0x22,0xde,0x81,0xbe,0x62,0x7c}, + .chunks = {0, 128}, + .num_chunks = 2, + }, { // 8 (59) + .key = {0x91,0x17,0xcf,0x3c,0xe9,0xf5,0xc6,0xe1,0x97, + 0x52,0xbf,0x0b,0x1c,0xf8,0x6a,0x78,0xce,0x3a, + 0xdb,0xba,0x87,0xda,0xe1,0x39,0x9a,0x2a,0x93, + 0x7b,0x0b,0x72,0x2b,0xa3,0xff,0x92,0x18,0x38, + 0x71,0xe8,0x4e,0x28,0x27,0x74,0xe1,0x0d,0xe4}, + .key_len = 45, + .data = {0x93,0x5a,0x3c,0x27,0x24,0x9d,0xcf,0x92,0xae, + 0xda,0xc8,0xdc,0x76,0xd2,0x2f,0xf7,0x74,0x2e, + 0x5c,0xee,0x57,0x71,0x17,0x78,0xc9,0x2a,0xfd, + 0xcd,0xf3,0x6e,0x26,0xb8,0x44,0x85,0x04,0xee, + 0x6e,0xe4,0x8e,0x9e,0xb2,0x5b,0x9e,0x49,0x5e, + 0x90,0x98,0xd4,0x94,0xac,0x4d,0xdc,0x4c,0x54, + 0x1f,0x49,0x9c,0xdb,0x65,0x26,0x38,0xb6,0x11, + 0xb0,0x35,0x30,0x90,0xac,0x12,0x5f,0xf1,0xfe, + 0xf8,0x56,0x4a,0x78,0x41,0x9c,0x57,0xf0,0x38, + 0xdd,0x65,0x95,0x1f,0xe0,0x6e,0x83,0x77,0xb9, + 0x86,0x94,0x7b,0x40,0x75,0x79,0xee,0xc1,0xa6, + 0x0a,0x16,0xf5,0x40,0xdb,0x09,0x31,0x92,0x10, + 0x27,0xde,0xb4,0x72,0xe8,0x29,0x6b,0xc2,0xd8, + 0xfb,0x4e,0x4d,0xdf,0x2c,0x27,0xc0,0xc6,0xf4, + 0x9c,0x3e}, + .data_len = 128, + .mac_len = 24, + .mac = {0x4c,0xd0,0x95,0xce,0x64,0x1f,0x21,0x7f,0x8b, + 0x5f,0x35,0x51,0x52,0xee,0xd0,0x0b,0x1d,0x9f, + 0xd7,0x21,0xa0,0x8d,0xc5,0xa0}, + }, { // 9 (60) + .key = {0x36,0x3b,0x32,0xac,0xcf,0xa5,0x93,0xe4,0x54, + 0xcc,0x3e,0xc8,0x3b,0x9d,0x77,0x5a,0x0d,0xd0, + 0x27,0xb0,0x17,0xca,0x2f,0xf8,0x63,0xc1,0xfc, + 0xb9,0xe6,0x21,0x5b,0x5c,0xfb,0x2e,0x8f,0xea, + 0x10,0xeb,0xa2,0x17,0x9f,0x3b,0xf8,0x80,0x61}, + .key_len = 45, + .data = {0x54,0x85,0x64,0xe5,0xb7,0x37,0x04,0x26,0xd5, + 0x75,0xbb,0xe8,0x17,0x5b,0x48,0xc2,0x44,0xde, + 0xdc,0xef,0x3d,0xaf,0x72,0x52,0xec,0x62,0x5f, + 0xb7,0x77,0xd0,0x2a,0x5c,0xb9,0xba,0x9d,0xb0, + 0xf2,0xaf,0x1c,0x5a,0xbd,0x2f,0x36,0x7d,0x43, + 0x10,0x7a,0x3a,0xaf,0x21,0x8c,0x77,0xe2,0x0e, + 0x78,0xdf,0x67,0x83,0x45,0x2a,0xa9,0x94,0xce, + 0x9f,0x63,0x5d,0xcd,0xd7,0x59,0xe5,0x39,0xc3, + 0x46,0x49,0xd2,0xf1,0x15,0x16,0xfa,0x0a,0x53, + 0xf6,0xc6,0xa0,0xe5,0x8f,0x55,0x26,0xf6,0xa8, + 0x60,0x40,0x34,0x8d,0x13,0x3e,0x3c,0xb5,0x1b, + 0xe2,0x52,0xa3,0x01,0x6a,0x56,0x0a,0xb6,0xca, + 0xf3,0x34,0x6f,0x3a,0x1a,0xa4,0xb2,0xf0,0xaf, + 0xfb,0xb1,0x2f,0x82,0x18,0xd8,0x80,0x80,0x83, + 0xa2,0x40}, + .data_len = 128, + .mac_len = 24, + .mac = {0x64,0x6a,0xbb,0xd4,0x26,0x25,0x5d,0x2e,0x36, + 0x9b,0x7a,0xc9,0xeb,0x3c,0x3a,0xf1,0x9c,0x71, + 0x85,0xec,0xd2,0x8b,0xd8,0x2c}, + }, { // 10 (75) + .key = {0xb7,0x63,0x26,0x3d,0xc4,0xfc,0x62,0xb2,0x27, + 0xcd,0x3f,0x6b,0x4e,0x9e,0x35,0x8c,0x21,0xca, + 0x03,0x6c,0xe3,0x96,0xab,0x92,0x59,0xc1,0xbe, + 0xdd,0x2f,0x5c,0xd9,0x02,0x97,0xdc,0x70,0x3c, + 0x33,0x6e,0xca,0x3e,0x35,0x8a,0x4d,0x6d,0xc5}, + .key_len = 45, + .data = {0x53,0xcb,0x09,0xd0,0xa7,0x88,0xe4,0x46,0x6d, + 0x01,0x58,0x8d,0xf6,0x94,0x5d,0x87,0x28,0xd9, + 0x36,0x3f,0x76,0xcd,0x01,0x2a,0x10,0x30,0x8d, + 0xad,0x56,0x2b,0x6b,0xe0,0x93,0x36,0x48,0x92, + 0xe8,0x39,0x7a,0x8d,0x86,0xf1,0xd8,0x1a,0x20, + 0x96,0xcf,0xc8,0xa1,0xbb,0xb2,0x6a,0x1a,0x75, + 0x52,0x5f,0xfe,0xbf,0xcf,0x16,0x91,0x1d,0xad, + 0xd0,0x9e,0x80,0x2a,0xa8,0x68,0x6a,0xcf,0xd1, + 0xe4,0x52,0x46,0x20,0x25,0x4a,0x6b,0xca,0x18, + 0xdf,0xa5,0x6e,0x71,0x41,0x77,0x56,0xe5,0xa4, + 0x52,0xfa,0x9a,0xe5,0xae,0xc5,0xdc,0x71,0x59, + 0x1c,0x11,0x63,0x0e,0x9d,0xef,0xec,0x49,0xa4, + 0xec,0xf8,0x5a,0x14,0xf6,0x0e,0xb8,0x54,0x65, + 0x78,0x99,0x97,0x2e,0xa5,0xbf,0x61,0x59,0xcb, + 0x95,0x47}, + .data_len = 128, + .mac_len = 32, + .mac = {0x73,0x73,0x01,0xde,0xa9,0x3d,0xb6,0xbc,0xba, + 0xdd,0x7b,0xf7,0x96,0x69,0x39,0x61,0x31,0x7c, + 0xa6,0x80,0xb3,0x80,0x41,0x6f,0x12,0xf4,0x66, + 0xf0,0x65,0x26,0xb3,0x6b}, + }, { // 11 (76) + .key = {0x9f,0xe4,0x2d,0xfa,0xc9,0x2a,0x4a,0x13,0x6f, + 0xa7,0xc9,0xf6,0xe3,0x31,0xb5,0xd3,0xa6,0x1a, + 0xa7,0x30,0x35,0xb5,0x3a,0x8d,0x25,0x17,0xbe, + 0x43,0x72,0x1b,0x31,0xb2,0x15,0xa9,0x6b,0x9b, + 0xd4,0x37,0x98,0xcb,0x5e,0x8f,0xeb,0xfa,0x97}, + .key_len = 45, + .data = {0xf9,0x66,0x0f,0xb7,0x84,0xc1,0x4b,0x5f,0xbe, + 0xc2,0x80,0x52,0x6a,0x69,0xc2,0x29,0x4f,0xba, + 0x12,0xae,0xa1,0x63,0x78,0x9b,0xbe,0x9f,0x52, + 0xa5,0x1b,0x5a,0xeb,0xb9,0x7d,0x96,0x4f,0x86, + 0x6c,0x0d,0x5e,0x3b,0xe4,0x18,0x20,0x92,0x4f, + 0xcf,0x58,0x0d,0xb0,0x72,0x5c,0x7f,0x21,0x08, + 0x23,0xcf,0x7f,0x45,0xa0,0xf9,0x64,0xb1,0x4e, + 0x55,0x55,0x07,0x0d,0x1c,0x3d,0xdb,0x2c,0x28, + 0x1a,0x80,0xc7,0xfb,0xf7,0x29,0x53,0x03,0x1a, + 0x4e,0x77,0x1d,0x7e,0x52,0x1d,0x57,0x84,0x62, + 0xca,0xfa,0xe5,0xa0,0x2a,0xc8,0xeb,0x81,0xf0, + 0x82,0xe1,0x73,0xdd,0xad,0xc8,0xc4,0x1d,0x96, + 0x4b,0xbf,0xda,0x94,0xf5,0x18,0x0c,0x8d,0xa2, + 0x8a,0x8e,0xbb,0x33,0xbe,0x77,0xb0,0x86,0x6f, + 0xa7,0x98}, + .data_len = 128, + .mac_len = 32, + .mac = {0x77,0x86,0xc1,0x55,0xd1,0x0c,0x74,0x1b,0x63, + 0xec,0x65,0x0b,0x7b,0x1a,0xa3,0xbf,0xd7,0x1a, + 0xc7,0x18,0x81,0xad,0x06,0xae,0x98,0xfb,0x08, + 0x2f,0x17,0xe0,0xca,0xa0}, + }, { // 12 (90) + .key = {0x79,0xf8,0x77,0x34,0xc4,0x6c,0x5a,0x11,0xd8, + 0x6a,0xed,0xea,0xd2,0x2e,0xd3,0xea,0x01,0x57, + 0x7a,0xd4,0xec,0xdf,0x42,0x96,0x96,0x50,0xe1, + 0x20,0x00,0x35,0x06,0x76,0xf0,0xcf,0x3c,0x04, + 0xf1,0x0a,0x11,0x33,0x9b,0xaf,0x78,0x39,0x14, + 0xdb,0x6d,0x35,0xd7,0xb0,0xd7,0x7b,0xb4,0x4a, + 0xb2,0x2c,0x18,0xf5,0x6d,0x0b,0x8f,0x9d,0x91, + 0x8b}, + .key_len = 64, + .data = {0x50,0x9a,0x0a,0x45,0xa1,0x51,0x2b,0x50,0x72, + 0x47,0x4b,0x29,0x7f,0x9c,0x1a,0x8c,0x24,0x89, + 0x00,0x16,0x14,0x44,0x68,0x50,0x4e,0x24,0x5f, + 0xe9,0x4d,0x06,0x5d,0x43,0x7f,0xef,0x62,0x32, + 0xf9,0xf3,0x45,0x00,0x69,0x55,0x49,0xb4,0x4c, + 0xef,0xf2,0x93,0x61,0xd4,0x17,0xe8,0x5d,0x35, + 0x37,0x01,0xe0,0x81,0x11,0x7a,0xa8,0xd0,0x6e, + 0xbe,0x05,0x82,0x42,0xca,0x8c,0x23,0xf3,0x34, + 0x10,0x92,0xf9,0x6c,0xce,0x63,0xa7,0x43,0xe8, + 0x81,0x48,0xa9,0x15,0x18,0x6e,0xbb,0x96,0xb2, + 0x87,0xfd,0x6c,0xa0,0xb1,0xe3,0xc8,0x9b,0xd0, + 0x97,0xc3,0xab,0xdd,0xf6,0x4f,0x48,0x81,0xdb, + 0x6d,0xbf,0xe2,0xa1,0xa1,0xd8,0xbd,0xe3,0xa3, + 0xb6,0xb5,0x86,0x58,0xfe,0xea,0xfa,0x00,0x3c, + 0xce,0xbc}, + .data_len = 128, + .mac_len = 16, + .mac = {0xb5,0xb0,0xc4,0x30,0x28,0xe8,0x16,0x28,0xdc, + 0xe8,0x25,0x17,0xfa,0x36,0xaa,0x29}, + }, { // 13 (91) + .key = {0xea,0xe2,0x55,0xd9,0xe0,0x83,0x26,0x8f,0x89, + 0x64,0x29,0xce,0x36,0x64,0x55,0x02,0xaf,0xf9, + 0xdb,0xea,0xca,0x71,0x59,0xf9,0x3c,0x7d,0x51, + 0xfd,0xae,0xef,0xdb,0xfe,0x14,0xc3,0x96,0x69, + 0x3a,0x5c,0xe4,0x6e,0x9f,0x11,0x57,0xa6,0x87, + 0xe8,0x66,0xf9,0x4c,0xa1,0x65,0xbf,0xf5,0xf7, + 0xb4,0x25,0x09,0x22,0x36,0xd2,0xa6,0xa0,0x04, + 0xcb}, + .key_len = 64, + .data = {0xc2,0x8f,0x6a,0x09,0xce,0x07,0x6e,0xf2,0x70, + 0x45,0x89,0x67,0xfe,0x19,0xd4,0x6e,0x6f,0x6b, + 0x2c,0xbe,0xb6,0x36,0x2b,0xdc,0x4f,0xd5,0x56, + 0x84,0x17,0x7e,0x98,0x4a,0x60,0x0c,0xf0,0x81, + 0x45,0x01,0x66,0x5c,0x3b,0xcb,0x43,0x53,0xe9, + 0x46,0x81,0xc8,0x3a,0x83,0x81,0xeb,0xb0,0xc8, + 0xfc,0xdb,0xfb,0xd7,0x3c,0x0e,0xca,0x73,0x8c, + 0xf2,0xe1,0x21,0xed,0xd4,0x6b,0x2c,0x0a,0x02, + 0x92,0xeb,0x6e,0x2c,0x4e,0x46,0xf5,0x10,0x7a, + 0x77,0x80,0x57,0x2d,0x0e,0xed,0xb9,0x47,0x38, + 0x47,0x68,0x4a,0x40,0x39,0xac,0x6c,0x56,0xc9, + 0xca,0xea,0x90,0x43,0x2b,0x9e,0x2e,0x72,0xba, + 0xd4,0x22,0x16,0x8e,0x5a,0xd0,0x93,0xc9,0xd6, + 0x12,0xe7,0xc0,0x5c,0x7f,0xde,0x5c,0x40,0xed, + 0x89,0xc0}, + .data_len = 128, + .mac_len = 16, + .mac = {0xb8,0x40,0x03,0xc4,0x17,0xa4,0x72,0xfd,0x29, + 0x35,0x34,0x19,0x62,0x74,0x43,0x30}, + }, { // 14 (105) + .key = {0xa5,0xfd,0x99,0xca,0x57,0xc1,0xfe,0xc8,0x15, + 0x9a,0x79,0x87,0x92,0x42,0x6d,0x29,0x6f,0xa1, + 0xb1,0x7d,0x53,0x92,0x41,0xde,0x3d,0xea,0x33, + 0x58,0x19,0xb7,0xed,0x0d,0x92,0xc5,0x96,0xd7, + 0x28,0x67,0xca,0x2f,0x82,0x73,0x92,0x4e,0x05, + 0x8f,0x93,0x91,0xa5,0xab,0x85,0x22,0xfb,0xcf, + 0xe7,0xd5,0x98,0x17,0xf1,0x50,0x9a,0xfc,0xcb, + 0x6f}, + .key_len = 64, + .data = {0x5c,0xf3,0xa5,0x20,0x2d,0xf8,0x70,0x6f,0x6b, + 0xff,0x5b,0xf2,0x59,0x0d,0xe3,0x7c,0x90,0x2c, + 0x7f,0xfd,0x4e,0x6c,0x8e,0xa6,0x11,0x28,0x8e, + 0x4e,0x65,0x8a,0x8e,0x15,0xfa,0x51,0xe6,0x47, + 0xf9,0xd2,0x25,0x83,0x98,0x3d,0x4b,0x1c,0xed, + 0x22,0x39,0xbf,0xff,0x34,0x65,0x56,0x23,0x4c, + 0xd2,0x2d,0x86,0xb1,0x40,0x53,0x06,0x96,0xa0, + 0x44,0x46,0xe4,0xca,0xc4,0x01,0x3a,0x72,0x0e, + 0x9e,0x32,0x58,0x2e,0x05,0xe7,0xc0,0xac,0xb2, + 0xb4,0x22,0x6a,0x07,0x3e,0x22,0xcf,0xe7,0xb4, + 0xc2,0x25,0x80,0x55,0xd7,0x40,0x68,0x33,0xba, + 0x61,0xec,0x37,0x3f,0x5a,0xa5,0x66,0xeb,0xf2, + 0x4c,0x62,0x61,0x8a,0xce,0x34,0x1e,0x01,0xa3, + 0x48,0x66,0xd6,0x5c,0xb9,0x7e,0x8c,0x7c,0xd0, + 0x1c,0x53}, + .data_len = 128, + .mac_len = 24, + .mac = {0x2c,0x2b,0xc8,0xc8,0x70,0x17,0xf2,0x04,0xc9, + 0x58,0xab,0xd9,0xaa,0xb2,0xbe,0xb6,0xac,0x67, + 0x78,0x1d,0x8d,0x9d,0x80,0x4c}, + }, { // 15 (106) + .key = {0x30,0xbc,0x3e,0x32,0x1a,0x89,0x78,0xe2,0x35, + 0xfa,0x1b,0x55,0x00,0x64,0xb8,0x2e,0xaa,0x0c, + 0x10,0x75,0x25,0xea,0xcc,0x82,0x7c,0xad,0x6f, + 0x1d,0x66,0xff,0x88,0xe3,0x1b,0x09,0x2c,0xec, + 0x66,0x3a,0xa3,0xaa,0xfc,0x44,0x62,0x14,0x0c, + 0x68,0x39,0x04,0x17,0xf4,0xce,0xde,0x02,0x0a, + 0x4a,0x73,0x6a,0xa2,0x52,0x25,0x37,0xd2,0x39, + 0x4b}, + .key_len = 64, + .data = {0xc1,0x26,0x3b,0xe4,0x23,0xe7,0x88,0x8e,0xac, + 0xec,0xcf,0xef,0x26,0xf0,0xb5,0xaa,0xef,0xe0, + 0x3f,0x3c,0xe7,0x32,0xdd,0xe9,0x8c,0x78,0xa7, + 0xf6,0x64,0x35,0xe6,0x19,0x9c,0xef,0xd6,0x2e, + 0xee,0x85,0xaa,0x2b,0xc8,0xc3,0xd1,0x56,0xaa, + 0x34,0x78,0xb6,0xcf,0x37,0x50,0xc7,0x11,0x55, + 0x91,0x72,0x07,0xd2,0x3f,0x3b,0x70,0x82,0xac, + 0xbd,0xd4,0xde,0x3e,0x53,0x68,0x57,0x72,0x19, + 0x33,0xeb,0x21,0x13,0x6f,0xf5,0x02,0xab,0x32, + 0x49,0x71,0x61,0x4d,0x80,0x6e,0xbe,0x74,0x91, + 0xe9,0x89,0xa0,0xa2,0x3d,0x3e,0xb2,0x1d,0xfa, + 0xbc,0x59,0x05,0xe7,0x3e,0x35,0x8b,0x47,0x8c, + 0x3d,0xdc,0x5c,0x73,0x5e,0x3e,0x2a,0x72,0x64, + 0x5b,0x7d,0xb6,0x1e,0xdc,0x2d,0x49,0xbd,0x3a, + 0xa1,0x86}, + .data_len = 128, + .mac_len = 24, + .mac = {0xd7,0x22,0xb5,0x7c,0x48,0x12,0x8b,0x37,0xba, + 0x38,0x77,0x0c,0xbf,0x46,0x60,0x69,0x77,0x57, + 0xba,0xb9,0x5c,0x00,0xc4,0x84}, + }, { // 16 (120) + .key = {0x99,0x28,0x68,0x50,0x4d,0x25,0x64,0xc4,0xfb, + 0x47,0xbc,0xbd,0x4a,0xe4,0x82,0xd8,0xfb,0x0e, + 0x8e,0x56,0xd7,0xb8,0x18,0x64,0xe6,0x19,0x86, + 0xa0,0xe2,0x56,0x82,0xda,0xeb,0x5b,0x50,0x17, + 0x7c,0x09,0x5e,0xdc,0x9e,0x97,0x1d,0xa9,0x5c, + 0x32,0x10,0xc3,0x76,0xe7,0x23,0x36,0x5a,0xc3, + 0x3d,0x1b,0x4f,0x39,0x18,0x17,0xf4,0xc3,0x51, + 0x24}, + .key_len = 64, + .data = {0xed,0x4f,0x26,0x9a,0x88,0x51,0xeb,0x31,0x54, + 0x77,0x15,0x16,0xb2,0x72,0x28,0x15,0x52,0x00, + 0x77,0x80,0x49,0xb2,0xdc,0x19,0x63,0xf3,0xac, + 0x32,0xba,0x46,0xea,0x13,0x87,0xcf,0xbb,0x9c, + 0x39,0x15,0x1a,0x2c,0xc4,0x06,0xcd,0xc1,0x3c, + 0x3c,0x98,0x60,0xa2,0x7e,0xb0,0xb7,0xfe,0x8a, + 0x72,0x01,0xad,0x11,0x55,0x2a,0xfd,0x04,0x1e, + 0x33,0xf7,0x0e,0x53,0xd9,0x7c,0x62,0xf1,0x71, + 0x94,0xb6,0x61,0x17,0x02,0x8f,0xa9,0x07,0x1c, + 0xc0,0xe0,0x4b,0xd9,0x2d,0xe4,0x97,0x2c,0xd5, + 0x4f,0x71,0x90,0x10,0xa6,0x94,0xe4,0x14,0xd4, + 0x97,0x7a,0xbe,0xd7,0xca,0x6b,0x90,0xba,0x61, + 0x2d,0xf6,0xc3,0xd4,0x67,0xcd,0xed,0x85,0x03, + 0x25,0x98,0xa4,0x85,0x46,0x80,0x4f,0x9c,0xf2, + 0xec,0xfe}, + .data_len = 128, + .mac_len = 32, + .mac = {0x2f,0x83,0x21,0xf4,0x16,0xb9,0xbb,0x24,0x9f, + 0x11,0x3b,0x13,0xfc,0x12,0xd7,0x0e,0x16,0x68, + 0xdc,0x33,0x28,0x39,0xc1,0x0d,0xaa,0x57,0x17, + 0x89,0x6c,0xb7,0x0d,0xdf}, + }, { // 17 (121) + .key = {0xce,0xab,0x39,0x8e,0x41,0x07,0x48,0x3e,0xde, + 0x64,0xce,0x10,0x7c,0x92,0x70,0xe6,0x02,0x27, + 0x78,0xb6,0x1f,0x6a,0x25,0x8d,0x3b,0x70,0x45, + 0xd4,0xad,0x85,0x06,0xd3,0x2e,0xce,0x0a,0x73, + 0x8d,0x2c,0xb9,0x48,0xa5,0x62,0xdb,0xce,0x8d, + 0x7b,0x66,0xf3,0x0e,0x66,0x94,0xd6,0x5a,0xe4, + 0x39,0xcf,0xfa,0xa4,0x54,0xaf,0x09,0xab,0xe4, + 0x49}, + .key_len = 64, + .data = {0x6d,0xde,0x9a,0xe8,0x67,0xe2,0xfe,0xb3,0x67, + 0x00,0x8a,0x97,0x5d,0x78,0x53,0xed,0x8f,0x89, + 0x69,0x0f,0x3c,0x87,0xa1,0x10,0x7f,0x2e,0x98, + 0xaa,0x77,0x36,0xf4,0x77,0xa5,0x27,0xed,0x64, + 0x95,0x6f,0x0d,0x64,0xc1,0xb2,0x33,0x61,0xb2, + 0x61,0xde,0x78,0x68,0x8e,0xa8,0x65,0xfc,0xff, + 0x11,0x3c,0x84,0x81,0x7e,0x5b,0x37,0x7e,0x82, + 0x9c,0xd2,0xd2,0x5b,0xcf,0x3a,0xdb,0xc0,0x67, + 0x62,0xcf,0xda,0x73,0x6f,0x53,0x90,0xd0,0x1a, + 0x49,0x07,0x9d,0x56,0xe9,0x69,0xf0,0x33,0x13, + 0xe6,0xc7,0x03,0xe3,0xf9,0x42,0xbb,0x87,0xed, + 0x0f,0x9c,0x4d,0x9f,0x25,0x12,0x00,0x85,0xb5, + 0xdc,0x75,0xef,0x5d,0x6d,0x61,0x8d,0xa0,0x92, + 0x6d,0x32,0x93,0x56,0x8d,0xd7,0xd8,0x23,0x8d, + 0xe3,0xd0}, + .data_len = 128, + .mac_len = 32, + .mac = {0x2d,0x3a,0x76,0x05,0x95,0xf3,0xfb,0x19,0x29, + 0x3c,0xc6,0xd2,0x36,0x51,0x22,0x2a,0x9f,0x5a, + 0x4f,0x02,0x28,0x44,0x57,0xa9,0xc1,0xed,0x4c, + 0x43,0xac,0x99,0x3c,0xa5}, + }, { // 18 (135) + .key = {0x07,0xc3,0x58,0xed,0x1d,0xf3,0xb0,0x6d,0x47, + 0xb5,0xec,0x76,0x3a,0xfa,0x07,0xa6,0x67,0x7c, + 0xa3,0xa7,0x22,0x52,0x4e,0x61,0x03,0xc1,0x05, + 0x6d,0x8c,0x56,0xf6,0xcd,0x0d,0x31,0x8a,0xdb, + 0xc5,0xa4,0xa3,0x80,0x4a,0xfd,0x23,0xa6,0x2b, + 0x9f,0xad,0xf0,0xd3,0x58,0xaf,0xa8,0xb0,0xee, + 0xa0,0xf9,0x95,0xfb,0x86,0x5e,0x5d,0xfb,0xbc, + 0x5a,0xd2,0xa4,0xf2,0x6a,0xcd,0x76}, + .key_len = 70, + .data = {0x2a,0xa1,0xd9,0x4e,0xc8,0x3c,0xe7,0xc3,0xc7, + 0x5c,0x6b,0xc8,0x47,0x75,0x9b,0x08,0x52,0x34, + 0xfd,0x44,0xb4,0x07,0xd8,0xf8,0x0d,0xdf,0xe9, + 0x3c,0x24,0x35,0x56,0xe8,0x7e,0x4b,0xe8,0xfb, + 0x30,0xb4,0x74,0x3e,0xf1,0x16,0x9a,0x24,0x73, + 0x2f,0xb2,0xf5,0xf4,0x16,0x04,0x2b,0x10,0xc3, + 0x37,0x1d,0xd9,0xd2,0x0d,0xda,0x29,0x84,0x4d, + 0x58,0x37,0x07,0x00,0xce,0x69,0xf7,0xdf,0x5e, + 0x69,0x24,0x0d,0xf7,0x7b,0x96,0x02,0x7a,0x0e, + 0xce,0xc7,0x1b,0x90,0x4f,0x69,0x0b,0x87,0x5d, + 0xa8,0x54,0xde,0x05,0xef,0x04,0x7c,0x5d,0x89, + 0x8d,0x1c,0x0d,0x11,0x6c,0x58,0x0e,0x2a,0x09, + 0x06,0xb2,0x71,0xde,0xc8,0xe5,0xb0,0xdc,0xdf, + 0xb2,0x55,0x0a,0x40,0x09,0x22,0x70,0xea,0xbf, + 0x25,0x33}, + .data_len = 128, + .mac_len = 16, + .mac = {0xb3,0xa1,0x89,0xa1,0x7e,0x8d,0x9e,0x98,0x6c, + 0xd3,0x1b,0xbe,0x01,0xb4,0x9f,0xb3}, + }, { // 19 (136) + .key = {0xab,0x8d,0xfb,0xa4,0x41,0x4e,0x69,0x86,0x51, + 0x3a,0x97,0x67,0xaf,0x5e,0xae,0xd9,0x72,0x08, + 0x11,0xc4,0xb3,0x80,0x40,0xb9,0x91,0xf3,0xfd, + 0x82,0x78,0xb0,0xad,0xfe,0xa4,0x97,0x00,0x2c, + 0xe0,0xcd,0xd4,0x85,0x94,0xb5,0x57,0x8f,0xfe, + 0x1c,0x6c,0xaf,0xc0,0xb4,0x51,0x3e,0x9b,0xc4, + 0x7e,0xe0,0x7a,0x1d,0xd0,0x11,0xb2,0x50,0xe6, + 0x01,0x88,0x1e,0xcc,0xa2,0xf4,0x30}, + .key_len = 70, + .data = {0xd1,0xa7,0x08,0x6d,0x13,0x4c,0x11,0xa8,0xa3, + 0x20,0x4e,0x01,0x9f,0x52,0x84,0x3e,0x89,0xf2, + 0xd0,0x1a,0x02,0xa8,0x8a,0x94,0xd4,0xa6,0x6e, + 0x8d,0x36,0xdb,0xfe,0x92,0x4c,0x69,0x22,0xf7, + 0xee,0x5a,0x12,0x25,0xaa,0x8e,0x75,0x34,0x0c, + 0xf8,0xcb,0xbd,0x1c,0x0b,0x08,0xe9,0x29,0x6e, + 0x81,0xce,0xc5,0xf7,0x0c,0xfc,0x11,0xd7,0x63, + 0x52,0x3b,0x12,0xca,0x17,0x44,0x33,0xf2,0x46, + 0x07,0x3d,0x1c,0x28,0x77,0xe4,0x81,0x28,0x28, + 0xfd,0xf2,0xe4,0x11,0x34,0xbc,0x80,0x90,0xfd, + 0xce,0x3f,0xae,0xcd,0x1e,0x54,0xa5,0x89,0x48, + 0xf5,0x9f,0x3f,0x78,0xb2,0xc1,0x14,0x8b,0x05, + 0x68,0x7d,0x71,0x2a,0xb2,0xb2,0xd6,0x30,0x41, + 0x60,0x01,0x51,0x3b,0x9e,0xfc,0x7f,0x95,0x23, + 0xf5,0x3f}, + .data_len = 128, + .mac_len = 16, + .mac = {0x7a,0xea,0x0e,0x2d,0x93,0xe9,0xa6,0xa3,0x00, + 0x41,0x17,0xad,0x4a,0x4a,0x72,0xa3}, + }, { // 20 (150) + .key = {0x05,0x8f,0x60,0x4e,0x53,0x05,0x1a,0x0f,0x85, + 0x50,0xde,0x16,0xb7,0x24,0x5f,0xda,0xd3,0xda, + 0x63,0x9a,0x6c,0xc3,0xc8,0x4e,0xea,0xbc,0xc5, + 0xdd,0xe8,0x02,0x73,0x90,0xda,0x48,0x8c,0xc7, + 0xf3,0x07,0x72,0xeb,0x46,0x16,0x73,0xa3,0x2b, + 0x7a,0x4b,0x4b,0xe4,0x7f,0xea,0xa2,0x80,0x08, + 0x78,0xc2,0x00,0x23,0x97,0x56,0xb9,0xe0,0xe8, + 0x07,0xf9,0x64,0xd0,0x37,0xed,0x39}, + .key_len = 70, + .data = {0xa7,0x41,0x00,0xcf,0x30,0xcd,0x26,0x41,0x6e, + 0x98,0x78,0x73,0x9d,0xfd,0xb3,0xc1,0xfa,0x56, + 0x9d,0x64,0x27,0xca,0x8e,0xe9,0xd0,0x66,0x30, + 0xe1,0x8f,0x6f,0x83,0xdb,0x0d,0xf7,0x24,0x8f, + 0x6b,0xaf,0xce,0x5c,0xe0,0xfc,0x21,0xf5,0xa3, + 0x4d,0xa2,0x57,0x0b,0xab,0x04,0xfe,0xf4,0x92, + 0xa6,0x58,0x66,0xff,0x5c,0x7a,0x71,0xca,0x72, + 0x12,0x5b,0x36,0xee,0x9c,0xfe,0xc7,0x16,0xd9, + 0x6b,0x53,0x32,0x7d,0xd3,0x5c,0x93,0x28,0xa8, + 0x9d,0xd4,0x98,0xff,0xe3,0x60,0x1d,0x39,0x1e, + 0x34,0x4d,0xe2,0xb8,0xe7,0xf8,0xd9,0x25,0xe7, + 0x5f,0xb1,0xbc,0x05,0xa0,0x58,0xc5,0x34,0x75, + 0xf6,0xd3,0x8d,0x1e,0x18,0x54,0x97,0x9c,0x0e, + 0x66,0xc6,0x20,0x91,0xec,0x41,0xc3,0xaa,0xe1, + 0xe8,0x77}, + .data_len = 128, + .mac_len = 24, + .mac = {0x08,0xe3,0xa1,0x71,0x8c,0x6d,0x1c,0xde,0xf2, + 0xc0,0xc6,0x76,0x60,0xf7,0xc1,0xe8,0xa4,0x59, + 0x63,0xe5,0xff,0xed,0x54,0xa7}, + }, { // 21 (151) + .key = {0x98,0x6e,0x0d,0x3c,0x3e,0x76,0x45,0xe4,0x93, + 0xd3,0x59,0x62,0x29,0x1d,0x97,0x9d,0xdf,0x09, + 0xe8,0xa6,0x10,0xd5,0xa7,0x3d,0x0a,0xe7,0xb3, + 0x97,0xc2,0xb1,0xc3,0x5e,0xc6,0xd7,0xfa,0xfa, + 0x72,0x94,0xbc,0x0f,0x67,0x5a,0xbf,0x46,0x39, + 0xb8,0x65,0x51,0x68,0x81,0x49,0x29,0x92,0x2b, + 0x17,0x9a,0xe6,0x75,0xa2,0x02,0xdc,0x4c,0x30, + 0x56,0x23,0xf0,0x18,0x65,0xdb,0x53}, + .key_len = 70, + .data = {0x72,0xc2,0x1b,0xe6,0xf0,0xc4,0xdf,0x7c,0xc8, + 0xa5,0x3f,0x92,0x26,0xf3,0x61,0x46,0xf9,0xec, + 0x5b,0xea,0x9c,0x94,0xf3,0xb7,0xb6,0x04,0xa8, + 0xbf,0x5f,0x05,0xf7,0x24,0x84,0xdd,0xd7,0x88, + 0x8c,0x69,0x86,0xc4,0x3b,0x6c,0x87,0xdd,0xd7, + 0x27,0xec,0x34,0x8a,0x2a,0xd1,0xfc,0x08,0x69, + 0x29,0xf1,0x71,0x92,0xbd,0x47,0x79,0x9e,0x71, + 0xe1,0xc6,0xa7,0xc9,0xc4,0x9a,0xf9,0xad,0xcb, + 0xb1,0x6b,0x69,0x9c,0x6d,0xf0,0xf8,0xda,0x30, + 0x69,0x82,0x9d,0x09,0xbd,0x23,0x1f,0x94,0x2c, + 0xee,0xb8,0x1b,0xe0,0x32,0x0c,0x01,0xc5,0xfb, + 0x83,0x61,0x9b,0xdc,0xf9,0xf2,0x4a,0xec,0xb7, + 0x2e,0x75,0x0f,0xa2,0xb3,0x51,0x77,0xb3,0xe9, + 0xb8,0x6a,0xa7,0xe5,0x79,0x45,0xf8,0x8d,0xf3, + 0xc1,0x0b}, + .data_len = 128, + .mac_len = 24, + .mac = {0xb5,0x79,0xea,0xf7,0x70,0x69,0x76,0x15,0x2b, + 0x16,0x22,0xc1,0x7f,0xc4,0x7c,0x5d,0xb3,0x80, + 0x2a,0xa3,0xf4,0x6f,0x6a,0x3e}, + }, { // 22 (165) + .key = {0xc0,0x9e,0x29,0x07,0x1c,0x40,0x5d,0x5e,0x82, + 0x0d,0x34,0x5a,0x46,0xdb,0xbf,0x1e,0x0f,0x82, + 0x02,0xe9,0x2d,0xe3,0xed,0x3e,0x2d,0x29,0x8e, + 0x43,0xaa,0x4f,0x84,0x68,0x66,0xe3,0xb7,0x48, + 0x99,0x09,0x46,0xd4,0x88,0xc2,0xc1,0xae,0x5a, + 0x6e,0x99,0xd3,0x27,0x90,0xd4,0x7d,0x53,0xd2, + 0x05,0x48,0x1a,0x49,0x7c,0x93,0x6b,0xf9,0xba, + 0x29,0xfa,0x9c,0x28,0x21,0x91,0x9f}, + .key_len = 70, + .data = {0xea,0x72,0x40,0x52,0x99,0x80,0x07,0x6d,0x3b, + 0x02,0x8a,0x08,0x3e,0xbc,0x4e,0x24,0xef,0xda, + 0xa0,0x6c,0x9c,0x84,0xd7,0x6b,0xf5,0xb2,0xd9, + 0xfd,0xb8,0x42,0xe1,0x03,0x8e,0x48,0x7f,0x5b, + 0x30,0xa5,0xe0,0x10,0xcd,0xdb,0x4f,0xcd,0xb0, + 0x1f,0xfc,0x98,0x1e,0xb0,0xfc,0xbc,0x7d,0x68, + 0x92,0x07,0xbc,0x90,0xad,0x36,0xee,0xf9,0xb1, + 0xae,0x38,0x48,0x7a,0x6d,0xee,0x92,0x9f,0x3f, + 0xf9,0x29,0xf3,0x35,0x7c,0xb5,0x52,0x53,0xb7, + 0x86,0x9a,0x89,0x2b,0x28,0xf7,0xe5,0xfe,0x38, + 0x64,0x06,0xa2,0x77,0x6e,0xd4,0xb2,0x1d,0x3b, + 0x6e,0x1c,0x70,0xcc,0x64,0x85,0x94,0x7f,0x27, + 0xe9,0xa5,0xd8,0xbd,0x82,0x03,0x80,0xb9,0xec, + 0xed,0x8e,0x6b,0x86,0x52,0x06,0x54,0x1b,0xe3, + 0x9f,0xdc}, + .data_len = 128, + .mac_len = 32, + .mac = {0x49,0xae,0x1c,0x4a,0x7a,0x57,0x0f,0xde,0x47, + 0xf7,0x51,0x7a,0xb1,0x88,0x98,0xb1,0xb9,0x91, + 0xd0,0x3c,0xfc,0xf8,0xc4,0x5b,0xb3,0x61,0x5b, + 0x5f,0x75,0x5d,0xa6,0x82}, + }, { // 23 (166) + .key = {0xbc,0xe5,0x0c,0xdf,0xff,0x84,0x38,0x85,0xd4, + 0xf3,0x64,0xd6,0x9f,0x93,0xbf,0x58,0xa2,0x32, + 0x2c,0x70,0x7b,0x82,0xe8,0x78,0xee,0xc9,0x6d, + 0x11,0xe5,0xdb,0x97,0xbb,0xb5,0x46,0x06,0xa3, + 0xa3,0xcc,0xc3,0xbb,0xa7,0x16,0x26,0x10,0x70, + 0xa6,0xf7,0x59,0xa7,0x0e,0xd3,0xcb,0x78,0x5f, + 0xd1,0x35,0x4f,0xe5,0x66,0x48,0xdf,0x11,0x86, + 0x36,0x69,0xb7,0x0c,0x80,0x3b,0x7a}, + .key_len = 70, + .data = {0x93,0xb7,0xef,0x0e,0x47,0x0d,0xdf,0xac,0x6a, + 0xef,0x93,0xc0,0xdc,0xd3,0x7b,0x8f,0x1c,0x4b, + 0xaf,0x5e,0xad,0xd9,0x78,0xe3,0xbf,0x05,0x12, + 0xfa,0x0b,0xae,0xb0,0x99,0xff,0x9e,0xc1,0x06, + 0x1b,0x61,0x72,0x47,0x9b,0x56,0x74,0xdb,0x56, + 0x06,0xff,0xa7,0xe6,0xb5,0x17,0x33,0x09,0x37, + 0x0e,0x16,0x47,0x05,0x4a,0xaf,0xd5,0x90,0x48, + 0x16,0xba,0xd5,0xe1,0x52,0x30,0x32,0xcc,0xcd, + 0x4d,0x78,0x65,0x05,0xe2,0x41,0xac,0x83,0xa4, + 0x84,0x91,0x11,0x89,0x66,0x6f,0x28,0x75,0x53, + 0xd6,0xa8,0x16,0x4e,0x8d,0xcb,0x0c,0x85,0xd7, + 0x5c,0x4e,0x29,0xf6,0x24,0xc9,0x7c,0xee,0xa6, + 0x4a,0x2c,0x8b,0x0c,0x9d,0xdf,0xa5,0x60,0xf7, + 0x0f,0xa3,0xff,0x91,0x18,0x3e,0x4b,0x96,0x8f, + 0x88,0xa1}, + .data_len = 128, + .mac_len = 32, + .mac = {0x37,0xf9,0xf3,0x29,0x18,0x30,0x82,0x10,0x84, + 0x9d,0xfe,0xbf,0x8d,0xd4,0x56,0x80,0x4b,0xab, + 0xd6,0x84,0x5a,0xf0,0x72,0x18,0xf9,0xd9,0xbe, + 0x9d,0xf9,0x74,0x3d,0x55}, + }, { // 24 (180) + .key = {0x81,0x5c,0x2a,0x91,0x1a,0xaf,0x0f,0x84,0x98, + 0x70,0x61,0x10,0xa9,0x5e,0x6f,0x9c,0x26,0xc3, + 0xef,0x52,0xa3,0xb1,0x37,0x81,0x44,0x8c,0xb0, + 0x3f,0xd2,0xc8,0x87,0x52,0x0d,0xf4,0xa5,0x51, + 0x44,0xf8,0xe2,0x06,0x24,0x9b,0x75,0x17,0xce, + 0x48,0xaf,0xe5,0x2c,0x11,0xea,0xb5,0x84,0xf4, + 0xbc,0x0e,0x4d,0x5d,0x70,0x61,0x42,0xed,0xb6, + 0xf0,0xb6,0x7a,0x99,0xe8,0x27,0x57,0xb2,0xd0, + 0x15,0xd5}, + .key_len = 74, + .data = {0x8b,0x7f,0xdf,0x79,0x2a,0x90,0x21,0x8f,0x91, + 0x99,0x8b,0x08,0x47,0x56,0xf3,0x2f,0xf8,0x14, + 0x88,0x46,0x6b,0xcd,0x66,0xce,0xb4,0x95,0x67, + 0x02,0xab,0x34,0x3c,0xa5,0x9c,0x15,0xbd,0xfd, + 0x40,0x5f,0x7e,0x20,0xec,0x61,0xa3,0x6e,0x09, + 0x33,0xf5,0x5f,0xc4,0x9a,0x35,0x7f,0x06,0x2d, + 0xb0,0xb6,0xa7,0xb6,0x13,0xcd,0xdf,0xdb,0x81, + 0x2e,0xfd,0xfe,0xe3,0xeb,0x5b,0x61,0x7f,0x02, + 0x91,0x8e,0xcd,0xe0,0xe9,0xf6,0x85,0x23,0x13, + 0xd8,0xfd,0xa4,0x1a,0x64,0xb2,0xb5,0x97,0x21, + 0x24,0xa7,0x25,0x8c,0xe8,0x90,0x14,0x02,0xf8, + 0x4a,0x62,0xdf,0x4d,0xbf,0xe6,0xe8,0xb0,0x64, + 0xcf,0xe6,0xcd,0x04,0x4d,0x94,0x89,0xbf,0x8e, + 0xbb,0x95,0x52,0xec,0x9c,0x43,0x99,0x65,0x8e, + 0x99,0x52}, + .data_len = 128, + .mac_len = 16, + .mac = {0x79,0x66,0x44,0x0d,0xf7,0x9b,0x13,0xe9,0x5c, + 0x41,0x34,0x6e,0xb7,0x92,0xf3,0xec}, + }, { // 25 (181) + .key = {0x48,0x09,0xf3,0x1e,0x93,0x42,0x3c,0xab,0xf4, + 0x4c,0xdd,0xca,0xd2,0x3d,0xa7,0xd7,0xae,0xe7, + 0x34,0xd3,0x11,0xfc,0x7b,0xab,0xc2,0x76,0xa1, + 0xbd,0x3d,0x35,0x13,0x98,0x61,0xea,0xd1,0x03, + 0x69,0x35,0x0d,0x42,0x1d,0x0a,0xf4,0x94,0x49, + 0x59,0xcc,0x00,0x6f,0xee,0x3f,0x51,0xb9,0x96, + 0xf6,0x60,0x31,0x83,0x6a,0x91,0x34,0xf1,0xf7, + 0xa0,0x24,0x0a,0x33,0x9e,0x5e,0x07,0x7d,0x36, + 0x6c,0x99}, + .key_len = 74, + .data = {0x6e,0x4a,0xbd,0x41,0x4d,0xca,0x21,0xa6,0xad, + 0x43,0x31,0x46,0x98,0x62,0x73,0xe2,0xda,0x95, + 0x2e,0xf6,0x13,0xcd,0x1f,0x9a,0x0a,0x83,0x6c, + 0xa6,0x44,0xf9,0xde,0x19,0xd6,0xc2,0x4a,0xbc, + 0x77,0x84,0x50,0x02,0xd9,0xfd,0x48,0x33,0x3a, + 0x44,0x7a,0xc9,0x36,0x51,0x8d,0x1b,0xdf,0xc0, + 0x43,0x38,0x0f,0xd2,0x63,0x16,0xfd,0xb5,0xf6, + 0xec,0x0f,0x05,0xb5,0xdc,0xef,0x92,0xc3,0xd5, + 0xe1,0x64,0x98,0xb8,0x54,0xfc,0x3d,0xb9,0xb6, + 0xdd,0xbf,0x09,0x8d,0x4b,0xde,0xb2,0xc4,0x53, + 0x05,0xc2,0x42,0x0b,0x7f,0xab,0xc2,0x1b,0xe7, + 0xea,0xde,0x7c,0xe0,0xe7,0x6c,0x80,0x07,0x1c, + 0x0e,0x13,0x26,0x7a,0x05,0x40,0xab,0x08,0x46, + 0xf7,0x58,0xce,0xd0,0x0d,0x3b,0xf1,0x3c,0x84, + 0xe1,0x1f}, + .data_len = 128, + .mac_len = 16, + .mac = {0xd7,0xba,0xa0,0x11,0x7d,0x00,0x8a,0xf7,0x86, + 0xc2,0xba,0xcb,0x38,0xb9,0xd3,0x86}, + }, { // 26 (195) + .key = {0xfe,0xe6,0x03,0x25,0x85,0x82,0xe3,0xa3,0xe8, + 0xfe,0xb8,0x86,0x59,0x9d,0x4a,0xc4,0x05,0xa1, + 0x63,0x4c,0x32,0x0e,0x85,0xea,0x8a,0xb0,0xdc, + 0x6b,0xb6,0x5f,0x72,0x01,0x2f,0x82,0xa2,0xe9, + 0x51,0xd2,0xcf,0x4a,0xb2,0x61,0x56,0x61,0xb1, + 0xda,0xc0,0xdb,0x52,0x0a,0x3d,0x82,0x49,0x9f, + 0x4e,0x1c,0x54,0x30,0xc1,0x90,0xce,0x7e,0xe2, + 0x4b,0x82,0xfa,0xf0,0xe2,0xbd,0x87,0xce,0xf9, + 0xa7,0x80}, + .key_len = 74, + .data = {0x67,0x54,0x1f,0x77,0xf4,0xe4,0x0d,0x14,0x30, + 0x35,0x46,0x25,0x05,0xde,0x14,0xa0,0x21,0x24, + 0xb9,0x92,0xec,0x1d,0x00,0x64,0xbd,0x15,0x18, + 0x5d,0x4d,0x30,0xa2,0x69,0x6c,0x51,0x09,0x19, + 0xf2,0x3b,0x12,0xea,0xf9,0xf6,0xb4,0xca,0x49, + 0x75,0x29,0xd8,0x14,0x75,0x45,0x6c,0xe4,0xa8, + 0x07,0x57,0xd1,0x13,0x6e,0x6c,0xf7,0xb4,0x8d, + 0x3f,0x27,0x69,0xe2,0x2c,0xdd,0x0d,0xe4,0x9b, + 0x72,0xe4,0xdb,0x83,0x93,0x39,0xf4,0x2d,0xf2, + 0x45,0x95,0x3b,0x3b,0x53,0xee,0xe8,0x4a,0x22, + 0xd1,0x91,0x9b,0x8b,0xc3,0x75,0x02,0x63,0x53, + 0xb9,0x9c,0xa3,0xaa,0xaf,0x05,0xc6,0x64,0x57, + 0xcb,0x73,0x9e,0x26,0x23,0x5c,0x50,0x07,0xdb, + 0x66,0xde,0xa0,0x90,0x0a,0xe9,0xd6,0x21,0xfb, + 0x6b,0x93}, + .data_len = 128, + .mac_len = 24, + .mac = {0xf9,0x14,0xc8,0x42,0xb7,0x8c,0x3b,0x91,0xfe, + 0x66,0x26,0x27,0x2c,0x04,0xf6,0xbf,0xa3,0x9c, + 0x58,0x6d,0x48,0x23,0xce,0x0e}, + }, { // 27 (196) + .key = {0x83,0x2f,0x87,0xd5,0x96,0x44,0x9a,0xec,0xa6, + 0x56,0xe0,0xe0,0xb4,0xae,0x92,0xdc,0xd1,0x6a, + 0x66,0x88,0x90,0x20,0xa9,0xd2,0xbb,0xc4,0x8e, + 0xee,0x45,0xcc,0xc6,0x9b,0x80,0x91,0x50,0xa9, + 0x90,0xf9,0x93,0xb8,0x20,0x53,0xaa,0x42,0x53, + 0x82,0xff,0xdc,0xfd,0x5e,0x1b,0xb8,0x14,0x57, + 0xbc,0x6f,0x61,0x5c,0x28,0xfd,0x7b,0xfb,0xc2, + 0x0d,0xf6,0xc9,0xdb,0x78,0xd8,0x04,0xca,0x08, + 0x4c,0x77}, + .key_len = 74, + .data = {0x78,0x2a,0xc1,0x6b,0xcd,0x74,0x4e,0xc0,0x16, + 0xff,0xb6,0xb0,0x14,0xe0,0xc8,0x98,0x3d,0xfd, + 0xe2,0x31,0xfa,0x72,0xc3,0x12,0x12,0x34,0x9a, + 0x77,0x66,0xf4,0x62,0x40,0xe0,0x47,0x72,0x3d, + 0xa6,0x03,0x50,0xa8,0x93,0xec,0xc7,0xf3,0xe7, + 0x90,0x39,0xc5,0x3d,0x6f,0x36,0x3f,0xbe,0x5f, + 0x4c,0x83,0x95,0x2f,0x21,0x77,0xa2,0x8b,0xc0, + 0xc6,0x73,0x1f,0x31,0x28,0x70,0x00,0x4c,0xe4, + 0x55,0x47,0xce,0x93,0xe6,0xff,0xad,0x26,0xde, + 0x41,0xa9,0x2a,0x28,0x9d,0x24,0x4b,0x51,0xbc, + 0x33,0x17,0x3e,0x44,0xf5,0x05,0x1a,0xfc,0x24, + 0xb6,0x93,0x31,0xe9,0x7a,0x46,0x58,0xf5,0x16, + 0x77,0xf4,0xcd,0xc5,0x06,0xba,0x65,0x7c,0x9e, + 0xf3,0xf1,0x72,0x30,0x23,0xf8,0xe0,0xa0,0xe8, + 0xaa,0x05}, + .data_len = 128, + .mac_len = 24, + .mac = {0xc6,0x8f,0x21,0x5b,0x05,0x98,0x81,0xc9,0xf9, + 0x71,0x17,0xb3,0xc6,0xd9,0xd6,0xde,0xea,0x2e, + 0x09,0x45,0xe3,0xe1,0x97,0x2d}, + }, { // 28 (210) + .key = {0x81,0x57,0x43,0x23,0xc9,0x73,0x54,0x07,0x19, + 0xd1,0x92,0x83,0x3d,0xdb,0x51,0xf1,0x3a,0x52, + 0xdc,0xba,0xe2,0x94,0xae,0xbe,0xa5,0x1b,0xe5, + 0xf6,0xaa,0x47,0xf3,0x57,0x1f,0x5d,0x97,0xfa, + 0xcd,0xcf,0x0c,0x7b,0xef,0xbe,0x80,0x9f,0x44, + 0xbd,0xc7,0x39,0x63,0xd8,0x51,0x4e,0x4f,0xd5, + 0x59,0x77,0x4b,0xb9,0x60,0x87,0xef,0x8e,0xda, + 0x6e,0x7c,0x64,0x27,0x5d,0x6d,0x96,0xc4,0x2b, + 0x4e,0x4e}, + .key_len = 74, + .data = {0xb9,0xe9,0x44,0xe0,0xb4,0x2d,0x0f,0xf4,0x54, + 0xf7,0xf8,0xaa,0x24,0xf0,0x0e,0x9e,0xe0,0x39, + 0x05,0x8c,0xe4,0x09,0x41,0x11,0xe3,0x97,0x31, + 0xb6,0xdc,0x3a,0xde,0x2a,0x4a,0xce,0xc4,0xcf, + 0x9c,0x5b,0xe0,0x78,0xe4,0xf1,0x0a,0x72,0xd3, + 0xd6,0x85,0xc1,0xe5,0xe4,0xd5,0xab,0xd9,0x2c, + 0xd0,0x7b,0x64,0xdf,0xf8,0x7f,0x26,0x6f,0x08, + 0x53,0xdd,0xf1,0xcd,0x61,0xd9,0xc6,0x37,0xa9, + 0xb0,0x7a,0xb0,0xbe,0x32,0xec,0xac,0x11,0x9f, + 0xaf,0x82,0x72,0x18,0xb1,0x7a,0xd4,0x54,0x1a, + 0x27,0x51,0x94,0x77,0xf7,0x6e,0xd9,0x18,0x08, + 0x9f,0x54,0xb6,0x3d,0x0e,0x1e,0x5a,0x92,0x98, + 0x29,0x79,0xac,0x18,0x77,0x64,0xb5,0xe9,0x89, + 0xe0,0x66,0xa6,0x1b,0x10,0x65,0x34,0x0e,0x9c, + 0xd2,0x03}, + .data_len = 128, + .mac_len = 32, + .mac = {0x51,0x4b,0xd1,0x84,0x95,0xf6,0xde,0x0e,0x23, + 0x70,0x54,0xb8,0xe3,0xba,0x1a,0x74,0xc3,0xfa, + 0xda,0x42,0x79,0xad,0x6b,0x85,0x50,0xf3,0xa1, + 0x47,0x12,0xc5,0x28,0xdf}, + }, { // 29 (211) + .key = {0x44,0xf7,0x1c,0x23,0x17,0xcd,0xe5,0x21,0x51, + 0xc8,0x42,0x60,0xd1,0xd3,0xc0,0x4a,0x28,0xcc, + 0x15,0xce,0x5b,0x38,0x02,0xb2,0xe5,0x35,0x7e, + 0x2b,0xfc,0xaf,0x10,0xab,0x15,0xd7,0x7d,0xfa, + 0xaa,0xd1,0xa3,0x88,0x3b,0xad,0xa5,0x02,0x93, + 0x99,0x48,0x23,0x4c,0x55,0x9d,0xcd,0x95,0xe7, + 0xe1,0x58,0x33,0x8f,0xa1,0x2a,0xc6,0xfd,0x21, + 0x87,0x4e,0xc2,0xff,0xab,0xed,0x05,0x14,0x16, + 0xef,0x77}, + .key_len = 74, + .data = {0x2a,0xc0,0xbb,0x05,0x24,0xc2,0x2b,0x90,0x2d, + 0xe3,0x4c,0xe6,0x4e,0x61,0x72,0xd1,0xb2,0x07, + 0x4e,0x15,0x9f,0x51,0x7a,0xb1,0xab,0xd1,0x52, + 0x62,0x2c,0xd1,0x06,0x69,0xf0,0x3a,0xed,0x8e, + 0x2e,0xb5,0x1c,0x65,0xbd,0x0f,0x38,0xd0,0x84, + 0xe2,0x88,0xc5,0x32,0x72,0x4e,0x51,0x2f,0xd5, + 0x58,0xdd,0xd2,0x57,0xd2,0xb1,0xd4,0x1c,0x5e, + 0xb6,0x04,0x07,0x67,0x80,0x3d,0xdb,0xb1,0x8b, + 0x95,0xa0,0x35,0xc5,0xd8,0x49,0x2d,0x4d,0x35, + 0x93,0x6b,0x7b,0x36,0x30,0xee,0x20,0xf6,0x25, + 0xb7,0x0f,0x8e,0x71,0xd9,0xdc,0xd0,0xef,0xd0, + 0xe3,0x38,0x7d,0x13,0x8c,0x1f,0x5e,0xed,0xce, + 0x32,0xdd,0x88,0xf2,0x23,0x33,0x4b,0x9a,0x9e, + 0xab,0x65,0x01,0x7f,0x04,0xaa,0x84,0x42,0x17, + 0x9f,0x62}, + .data_len = 128, + .mac_len = 32, + .mac = {0xca,0x00,0x53,0xd5,0x1f,0x6c,0xf6,0xf9,0x99, + 0x8f,0xf1,0xe0,0xdb,0x00,0xb9,0x0e,0x82,0xc7, + 0xb1,0x8c,0xb5,0x37,0x7a,0xcc,0x8e,0xbe,0x9a, + 0xfe,0x20,0xda,0x1c,0x3d}, + } +}; + +struct HMAC_TEST_VECTOR fips_sha384_hmac_general_test_vector[] = { + { // 0 (0) + .key = {0xf1,0x6a,0xd7,0x37,0x90,0xca,0x39,0xc7,0xf9,0x85, + 0x6c,0x44,0x83,0x20,0x2e,0x7f,0x8e,0x0c,0x82,0x83, + 0xc7,0xd5,0x0d,0x6d,0xa7,0x9c,0xc0,0x7d,0x3d,0xc7, + 0xb7,0x6c,0x2e,0xf7,0x61,0x00,0xfa,0x3a,0xe2,0xdf, + 0x80,0x83,0xb5,0xa1,0xc5,0x57,0x96,0x28,0xf1,0xc8}, + .key_len = 50, + .data = {0x98,0x70,0x00,0x76,0x54,0xeb,0xc3,0xd2,0x8f,0x88, + 0x3b,0xb8,0x32,0xe0,0xb3,0x17,0x00,0xf9,0x23,0xd9, + 0xc9,0xb1,0x01,0x68,0xe0,0x60,0x59,0x71,0xcf,0xb9, + 0x20,0xe8,0x48,0xf1,0xc6,0x4c,0x5f,0x24,0x0a,0x2c, + 0xf7,0xf4,0x12,0xea,0x7a,0x73,0xbb,0xbf,0xce,0x43, + 0x2e,0xff,0x84,0xfb,0xb4,0x9e,0x52,0xcd,0xcb,0xf4, + 0xc3,0x66,0x79,0xbd,0x2d,0x16,0xe0,0x64,0xe4,0x31, + 0x13,0x81,0xad,0xb5,0x28,0xa0,0x75,0x2c,0x8e,0x44, + 0x43,0xd4,0xa1,0x2b,0x6c,0xfe,0x7c,0xd4,0x06,0xb4, + 0x0e,0x3f,0x9e,0x9e,0x71,0xf4,0x2e,0x27,0x76,0x46, + 0x49,0xdb,0x85,0xd9,0x99,0x13,0xa4,0x62,0x8b,0xd5, + 0xd5,0xae,0x49,0xf6,0xa5,0xe6,0xe9,0x81,0x02,0x11, + 0xe3,0x5d,0x4d,0xda,0xc9,0x29,0xb0,0x93}, + .data_len = 128, + .mac_len = 24, + .mac = {0x79,0xe2,0x4a,0x20,0x3b,0xf4,0x20,0x74,0xe7,0x2c, + 0x8b,0x4a,0x02,0x22,0xaf,0xac,0xe3,0xe8,0xce,0x7b, + 0x40,0x04,0xce,0xc2}, + }, { // 1 (1) + .key = {0xa5,0x70,0x9b,0xa5,0x52,0x9c,0xb9,0xa1,0xa2,0x27, + 0xf0,0xbe,0x44,0x8e,0x11,0x9a,0x35,0x6f,0x92,0xe1, + 0x3e,0xfc,0x34,0x63,0xbe,0xaa,0xe4,0x6a,0xa9,0x29, + 0xdf,0x4a,0xd1,0x99,0x1a,0x39,0x64,0xfb,0xe1,0x61, + 0xb6,0xe5,0xbe,0x34,0x41,0x7a,0x9c,0x00,0xeb,0x9a}, + .key_len = 50, + .data = {0x4f,0x56,0x9d,0x60,0x40,0x56,0x63,0xff,0xd4,0x89, + 0x37,0x77,0xcb,0xc3,0x71,0x55,0xd4,0x03,0xe2,0xb0, + 0xf5,0x48,0x5d,0xa4,0x2c,0xa6,0x75,0x03,0x57,0x98, + 0x89,0x46,0x51,0x98,0xfe,0xca,0x5e,0xed,0xcc,0x39, + 0xc9,0xc5,0x3c,0x45,0xcb,0x83,0xf0,0x9d,0xaf,0x5a, + 0x23,0x19,0x34,0x1b,0x32,0x38,0x33,0x4b,0x5b,0xcd, + 0x81,0x79,0xc5,0xf5,0x17,0xce,0xc1,0x4c,0x70,0xe6, + 0x50,0x61,0x33,0xde,0xe5,0x67,0x12,0xaf,0x6c,0x2d, + 0xf2,0xba,0x8a,0x50,0x4c,0xa4,0x27,0xaf,0xd3,0x63, + 0x2a,0x1f,0x57,0x99,0x83,0x60,0xe9,0x21,0x6f,0x50, + 0x40,0xe8,0xf7,0x5f,0x5b,0xff,0xba,0x43,0x68,0xee, + 0xed,0xed,0xe5,0x4a,0xa0,0xbb,0x05,0x8a,0x43,0xef, + 0x55,0x16,0x68,0x60,0x9f,0xa1,0xcb,0x6f}, + .data_len = 128, + .mac_len = 24, + .mac = {0x24,0x7e,0xb5,0x1a,0x39,0x7b,0xa3,0x69,0xec,0xba, + 0x43,0xb9,0x5a,0x46,0xa9,0x33,0xcf,0xf0,0xb1,0x00, + 0x57,0x14,0xf0,0xe5}, + }, { // 2 (15) + .key = {0xc2,0xf2,0xf7,0x98,0x57,0x28,0xb6,0x77,0xa7,0xad, + 0x06,0x2d,0xd9,0x60,0x5a,0x2c,0x24,0xe7,0xcd,0xfa, + 0x86,0x98,0x6f,0x35,0xb9,0x9a,0xdc,0xd4,0x63,0x47, + 0x14,0xaf,0x8d,0xd5,0x86,0x42,0x56,0x36,0x6e,0xad, + 0xe8,0x3c,0x61,0x00,0xac,0x01,0x26,0xb6,0xba,0x86}, + .key_len = 50, + .data = {0x35,0xaf,0x2e,0xa1,0x67,0xe5,0x6c,0x84,0x21,0xcd, + 0xab,0x1b,0x9f,0xc9,0x9b,0xe4,0xb8,0x5f,0x74,0xc7, + 0x06,0xd4,0x3a,0x49,0x47,0xfc,0x3f,0x02,0x03,0x50, + 0xe9,0x51,0x70,0x41,0xb5,0x4e,0x92,0xcc,0x7c,0x00, + 0xa6,0x4f,0xf6,0xd1,0xc1,0x9b,0x7c,0x3e,0xb5,0x4a, + 0x12,0xd3,0x34,0x53,0xa4,0x57,0x38,0xdb,0x90,0x44, + 0xa1,0x4e,0x65,0x7a,0x20,0xaf,0xea,0x33,0x55,0x2c, + 0x63,0x3a,0x34,0xf6,0x0f,0x58,0xad,0x4f,0xf5,0x0f, + 0x8c,0xe5,0xe1,0x8b,0x9e,0x5e,0xa9,0xd6,0x15,0x34, + 0xb4,0x4b,0x2d,0xc3,0xbd,0x4d,0x10,0xa0,0xd5,0x39, + 0xf7,0x2d,0xa7,0x98,0x93,0x6a,0x00,0x9a,0xab,0x0e, + 0x8f,0xc0,0x06,0xd7,0xe9,0xd8,0x8b,0x1e,0xcf,0x2e, + 0xa7,0xae,0xb4,0x01,0xef,0xd6,0x7a,0x34}, + .data_len = 128, + .mac_len = 32, + .mac = {0x6e,0x49,0xe4,0xaa,0x01,0xda,0x45,0xcc,0x5f,0xfb, + 0x71,0x56,0x9f,0x25,0x7e,0xcf,0x11,0x4f,0xe8,0x58, + 0xba,0x95,0x90,0xaf,0xc2,0x3a,0xfa,0xc9,0xc0,0xd6, + 0x7f,0x52}, + }, { //3 (16) + .key = {0x8f,0x23,0x9b,0x06,0xfc,0x66,0x78,0xbe,0x26,0x30, + 0x7d,0xc7,0x02,0xf8,0x54,0xf6,0xa3,0xd0,0xd9,0x80, + 0xf6,0x45,0x73,0x04,0xaf,0x87,0xa5,0xcc,0x83,0xca, + 0xe0,0x50,0x98,0xeb,0x9c,0xfb,0x3a,0x57,0xa7,0x32, + 0xcf,0x29,0xbc,0x93,0x0d,0x92,0x57,0x7a,0x6a,0x7e}, + .key_len = 50, + .data = {0x35,0xb1,0x27,0xb5,0x2a,0x9b,0x4a,0xec,0xe9,0x78, + 0xad,0x17,0xaa,0xa7,0x00,0xb5,0x47,0xb1,0x7e,0xab, + 0x59,0xda,0x27,0x81,0x9e,0xf6,0x50,0xce,0x9f,0x7e, + 0x5e,0xf1,0x8f,0xe3,0xcf,0x02,0x75,0x22,0x7a,0x09, + 0x8e,0x99,0x17,0x6d,0xec,0x19,0x01,0xaf,0x64,0x3c, + 0x3b,0x57,0xa7,0xf9,0xb1,0x2f,0xaf,0x75,0xc1,0xb0, + 0x5d,0x1c,0xfa,0xba,0x60,0xf1,0x24,0x88,0x58,0x22, + 0x80,0xe2,0x3b,0xe0,0x51,0x94,0xf8,0x6d,0x9a,0x20, + 0x5b,0x77,0x2a,0xb0,0x31,0xa4,0xd6,0x4e,0xac,0x6e, + 0x06,0x57,0x09,0x31,0x73,0x2d,0x6f,0x82,0x2e,0x2d, + 0x1b,0xc3,0xe5,0xe1,0xba,0xf4,0x62,0x76,0x16,0xcc, + 0x54,0x70,0xf5,0x09,0x52,0x9c,0x3e,0x04,0x1d,0x46, + 0x5e,0x88,0x25,0xad,0xea,0xe4,0x4f,0xb4}, + .data_len = 128, + .mac_len = 32, + .mac = {0x4a,0x13,0x78,0x36,0x50,0xcb,0x96,0xaa,0x0d,0xcb, + 0x4b,0xca,0x10,0xec,0x30,0xee,0x2a,0x9d,0x37,0x68, + 0xf2,0xb6,0xf1,0xdc,0x62,0x6f,0x99,0x54,0x5e,0xfd, + 0xef,0xe6}, + }, { // 4 (30) + .key = {0x1c,0xe7,0xe2,0x0a,0xbb,0xdc,0xd1,0x15,0x4d,0x4b, + 0x53,0x67,0x14,0xff,0x53,0x4a,0x01,0xb8,0xe8,0x8c, + 0x78,0xda,0x34,0xd6,0x53,0x63,0x8c,0x39,0x29,0x1f, + 0xd8,0x0a,0xd0,0x1f,0x3d,0xf0,0x20,0x67,0xfa,0x3b, + 0xfa,0xe7,0x90,0x77,0x89,0xad,0x26,0x41,0xc8,0x58}, + .key_len = 50, + .data = {0x7c,0xd7,0x50,0xb5,0xc9,0xb2,0xbb,0xc3,0xee,0x95, + 0x5a,0x4f,0x4f,0xa7,0xc9,0x56,0x84,0x6c,0x8b,0x1b, + 0x52,0xea,0xa0,0x6f,0xd9,0x0a,0x5a,0x30,0x0e,0x42, + 0x6c,0x10,0x6c,0x71,0x44,0x97,0xe7,0x0a,0x9b,0x6c, + 0x22,0x75,0x4a,0xd0,0xe1,0xb2,0x5f,0x6b,0xc1,0x40, + 0x70,0x4b,0x27,0x3d,0x2f,0x2a,0x76,0xce,0x3f,0xef, + 0x85,0xc1,0x46,0x78,0x50,0x71,0x44,0x97,0xed,0xea, + 0x23,0x5a,0xc2,0x4e,0x8f,0x90,0xf6,0x78,0x07,0x88, + 0x25,0xde,0x34,0x1c,0x58,0xbc,0x7a,0xee,0x34,0x6f, + 0xce,0xf2,0x71,0x1e,0xc7,0x2d,0x8e,0xa0,0xf7,0xbc, + 0xc3,0x9a,0x7b,0x17,0x38,0xe8,0xd1,0x97,0x74,0x3f, + 0xea,0x36,0x18,0x10,0x80,0x97,0xcd,0xaf,0xaa,0x46, + 0x7b,0xb4,0xae,0x40,0xbc,0xa2,0x16,0xb6}, + .data_len = 128, + .mac_len = 40, + .mac = {0x72,0x9a,0x16,0x7f,0x19,0x86,0xca,0xc5,0x3f,0xf3, + 0xe1,0x11,0xff,0x82,0xf2,0xa7,0x7b,0x57,0x3d,0x08, + 0x63,0xe1,0xa3,0xae,0xaf,0x00,0x04,0x1a,0x03,0xe1, + 0x43,0x01,0x88,0xa2,0x02,0xbd,0xb7,0xe9,0xbf,0xd4}, + }, { // 5 (31) + .key = {0x36,0x2b,0xc4,0x40,0xe5,0xda,0xc1,0x6a,0x43,0x69, + 0x58,0x1c,0x0c,0xb5,0xbe,0x45,0xbf,0x4f,0x17,0x08, + 0x47,0x87,0x3d,0x6c,0xdb,0xc9,0xbd,0x55,0x23,0x2d, + 0x23,0xb3,0x9c,0x49,0x78,0xf9,0x3d,0x4a,0x08,0xd1, + 0x5b,0x43,0x69,0x0d,0xca,0xc4,0xb8,0xe1,0x45,0xaf}, + .key_len = 50, + .data = {0x1a,0xf3,0xae,0xda,0xa8,0xfa,0xc5,0x51,0x57,0xf3, + 0x06,0x42,0xa0,0x02,0x58,0x10,0x2d,0xbd,0x48,0x21, + 0x98,0xe0,0xf1,0x34,0x76,0x41,0x1f,0xf5,0x94,0x06, + 0xb4,0xce,0x80,0x15,0x4a,0x01,0x4b,0xcc,0x19,0xf4, + 0x8e,0xf3,0x1b,0xcb,0xab,0xee,0x6f,0x3c,0x55,0x37, + 0xfc,0x9f,0x53,0x0c,0x56,0x45,0x80,0x65,0xe5,0x0b, + 0x17,0x29,0x44,0x2f,0x2d,0xa1,0xe7,0x62,0x7f,0x2d, + 0x01,0x1e,0x6e,0x36,0xa4,0x39,0x48,0x63,0x2a,0xbb, + 0xc9,0x10,0xd5,0xed,0xe2,0xfc,0xb2,0xb2,0xb8,0x41, + 0xc3,0x1a,0xf0,0x8a,0x5c,0x35,0x2a,0x80,0xce,0x25, + 0xcb,0x85,0x43,0x77,0x00,0xa5,0xe9,0xb4,0x00,0xc9, + 0x53,0x32,0x91,0x2e,0x1c,0x30,0xcd,0x16,0xcd,0x22, + 0x26,0xbe,0x00,0x4a,0xa8,0x8f,0xc6,0x88}, + .data_len = 128, + .mac_len = 40, + .mac = {0x64,0x67,0xe5,0xa6,0x90,0xbd,0x32,0xe1,0x57,0xcf, + 0x8c,0xe6,0x74,0xac,0x63,0x0b,0x74,0xce,0x32,0xa7, + 0x8e,0x8f,0x78,0x41,0x53,0x46,0xc0,0x0c,0x30,0x60, + 0xa4,0xa2,0x6c,0x40,0xc3,0xe2,0xea,0xbd,0x80,0xa7}, + }, { // 6 (45) + .key = {0x5e,0xab,0x0d,0xfa,0x27,0x31,0x12,0x60,0xd7,0xbd, + 0xdc,0xf7,0x71,0x12,0xb2,0x3d,0x8b,0x42,0xeb,0x7a, + 0x5d,0x72,0xa5,0xa3,0x18,0xe1,0xba,0x7e,0x79,0x27, + 0xf0,0x07,0x9d,0xbb,0x70,0x13,0x17,0xb8,0x7a,0x33, + 0x40,0xe1,0x56,0xdb,0xce,0xe2,0x8e,0xc3,0xa8,0xd9}, + .key_len = 50, + .data = {0xf4,0x13,0x80,0x12,0x3c,0xcb,0xec,0x4c,0x52,0x7b, + 0x42,0x56,0x52,0x64,0x11,0x91,0xe9,0x0a,0x17,0xd4, + 0x5e,0x2f,0x62,0x06,0xcf,0x01,0xb5,0xed,0xbe,0x93, + 0x2d,0x41,0xcc,0x8a,0x24,0x05,0xc3,0x19,0x56,0x17, + 0xda,0x2f,0x42,0x05,0x35,0xee,0xd4,0x22,0xac,0x60, + 0x40,0xd9,0xcd,0x65,0x31,0x42,0x24,0xf0,0x23,0xf3, + 0xba,0x73,0x0d,0x19,0xdb,0x98,0x44,0xc7,0x1c,0x32, + 0x9c,0x8d,0x9d,0x73,0xd0,0x4d,0x8c,0x5f,0x24,0x4a, + 0xea,0x80,0x48,0x82,0x92,0xdc,0x80,0x3e,0x77,0x24, + 0x02,0xe7,0x2d,0x2e,0x9f,0x1b,0xab,0xa5,0xa6,0x00, + 0x4f,0x00,0x06,0xd8,0x22,0xb0,0xb2,0xd6,0x5e,0x9e, + 0x4a,0x30,0x2d,0xd4,0xf7,0x76,0xb4,0x7a,0x97,0x22, + 0x50,0x05,0x1a,0x70,0x1f,0xab,0x2b,0x70}, + .data_len = 128, + .mac_len = 48, + .mac = {0x7c,0xf5,0xa0,0x61,0x56,0xad,0x3d,0xe5,0x40,0x5a, + 0x5d,0x26,0x1d,0xe9,0x02,0x75,0xf9,0xbb,0x36,0xde, + 0x45,0x66,0x7f,0x84,0xd0,0x8f,0xbc,0xb3,0x08,0xca, + 0x8f,0x53,0xa4,0x19,0xb0,0x7d,0xea,0xb3,0xb5,0xf8, + 0xea,0x23,0x1c,0x5b,0x03,0x6f,0x88,0x75}, + }, { // 7 (46) + .key = {0xf8,0x69,0x02,0xe5,0xe5,0xdb,0x47,0x8e,0xc6,0xe2, + 0x78,0x69,0x27,0x28,0xa8,0x12,0xc4,0xcd,0x87,0x45, + 0xf9,0x0a,0x7d,0x9f,0x79,0x15,0xf5,0xa9,0x43,0x45, + 0xfc,0x12,0xd2,0x77,0x0a,0x3c,0x94,0xb0,0x1f,0xfb, + 0x9e,0x04,0x12,0x99,0x9e,0xb6,0x26,0x1d,0x11,0xa0}, + .key_len = 50, + .data = {0xe0,0xbc,0xac,0xbe,0x96,0xda,0xd6,0xf6,0x0e,0x51, + 0x12,0x9f,0x35,0xac,0xd0,0x3e,0x12,0x27,0x6a,0x91, + 0xfa,0x13,0xfc,0x15,0x03,0x7c,0x75,0xca,0xbb,0x0a, + 0xee,0x3a,0x19,0x25,0x3b,0xb8,0xb3,0x5c,0xc0,0xe6, + 0x32,0x08,0x86,0x7a,0x03,0x2c,0x8f,0x41,0x50,0xa0, + 0x66,0x64,0x2f,0x6f,0xf9,0xea,0x19,0x7d,0xab,0x7e, + 0x9d,0x6d,0xa6,0x72,0x55,0xc1,0x6e,0x05,0x1a,0x43, + 0xbc,0xe1,0x74,0xa4,0x89,0xe8,0x54,0x64,0x69,0x30, + 0x06,0xf1,0x1a,0x4c,0x61,0x13,0x5d,0xce,0x41,0x87, + 0x04,0x09,0x37,0xeb,0x4d,0x1c,0x7e,0xda,0x6e,0x2c, + 0x31,0x57,0x71,0xf0,0xbc,0x6f,0x42,0x73,0x91,0x1a, + 0x07,0x15,0x1c,0x63,0xaf,0xd3,0xf8,0xc8,0xce,0xc9, + 0x63,0xe4,0xa8,0xf5,0xef,0x4b,0x8b,0x3e}, + .data_len = 128, + .mac_len = 48, + .mac = {0x4b,0xb4,0xeb,0x2d,0xb2,0xcc,0x92,0x1b,0x15,0x9b, + 0x78,0xa2,0xbb,0x9e,0xdc,0x16,0x08,0xbb,0x2a,0x1c, + 0xa9,0x87,0x3b,0x41,0x1a,0xe3,0x0a,0x63,0x38,0x6e, + 0x46,0x2f,0x9f,0x69,0xd9,0xf5,0xfc,0x83,0x8f,0xf1, + 0x81,0x87,0x48,0xaa,0xb7, 0x4d,0xa9,0x4f}, + }, { // 8 (60) + .key = {0x40,0xea,0xe6,0xb8,0xe3,0xab,0xea,0x17,0xc0,0x69, + 0xf0,0x88,0x26,0x49,0x57,0x7b,0x19,0x52,0xde,0x40, + 0xf4,0x7c,0x6a,0xc0,0x53,0x0a,0x03,0x6b,0x2f,0x1a, + 0x1f,0x71,0x4b,0x7b,0x23,0x35,0xcf,0xbe,0x27,0xff, + 0x33,0x90,0xf9,0xf0,0x5f,0x47,0x65,0x3c,0x11,0xba, + 0xb4,0x93,0x7e,0x56,0x73}, + .key_len = 55, + .data = {0xd2,0x81,0x3f,0x53,0x1c,0xe4,0x93,0x1c,0xb2,0x90, + 0x89,0x95,0x79,0xe6,0xc7,0x5b,0xea,0x8a,0x32,0x4d, + 0xb8,0x75,0xb4,0x40,0xb2,0x46,0x3d,0xf5,0xec,0xd9, + 0x07,0x48,0x19,0x1b,0x1f,0xa9,0x3c,0x1d,0x21,0xd0, + 0x80,0x67,0x42,0xad,0x63,0x8e,0x94,0x9e,0x1a,0x09, + 0x86,0xe5,0x31,0x40,0xaa,0x59,0x73,0xe6,0xbc,0x5b, + 0x09,0x89,0xdf,0x0c,0xe6,0x67,0x29,0xbe,0x62,0x84, + 0x62,0xa8,0x24,0xf9,0x09,0xdd,0x46,0x8f,0x98,0x7f, + 0xb4,0x8c,0x0a,0x2f,0xd5,0xcd,0x99,0xc9,0x6e,0x15, + 0xcc,0x4e,0xc3,0xa5,0xb1,0x22,0xff,0x0d,0x67,0x78, + 0xd5,0x41,0xe0,0x0a,0x68,0xef,0xe5,0x0d,0x68,0x10, + 0x5b,0x64,0x7e,0xbe,0xc4,0x14,0xeb,0x45,0x09,0xf8, + 0x6c,0x7c,0x76,0xb6,0x60,0x56,0x06,0xf1}, + .data_len = 128, + .mac_len = 24, + .mac = {0x3f,0x25,0x54,0x80,0xd6,0x45,0x36,0x92,0x98,0xf7, + 0x72,0x4f,0x42,0xbc,0xa1,0xb9,0x84,0x23,0x38,0x52, + 0x77,0x7f,0xf7,0xf7}, + }, { // 9 (61) + .key = {0x4e,0x58,0x96,0x74,0x03,0x0c,0x40,0x67,0x9c,0x34, + 0x38,0x74,0xd6,0xa2,0xd6,0x25,0x63,0x55,0xeb,0x95, + 0x48,0x4e,0x4a,0xdd,0x84,0xa0,0x87,0xcf,0xf2,0xc7, + 0xfe,0xe7,0x70,0x3a,0x17,0x7e,0x41,0x44,0xc9,0x41, + 0xb0,0x0f,0x5d,0xe2,0xf6,0x02,0x75,0x0d,0x5e,0x4c, + 0x4c,0x9e,0xa7,0xc1,0x3f}, + .key_len = 55, + .data = {0xe9,0xe8,0x35,0x61,0xcf,0x23,0xff,0xd4,0x4a,0x79, + 0xee,0x76,0x54,0xc8,0xf3,0xc7,0x80,0x2a,0x5a,0x35, + 0x8f,0x2f,0xfa,0x88,0x3e,0x69,0xaf,0x7d,0x63,0x2e, + 0x0a,0xb1,0x38,0x99,0x46,0xc1,0xf7,0xd2,0x7e,0xb0, + 0xa7,0x8f,0x1e,0x89,0x35,0xdb,0x98,0x45,0xc6,0x17, + 0x58,0xee,0x4c,0x3e,0xf9,0x05,0x57,0x6d,0xb9,0x22, + 0x2f,0xa2,0x2a,0xda,0x1f,0xc3,0x2b,0xe5,0x13,0xe3, + 0x17,0x80,0x66,0xc2,0x3c,0x11,0xf5,0x92,0x8f,0x0a, + 0x78,0x01,0x9d,0x0f,0x12,0x73,0xc5,0x5b,0x26,0x8f, + 0xa5,0x60,0x6d,0xfe,0xd2,0xad,0x45,0x6f,0xcc,0x15, + 0x4c,0xdf,0x31,0x0e,0x2e,0x17,0x30,0x57,0xbb,0x76, + 0x41,0xde,0x3d,0xf0,0x13,0xe0,0x08,0x57,0xc6,0x52, + 0x52,0xd9,0x5b,0x80,0x45,0xcb,0x69,0xf4}, + .data_len = 128, + .mac_len = 24, + .mac = {0xa1,0x22,0x75,0x28,0xf8,0xc2,0x1c,0xf0,0x4c,0x7c, + 0x9e,0x6c,0x02,0x01,0x19,0xbb,0x6e,0xe9,0x07,0xa9, + 0xe1,0x10,0x7c,0x61}, + }, { // 10 (75) + .key = {0x88,0x60,0x41,0x8e,0x48,0xec,0x77,0xa2,0x29,0x2c, + 0x51,0x87,0x62,0x07,0x6b,0x7a,0x0c,0xc6,0x39,0x2c, + 0xe1,0xc9,0xee,0x17,0x43,0x78,0x9c,0x11,0x80,0x7d, + 0x9d,0x22,0x54,0x31,0x33,0x93,0xaf,0x53,0x6b,0x47, + 0xb9,0x00,0x47,0x4f,0x13,0xdf,0x1b,0xb8,0x60,0x9d, + 0x38,0xa7,0x05,0x99,0xc8}, + .key_len = 55, + .data = {0x10,0x7f,0xd2,0xe4,0xbd,0x7a,0x19,0xa4,0xff,0x6f, + 0x48,0x2d,0x62,0x89,0x6d,0xa5,0x83,0xc3,0x27,0x7e, + 0x23,0xab,0x5e,0x53,0x7a,0x65,0x31,0x12,0xcd,0xf2, + 0x30,0x60,0x43,0xb3,0xcc,0x39,0xf5,0x28,0x0b,0xd7, + 0x44,0xfe,0x81,0xd6,0x6f,0x49,0x7b,0x95,0x65,0x0e, + 0x7d,0xdf,0xd7,0x04,0xef,0xcb,0x92,0x9b,0x13,0xe0, + 0x0c,0x3e,0x3a,0x7d,0x3c,0xd5,0x38,0x78,0xaf,0x8f, + 0x15,0x06,0xd9,0xde,0x05,0xdb,0xa9,0xc3,0x9a,0x92, + 0x60,0x4b,0x39,0x4e,0xa2,0x5a,0xcb,0xa2,0xcd,0xa7, + 0xb4,0xae,0x8b,0x08,0x09,0x8b,0xa3,0xf0,0xfd,0xea, + 0x15,0x35,0x9d,0xf7,0x65,0x17,0xbe,0x84,0x37,0x7f, + 0x33,0x63,0x1c,0x84,0x43,0x13,0xac,0x33,0x5a,0xa0, + 0xd5,0x90,0xfe,0xc4,0x72,0xd8,0x05,0x52}, + .data_len = 128, + .mac_len = 32, + .mac = {0x51,0x28,0x05,0xc9,0x80,0x6a,0x47,0x39,0xd0,0x4c, + 0x19,0x4a,0x1f,0x1b,0xe6,0x79,0xe9,0xe5,0x0e,0x31, + 0x3f,0xe6,0x3e,0xc5,0xd1,0x2c,0xfc,0x3c,0xf4,0xb0, + 0x70,0x73}, + }, { // 11 (76) + .key = {0xf1,0x57,0x76,0x97,0x6b,0x37,0x2a,0xbe,0x66,0x37, + 0x99,0x61,0xf0,0x78,0x73,0x38,0x76,0x0a,0x9a,0x75, + 0xef,0x51,0xec,0x49,0x57,0xad,0x5c,0xa9,0x5f,0x59, + 0x48,0x52,0x63,0x94,0x07,0x0b,0x9c,0xff,0xc1,0x2a, + 0x97,0x47,0x83,0x59,0xe5,0x03,0x92,0x9a,0x15,0xe0, + 0x00,0x89,0xdf,0xfb,0x7e}, + .key_len = 55, + .data = {0xcf,0x85,0x77,0x54,0xd1,0x8e,0x6b,0x8b,0x32,0x94, + 0x1d,0x69,0xfe,0x44,0x16,0xa1,0x28,0x91,0x0b,0x68, + 0x20,0xfc,0x0d,0xda,0xa7,0x13,0x00,0x99,0xe3,0x38, + 0x4e,0xb7,0xae,0xa4,0xdd,0xd6,0x34,0xac,0x3e,0x8d, + 0xbd,0x42,0x27,0x0e,0xc7,0xbe,0x23,0x06,0x58,0xdf, + 0x88,0xc5,0x92,0x0c,0xa9,0x9f,0x88,0xe0,0x4e,0x92, + 0x50,0xe6,0x61,0x29,0x5a,0xa1,0xea,0x9f,0xff,0xd0, + 0x3e,0x48,0x5d,0xef,0x72,0x2d,0x63,0x01,0x16,0xf6, + 0x28,0x8d,0x20,0x0e,0x81,0xe7,0x27,0x01,0xd2,0xb0, + 0xd2,0x29,0x24,0xa0,0x8f,0x89,0x78,0x83,0x88,0xf9, + 0x5b,0x82,0xd3,0x84,0xbb,0xa4,0xe8,0x0e,0xf9,0x95, + 0x59,0x39,0x3f,0xa5,0xbd,0x8a,0x14,0x13,0xed,0xc8, + 0x2e,0x8c,0x74,0xa5,0x87,0xef,0x40,0xa1}, + .data_len = 128, + .mac_len = 32, + .mac = {0x6b,0x44,0x2d,0x4f,0x5c,0xd3,0xe4,0xbc,0x60,0x9b, + 0xd2,0x09,0x6d,0xb3,0x1f,0x2b,0x2e,0x1e,0x41,0x3a, + 0xab,0xd5,0xdb,0x0a,0xef,0xdc,0x59,0x98,0x13,0xf6, + 0xdd,0x1b}, + }, { // 12 (90) + .key = {0x30,0x4f,0x1d,0xe5,0xe8,0xfc,0xd7,0xae,0xe3,0x4d, + 0x5f,0xe5,0x12,0x7f,0xcf,0xca,0x0b,0xdd,0x11,0x2b, + 0xb0,0xd9,0xa4,0x1f,0x0b,0x5b,0x9c,0xf7,0x7d,0x59, + 0xeb,0x72,0x18,0xa8,0xe0,0x30,0x49,0x12,0xed,0x69, + 0xba,0xa8,0xad,0xdf,0x76,0x59,0x25,0x11,0x4f,0xc4, + 0x4b,0xb2,0x7d,0x4b,0xc4}, + .key_len = 55, + .data = {0x0b,0x99,0x5e,0xb3,0xf8,0xd1,0xfb,0x4c,0x1b,0xe0, + 0xa7,0xfb,0x36,0x4e,0x5d,0x1b,0x4e,0xdf,0x5e,0x3e, + 0xba,0x5d,0xdd,0x14,0x7b,0x97,0xfc,0x8e,0xcb,0xaa, + 0xf7,0x42,0xf8,0x7f,0x9f,0x12,0x73,0x95,0x0b,0x08, + 0x24,0x01,0x8a,0x85,0x01,0xb3,0xdb,0x9b,0xdf,0xfa, + 0xa1,0xb7,0x88,0x4b,0x11,0x83,0x0d,0x3e,0xee,0x0a, + 0x5e,0xd9,0xb7,0x1e,0x17,0x11,0x1f,0xf6,0x9d,0x8e, + 0xbd,0x1c,0x6a,0xaf,0x05,0x87,0xa5,0xce,0x77,0x03, + 0xf6,0xc5,0x16,0xda,0x98,0xb0,0x1c,0xad,0xb0,0xf5, + 0xec,0xa3,0xdd,0x82,0x48,0xc6,0x10,0x56,0xc4,0xa9, + 0x9e,0x43,0x7a,0x4e,0x93,0xf2,0x00,0x48,0x4a,0x27, + 0x97,0x1d,0x3a,0x46,0xa5,0xee,0x13,0x17,0x66,0x5a, + 0x0a,0xc6,0xde,0x9f,0x70,0x2e,0x12,0x02}, + .data_len = 128, + .mac_len = 40, + .mac = {0x03,0xfc,0x9f,0xc8,0xd4,0xf1,0x86,0xe8,0x71,0x84, + 0x75,0xc6,0xa3,0xe8,0x23,0x89,0x16,0xef,0xa8,0x28, + 0xb5,0x40,0x42,0x93,0x2e,0x87,0x2b,0xff,0x0a,0x13, + 0x62,0xa6,0x75,0x05,0x63,0x79,0x7d,0x35,0x71,0xe8}, + }, { // 13 (91) + .key = {0x9e,0x1c,0x51,0xd3,0x5e,0x36,0x36,0xce,0xae,0xc4, + 0x4d,0x7f,0xf4,0x27,0xca,0x5e,0x98,0xb3,0xfb,0x8c, + 0x0c,0xa7,0x73,0x64,0x09,0x63,0x67,0x52,0x1b,0xd5, + 0x58,0xe8,0x5f,0x35,0xf2,0x2e,0x8b,0xf2,0x35,0x3a, + 0x30,0xec,0xd2,0x01,0x3c,0xe3,0xd8,0x6d,0xc3,0x2f, + 0x8f,0xb0,0xff,0xb2,0xa4}, + .key_len = 55, + .data = {0xd7,0x77,0x21,0xf0,0xca,0x5a,0x83,0xee,0xa7,0x82, + 0x10,0x73,0xd4,0x09,0x90,0xfb,0x6c,0xf0,0x0b,0x36, + 0xf0,0x06,0x27,0x0b,0x39,0x0b,0xb1,0xde,0xb1,0x16, + 0x79,0x0e,0xc3,0x34,0x63,0xc2,0x90,0x52,0xbb,0xe6, + 0xe4,0x5d,0xc9,0x70,0x68,0xa7,0xa5,0xe8,0x19,0x8d, + 0x4d,0x27,0xf8,0x57,0xf5,0x5f,0x03,0x5f,0x9e,0x5b, + 0x65,0x76,0xea,0x08,0xea,0x83,0x2f,0x35,0xb5,0x6d, + 0xca,0x97,0x35,0x3b,0xb6,0x10,0x55,0x7a,0x5d,0x30, + 0xf3,0xdf,0xad,0xfd,0x94,0x2e,0x6f,0xef,0x56,0x5a, + 0xd4,0x3f,0x26,0xee,0x51,0x62,0x32,0xab,0xad,0xd0, + 0xa1,0x73,0x59,0x09,0x82,0x66,0xff,0xda,0x03,0x4a, + 0x5d,0xdc,0xe4,0x30,0x54,0x3f,0x2b,0x54,0x3c,0xc5, + 0x18,0x46,0x7b,0x11,0x5b,0x47,0x56,0x22}, + .data_len = 128, + .mac_len = 40, + .mac = {0x63,0x21,0xb0,0x2d,0x91,0x59,0x10,0x09,0x91,0x3f, + 0x81,0x70,0xfb,0x0b,0x5e,0xa6,0x79,0x3e,0xe8,0xbb, + 0x32,0xa3,0xe6,0x2f,0xbe,0x11,0xcb,0xee,0x2d,0x06, + 0x7d,0xba,0xe2,0x61,0x14,0x20,0xa0,0x3f,0xb0,0x03}, + }, { // 14 (105) + .key = {0xbf,0xe6,0xbb,0x4c,0x9b,0x17,0x1b,0x93,0xd2,0x8e, + 0x9f,0x8f,0x86,0xb8,0x8d,0xbe,0x50,0x9c,0x66,0xee, + 0xd4,0x18,0x18,0xa1,0x98,0x6d,0x75,0xb6,0x16,0xfe, + 0xe4,0x46,0x0f,0x54,0x56,0xcd,0x23,0x66,0x7c,0x8a, + 0x9f,0x17,0x38,0x28,0x96,0x01,0x51,0x9d,0x33,0x71, + 0x6a,0x53,0x4d,0xb2,0x35}, + .key_len = 55, + .data = {0x5b,0x7a,0x07,0x8f,0x98,0x0b,0xb8,0x91,0x97,0x43, + 0xbb,0xce,0x52,0xfd,0x0b,0xa3,0xc2,0x20,0x83,0xd2, + 0xb0,0x25,0x4e,0x28,0xc8,0xd3,0xa0,0x5d,0xef,0x4d, + 0xa3,0x3b,0xd6,0x4f,0xb5,0x02,0xcf,0xb5,0xd0,0x0c, + 0xe0,0x3d,0x49,0xad,0x16,0x8d,0xbe,0x5d,0x1c,0x78, + 0x4a,0x19,0x0c,0x7d,0xfa,0x06,0x85,0x90,0x85,0x58, + 0xfe,0x1e,0x37,0x72,0x5a,0x4b,0x2f,0x4e,0xbc,0x7e, + 0xca,0x20,0x9c,0x1f,0x5f,0x36,0x1b,0x9f,0x2d,0x23, + 0x93,0xb9,0x91,0x1c,0x73,0xf8,0x7d,0xa2,0x4a,0x7a, + 0x25,0x62,0x21,0xf3,0xfb,0x59,0x0e,0xf4,0xde,0x3b, + 0x06,0x6e,0x8e,0x16,0xf3,0x72,0x64,0x32,0x06,0x3a, + 0x40,0x3d,0x4f,0x6d,0xc2,0xa4,0x8b,0x9f,0xbd,0x44, + 0x3d,0x17,0xe8,0x42,0x00,0xd6,0xd7,0x37}, + .data_len = 128, + .mac_len = 48, + .mac = {0xe8,0x2e,0xeb,0x7f,0x4b,0x74,0x15,0xa4,0xc9,0x5d, + 0xc8,0x2c,0x46,0xbb,0x59,0x71,0x5f,0xda,0x4e,0x0b, + 0xda,0xf6,0x4a,0x7f,0xb3,0xaf,0x3c,0x70,0x58,0xec, + 0x7d,0x2a,0x17,0x2b,0x82,0x93,0x05,0x7b,0x72,0xf9, + 0x66,0x44,0x54,0xe7,0xde,0xe1,0x1d,0x95}, + }, { // 15 (106) + .key = {0x4c,0xf5,0x4e,0xb8,0xcf,0x7b,0xd4,0x21,0xdd,0xb0, + 0x58,0x6a,0xc4,0xfa,0xb9,0xc4,0x78,0xcd,0xae,0xdd, + 0x89,0xcc,0x5a,0x19,0x53,0x32,0x21,0x1f,0x75,0x71, + 0xb9,0x98,0x84,0x19,0x84,0x33,0x00,0xfa,0x1d,0xed, + 0x86,0x8d,0x31,0x8f,0x48,0x90,0x90,0x78,0xbb,0xf1, + 0x83,0x9c,0x8f,0xed,0x61}, + .key_len = 55, + .data = {0xd2,0x2f,0x19,0x4a,0x1a,0xf3,0x3c,0xd8,0xcd,0xff, + 0xe9,0x96,0x7f,0x67,0x7a,0xcb,0x68,0x50,0x0d,0x6c, + 0xbb,0xf7,0x7a,0x3f,0x34,0xf5,0x88,0x40,0xf0,0xc1, + 0x60,0x44,0x82,0x76,0x41,0xdc,0x43,0xd6,0x76,0x7c, + 0xe9,0x8f,0x85,0xdd,0x5c,0xbe,0xaa,0x9f,0xc5,0xb2, + 0x83,0x33,0xe7,0xf2,0x0d,0xf8,0xb2,0x81,0xcf,0xa4, + 0x15,0x60,0x55,0xe6,0x15,0x55,0xe0,0x4a,0x1c,0xeb, + 0x5c,0x5c,0x93,0xba,0x92,0x10,0xb2,0xe8,0x9f,0x61, + 0x97,0xf0,0xa5,0x39,0x96,0xa2,0xc0,0x91,0xd1,0x6c, + 0x3c,0xd9,0x08,0xd7,0x05,0x9a,0xb2,0x54,0x5e,0x5a, + 0x4c,0x39,0xd6,0xc0,0xf1,0x07,0x78,0xf8,0x2b,0xee, + 0x43,0x59,0x09,0x93,0xda,0x45,0x71,0x10,0x7c,0x51, + 0xb8,0x3c,0x35,0xa6,0x70,0x2e,0x56,0xa8}, + .data_len = 128, + .mac_len = 48, + .mac = {0x83,0x0b,0x4a,0x79,0x8f,0x85,0xc4,0x48,0xb3,0xd5, + 0x4a,0xbf,0xee,0x61,0xb3,0x76,0x59,0x7f,0x65,0x66, + 0x6d,0x83,0xa2,0x10,0x52,0xcb,0x3f,0x44,0x66,0xf4, + 0x47,0x47,0x43,0x16,0x07,0xbc,0x65,0x9c,0x91,0xcb, + 0x52,0x03,0x08,0xfb,0xf4,0xfc,0xdb,0x58}, + }, { // 16 (120) + .key = {0xc6,0x3b,0xff,0x38,0x2d,0xe2,0xbd,0x2d,0x07,0x65, + 0x38,0xea,0x88,0xff,0x54,0x13,0xd1,0x19,0x69,0xf5, + 0x0a,0x0d,0xf1,0x6d,0xb1,0x2f,0x84,0x05,0x31,0x0e, + 0x07,0x61,0xb7,0xf7,0x20,0xda,0x41,0xbb,0xec,0x68, + 0xf8,0xb2,0xf5,0xc5,0xbf,0x00,0x5e,0xcf,0x0c,0x17, + 0x61,0x2f,0xf6,0x7e,0xfc,0x38,0x90,0xd0,0xe6,0x11, + 0x76,0x07,0xc8,0x17,0xa5,0xfa,0xaa,0x7d,0x90,0x25, + 0xab,0x35,0x70,0xa9,0xf6,0x14,0xdb,0x93,0xf1,0x31, + 0x98,0x61,0xb8,0x8e,0xb2,0xc3,0xc9,0xfa,0xcb,0x9e, + 0x01,0x35,0xb3,0x56,0xc7,0x56,0x39,0x4d,0x87,0x6a, + 0x41,0xa7,0x62,0x5e,0x17,0x51,0x23,0x1f,0x03,0x41, + 0x75,0xff,0x1e,0xff,0x54,0x5b,0x63,0x64,0xc2,0x7a, + 0x09,0xa1,0xbb,0xb9,0x11,0x84,0x6a,0xe5}, + .key_len = 128, + .data = {0x99,0x2a,0x5b,0x8a,0x63,0x9a,0xe2,0xb2,0xf7,0xfc, + 0x9e,0x13,0x53,0xa7,0x9e,0x52,0x1c,0xfd,0xc9,0x89, + 0x90,0x93,0x72,0x90,0xbc,0x93,0x2c,0x7b,0xef,0x5e, + 0xdf,0x63,0x6e,0x75,0x1b,0x6a,0x69,0x99,0xad,0xf9, + 0x2e,0x31,0x70,0x4c,0x9d,0xed,0x66,0x31,0xdc,0xa9, + 0x07,0x0c,0x4c,0x94,0xd9,0x1f,0xbb,0x91,0x41,0x08, + 0xdb,0xdd,0x99,0x8b,0xf2,0xf2,0x82,0x92,0xd4,0xac, + 0x7c,0x72,0x0f,0xab,0xb4,0x70,0x65,0xf8,0x1c,0x84, + 0x7f,0xeb,0xc1,0x5d,0xdf,0x4c,0x5a,0xa4,0x17,0xb8, + 0x1c,0x85,0x38,0x46,0xd6,0x6c,0x8e,0x6b,0x39,0x0c, + 0x8a,0x1b,0x77,0xa6,0x00,0x31,0x11,0x88,0x93,0x11, + 0xe9,0xd4,0x6d,0x8c,0x9f,0x82,0x33,0x04,0x1a,0xa8, + 0x37,0xd0,0x65,0xf9,0xf0,0xe1,0xbd,0x8c}, + .data_len = 128, + .mac_len = 24, + .mac = {0x44,0x8a,0xbc,0xe3,0xc3,0x8e,0x7f,0x10,0x90,0x73, + 0xf1,0x51,0x34,0x55,0x21,0x4d,0x03,0x61,0xca,0x75, + 0x9c,0x77,0x54,0x52}, + }, { // 17 (121) + .key = {0x43,0x59,0xb0,0x93,0x28,0xdd,0xce,0x80,0xcc,0xf1, + 0xd3,0xec,0x54,0x37,0xab,0xa6,0xa1,0x1a,0xe7,0x89, + 0x77,0x5f,0x04,0xac,0xde,0xfc,0xf0,0xd8,0xc8,0x2e, + 0xca,0x3f,0xf5,0xc6,0xe9,0x6a,0x14,0xc3,0x21,0x74, + 0x2b,0x26,0x41,0x76,0x38,0x02,0xe0,0x42,0x19,0xd3, + 0x5a,0x54,0xa9,0x10,0x15,0x05,0x2c,0x04,0x09,0x02, + 0xed,0xd9,0x7f,0xfd,0x25,0xf6,0x18,0xa2,0x1f,0x8b, + 0x12,0xcd,0x9a,0x69,0xc7,0xfa,0x6f,0x18,0x76,0xfd, + 0x73,0x23,0x46,0xf3,0x9f,0xb7,0x88,0x78,0x6e,0x6c, + 0x3d,0x1a,0x87,0x63,0xd8,0x0e,0x9c,0x91,0x45,0x22, + 0x92,0x5a,0x29,0xf3,0xe2,0x62,0x6c,0x60,0x3f,0xa0, + 0xf5,0x3e,0x79,0xb4,0xb4,0x4d,0xa1,0x7a,0xe6,0x6b, + 0x6e,0xdf,0x94,0x08,0xdf,0xf3,0x5d,0xda}, + .key_len = 128, + .data = {0xa5,0x71,0x95,0xbf,0xf0,0x00,0xd7,0x68,0xe3,0x9c, + 0xe6,0xda,0xf6,0x6e,0x91,0xb3,0x1a,0x30,0xfe,0x94, + 0x42,0x9d,0x4c,0x2f,0x22,0x25,0x76,0xa1,0x36,0xe6, + 0x7b,0x03,0x07,0xd8,0xbc,0x3b,0xaa,0x47,0xa5,0x18, + 0x89,0x87,0x8f,0x9f,0x66,0xe3,0xe5,0x9f,0x9c,0xd6, + 0x86,0x8c,0xa8,0x7e,0x6b,0x89,0xe9,0x4d,0x8a,0xc7, + 0xa4,0x02,0xfa,0x0e,0x4b,0xd7,0x57,0x99,0xff,0xfc, + 0x68,0x27,0x53,0x45,0xff,0x4f,0x53,0x20,0x21,0x14, + 0xc5,0xc9,0x67,0xb9,0xae,0xc1,0xa4,0xd7,0x18,0x7c, + 0xc8,0xac,0x13,0x59,0x05,0xb6,0xfa,0xd8,0x30,0x80, + 0xf7,0x08,0x69,0xbd,0xc9,0x3e,0xfe,0x93,0xc5,0x0c, + 0x8d,0x39,0x1b,0x71,0x69,0xc4,0x5b,0x4e,0x3f,0x3e, + 0x38,0x19,0xfa,0xf9,0x8b,0xd5,0xe3,0x22}, + .data_len = 128, + .mac_len = 24, + .mac = {0xf2,0x15,0xc9,0x88,0x60,0x11,0x19,0x87,0x33,0x40, + 0xc4,0xcf,0xf6,0x06,0x3f,0xf9,0x7c,0xea,0xcb,0x3e, + 0xed,0xc4,0x0a,0xef}, + }, { // 18 (135) + .key = {0x14,0x16,0x13,0x40,0xbb,0xfa,0x1c,0x47,0x80,0x58, + 0x37,0x96,0xf7,0x07,0x31,0xd2,0x02,0xee,0xa4,0x42, + 0x97,0xbc,0xd4,0x28,0xc3,0xd9,0xd7,0x52,0xef,0x9c, + 0xf9,0xec,0x63,0xbe,0x5e,0x98,0x08,0x0e,0xe9,0xc1, + 0x72,0x67,0x5d,0x2b,0x1d,0xdf,0xc2,0xcf,0xf7,0x42, + 0x0b,0xe7,0x1f,0xbf,0xf5,0x45,0xed,0xe0,0x32,0xe8, + 0x32,0xc0,0xc7,0xd1,0xc1,0x78,0xb3,0x13,0x2e,0xda, + 0xd1,0x2a,0xd5,0x62,0xff,0x8d,0x1e,0x69,0x80,0x87, + 0x00,0x9c,0x9f,0x42,0xc4,0xad,0x95,0x25,0x0c,0x48, + 0xad,0x5f,0x13,0x49,0xa6,0xc4,0x36,0x2c,0x59,0xd9, + 0xb4,0xc4,0x9c,0x2a,0xb2,0x30,0x65,0xe4,0x82,0x0c, + 0x33,0x9f,0x24,0xe4,0xa9,0x7c,0x0d,0xee,0x7c,0x70, + 0x28,0xf8,0x90,0xdf,0x1b,0x9f,0x5e,0x6d}, + .key_len = 128, + .data = {0x6f,0x24,0xfa,0x08,0xde,0x52,0x44,0xf3,0x01,0x73, + 0x80,0x9f,0x1a,0x14,0x1a,0x9e,0x00,0xff,0xc2,0xa9, + 0x14,0x5f,0x07,0xe6,0x77,0x26,0x27,0x6b,0x7a,0xac, + 0x25,0xfe,0x56,0x98,0x1d,0x1e,0x1e,0x04,0xd5,0x48, + 0xf1,0xdc,0x94,0x73,0x74,0x87,0x37,0xdd,0x7f,0xca, + 0x81,0x09,0x17,0xe9,0xb3,0x08,0x9d,0x0f,0x5c,0xf9, + 0x44,0xef,0x73,0xcc,0xc9,0xac,0xa3,0x4b,0x5e,0xf6, + 0xe6,0x5a,0xe7,0x77,0x55,0x7d,0x68,0x6d,0x3f,0x9c, + 0xbe,0x98,0x78,0x03,0x8e,0x56,0xf3,0xad,0x7c,0x0d, + 0x93,0xc2,0x9d,0xc9,0x3f,0x5e,0x2e,0x26,0x35,0x94, + 0x86,0x71,0xa0,0xb3,0x49,0x0a,0x6c,0xc7,0xdf,0x0c, + 0x59,0x63,0x24,0x30,0x4e,0x9e,0x61,0xef,0xf1,0x5c, + 0x7c,0xe7,0x74,0xcf,0x6b,0x80,0xb1,0x3d}, + .data_len = 128, + .mac_len = 32, + .mac = {0x64,0x2a,0xba,0xb1,0x3c,0x76,0x78,0xba,0xa4,0x46, + 0x0e,0x4b,0x6d,0xec,0x2f,0x4e,0xa8,0x41,0x23,0x99, + 0x95,0x76,0x25,0x0c,0x98,0x00,0x6a,0x8a,0x0a,0x06, + 0xeb,0x57}, + }, { // 19 (136) + .key = {0x8b,0xcd,0x18,0x2e,0x78,0xa9,0xdc,0x1d,0x38,0xff, + 0x52,0x95,0x86,0x32,0xa2,0x2b,0x73,0x9e,0x06,0x41, + 0xaa,0xcf,0x2e,0xd8,0xf8,0xf1,0xe4,0xa5,0x0c,0x88, + 0xec,0x66,0x7b,0x62,0x2e,0x76,0x07,0xc9,0x17,0x9f, + 0x20,0xfd,0x3c,0x30,0xab,0xe1,0x40,0x50,0x03,0xf4, + 0xf8,0x92,0x3d,0x83,0xce,0xca,0xb1,0x1d,0x63,0x1e, + 0xb5,0x48,0x79,0x60,0xac,0x72,0x0f,0x9b,0x40,0x2a, + 0xcd,0xeb,0xeb,0x90,0xa3,0x92,0xbc,0x0a,0xae,0x49, + 0x58,0x39,0x5b,0xd4,0x3f,0x2c,0xce,0xd9,0x50,0xd3, + 0x85,0xf2,0x90,0xb6,0x38,0x01,0x27,0xe6,0x04,0xc4, + 0xab,0x34,0xc9,0xa9,0xa1,0xa2,0xd1,0xe3,0x41,0x17, + 0xb2,0xbd,0x7a,0x57,0x75,0x2e,0x36,0x31,0xf7,0xae, + 0xdf,0xfb,0x90,0x49,0x22,0x3b,0xf3,0xf2}, + .key_len = 128, + .data = {0x80,0x3b,0x54,0xa0,0xa9,0xb4,0x4c,0xc9,0x35,0x34, + 0x9e,0x9d,0x99,0xaf,0x7c,0x5a,0xa6,0x00,0x64,0x4e, + 0xff,0x8b,0x3c,0x9d,0xd0,0x21,0xa0,0x3f,0xbd,0x24, + 0x7b,0x48,0x19,0xeb,0xd4,0x6c,0x59,0x67,0xeb,0xc2, + 0xc8,0x07,0x85,0xc8,0x7c,0xda,0x84,0xa8,0x88,0xf4, + 0xba,0xb9,0x73,0x12,0xff,0x49,0xe9,0x81,0x81,0x9a, + 0xb1,0x3b,0x5c,0x2a,0xdf,0x54,0x6b,0x37,0x4b,0x94, + 0x5d,0x83,0x41,0x66,0x0b,0x55,0x7a,0xf0,0x08,0xc0, + 0x4b,0x84,0x7a,0x27,0x1d,0x37,0x29,0x01,0x1d,0xcf, + 0xd6,0xda,0x35,0xe3,0xce,0x9a,0x3a,0x3d,0xbf,0x0a, + 0x67,0x83,0xc9,0x94,0x0a,0x17,0xd8,0x4b,0x7d,0x3b, + 0x32,0x2b,0x58,0x79,0x4c,0xa1,0xe5,0x42,0xe2,0x4e, + 0xd4,0xd5,0x46,0x08,0x30,0x62,0xf9,0x21}, + .data_len = 128, + .mac_len = 32, + .mac = {0xbc,0x08,0x20,0x56,0x94,0xfe,0x5b,0xcd,0x78,0x6c, + 0x78,0x5a,0x07,0x31,0xb7,0xb7,0x37,0xa6,0x7b,0xea, + 0x10,0x52,0x8b,0xfa,0x33,0x44,0x8a,0x7e,0xa9,0x3d, + 0xff,0x0b}, + }, { // 20 (150) + .key = {0x66,0x58,0x12,0xa5,0x54,0xfe,0x08,0x43,0x39,0x55, + 0x3e,0x3c,0xc2,0x9d,0xfa,0x89,0x96,0x36,0x2e,0x29, + 0x43,0xc4,0x05,0x68,0x78,0x8b,0xbc,0x61,0x76,0x1b, + 0xb3,0xc2,0xc1,0x32,0xc4,0xcf,0x1b,0xde,0xd3,0xaa, + 0xb2,0xe2,0xa6,0xd1,0x99,0x5b,0xf7,0xe8,0x75,0xa3, + 0xc8,0xb9,0x79,0x76,0xf7,0x79,0x94,0x53,0x12,0x4c, + 0xe8,0x25,0x6c,0x0c,0x7f,0x23,0x71,0x46,0x39,0xf5, + 0x36,0x86,0x09,0x18,0x55,0xd5,0x61,0x83,0xf7,0x7f, + 0xeb,0x8b,0x32,0x1a,0x7a,0x04,0x96,0xc3,0x40,0xa9, + 0x02,0xab,0x41,0xbe,0xbc,0xd3,0x07,0xf3,0xc1,0x13, + 0x98,0x8c,0x5a,0x61,0xa5,0xbf,0xf0,0x50,0x04,0x5d, + 0x21,0xd7,0x61,0xb5,0x14,0x54,0x30,0xb6,0x09,0xd0, + 0xe5,0x53,0x34,0x85,0x68,0x2c,0xcb,0x9d}, + .key_len = 128, + .data = {0x8d,0xf0,0xa3,0x67,0x32,0x78,0xe2,0x60,0x64,0xcb, + 0x6f,0x68,0x80,0x22,0xac,0x2a,0x0f,0x2e,0x99,0x73, + 0x41,0xb6,0xed,0xf2,0x97,0x81,0x66,0x3c,0xdf,0x76, + 0x5d,0x12,0x65,0x02,0x9d,0xe7,0x68,0xba,0x75,0x9d, + 0xcb,0x42,0x0c,0x90,0x0d,0x6d,0xf5,0xd5,0x7b,0xa5, + 0x03,0xc4,0xa4,0x8e,0x5f,0xb3,0x0e,0xe6,0xd7,0x05, + 0x27,0xb0,0x79,0x64,0x7e,0x91,0x61,0x4a,0x33,0x7a, + 0xcf,0xc6,0xad,0x87,0x7d,0x7d,0x8a,0x27,0x2f,0xef, + 0xdc,0x7e,0x8b,0xfb,0x92,0x07,0x2b,0xa5,0x34,0x7e, + 0xf1,0x18,0xd4,0xfd,0x9a,0xe7,0x41,0x65,0x96,0x98, + 0x7d,0xff,0x17,0x63,0x71,0x63,0x69,0x37,0xe0,0x99, + 0x81,0xfe,0x9a,0x7f,0xd8,0x22,0xf2,0x6a,0x7a,0x50, + 0x71,0x10,0x59,0x7c,0xcc,0xa6,0xe8,0x25}, + .data_len = 128, + .mac_len = 40, + .mac = {0x20,0x31,0x30,0x5f,0x71,0xc6,0x9a,0xe3,0xea,0x4d, + 0x55,0x47,0x27,0xf8,0x3c,0x7d,0x9c,0x48,0x57,0x65, + 0x96,0x8b,0x19,0x79,0x6b,0xb0,0x18,0x7c,0xe0,0x4a, + 0xa7,0x41,0x03,0x02,0xe2,0xfb,0x09,0xcf,0x4b,0x07}, + }, { // 21 (151) + .key = {0x71,0x08,0xc0,0xd1,0xe1,0x15,0xbf,0x9d,0x61,0x31, + 0xdc,0x37,0x05,0x2b,0x76,0x0b,0xdd,0xe7,0xb4,0x3a, + 0xd5,0xb1,0x82,0x8f,0xda,0xd1,0xd6,0xb6,0x3e,0x60, + 0x38,0xa8,0x5e,0x5a,0x81,0x6a,0x82,0xf4,0xe3,0xf7, + 0x04,0x2f,0x29,0x7b,0xb5,0xad,0x40,0xc1,0x7c,0xc3, + 0xf7,0xef,0x40,0xd1,0x03,0x71,0x08,0xce,0x46,0x33, + 0x61,0x27,0x51,0x13,0x01,0xca,0x27,0x96,0xa9,0x7d, + 0x43,0xd9,0x50,0x75,0xdd,0xcb,0x7d,0x24,0x6a,0x9a, + 0xf5,0x52,0x62,0x6b,0x96,0x6f,0x45,0x4e,0x83,0x28, + 0xe0,0x71,0x81,0x38,0xcd,0x94,0xa1,0x81,0x39,0xbc, + 0x20,0x5b,0xe9,0x2c,0x8b,0x2c,0x7f,0x91,0x26,0x39, + 0xfa,0x7d,0x8f,0xbb,0x7d,0x16,0x9f,0x36,0x51,0x10, + 0x91,0x06,0x2c,0xd8,0x66,0x3a,0xb4,0x12}, + .key_len = 128, + .data = {0x2c,0x72,0x3d,0x78,0xa6,0x6c,0x53,0x64,0x94,0xcd, + 0xf3,0x7d,0xa0,0xe4,0x3e,0x2e,0x17,0x1a,0x09,0xc7, + 0x9d,0xd5,0x32,0x7e,0x20,0x9c,0x34,0xb4,0x0a,0x7b, + 0xfa,0x79,0xbb,0xa9,0xf1,0x51,0x36,0x68,0x61,0x38, + 0x1a,0x2d,0xfd,0xe5,0xd5,0x01,0xb9,0x4c,0x14,0x27, + 0xdb,0x66,0x7d,0xff,0x55,0x34,0xa1,0x2a,0x52,0x02, + 0x2c,0xef,0x0f,0xe9,0x5f,0xdd,0xec,0x97,0xc1,0xb2, + 0xc3,0x53,0x11,0x7c,0x78,0x3b,0x7e,0xfe,0xd1,0xd0, + 0x1b,0x55,0x88,0xb5,0x8d,0xdc,0x9f,0xb4,0x06,0x4c, + 0xf4,0x02,0x78,0x28,0x15,0xc4,0x02,0x58,0x55,0xd1, + 0xaf,0x13,0x20,0xba,0x5f,0x03,0x8b,0x08,0x05,0xa4, + 0x2f,0xc4,0x13,0xee,0x38,0x3d,0x33,0x33,0xb9,0x05, + 0x38,0x4a,0x43,0x3d,0x54,0xed,0xb5,0x12}, + .data_len = 128, + .mac_len = 40, + .mac = {0x82,0x6a,0x2a,0x11,0x38,0x0c,0x26,0x08,0x73,0x66, + 0x38,0x15,0xff,0x5e,0x02,0x20,0x1a,0x17,0xde,0xdc, + 0xa1,0xb2,0x0c,0x61,0x3d,0x0d,0xcc,0x01,0x90,0x95, + 0xb4,0x44,0xfa,0x0e,0x96,0xc8,0xb2,0xdf,0x54,0x33}, + }, { // 22 (165) + .key = {0xb6,0x19,0xd9,0xd0,0x74,0x61,0xc1,0x1b,0xc9,0xfb, + 0x66,0x11,0x7d,0x61,0xed,0x90,0x00,0x13,0x66,0xbb, + 0xff,0xdb,0xff,0x58,0x35,0x56,0x77,0x75,0x84,0xb0, + 0xd6,0x52,0x44,0xaf,0x5c,0x7b,0xdb,0xf3,0xb7,0x35, + 0x8d,0x7c,0x79,0x1b,0x96,0x6c,0xc8,0x09,0x76,0x0e, + 0x57,0x39,0x8d,0x18,0x96,0xac,0xe7,0x2d,0x26,0xcc, + 0x59,0xa6,0x90,0x4f,0xcd,0x92,0x36,0x5e,0xda,0xfb, + 0x8a,0xf7,0x98,0x6c,0x7d,0x90,0xb2,0xaf,0x3b,0xfd, + 0xbc,0xdb,0x15,0x93,0xc7,0x8f,0xbe,0x8e,0x33,0x78, + 0xbb,0xb0,0xc5,0x19,0x15,0x2b,0xf9,0xcb,0x51,0xc1, + 0x9a,0x02,0xa1,0x2a,0x8f,0xd3,0x5c,0xb6,0xf8,0xb3, + 0xac,0x33,0x7a,0x82,0x87,0x11,0xd6,0xc8,0xe0,0xc4, + 0xc1,0x3e,0x1e,0x6a,0xf0,0x90,0xcd,0xae}, + .key_len = 128, + .data = {0x5a,0x81,0xe7,0x11,0xad,0xfe,0x50,0x77,0xdd,0x8c, + 0x8b,0x57,0xc9,0x5e,0x8e,0x1f,0x3d,0xe3,0x9f,0x4f, + 0xc4,0x48,0xc5,0x23,0xbd,0x3e,0x7c,0x72,0xb1,0xfd, + 0xac,0xd6,0xe4,0x89,0xdc,0x0d,0x2a,0x34,0xa3,0x9f, + 0xfc,0x64,0x60,0xc1,0xcb,0x96,0x2b,0x7a,0x94,0xa3, + 0x0c,0x04,0xb5,0x42,0x6a,0x75,0xff,0xcf,0xc6,0x9f, + 0x0c,0x4b,0xa9,0x34,0xd3,0xa3,0xda,0x2e,0x79,0x35, + 0xd5,0x6d,0x6b,0x90,0x79,0xa2,0xa9,0x7b,0x01,0x6d, + 0x65,0x3a,0x35,0xc2,0xcc,0x0c,0xe1,0x91,0x24,0xf8, + 0x87,0xa6,0x17,0xc9,0x51,0xce,0x4e,0x58,0x49,0x3b, + 0x42,0x09,0xcc,0x29,0x4f,0x98,0x3c,0xc2,0x0b,0x16, + 0xf6,0x3f,0xd5,0x2e,0x84,0x51,0xb1,0xad,0x13,0xbf, + 0x53,0x42,0x27,0x50,0x79,0x81,0x8d,0xeb}, + .data_len = 128, + .mac_len = 48, + .mac = {0x8b,0x42,0x58,0xbe,0x4c,0x09,0x4a,0xa4,0x05,0x6f, + 0x33,0x2e,0xde,0x8c,0x73,0x37,0x72,0x66,0x4b,0x08, + 0x8b,0xa2,0x2e,0xf8,0xca,0xae,0x7c,0xef,0xd7,0x7e, + 0xce,0xb3,0x5e,0x83,0xaf,0x8d,0x9c,0x12,0x83,0xcb, + 0xbf,0xfe,0x4a,0x37,0x2b,0x69,0x9c,0x21}, + }, { // 23 (166) + .key = {0xe4,0x88,0x25,0xa5,0x50,0x3a,0x6a,0xfe,0x0b,0xf9, + 0xa2,0x40,0xc6,0x7f,0x27,0xac,0xd4,0xa8,0xf6,0x99, + 0x38,0x34,0x64,0x5e,0x03,0xc8,0x0c,0x72,0xdd,0x37, + 0x0c,0xd2,0xe1,0x00,0x71,0xa3,0xae,0x18,0xef,0x19, + 0xba,0xe9,0xd6,0x97,0xea,0x9a,0x41,0x18,0x60,0x91, + 0x90,0xcd,0x95,0x36,0x19,0x07,0xa7,0xfa,0x1b,0x58, + 0xf4,0x99,0xf3,0xf5,0xe7,0x9b,0x93,0x5f,0x12,0x21, + 0x2f,0x43,0x7d,0xde,0x39,0x9e,0x3e,0x64,0x90,0x24, + 0x4a,0xa1,0xf5,0xe3,0x8b,0xa9,0xbe,0x24,0x33,0xb6, + 0xce,0x92,0x4f,0x6c,0xc4,0x9e,0x9f,0x62,0x73,0x21, + 0xa5,0xdf,0x93,0x43,0xfc,0xe1,0xb5,0x9d,0xeb,0x64, + 0x7d,0x9a,0x3a,0xe0,0x0b,0x23,0x44,0x14,0xba,0x7b, + 0x4e,0x02,0x0d,0x67,0x17,0x3b,0xe6,0x93}, + .key_len = 128, + .data = {0x85,0x61,0x86,0x5a,0xc2,0xce,0x12,0x83,0x27,0x46, + 0xf8,0x25,0x84,0xa4,0xb9,0x8e,0x7f,0x4c,0x3a,0xe2, + 0x41,0x0e,0x18,0x19,0x6f,0x4e,0x3b,0x47,0x5c,0x62, + 0xae,0x20,0x7d,0x3c,0xad,0xbb,0x1d,0x49,0x00,0x96, + 0x51,0x98,0x88,0xdb,0x2f,0x3f,0x18,0xe1,0x3b,0xfb, + 0x86,0xf6,0x22,0x16,0x01,0x5c,0xab,0x8e,0xa4,0x91, + 0xea,0x73,0x4c,0xd3,0xb7,0x91,0xa7,0xe4,0x5e,0x4f, + 0x8e,0x0b,0x98,0xd7,0x95,0x5b,0xba,0x77,0xe0,0x37, + 0x2d,0x47,0x38,0x16,0x1e,0x0d,0x5d,0x84,0x76,0x5d, + 0x9e,0x6a,0x0d,0x05,0xa8,0x8e,0x1a,0xa8,0x9c,0x5d, + 0xef,0xa8,0x64,0xe9,0xe3,0x49,0x46,0x2e,0x8f,0x14, + 0xb9,0x99,0x3d,0x7a,0x78,0xcb,0x9d,0xba,0xd6,0x9a, + 0xba,0x05,0x51,0x58,0x2d,0xdf,0x69,0x58}, + .data_len = 128, + .mac_len = 48, + .mac = {0xec,0x78,0x0a,0x91,0x5e,0xc7,0xde,0xeb,0xa2,0xc8, + 0xc9,0xe2,0xab,0x15,0xc9,0x76,0x2a,0x3e,0xb1,0x8f, + 0xaf,0xa2,0xd4,0x8a,0x55,0x4a,0xe1,0xfe,0x6c,0x44, + 0x59,0xda,0x1a,0x54,0xe2,0xd5,0x8b,0xdf,0x06,0xfe, + 0xa0,0x74,0x00,0x98,0xee,0xbb,0xb6,0x99}, + }, { // 24 (180) + .key = {0xe6,0x2c,0x2c,0xe5,0xff,0x8e,0x3d,0x46,0x5d,0x34, + 0x45,0x82,0xf2,0xdd,0x56,0x6e,0x0d,0x29,0xdd,0xd6, + 0x20,0x51,0x84,0xcb,0xc6,0x14,0x56,0x3a,0x04,0xf5, + 0x24,0xc3,0xcf,0xa3,0x28,0xc7,0xcf,0xb9,0xe9,0xc3, + 0x63,0xa7,0x5e,0xdd,0xe5,0xf0,0x56,0xbd,0x2f,0x97, + 0x18,0x9e,0x5e,0xd3,0x46,0xa5,0xd6,0x0a,0x07,0x71, + 0x86,0xfd,0x64,0xf3,0x6d,0x41,0xf3,0x80,0x5c,0xee, + 0xb3,0x24,0xfe,0x9b,0x38,0x3a,0x17,0x89,0x08,0x39, + 0x09,0x1e,0x44,0xd1,0x9c,0x95,0x8b,0x37,0xfe,0xf5, + 0x1b,0xbd,0x09,0x3f,0x39,0xa5,0xc5,0xec,0xd4,0x37, + 0x2e,0x96,0x65,0x11,0x37,0xf6,0x19,0xbf,0x0e,0x0e, + 0x32,0x8b,0xa2,0xa7,0xaa,0x96,0x63,0xfe,0x1a,0x28, + 0x48,0xbb,0xdb,0x45,0x17,0x22,0x6b,0x81,0xe1,0x8d}, + .key_len = 130, + .data = {0x7a,0xc2,0x40,0xb4,0xbd,0xe6,0x4b,0x6b,0x51,0x42, + 0x37,0xf1,0x22,0xdd,0x77,0x3a,0x6a,0xdc,0x2f,0x2d, + 0x83,0x04,0xa4,0x49,0xfa,0x7b,0xf2,0x8e,0xe4,0xce, + 0xfd,0x9b,0x75,0x38,0xa9,0x14,0xce,0x22,0x4e,0x46, + 0x17,0xe6,0x66,0x0e,0xce,0xd8,0x89,0xf6,0x5e,0x87, + 0x9c,0xa2,0xf4,0x40,0x45,0x6b,0x8e,0xd4,0xa1,0x49, + 0x55,0x9b,0x3a,0xf6,0x2c,0xb9,0x33,0x50,0x89,0xa0, + 0xc6,0x00,0x83,0xd7,0xf1,0x59,0x2d,0xf9,0x6b,0x82, + 0x23,0x00,0xdd,0xd8,0x62,0xc3,0x4f,0x8e,0x5d,0xbe, + 0xe0,0x96,0x4d,0x12,0xbb,0xc5,0xc8,0xcc,0x46,0x32, + 0x95,0x6a,0x9d,0xdf,0xbf,0x9c,0x3e,0x9b,0xe8,0x47, + 0x06,0x26,0xe0,0xcf,0x5c,0x97,0x76,0x96,0xac,0xfb, + 0x8e,0xc0,0x17,0x3f,0x74,0x3a,0x68,0x50}, + .data_len = 128, + .mac_len = 24, + .mac = {0x98,0x4e,0x2d,0xc5,0xdd,0x32,0x74,0x86,0x5d,0x0a, + 0x65,0x8e,0x1f,0x6d,0x2e,0xb0,0x85,0x4d,0xb7,0x5e, + 0x1e,0x02,0x93,0x7b}, + }, { // 25 (181) + .key = {0x4b,0xb9,0x7c,0x7c,0x53,0x36,0x87,0x16,0x93,0x8c, + 0x83,0x65,0x19,0xe2,0x0d,0x64,0x84,0xa7,0xe6,0xa1, + 0xbc,0x79,0x46,0x40,0xe0,0x46,0x73,0x42,0x80,0xb1, + 0x91,0x08,0x0d,0xb7,0xbc,0x12,0x8d,0x92,0x54,0x0d, + 0x93,0xdd,0x98,0x0d,0x6f,0xfa,0x77,0x17,0xa2,0xb1, + 0xa2,0xe2,0x95,0x19,0xe6,0xde,0x8a,0xbc,0xb9,0x76, + 0xd2,0xf6,0x13,0x92,0x40,0x9e,0x7f,0x61,0xdf,0xe8, + 0x71,0x55,0xe0,0x8a,0xda,0x6f,0xd6,0x1e,0xfa,0xbc, + 0x26,0xc8,0x75,0x20,0xb8,0x18,0xaa,0x52,0xf3,0x32, + 0x40,0x28,0xe9,0x2c,0x01,0x15,0xce,0xb7,0xec,0xf0, + 0xaf,0x02,0x85,0xf6,0x60,0xdb,0x70,0x13,0xb7,0x18, + 0x3e,0x5d,0xf7,0x35,0x87,0xe1,0x8f,0x3e,0x39,0xa3, + 0x05,0xef,0x2f,0xe0,0x2d,0x1b,0x06,0x96,0x9e,0x4a}, + .key_len = 130, + .data = {0x4f,0xe1,0xa8,0x51,0x0a,0xb3,0x6b,0x97,0xc6,0x13, + 0xd3,0x09,0xb5,0xb7,0xcc,0xb2,0x43,0xb3,0x28,0xe7, + 0x02,0x9d,0x3a,0x88,0xe3,0xef,0xa0,0x82,0xac,0xac, + 0x60,0x98,0xa6,0x47,0x37,0x64,0x96,0xc0,0x2d,0x98, + 0xef,0x10,0x6d,0x8a,0x46,0xc7,0x54,0xf0,0x06,0xf4, + 0xc8,0xe7,0x65,0x45,0xcb,0x3b,0x97,0x6f,0x4f,0xe2, + 0x41,0xd0,0x4c,0xc9,0x30,0x53,0x11,0xd4,0x4b,0x95, + 0xd8,0x20,0xc6,0x46,0x9c,0x8b,0x99,0xd1,0x2f,0x76, + 0x31,0x3f,0x87,0xc9,0x65,0x58,0x58,0x38,0xab,0x0c, + 0xe9,0xc5,0x8c,0x12,0x20,0x86,0x55,0xcf,0xde,0xa9, + 0x10,0x79,0x93,0xb5,0xb2,0x7c,0x09,0x12,0x96,0x1d, + 0x84,0xcc,0x2a,0x5d,0x0d,0x94,0xe9,0x20,0x0b,0x08, + 0x89,0x8e,0x13,0x34,0x75,0xba,0x01,0x58}, + .data_len = 128, + .mac_len = 24, + .mac = {0xf2,0x72,0x23,0x78,0xf0,0x2b,0xf8,0xd1,0x04,0xb3, + 0xb5,0x0c,0x77,0xd1,0x32,0xfa,0x35,0xac,0x86,0xe4, + 0xda,0x34,0xf1,0xc8}, + }, { // 26 (195) + .key = {0xf3,0xac,0x44,0x22,0xcc,0x72,0x43,0x78,0x10,0x0d, + 0x75,0x15,0xdd,0xfb,0xf3,0xfe,0x34,0x00,0x02,0xb7, + 0x97,0x6c,0x43,0xac,0xd6,0x9c,0x2a,0xcf,0x26,0xc3, + 0xb1,0x81,0x73,0xeb,0x4e,0xb6,0xf7,0x36,0x22,0x54, + 0x0c,0x6a,0x73,0xdd,0x3e,0xac,0x5c,0x4e,0xa5,0x8c, + 0xc3,0x47,0x72,0x42,0x8c,0x6b,0xc7,0x37,0x0c,0x0a, + 0xcc,0xc8,0xc1,0xfe,0xff,0x46,0x40,0xd2,0xcb,0x41, + 0x6e,0x2a,0x5d,0x06,0xf3,0x5e,0xb3,0x66,0xec,0x69, + 0xf5,0xb9,0xe0,0x02,0x09,0x23,0xf6,0x08,0x62,0x16, + 0x65,0x23,0x18,0x18,0x2b,0xa9,0x3e,0xc7,0x02,0xbe, + 0x70,0x1a,0x90,0xc0,0xab,0xe9,0xde,0xe2,0x61,0xb0, + 0x0b,0x16,0xcd,0x90,0x42,0x31,0x85,0x96,0xe9,0x49, + 0x4e,0x40,0x1b,0x62,0x33,0x3d,0x59,0x4a,0xd9,0x75}, + .key_len = 130, + .data = {0x04,0xa3,0xc1,0xe8,0x9e,0xeb,0xe7,0xb9,0x9e,0xd3, + 0xbc,0xda,0xa3,0xca,0xfe,0xd8,0x95,0x6e,0xe8,0xda, + 0x93,0xac,0xbf,0xde,0x2d,0x29,0xa8,0x45,0xd4,0xe1, + 0xbc,0x92,0x8e,0x0f,0x5e,0x6f,0xef,0x4c,0xcc,0xf1, + 0x44,0xfa,0xf5,0x1c,0x11,0xe3,0x8b,0xaa,0xbe,0x1e, + 0x58,0x08,0x8d,0x33,0xd5,0xa2,0xcf,0x7e,0xf9,0x60, + 0x58,0xd9,0x4f,0x70,0x30,0x75,0x4b,0x47,0x8b,0x09, + 0xde,0xe2,0xfb,0x2f,0x48,0x52,0xe5,0x0a,0x2e,0x77, + 0x32,0x2d,0xec,0x0c,0x46,0xb8,0x2c,0xe3,0x36,0xc4, + 0xb8,0x72,0x35,0x02,0x8c,0x8f,0x50,0x9e,0x30,0x78, + 0x5c,0x6a,0x44,0x16,0x2c,0x38,0x5c,0x83,0x07,0x87, + 0x0f,0xc9,0x58,0x63,0x4b,0xed,0xa8,0x86,0xeb,0x2c, + 0xca,0xc3,0x8c,0x84,0x55,0xa5,0x9c,0x76}, + .data_len = 128, + .mac_len = 32, + .mac = {0x07,0xf7,0x3d,0x06,0x6e,0xee,0x17,0x80,0xfe,0x94, + 0x88,0xca,0x2f,0x02,0x4e,0xd5,0x66,0x00,0x92,0x0f, + 0x6e,0x0c,0x72,0x86,0x40,0xd1,0xf6,0xb5,0x3b,0x24, + 0x00,0x2c}, + }, { // 27 (196) + .key = {0x6f,0x67,0xac,0xc5,0x6e,0x89,0x29,0xe4,0x91,0xdf, + 0x25,0x2d,0x3c,0x8d,0x49,0x7a,0x6f,0xe7,0xa6,0x62, + 0xf6,0xd6,0x91,0xbb,0xdf,0x7d,0xb1,0x5d,0x31,0x1c, + 0x56,0x29,0xdb,0x34,0x0c,0x4a,0xeb,0xec,0x71,0xbb, + 0x00,0xb3,0x43,0x09,0x02,0x27,0xbd,0x5b,0x10,0x35, + 0x24,0xaf,0xba,0x82,0x9d,0x66,0x71,0x0a,0x41,0x03, + 0x3b,0x08,0x73,0x30,0xac,0x15,0x71,0x02,0x11,0x93, + 0x2a,0x7d,0xee,0x4c,0x50,0x5b,0xab,0x57,0xad,0x09, + 0x8a,0x3c,0xba,0xf3,0xdc,0x57,0x6e,0x01,0x75,0x82, + 0x54,0x61,0x5d,0xee,0xe0,0x88,0xc8,0x52,0x03,0x73, + 0x48,0x48,0xfd,0x33,0x42,0xf3,0x73,0xa8,0x9f,0xe6, + 0xc1,0x8d,0xc3,0x41,0x91,0xb4,0xc3,0x1d,0xad,0x93, + 0xd2,0x2b,0x11,0x00,0xfd,0x97,0x45,0x39,0x19,0x33}, + .key_len = 130, + .data = {0x4f,0x34,0xc8,0x74,0xa9,0x09,0xe1,0xa3,0xec,0x18, + 0x69,0x23,0x61,0x16,0x99,0x5b,0xaa,0xaf,0xba,0x7b, + 0x02,0xbc,0x8b,0x54,0xc6,0xbc,0xe7,0x6e,0x35,0x82, + 0xa3,0x54,0x74,0x2b,0xb6,0x33,0xd4,0x53,0x9c,0xa3, + 0x58,0x89,0xfc,0xc5,0x72,0xff,0x88,0x8e,0x0e,0x86, + 0x24,0x62,0xd1,0xba,0x4b,0xe5,0xa3,0x7a,0xaf,0x0e, + 0x6b,0x9c,0x20,0x7d,0x19,0xde,0xaf,0x0e,0xea,0x1f, + 0x13,0xae,0xe7,0xcf,0x4c,0x6d,0xb0,0xa4,0x86,0xd5, + 0x77,0x8e,0x3f,0x7a,0x4f,0xee,0xac,0xd3,0xa7,0x03, + 0x59,0x48,0x11,0xa4,0x11,0x8c,0x49,0x35,0xfd,0x2d, + 0x72,0xd4,0x0f,0x6a,0xa2,0xd3,0xa2,0x44,0xa1,0x6b, + 0x5a,0xd8,0xee,0xae,0x52,0xeb,0x03,0xbe,0x76,0xc7, + 0xda,0x3d,0x2d,0x46,0xb0,0x04,0x3c,0x2c}, + .data_len = 128, + .mac_len = 32, + .mac = {0x0c,0xd3,0xc2,0xf7,0xae,0x63,0x53,0xec,0x7d,0x70, + 0xce,0x93,0x2f,0x39,0x80,0xcb,0xaf,0xb7,0x71,0x59, + 0xb2,0xfb,0x7a,0x5c,0x85,0xa1,0xcb,0xc3,0xa5,0x66, + 0xba,0x86}, + }, { // 28 (210) + .key = {0xe4,0x86,0x31,0x6b,0x3a,0xc5,0xec,0x10,0x0f,0x43, + 0xc0,0xea,0xbd,0xbc,0x0a,0x32,0xb3,0xb9,0xbb,0x65, + 0x80,0x58,0x0a,0x33,0x2d,0x4f,0x66,0x98,0xd0,0x2f, + 0xaf,0x49,0x5e,0xe6,0xa5,0x51,0xc1,0x88,0xa1,0xfc, + 0x2a,0x4f,0x83,0xf4,0xa9,0xe0,0xeb,0xaa,0xfb,0xcf, + 0xac,0xf7,0xa3,0x66,0x7d,0x04,0x3c,0xa2,0xf2,0x67, + 0x0d,0x7f,0xab,0x8e,0xde,0x75,0xcc,0x61,0x0a,0x43, + 0xac,0x23,0xd6,0xeb,0xd2,0x99,0x01,0xfe,0x1d,0x6f, + 0x9c,0x19,0x42,0xd7,0x1c,0xb0,0x7c,0x73,0xae,0x0a, + 0x7e,0x75,0xca,0x8d,0xad,0x05,0x0b,0x3c,0x8c,0xe3, + 0x3e,0x7e,0x77,0x4d,0xb9,0x21,0x95,0x23,0xee,0x9e, + 0x08,0x49,0x3f,0x9f,0x66,0x4d,0x14,0xbe,0x6d,0x49, + 0x2b,0x90,0xf2,0x0b,0x30,0xe2,0x1b,0x74,0x8e,0x42}, + .key_len = 130, + .data = {0x7a,0x04,0xf8,0x51,0xd5,0x0c,0xd1,0x35,0x25,0x6e, + 0xf0,0x44,0xed,0x74,0x0a,0xb5,0x9e,0x96,0x45,0x65, + 0xb0,0x40,0xed,0xbe,0xf0,0xd5,0x68,0xde,0x1c,0xf3, + 0x6c,0xf5,0xad,0xf9,0x6f,0xef,0xf4,0xc6,0x5f,0x54, + 0x68,0xc4,0x94,0x6c,0x3f,0x26,0x03,0xa6,0x3b,0x6d, + 0xb4,0x3a,0xc7,0x31,0x76,0x0e,0x42,0x1e,0xd1,0xd7, + 0x9b,0x3d,0x3c,0x80,0x1e,0x74,0x90,0xcf,0x8d,0x51, + 0xbd,0x46,0x73,0x03,0xbb,0x47,0xb5,0xa9,0xc4,0x7c, + 0x6a,0xd0,0xc1,0x76,0xec,0x36,0x02,0x94,0x2f,0xd4, + 0x31,0x27,0x52,0x1c,0x89,0xd3,0x74,0x80,0x43,0x39, + 0xc9,0x33,0x51,0xd2,0xed,0x33,0x4f,0x1e,0x78,0x87, + 0xb7,0xff,0xd2,0xc5,0x54,0x5f,0x49,0xd8,0xf9,0x19, + 0x60,0x00,0x72,0x17,0x6a,0x1a,0xbb,0xb8}, + .data_len = 128, + .mac_len = 40, + .mac = {0x24,0xed,0x01,0x15,0x18,0x82,0x5f,0x9d,0x39,0xd0, + 0x6a,0x25,0x23,0x27,0x15,0x21,0xdc,0x79,0x49,0xd1, + 0x54,0xd6,0xcb,0x37,0x8b,0xe2,0x0e,0xcc,0x22,0x81, + 0xb2,0xce,0xac,0xd3,0x49,0xa6,0x1a,0x28,0x06,0xb2}, + }, { // 29 (211) + .key = {0x0a,0xc0,0x1a,0x06,0x05,0xad,0xf7,0xc6,0x08,0x26, + 0x4e,0xbd,0x66,0x7c,0x38,0x79,0x0e,0x36,0x36,0x3e, + 0xbd,0x6b,0x0d,0x93,0x72,0x70,0xd4,0x00,0x23,0xb4, + 0x4b,0x17,0xae,0xe7,0x6e,0xb1,0x12,0x62,0x4a,0x7a, + 0xdf,0xc3,0x10,0xb0,0xeb,0xd7,0x68,0x27,0x47,0xbe, + 0x07,0x91,0x71,0x49,0x84,0xfc,0xcb,0xa7,0x67,0x9c, + 0x4c,0x41,0x84,0xcb,0x76,0xe2,0x87,0x4e,0x88,0x1b, + 0xcf,0xda,0xf4,0xe6,0x80,0xd6,0x13,0x89,0xd3,0x63, + 0x18,0xbd,0xb1,0x9a,0x43,0x10,0x81,0x14,0x57,0x88, + 0x3e,0xb0,0x4d,0x89,0xcc,0x90,0x4a,0xf8,0x8c,0x65, + 0xcf,0xa1,0x2e,0xed,0x2f,0xd6,0xc6,0xba,0x47,0x59, + 0x22,0x34,0x69,0x7d,0x5b,0xe1,0x99,0x87,0xab,0xe4, + 0xfc,0x5a,0x7e,0xc4,0x8d,0x54,0xcc,0x6f,0x12,0x73}, + .key_len = 130, + .data = {0xff,0x56,0x11,0xcc,0x44,0x96,0x62,0xec,0xf2,0xa0, + 0x42,0x87,0xa8,0x28,0xec,0x04,0x00,0xee,0x6c,0x4b, + 0x15,0x36,0x4a,0xd8,0x42,0x78,0x68,0x0d,0x2c,0x58, + 0x2d,0xcd,0x02,0xd8,0xe3,0x46,0x03,0xcd,0x5e,0x0e, + 0x41,0x90,0xdf,0x72,0xa5,0xf5,0x38,0x0b,0x34,0x81, + 0x30,0x92,0x90,0xd7,0x28,0xf4,0xc2,0x74,0xff,0xa9, + 0x36,0x9c,0x34,0x42,0x07,0x94,0x4a,0x42,0x7e,0x12, + 0x71,0x2f,0xd5,0xf2,0x62,0xe9,0x40,0x2a,0x8b,0x3a, + 0x2e,0x00,0x6c,0xad,0xcb,0x7b,0x41,0xa4,0xca,0x17, + 0xe1,0xa5,0x63,0xbc,0xe6,0xf5,0x97,0xf1,0x0e,0x68, + 0xbb,0x4e,0xe1,0x77,0x34,0x2f,0x94,0x93,0x80,0xb0, + 0x2e,0xb9,0x76,0xd5,0xe9,0x47,0xce,0x08,0xdb,0x0e, + 0xe3,0xc9,0xd5,0xa8,0xb8,0xa1,0x8c,0x0b}, + .data_len = 128, + .mac_len = 40, + .mac = {0xb9,0x69,0x36,0xda,0xc4,0x73,0x27,0x7b,0x4f,0x7f, + 0x63,0x27,0x30,0xdd,0x16,0xa8,0xfb,0xba,0x0d,0xe0, + 0xac,0xc0,0x21,0x3c,0xc4,0x4e,0xfe,0x4a,0xf6,0xf3, + 0x81,0xaf,0x6c,0x0f,0xe5,0xbe,0x56,0x3e,0x70,0x72}, + }, { // 30 (225) + .key = {0x74,0xf4,0x1a,0x6b,0x1c,0x4e,0x57,0x13,0x49,0x95, + 0x57,0xd6,0xf7,0xe8,0x89,0xf8,0xa8,0xce,0x2e,0x44, + 0x4e,0x82,0x61,0xfe,0x6a,0x8e,0x55,0x18,0x76,0x9b, + 0xdf,0xa8,0x81,0x88,0x34,0x9a,0x19,0xb9,0xf3,0xa2, + 0x6d,0xb2,0x66,0x75,0xb3,0xe4,0x05,0x39,0xc8,0xc6, + 0x3b,0x3a,0x16,0x28,0x6d,0xde,0xbb,0xc5,0x39,0xdb, + 0xe8,0x17,0xfb,0xa7,0x86,0x6f,0x96,0x31,0x20,0x44, + 0x71,0xce,0xfd,0xcb,0xbf,0x76,0x8c,0xc9,0x04,0x30, + 0x06,0xa6,0xd4,0xcb,0x4e,0xc2,0xde,0xcf,0x1c,0x0c, + 0x2a,0xb3,0x5a,0xd0,0x9f,0x50,0xce,0xd0,0xc8,0x96, + 0xfa,0x97,0xd8,0x7e,0x40,0x0a,0xeb,0x3f,0x4a,0x40, + 0x8e,0xc5,0xa9,0x93,0x82,0x5f,0xbc,0xf7,0xbd,0xb8, + 0xd4,0x8b,0xb2,0x08,0x95,0x6e,0xd2,0x8b,0xa0,0xd4}, + .key_len = 130, + .data = {0x9a,0x12,0x14,0x82,0xc7,0x77,0x5a,0x8b,0x5f,0xda, + 0xf1,0xc2,0xfb,0x7d,0xe1,0xa8,0x6e,0xf9,0x31,0xb1, + 0xa8,0x8c,0xf2,0x3d,0xdb,0xb4,0x7f,0xc9,0xdc,0xfd, + 0x02,0x67,0xcb,0x17,0x3a,0x6b,0xf6,0x2b,0x7c,0x68, + 0xfb,0x6f,0xf8,0x5b,0x2d,0xf9,0x3e,0x25,0x39,0xd1, + 0x01,0x3f,0x0a,0x49,0x1a,0xa9,0xe9,0x91,0xcf,0x23, + 0xe9,0x86,0x56,0xa0,0x82,0xcb,0x95,0xf8,0x7c,0x1b, + 0x2c,0xdd,0x0e,0xdd,0xb5,0x10,0x48,0xf9,0x4a,0xd4, + 0xae,0xeb,0x48,0xa4,0x26,0x16,0x53,0x21,0x14,0x5a, + 0x9b,0x4e,0xc3,0xe8,0x5d,0xff,0x07,0x55,0xac,0x8f, + 0x20,0xee,0x71,0xd2,0xe2,0x4c,0xb1,0x4a,0x13,0x28, + 0x0e,0x9e,0x15,0x70,0x91,0x47,0xc4,0x99,0xa6,0x8d, + 0xa2,0x38,0x68,0xb2,0x32,0xcc,0x1f,0x6d}, + .data_len = 128, + .mac_len = 48, + .mac = {0xb0,0xda,0x90,0xc0,0x43,0x49,0x35,0x11,0xd9,0x4f, + 0x22,0xfa,0xc3,0x5b,0x59,0x62,0x74,0x9c,0x49,0x97, + 0x2f,0xb4,0x35,0x71,0xb8,0x47,0x87,0x64,0xdf,0xfc, + 0x1c,0x25,0xe3,0xa7,0x52,0x3f,0xd4,0x05,0x33,0x8a, + 0x04,0x8d,0x38,0xdd,0x1b,0x75,0x51,0x1d}, + }, { // 31 (226) + .key = {0xd8,0x7f,0xb6,0xba,0x27,0x21,0x5e,0x5c,0xb6,0x5c, + 0x3b,0x5b,0x34,0xac,0x2a,0x32,0x03,0x7f,0x30,0xe1, + 0xf7,0xea,0x60,0x3d,0x5a,0x9b,0xff,0x8a,0x33,0x0f, + 0xe7,0x4b,0xc7,0x05,0x29,0x59,0x61,0x32,0xf6,0x33, + 0x4f,0x36,0xc0,0x95,0x2d,0xcf,0x9c,0x4c,0x66,0x4c, + 0xeb,0x48,0xf7,0x45,0x39,0xf3,0x76,0x8a,0x65,0xc1, + 0x53,0x59,0x02,0x08,0x5f,0xd4,0xfe,0x13,0x8a,0xb1, + 0x81,0x72,0xf1,0x34,0x18,0x93,0x18,0x5a,0x13,0x97, + 0x73,0x58,0x2c,0x5e,0x2c,0x43,0x69,0xe4,0x20,0x11, + 0x43,0xd1,0x2b,0xc0,0x07,0x4b,0xa5,0xd5,0x7d,0x0f, + 0x2c,0x08,0xc8,0xc0,0xa4,0x3e,0x8d,0x7e,0x7d,0xb7, + 0x57,0xbb,0x34,0x89,0x3a,0x4a,0x1d,0x4d,0xb7,0xb9, + 0x5f,0x18,0xe0,0xe1,0x40,0xad,0xbc,0xbb,0xa3,0xf0}, + .key_len = 130, + .data = {0x9e,0x1a,0x5d,0x9f,0x23,0x6e,0xf9,0x3f,0x2c,0xda, + 0x60,0x48,0x91,0x66,0xc8,0x2d,0xce,0x32,0x23,0x27, + 0x04,0x66,0x44,0xcc,0x40,0x6b,0x42,0xe3,0x00,0x5c, + 0x21,0x77,0xf3,0xb7,0xaf,0x2a,0x01,0x59,0xad,0xcc, + 0x8b,0xa9,0x2f,0x2c,0xf4,0x13,0x46,0x2e,0x60,0xb8, + 0xdb,0x1e,0xbb,0x63,0xde,0x44,0xfe,0xbf,0xa1,0xb9, + 0xad,0xc8,0x7e,0x79,0xa4,0x80,0xc0,0xb8,0x14,0xe3, + 0xc1,0x7a,0xc9,0x1c,0x4f,0x5e,0xae,0xf9,0x54,0xba, + 0x92,0x9d,0xb6,0xed,0x2c,0x75,0x7d,0xf1,0x5d,0x6d, + 0x34,0x30,0xb6,0x63,0x91,0x99,0x3a,0xdb,0x58,0xf2, + 0x65,0xf5,0x7c,0x70,0x6d,0x9d,0x87,0x85,0xc7,0x02, + 0x3d,0xf9,0xed,0x49,0x7c,0x3c,0x5f,0x82,0x67,0xfb, + 0xe7,0xdb,0xc4,0xf1,0x22,0x13,0xa1,0x00}, + .data_len = 128, + .mac_len = 48, + .mac = {0x3c,0x7c,0xee,0x96,0x02,0x21,0xc9,0xd9,0xf7,0x46, + 0x4a,0xeb,0x70,0xd1,0x98,0xbd,0x60,0x41,0x4d,0xc3, + 0xff,0xbf,0xa7,0xa2,0x22,0x7a,0x3a,0x37,0x5e,0xbb, + 0x8f,0x64,0x48,0xe5,0x24,0x70,0x6e,0x1e,0x3a,0xe9, + 0x55,0x41,0xbd,0xce,0xf2,0xb3,0x1d,0x9f}, + }, { // 32 (240) + .key = {0xdd,0x90,0x8e,0xc0,0x58,0xf1,0x37,0xa4,0x4d,0x76, + 0xc0,0x04,0x82,0x1a,0x47,0x50,0x35,0x76,0x15,0x82, + 0x0d,0xe3,0x2e,0x5d,0x51,0xdf,0x25,0xf2,0x58,0xb2, + 0x35,0x69,0x41,0x51,0x8e,0xfe,0xe4,0x82,0xed,0x4a, + 0x07,0x41,0x6f,0xc4,0xd6,0x62,0xa7,0x87,0x8d,0x79, + 0xee,0x56,0x78,0xf7,0xfa,0xdd,0x1d,0x95,0xb3,0x39, + 0xb8,0xf6,0x41,0xbb,0xe7,0x87,0x6a,0xe9,0xa7,0xab, + 0x1b,0xc6,0x7f,0x15,0x44,0x54,0xfb,0x74,0xe9,0x56, + 0x5c,0x56,0x77,0x5a,0x8e,0x46,0x54,0xf7,0x5a,0x38, + 0xb9,0x54,0xdd,0x28,0xc4,0xe9,0x39,0xfd,0xc9,0x8a, + 0x8a,0xb3,0xea,0xa1,0x1c,0xb9,0xe7,0xbb,0xdb,0x98, + 0x37,0x46,0x0a,0xd6,0x57,0x98,0x38,0x1a,0x62,0x34, + 0x70,0x90,0xe2,0x49,0xb1,0x8f,0xe5,0x7c,0x9d,0x7a, + 0x54,0xe7,0x75,0xe4,0x81,0x62,0x45,0xf7,0xff,0x01, + 0x5c,0x16,0xb6,0xde,0xff}, + .key_len = 145, + .data = {0xb9,0x37,0x7d,0x9b,0xdd,0xf4,0x0c,0xe1,0x76,0x28, + 0xb4,0x57,0x0a,0xce,0xd9,0xe4,0xb1,0x32,0xe6,0x55, + 0xd4,0xa5,0x35,0xaf,0x35,0x75,0x2f,0xc3,0x2f,0x1c, + 0xb4,0x04,0x40,0xb8,0xbd,0x96,0xc4,0xbb,0x3f,0xa7, + 0x03,0xe4,0x53,0x02,0x6e,0x6e,0x95,0xe1,0x26,0x87, + 0xc9,0x03,0xbe,0x03,0xc5,0xff,0x42,0x52,0x8b,0xd8, + 0x78,0xaf,0xb5,0xd1,0x65,0x9b,0x16,0x83,0x13,0x8a, + 0x9e,0x2c,0x92,0xdc,0x7e,0x4a,0x3d,0x0e,0x8d,0x69, + 0x3e,0x32,0xea,0x39,0x55,0x9c,0xe3,0xe3,0xd5,0xdf, + 0x16,0x9d,0xef,0xf8,0xd6,0x7d,0x32,0xc8,0xd1,0x8a, + 0x53,0xc8,0xef,0x19,0x2a,0xf8,0x7d,0x57,0xfe,0x18, + 0x8a,0x22,0x02,0x1b,0x91,0x1d,0x1f,0xd9,0x59,0x03, + 0xf4,0x04,0x1a,0x3b,0x1c,0x5d,0xe1,0xad}, + .data_len = 128, + .mac_len = 24, + .mac = {0x43,0x5e,0x4a,0xc3,0x7f,0x87,0x31,0x52,0x15,0x1b, + 0xa0,0x89,0xe7,0xf3,0x92,0x5c,0xcf,0x37,0x46,0xdf, + 0x52,0x5b,0x41,0xcc}, + }, { // 33 (241) + .key = {0x74,0x38,0xc5,0x42,0x4a,0xe9,0x5a,0xcb,0x1a,0x77, + 0xf2,0x7f,0xcb,0x43,0x38,0xed,0xfc,0x77,0x7f,0xb0, + 0x33,0x9a,0x03,0x9e,0x37,0x61,0x72,0x42,0xba,0xc8, + 0xab,0x8d,0x3b,0x62,0xc5,0xc8,0x2b,0xed,0x53,0xcd, + 0x4f,0x2a,0xe6,0x77,0x65,0xec,0xd4,0x57,0x0a,0x6e, + 0x38,0xa8,0xdb,0xe9,0x3a,0x85,0xdb,0x66,0x91,0x5a, + 0x15,0xd1,0x46,0x99,0x82,0x50,0xba,0xae,0x2c,0xd3, + 0xea,0x34,0x94,0xeb,0xf2,0x69,0x51,0xdf,0xd0,0xdf, + 0xfb,0xfd,0x6b,0x75,0x47,0x2e,0xd4,0x86,0x73,0xcd, + 0xcb,0x60,0xe5,0xb9,0x85,0xf8,0x0f,0xa9,0xac,0xdc, + 0x95,0xc0,0xa8,0x68,0xb2,0x62,0x1d,0x3d,0xd8,0x45, + 0xb4,0xef,0x96,0xcb,0x1f,0xfe,0xbf,0x8f,0x57,0x08, + 0xc9,0x3d,0x28,0x3c,0x73,0xa8,0xf0,0x12,0xaa,0x16, + 0xa4,0x39,0xae,0xde,0x13,0xd1,0x71,0x36,0x6f,0xdb, + 0x40,0x46,0x09,0xee,0xa4}, + .key_len = 145, + .data = {0xdc,0x64,0x30,0xd1,0x4e,0x67,0x5d,0xec,0x59,0x76, + 0xe6,0x71,0xaf,0x07,0xb9,0xa4,0x53,0xa3,0x8d,0x6e, + 0x5b,0x97,0xc9,0xb0,0xf5,0xed,0xa2,0xd7,0xa8,0x9a, + 0x84,0xb1,0xdc,0xf9,0xb4,0x7f,0x9d,0x78,0x33,0x4b, + 0x9c,0x92,0xe5,0x7b,0x76,0xfd,0xf2,0xa7,0x39,0x24, + 0x6d,0xa8,0x25,0xd7,0x34,0xf1,0xaf,0x41,0x17,0x23, + 0xcc,0x1b,0x3c,0xdb,0x6b,0x20,0xc1,0xce,0x43,0xc1, + 0xa4,0x19,0xd0,0x19,0xe0,0xd2,0x98,0x23,0xd9,0xe3, + 0xb3,0x2b,0xfa,0x18,0x8a,0x82,0x9d,0x76,0xdf,0x76, + 0x2b,0xcf,0x0e,0x81,0x84,0x93,0x92,0xc1,0xa1,0xe9, + 0xca,0xa8,0x78,0xfe,0xfd,0xf5,0x1f,0x9d,0x9d,0xe3, + 0x35,0x01,0xc8,0xa0,0x7e,0xe7,0x14,0x00,0xcd,0xe7, + 0x8c,0x73,0x27,0x03,0xf6,0x35,0x25,0x81}, + .data_len = 128, + .mac_len = 24, + .mac = {0x4f,0x9c,0x9a,0xb5,0x06,0xd2,0xb2,0x13,0x7d,0xef, + 0xee,0x27,0x7f,0xe2,0x05,0xc8,0x8c,0xeb,0x16,0xa6, + 0xeb,0x63,0xfa,0x9b}, + }, { // 34 (255) + .key = {0x7e,0xae,0x9b,0x4d,0xf8,0x1f,0xe3,0xe1,0x3a,0xa5, + 0xb2,0x91,0x14,0x9a,0x89,0x28,0x35,0xc3,0xa9,0x37, + 0xfb,0xd5,0x84,0xb8,0x8a,0x37,0x71,0xf1,0x1c,0x0a, + 0xa3,0x9b,0x98,0x67,0x5c,0x44,0x65,0xe7,0x5e,0xf2, + 0x80,0x69,0xa3,0x09,0xcc,0x0f,0x4d,0x6e,0xaa,0x8a, + 0xe0,0xed,0xca,0x98,0xaf,0xd8,0x41,0xca,0x94,0xf1, + 0xdb,0x8b,0xe4,0x8a,0xb2,0x5e,0xa2,0xeb,0xff,0x67, + 0xf3,0xf4,0x31,0x2d,0xd2,0x04,0x3c,0x9e,0x05,0x19, + 0x34,0x54,0x50,0x38,0x1a,0x16,0xe8,0x0f,0xf6,0xa2, + 0x2a,0xd9,0x25,0xa9,0x8d,0x82,0xf5,0x1c,0xd6,0x0b, + 0x6f,0xa6,0x8b,0x31,0x74,0x7a,0xa9,0x49,0x0c,0x4e, + 0x99,0x6f,0xfa,0xa7,0x61,0xdf,0x94,0x58,0x18,0xa3, + 0xd1,0x45,0x9c,0x6f,0xa4,0x6d,0x87,0xc9,0x88,0x28, + 0x5e,0x6c,0x5c,0xac,0x0c,0xef,0x72,0xd6,0x8f,0xa2, + 0xe3,0x28,0xf2,0xb9,0x25}, + .key_len = 145, + .data = {0x2a,0xe0,0x9d,0xb7,0xa5,0x9a,0x2f,0xfe,0x19,0x9f, + 0x37,0xe4,0xaf,0x4b,0x2d,0x51,0xbb,0x6c,0x3b,0x17, + 0xd9,0x01,0xf1,0xd6,0x3b,0x42,0x3a,0x1d,0x41,0xe0, + 0x8f,0xd1,0x4a,0x8d,0x6a,0xd3,0xcb,0xbf,0xfe,0xdd, + 0x9e,0xb1,0x25,0xad,0x9c,0xab,0x9a,0x66,0x6d,0x84, + 0x68,0x33,0x9f,0x65,0xa2,0x2d,0xf6,0xcf,0x55,0x7f, + 0x03,0xe0,0xbb,0xc7,0xf8,0xd2,0xb1,0xc0,0xbb,0xc4, + 0x6b,0x1f,0x39,0xbd,0x67,0xba,0xfd,0xee,0x9f,0xef, + 0x01,0x37,0x03,0x44,0xc4,0xed,0x26,0x4b,0x9c,0xdb, + 0x38,0xc9,0x4e,0x86,0x34,0x16,0xdc,0xb6,0x5a,0xc7, + 0x9e,0x31,0xe0,0x8b,0x94,0xca,0xe5,0x53,0xfb,0x9a, + 0xa6,0xb6,0x1e,0x8e,0xf4,0x93,0x6f,0x22,0xe6,0xf8, + 0xd6,0x6b,0xcb,0x42,0x49,0x5b,0x62,0x86}, + .data_len = 128, + .mac_len = 32, + .mac = {0xba,0x84,0xb3,0xd2,0x21,0xac,0x58,0x98,0x63,0xb7, + 0x87,0x60,0xbf,0x6b,0x98,0x39,0xd4,0x76,0xcf,0x8d, + 0x6b,0xf1,0x4f,0xaa,0x93,0x29,0xb3,0x0a,0x61,0x83, + 0x14,0x07}, + }, { // 35 (256) + .key = {0x76,0x0c,0x1d,0xa0,0x63,0xe1,0x04,0xfa,0x69,0xd2, + 0x67,0x6a,0x86,0x73,0xdc,0x45,0x8c,0xde,0x62,0x98, + 0x24,0xa9,0x8d,0xbb,0x12,0x15,0xe3,0x29,0xbb,0x88, + 0x85,0x8e,0xe4,0x3e,0x12,0x22,0xbc,0x3b,0xc8,0x36, + 0x1d,0x84,0xec,0x0c,0x0f,0x8e,0x6c,0xec,0x8e,0xf7, + 0xc4,0x74,0x8d,0x74,0x1e,0x30,0x3a,0x0b,0xbd,0x6b, + 0x84,0x82,0x9b,0x44,0xda,0x17,0x51,0x04,0x36,0x71, + 0x38,0xae,0x5b,0xd7,0xce,0xd8,0x5b,0xa0,0x5b,0xba, + 0x5b,0xea,0xd4,0x85,0x9a,0x8f,0xff,0xf6,0xb0,0x55, + 0xd8,0x2a,0x14,0x65,0x34,0xb4,0xe1,0xff,0xa4,0xed, + 0xda,0x6b,0x9c,0x8b,0xab,0x33,0xd4,0x75,0x72,0x8f, + 0xef,0xd6,0x7d,0x21,0x5b,0x70,0x55,0xe2,0x78,0x34, + 0xfc,0x5d,0xfc,0x0f,0x74,0x1b,0x96,0x06,0x80,0x5e, + 0xd1,0x85,0xaf,0x12,0x3c,0xf4,0x95,0x00,0xc8,0x8c, + 0x5c,0x45,0x71,0x69,0x7c}, + .key_len = 145, + .data = {0x42,0x14,0x50,0x74,0xb2,0x6d,0x88,0x40,0x32,0x7f, + 0xdd,0xe4,0x97,0x9c,0xe4,0xf6,0x30,0xa4,0x8e,0xef, + 0x9e,0x87,0x9f,0xd5,0xe6,0x05,0x61,0x17,0xc5,0xb8, + 0x99,0xb9,0x44,0x55,0xba,0xb0,0x8b,0x2f,0x59,0x90, + 0xfa,0xfc,0xe1,0x64,0x76,0xdc,0x88,0xdd,0x01,0x97, + 0x81,0xb0,0x8e,0x26,0x73,0x39,0x13,0x76,0x2b,0x64, + 0xdf,0x68,0x8e,0xcd,0x2e,0x1c,0xd1,0x26,0xfb,0x6f, + 0xec,0xda,0x15,0xc2,0x4b,0xef,0x75,0xfe,0xc7,0x31, + 0xcf,0xd4,0xd6,0x8d,0x67,0x4a,0xfe,0xbb,0x26,0x73, + 0x90,0x20,0xed,0x7d,0x92,0xf2,0x29,0xf2,0xfd,0x9d, + 0xa8,0x37,0x29,0x65,0xab,0x59,0x85,0x4d,0x3c,0x08, + 0x8b,0x38,0xc1,0xe4,0xf3,0x4f,0xd2,0xf8,0x27,0xa2, + 0x48,0x84,0xf8,0x12,0x96,0x00,0x8f,0x6e}, + .data_len = 128, + .mac_len = 32, + .mac = {0x24,0xb4,0xb0,0xca,0x23,0x48,0xc2,0x19,0xc1,0x51, + 0x29,0x7f,0x22,0x0b,0x2d,0x19,0xde,0xf3,0xbc,0x0d, + 0x8d,0x67,0x71,0x74,0x81,0x45,0xd6,0xeb,0x1e,0xfe, + 0x5a,0x5f}, + }, { // 36 (270) + .key = {0x81,0x6a,0xa4,0xc3,0xee,0x06,0x63,0x10,0xac,0x1e, + 0x66,0x66,0xcf,0x83,0x0c,0x37,0x53,0x55,0xc3,0xc8, + 0xba,0x18,0xcf,0xe1,0xf5,0x0a,0x48,0xc9,0x88,0xb4, + 0x62,0x72,0xea,0xc0,0xf2,0xf0,0x2a,0x0a,0x2d,0x2f, + 0xd8,0xfa,0xb2,0xe6,0x23,0x10,0xcb,0xc7,0x3f,0xc0, + 0xef,0xf9,0x0a,0x81,0x8c,0xc7,0xee,0x21,0x04,0x9a, + 0x09,0x5b,0xf5,0x24,0x8b,0xab,0xbe,0xdf,0x60,0x61, + 0x3f,0xb6,0x10,0xf5,0xe0,0x01,0xe3,0x9a,0xd4,0xb7, + 0x48,0x15,0x9f,0xdf,0x77,0xd0,0xd5,0x48,0x56,0x2a, + 0x25,0x7a,0x99,0x12,0x97,0xec,0x2e,0xd4,0x12,0x78, + 0xd8,0x32,0x21,0x0b,0x1a,0xb7,0xf6,0xa1,0x56,0x48, + 0xb0,0x71,0x36,0xfc,0xd9,0x64,0x4b,0x2e,0x33,0xcc, + 0xf4,0xd0,0xb4,0x53,0x82,0x01,0xcf,0x31,0x99,0xe2, + 0xf5,0xa3,0xd9,0xa6,0x5c,0x98,0xbe,0xe9,0xff,0xad, + 0xc5,0x43,0xe6,0x5b,0xd1}, + .key_len = 145, + .data = {0xd0,0xdb,0x3f,0xf9,0xcf,0x2d,0xa1,0x0d,0x1e,0xdf, + 0xef,0x38,0x9b,0xa7,0x17,0x80,0xcb,0x49,0xe0,0x5d, + 0xcc,0xb8,0x7c,0x08,0x8b,0x7e,0x60,0xf5,0x37,0x5f, + 0x53,0x9e,0xf5,0x39,0xc5,0x83,0xd5,0x2f,0x63,0x6f, + 0x04,0x06,0xe8,0xfc,0x44,0xcf,0x36,0x59,0x9a,0xc7, + 0xa5,0x4b,0x46,0x7b,0x9b,0x72,0xf8,0x30,0x5d,0xce, + 0x41,0x81,0x24,0x82,0x48,0x4a,0x74,0xd7,0xbe,0xc5, + 0xa9,0x83,0x14,0xf3,0xd3,0x2c,0xeb,0x3e,0xc3,0x28, + 0xcc,0x5c,0x66,0x87,0x19,0x76,0x52,0x53,0x43,0x8a, + 0x9f,0x16,0x3e,0x0e,0xf8,0x9d,0x32,0xd6,0xf1,0xfc, + 0x74,0x37,0x9b,0xd2,0xb4,0x6d,0x57,0xce,0x78,0x3a, + 0xe7,0x72,0xc9,0xd0,0xcb,0x17,0x2b,0xf1,0xca,0x32, + 0xd3,0x55,0xcf,0xd5,0x15,0x4c,0xf6,0x79}, + .data_len = 128, + .mac_len = 40, + .mac = {0x29,0x19,0x57,0xf7,0x98,0xa3,0x2c,0x65,0x95,0x4d, + 0x31,0x28,0x9a,0xac,0x24,0xd6,0x2e,0xa4,0x74,0x69, + 0xe5,0xb1,0x10,0x5c,0xca,0x37,0x2e,0xab,0xed,0x44, + 0x74,0x63,0x16,0xcb,0x24,0xfb,0x13,0xc2,0x48,0x53}, + }, { // 37 (271) + .key = {0xd9,0xaa,0x1a,0x8f,0x94,0x47,0x1a,0x4c,0x69,0xe7, + 0x1f,0xd2,0x56,0xdf,0x38,0xc6,0x00,0x92,0x4b,0x42, + 0xa5,0x95,0xad,0x1e,0x52,0x11,0xf0,0x6e,0x56,0x69, + 0xfc,0x4b,0xf6,0x1d,0x61,0xd7,0x62,0xef,0xec,0x7b, + 0xe8,0x44,0x79,0x73,0x68,0xcc,0x07,0x8d,0x08,0x65, + 0x12,0x2d,0x28,0x3d,0x1d,0x95,0x99,0x37,0x8e,0x63, + 0x09,0x91,0xbe,0x5b,0xc2,0xc3,0x51,0x67,0x95,0xaa, + 0xc3,0xdc,0x10,0xe5,0x44,0xff,0xf8,0x80,0xc6,0xc8, + 0xf3,0xcf,0x54,0xe6,0x84,0x9d,0xa5,0x02,0x3c,0x87, + 0xf1,0x48,0x2f,0xa2,0x03,0x24,0xa6,0x64,0x90,0x49, + 0x13,0xc1,0xc7,0xf8,0x4a,0x94,0x29,0x7f,0xed,0x41, + 0x9b,0x00,0x28,0x98,0xb9,0x73,0x9f,0xfd,0x6e,0xee, + 0xa5,0xc6,0xc1,0x24,0xaf,0xe5,0xf2,0x2d,0x08,0xc7, + 0xc6,0x85,0xc6,0x7c,0x1f,0x56,0xfc,0x17,0xcf,0xfa, + 0x31,0x58,0xae,0xbb,0x11}, + .key_len = 145, + .data = {0xdc,0xda,0x25,0xe0,0x85,0x0a,0x55,0x53,0x68,0xec, + 0x4a,0xdf,0xc4,0x13,0x5e,0x47,0xe4,0xf3,0x47,0x37, + 0x4e,0x42,0xec,0xcd,0x3e,0xa4,0x78,0x57,0x52,0x86, + 0xad,0x5f,0x87,0x4a,0x7c,0xe5,0x64,0xa5,0xd2,0xeb, + 0x75,0x46,0xb4,0x37,0xfb,0xb9,0x8e,0x54,0xe2,0x8a, + 0xc8,0xda,0xf3,0xad,0x9b,0xef,0x4b,0x1d,0x23,0x0e, + 0x0c,0xc4,0xb5,0x07,0x52,0x9b,0x72,0x47,0x69,0x12, + 0x1c,0x5a,0x3d,0xb2,0x29,0xae,0x11,0x01,0x16,0x9a, + 0x74,0xa6,0xfe,0x9e,0x71,0xcd,0x6b,0xed,0x07,0xcd, + 0x6c,0x28,0xd9,0x08,0xe8,0x6d,0x25,0x13,0x31,0x90, + 0xfa,0x18,0xdc,0xa8,0xa6,0x78,0xd1,0xce,0x6e,0xb4, + 0x9e,0x21,0x83,0x8d,0x11,0x0e,0x31,0x6a,0x05,0xce, + 0x58,0xfb,0x7c,0x2f,0x20,0x1c,0xee,0x98}, + .data_len = 128, + .mac_len = 40, + .mac = {0x97,0x11,0x17,0x3e,0x1c,0x86,0xfc,0xdb,0x11,0xb7, + 0xc2,0x24,0xec,0xb7,0x6b,0xa3,0x90,0xc2,0xe1,0x21, + 0x8d,0x26,0xf3,0x53,0x98,0x0e,0x65,0x6a,0x08,0xbb, + 0xaa,0xd9,0xca,0x8e,0x8f,0x27,0xc0,0xae,0xf6,0xad}, + }, { // 38 (285) + .key = {0xf0,0x5d,0x56,0x1f,0x5a,0xd7,0x04,0x03,0x26,0x4c, + 0x5e,0x0a,0x0e,0xdc,0x12,0xfd,0x47,0x3b,0x19,0xc0, + 0xb4,0x0f,0x8c,0xd8,0x5a,0x99,0xba,0x2a,0x14,0x98, + 0x77,0x05,0x87,0x6a,0xb7,0x63,0x59,0x75,0x5b,0x6c, + 0x9e,0xc5,0x4a,0x3c,0x93,0xf6,0xc4,0xe6,0x8f,0x55, + 0xf3,0xb9,0x36,0x42,0xc3,0xc2,0xf0,0xd9,0xf4,0x91, + 0x9a,0xd1,0x6e,0x40,0x7b,0xa3,0xd4,0xb2,0x79,0xef, + 0x5b,0x19,0x8c,0x1c,0xdd,0xbb,0x74,0x40,0x29,0xf5, + 0xa7,0x3f,0x9e,0x80,0x8e,0x36,0xf8,0xf3,0xf0,0x1a, + 0x69,0x89,0xaf,0x9c,0xec,0x25,0xb2,0x50,0xd6,0x93, + 0x22,0x0f,0xad,0x11,0xd9,0x9a,0x3e,0x0e,0x17,0x7f, + 0xea,0x31,0x77,0x41,0x41,0x9d,0x22,0xb3,0xd2,0x74, + 0x43,0xa5,0x40,0x99,0xbb,0xc2,0x99,0xbb,0x15,0xb9, + 0xe4,0x8f,0xbc,0x9b,0xf9,0x5c,0x6b,0x84,0x96,0xbd, + 0xe6,0x7e,0xae,0xa3,0xe8}, + .key_len = 145, + .data = {0x77,0xd3,0xf3,0xe6,0x47,0xe6,0x77,0x66,0xe5,0xf4, + 0xcf,0x1b,0xce,0x5f,0x63,0x1b,0xd5,0x75,0xdd,0xbd, + 0x02,0xf2,0x96,0x43,0xa0,0xc6,0x4d,0xbd,0x92,0x19, + 0x1f,0x2a,0xe6,0x8d,0xb3,0xdf,0xad,0xc3,0xb6,0x2d, + 0x09,0x20,0x87,0x3e,0x87,0xd1,0x33,0x40,0xaf,0x0c, + 0xa3,0xc5,0xda,0x99,0x14,0x6a,0x44,0x92,0xc8,0xb7, + 0x62,0x67,0xfb,0x47,0x76,0x24,0x19,0x29,0x60,0xf7, + 0x2e,0x85,0xb7,0xed,0x9e,0x83,0x18,0xfc,0x16,0x68, + 0xbe,0x46,0xc2,0x03,0x53,0x9c,0xc1,0x47,0x06,0x41, + 0xd6,0x39,0xde,0xf1,0x60,0x0d,0x4e,0x22,0x8c,0x8b, + 0x09,0x8a,0xc9,0xb8,0x17,0xe1,0x7c,0xb3,0x29,0xe8, + 0xf5,0xdd,0x2a,0xaa,0xa2,0x3c,0x16,0x02,0x83,0x22, + 0x0f,0x5d,0xde,0x09,0xae,0xc1,0x34,0xc2}, + .data_len = 128, + .mac_len = 48, + .mac = {0x72,0x4e,0x5d,0x2d,0x51,0xd9,0x8c,0x15,0xce,0x2e, + 0x78,0xf8,0x61,0xd7,0xb6,0xf8,0x95,0x28,0x82,0xe9, + 0xd9,0x3d,0x40,0x85,0x0b,0x78,0xa2,0x3e,0x63,0x2c, + 0x4e,0x14,0xa2,0x22,0xab,0x37,0x26,0xb1,0xa0,0xaa, + 0x7c,0x6b,0x2c,0xd6,0x60,0x82,0xed,0x95}, + }, { // 39 (286) + .key = {0x95,0xec,0xe1,0xc8,0xae,0x5e,0x94,0xd1,0x6e,0xc9, + 0x98,0x3b,0x10,0x89,0xa3,0x73,0x95,0xad,0x5b,0x1d, + 0x66,0x09,0x16,0xc1,0x3c,0x87,0xe4,0xc1,0x3d,0xbe, + 0xcf,0x8f,0x68,0xc6,0x61,0x1c,0x32,0x4a,0x67,0x94, + 0x71,0xde,0xf5,0x48,0x7a,0x93,0xaa,0xec,0x86,0xc9, + 0x35,0x02,0x5b,0x45,0x18,0x96,0x28,0x84,0xac,0x2c, + 0xb0,0x4e,0x66,0xf7,0xaa,0x8e,0x58,0x4b,0x68,0x60, + 0xfb,0x55,0xb8,0x6c,0x2b,0x0a,0x08,0x73,0x73,0x5d, + 0xcd,0x27,0x8b,0xb5,0x25,0x40,0x1f,0x9e,0xba,0xcc, + 0xd2,0xbe,0xea,0xc6,0x83,0x0c,0x26,0xeb,0xcf,0x3c, + 0x98,0xc9,0xd7,0x7d,0x09,0x19,0x43,0x67,0x01,0x4e, + 0x87,0x2f,0x30,0x6e,0x64,0x1e,0x0c,0x21,0xb2,0x41, + 0xbc,0x08,0x5e,0x61,0x35,0x4f,0xaf,0x35,0xa3,0x86, + 0xcd,0xd7,0x0a,0xac,0x83,0x75,0x2d,0x8d,0x44,0x49, + 0xaf,0x4f,0x6c,0xcb,0x78}, + .key_len = 145, + .data = {0x18,0xdb,0xab,0x9f,0x86,0xb9,0xd7,0x0b,0xbd,0xeb, + 0x01,0x8f,0x6a,0x76,0xea,0x7a,0xf2,0x3e,0xb2,0xff, + 0x11,0x1e,0x9b,0xe3,0xc1,0x38,0x11,0x79,0x5d,0x8a, + 0xe7,0xd0,0x06,0xc3,0xe4,0x2b,0x46,0x54,0x7e,0xb1, + 0xf3,0xc9,0xe5,0x66,0x56,0x5a,0x43,0x5a,0x8d,0xbd, + 0x42,0x21,0x2e,0x3f,0xd0,0x82,0x2d,0x13,0x1f,0x73, + 0x00,0xea,0xef,0x46,0x00,0xc4,0x0f,0x1d,0x13,0x05, + 0x21,0xa3,0x88,0xcb,0x9f,0xfe,0x42,0x7f,0x1b,0xff, + 0x19,0xaa,0xcb,0x9c,0x7d,0x0a,0x44,0xa1,0x5c,0xe6, + 0x86,0xa2,0x46,0x9e,0x39,0x34,0xd0,0x86,0x36,0x5d, + 0x36,0xf4,0x49,0x48,0x44,0x98,0x35,0x3d,0x76,0x0c, + 0xf9,0xd1,0x5e,0xac,0x52,0x5a,0x46,0xa8,0x81,0xa6, + 0x17,0x58,0x4e,0xed,0x79,0xcf,0x4d,0x03}, + .data_len = 128, + .mac_len = 48, + .mac = {0x2b,0xe1,0xbd,0x6a,0x76,0x6e,0x30,0x79,0x21,0x54, + 0xcd,0xa0,0x0a,0xf9,0x7c,0xc5,0x12,0xe8,0x14,0x13, + 0xe0,0xfb,0x76,0x16,0x98,0xf3,0x9a,0x26,0xce,0xcc, + 0x3f,0xac,0xe6,0xf9,0xa9,0x8b,0x7c,0x49,0x60,0x51, + 0x26,0xdf,0xa5,0xaa,0x8d,0xe1,0xad,0x72}, + } +}; + +struct HMAC_TEST_VECTOR fips_sha512_hmac_general_test_vector[] = { + { // 0 (0) + .key = {0x72,0x63,0x74,0xc4,0xb8,0xdf,0x51,0x75,0x10,0xdb, + 0x91,0x59,0xb7,0x30,0xf9,0x34,0x31,0xe0,0xcd,0x46, + 0x8d,0x4f,0x38,0x21,0xea,0xb0,0xed,0xb9,0x3a,0xbd, + 0x0f,0xba,0x46,0xab,0x4f,0x1e,0xf3,0x5d,0x54,0xfe, + 0xc3,0xd8,0x5f,0xa8,0x9e,0xf7,0x2f,0xf3,0xd3,0x5f, + 0x22,0xcf,0x5a,0xb6,0x9e,0x20,0x5c,0x10,0xaf,0xcd, + 0xf4,0xaa,0xf1,0x13,0x38,0xdb,0xb1,0x20,0x73,0x47, + 0x4f,0xdd,0xb5,0x56,0xe6,0x0b,0x8e,0xe5,0x2f,0x91, + 0x16,0x3b,0xa3,0x14,0x30,0x3e,0xe0,0xc9,0x10,0xe6, + 0x4e,0x87,0xfb,0xf3,0x02,0x21,0x4e,0xdb,0xe3,0xf2}, + .key_len = 100, + .data = {0xac,0x93,0x96,0x59,0xdc,0x5f,0x66,0x8c,0x99,0x69, + 0xc0,0x53,0x04,0x22,0xe3,0x41,0x7a,0x46,0x2c,0x8b, + 0x66,0x5e,0x8d,0xb2,0x5a,0x88,0x3a,0x62,0x5f,0x7a, + 0xa5,0x9b,0x89,0xc5,0xad,0x0e,0xce,0x57,0x12,0xca, + 0x17,0x44,0x2d,0x17,0x98,0xc6,0xde,0xa2,0x5d,0x82, + 0xc5,0xdb,0x26,0x0c,0xb5,0x9c,0x75,0xae,0x65,0x0b, + 0xe5,0x65,0x69,0xc1,0xbd,0x2d,0x61,0x2c,0xc5,0x7e, + 0x71,0x31,0x59,0x17,0xf1,0x16,0xbb,0xfa,0x65,0xa0, + 0xae,0xb8,0xaf,0x78,0x40,0xee,0x83,0xd3,0xe7,0x10, + 0x1c,0x52,0xcf,0x65,0x2d,0x27,0x73,0x53,0x1b,0x7a, + 0x6b,0xdd,0x69,0x0b,0x84,0x6a,0x74,0x18,0x16,0xc8, + 0x60,0x81,0x92,0x70,0x52,0x2a,0x5b,0x0c,0xdf,0xa1, + 0xd7,0x36,0xc5,0x01,0xc5,0x83,0xd9,0x16}, + .data_len = 128, + .mac_len = 32, + .mac = {0xbd,0x3d,0x2d,0xf6,0xf9,0xd2,0x84,0xb4,0x21,0xa4, + 0x3e,0x5f,0x9c,0xb9,0x4b,0xc4,0xff,0x88,0xa8,0x82, + 0x43,0xf1,0xf0,0x13,0x3b,0xad,0x0f,0xb1,0x79,0x1f, + 0x65,0x69}, + }, { // 1 (1) + .key = {0xe2,0x45,0xbe,0x9a,0x9c,0x81,0x01,0x26,0x38,0x30, + 0xad,0x35,0x15,0xc1,0xc6,0xcb,0xf2,0x85,0xa7,0xe4, + 0xb3,0x62,0xeb,0xc0,0x62,0xcb,0x8e,0x7e,0x75,0xef, + 0x50,0xec,0x4f,0x31,0x5a,0x9e,0x09,0xd9,0x24,0x3d, + 0x71,0x09,0x96,0x22,0x53,0xf2,0x6e,0x23,0xf8,0x47, + 0xe1,0xad,0xed,0xf2,0x85,0x14,0x05,0x07,0x6e,0x26, + 0xa1,0xf6,0x97,0x06,0x2f,0x04,0x84,0x38,0xf1,0xfc, + 0x26,0xf8,0x00,0x21,0xff,0xd0,0x90,0x68,0x87,0x69, + 0x75,0xe4,0xcd,0xa2,0xe7,0x82,0x61,0xdf,0x82,0xf6, + 0x72,0xa3,0x90,0xf5,0x34,0x62,0x8b,0xa5,0x84,0x90}, + .key_len = 100, + .data = {0x42,0x53,0x15,0xdd,0x8e,0xcc,0xd1,0x7a,0x84,0xc1, + 0xaa,0x00,0xff,0x72,0x76,0x3f,0x99,0xdd,0xcb,0xc2, + 0xc3,0x81,0xb8,0xb2,0x15,0x67,0xb2,0xf8,0xe2,0x63, + 0xd1,0xa2,0x10,0x98,0x3d,0x88,0x26,0x3a,0xe3,0x2f, + 0xa7,0x98,0x6c,0xed,0x9f,0x59,0x6f,0x4e,0x7b,0x05, + 0xe5,0xb7,0x1d,0xc8,0xde,0x49,0x30,0x73,0x73,0x08, + 0xb9,0xc4,0xfc,0x3d,0xef,0xe7,0x83,0x19,0x4d,0x3c, + 0x78,0x9a,0xe5,0x5b,0xa5,0xb3,0xf7,0x56,0x65,0xa7, + 0xc2,0x3e,0x11,0xb6,0x9a,0xe8,0xbc,0xfb,0x3b,0xf0, + 0x20,0x95,0x5d,0xff,0xd7,0x05,0x89,0x4a,0xcf,0xd7, + 0x2a,0x5b,0xf8,0x85,0xe7,0x14,0x3f,0x98,0x30,0xf1, + 0xc0,0x10,0x17,0x8d,0x37,0x06,0x62,0x68,0xb8,0x90, + 0xde,0xe7,0xa1,0xe5,0xf6,0x9c,0xcc,0xc1}, + .data_len = 128, + .mac = {0xc5,0x80,0x1d,0x80,0xa1,0x43,0x91,0x72,0x0e,0x77, + 0xeb,0x7f,0xfb,0x1a,0x0b,0x21,0xa1,0x63,0x23,0x64, + 0x1c,0x9a,0x31,0x2b,0x05,0xfd,0xc3,0x4e,0x90,0x38, + 0x3c,0x85}, + .mac_len = 32, + }, { // 2 (15) + .key = {0x6a,0xa1,0x14,0x66,0xa2,0xc9,0x6e,0x20,0x54,0x4c, + 0x5b,0x34,0xc9,0x1f,0x90,0xd1,0x7f,0x97,0x99,0xa5, + 0x7c,0x73,0xca,0x00,0xe2,0x1d,0x77,0x36,0xc4,0x2d, + 0x68,0x45,0x38,0x2f,0x87,0xb7,0xad,0xa6,0xdc,0xca, + 0x7f,0x51,0xbb,0xcf,0xc9,0xac,0x3c,0xd0,0x7b,0xba, + 0xec,0x75,0xac,0x02,0xc2,0x28,0x31,0xd7,0x55,0x78, + 0x6e,0xdd,0x4b,0xbb,0x6c,0xc9,0x15,0xf8,0x2c,0x68, + 0xda,0x04,0x3b,0xe3,0xb0,0xea,0x87,0x41,0x12,0x90, + 0x71,0x2d,0x8f,0x98,0x23,0xfa,0xbf,0x85,0x24,0xe4, + 0x7b,0x1f,0x29,0x99,0x4d,0x18,0x2f,0xf8,0x26,0xef }, + .key_len = 100, + .data = {0x27,0x71,0xcd,0xfd,0xd7,0x7a,0xab,0xbc,0xc9,0x57, + 0x40,0xbb,0xd9,0x40,0x75,0x87,0x6e,0xd3,0x02,0x4f, + 0x0b,0x5a,0x99,0x49,0x21,0x4d,0x60,0x52,0x28,0x18, + 0xa5,0xd5,0xed,0x1d,0xce,0xed,0x2e,0xfd,0x8e,0xce, + 0x64,0x13,0x5f,0x61,0xe0,0x42,0x2c,0x2e,0x19,0xf1, + 0x4d,0x7f,0x45,0x53,0xb9,0xc2,0x26,0xec,0x77,0x30, + 0x27,0x51,0x56,0xac,0xa7,0x2f,0xde,0xee,0x95,0x8e, + 0x86,0xe0,0x3d,0x57,0x28,0x48,0x61,0x14,0xb1,0xa8, + 0x8c,0xf8,0x1d,0x62,0xa3,0x1f,0xa3,0x20,0xbd,0x16, + 0x2c,0x73,0x34,0x9e,0x0a,0xbb,0xfd,0xad,0xe7,0x46, + 0x34,0xb6,0xfb,0xbc,0xfb,0x2a,0x83,0xba,0x85,0x3f, + 0x6e,0xbd,0x6e,0xf0,0x59,0x42,0x4e,0x45,0xbd,0x2b, + 0x8d,0xd4,0x67,0x65,0x79,0x88,0x29,0xc8}, + .data_len = 128, + .mac = {0x24,0x76,0xdf,0xac,0x04,0x3e,0x55,0x51,0x8d,0xdb, + 0xa3,0x12,0xe6,0x36,0x99,0xb2,0x2a,0x58,0x7f,0xbd, + 0xcc,0xcc,0xf3,0x98,0x12,0x07,0xef,0x5c,0xfc,0x2e, + 0x27,0xee,0xb6,0xa4,0x06,0x2b,0xda,0x6b,0x19,0xbf}, + .mac_len = 40, + }, { // 3 (16) + .key = {0x3b,0xeb,0x75,0x37,0x3a,0x0a,0x02,0x10,0x7b,0x27, + 0x48,0xa7,0xb9,0xa3,0x73,0x8b,0x1a,0x9d,0x75,0xfa, + 0xb1,0x67,0xa6,0xf8,0x47,0x3a,0xad,0x9e,0x5b,0x28, + 0xa4,0xb5,0x67,0x53,0x77,0x83,0x65,0x5d,0x8d,0xe5, + 0x92,0x1f,0xab,0x9e,0x72,0x9e,0x15,0xef,0x14,0x3a, + 0xf6,0x68,0x97,0x29,0x01,0xfd,0xed,0x24,0x59,0x5c, + 0xdf,0x60,0xae,0x7e,0x51,0xc0,0xa9,0x7c,0xc8,0x49, + 0x8b,0xa5,0x29,0xd6,0x11,0xcd,0xc4,0x0d,0x9a,0xe7, + 0x90,0x91,0x8b,0xd7,0xb8,0x79,0xf3,0x81,0x57,0x02, + 0x6b,0x26,0x80,0x80,0x41,0xf0,0x82,0x9b,0xd5,0xcb}, + .key_len = 100, + .data = {0x04,0x05,0x55,0x5d,0x89,0xa8,0x11,0x77,0x94,0xc6, + 0x42,0x85,0xcd,0x30,0x04,0x7d,0x64,0x2a,0x1d,0x63, + 0x5f,0x6e,0xeb,0x6b,0x33,0x73,0x9b,0x5e,0x92,0xee, + 0x9c,0x3e,0x85,0x9a,0x53,0x2d,0xba,0x34,0x11,0x8b, + 0x1f,0xca,0x42,0x5f,0xb0,0x36,0xe7,0xf8,0x8c,0xe6, + 0x46,0xd4,0x4f,0xde,0xdf,0xc0,0x9c,0xff,0xa3,0x41, + 0xf9,0x89,0x61,0x33,0xe0,0xdf,0x81,0xb0,0x12,0x8a, + 0xf4,0x33,0x2f,0x81,0x6b,0xfd,0x84,0xa7,0xc7,0xb8, + 0x24,0x96,0xd1,0x5b,0x3a,0x9b,0x2c,0x4d,0x9d,0x01, + 0x88,0xcd,0xa5,0x93,0x17,0x91,0x3e,0x5c,0x45,0xad, + 0x3a,0xb1,0xa4,0xb7,0xec,0x72,0x25,0x29,0xf2,0x8c, + 0x8e,0x06,0x52,0xc2,0x28,0xc1,0xc9,0xae,0xb8,0x5a, + 0x5f,0x02,0xb1,0xca,0x3f,0x14,0xa8,0xa1}, + .data_len = 128, + .mac = {0xfa,0x58,0xf0,0xaa,0xd7,0xa3,0x11,0x6c,0xae,0xc2, + 0x19,0x3a,0x3d,0xff,0xb0,0xd1,0xc0,0xb3,0x17,0x2c, + 0x3b,0x59,0xa9,0xa6,0x2e,0xbb,0xf3,0x1d,0x21,0xc7, + 0x66,0x81,0x8f,0x1c,0xef,0xb2,0x60,0x52,0xaf,0x72}, + .mac_len = 40, + }, { // 4 (30) + .key = {0x79,0x86,0x75,0x59,0xc9,0x91,0x9f,0x39,0x4c,0xde, + 0x76,0xb3,0x1f,0xe2,0x2f,0x79,0x3b,0x88,0x98,0x70, + 0x01,0x76,0x4e,0x11,0x15,0x91,0x30,0x0f,0x70,0xc3, + 0x13,0x39,0xb1,0xfc,0xb8,0xa3,0xb4,0x76,0xfb,0x00, + 0x66,0x3e,0x4c,0x53,0xd8,0xf0,0x63,0xc7,0x92,0xc1, + 0x30,0xda,0x29,0xc3,0x11,0xc1,0x14,0x65,0x48,0x08, + 0xbb,0x39,0xac,0x7a,0xd1,0xfb,0x9e,0x40,0xe4,0xce, + 0x3f,0x4d,0x32,0xc8,0xe1,0xf9,0xbf,0xb1,0xbb,0xeb, + 0xa4,0x08,0xe0,0x3d,0xaa,0x47,0x72,0xdb,0x17,0x69, + 0x12,0x2c,0xc8,0xa8,0x9c,0xf5,0x80,0x8b,0x11,0x7a}, + .key_len = 100, + .data = {0xd1,0x99,0x8d,0x3b,0x3f,0xf5,0xbc,0x1c,0x8f,0x72, + 0x4a,0xab,0x79,0x2d,0xe8,0xa3,0x5c,0x60,0xfb,0xa4, + 0xeb,0x41,0xf2,0x34,0x22,0x27,0xd6,0x03,0x80,0xef, + 0x22,0x73,0x70,0x9e,0xd6,0x57,0x08,0x47,0xc7,0xfb, + 0xf5,0x30,0x39,0x66,0xb6,0x30,0xaf,0xdb,0x09,0x5b, + 0x02,0xa6,0xa3,0xe2,0xb1,0x15,0x24,0x34,0x78,0xc4, + 0x4a,0x69,0x24,0x1d,0x65,0xe1,0xa5,0x20,0x0b,0x28, + 0x65,0x60,0x0c,0x1d,0xd8,0x4e,0xa8,0x54,0x55,0xba, + 0x00,0xb8,0x24,0x97,0xcb,0x75,0xd8,0xff,0x4a,0x15, + 0xde,0x77,0x7e,0xe8,0x57,0x73,0x98,0xaa,0x23,0x1d, + 0xb1,0x60,0x3e,0x52,0xbb,0x83,0x50,0xed,0xb8,0x60, + 0x7f,0x49,0x2a,0xbf,0x88,0x01,0xca,0xc3,0x0e,0xfa, + 0x7c,0x11,0x32,0xa4,0x83,0x34,0x63,0x7c}, + .data_len = 128, + .mac = {0xb6,0xb1,0x8c,0x4c,0x53,0x64,0xb4,0x7f,0xd7,0x8c, + 0x3d,0x32,0x1d,0xad,0xf6,0x0d,0xe1,0x87,0xfa,0x68, + 0xf5,0xd7,0xe5,0x5c,0xa7,0xfb,0xf7,0x1f,0x42,0xc7, + 0x42,0x41,0x1d,0x37,0x9c,0x8c,0x55,0x18,0x0d,0x3f, + 0x54,0xcb,0x97,0x47,0xb5,0x1a,0xef,0x7f}, + .mac_len = 48, + }, { // 5 (31) + .key = {0xe9,0x16,0x8c,0x65,0x9c,0x63,0xb6,0xf4,0x05,0x23, + 0xc9,0x05,0x32,0xba,0xe7,0x43,0xf2,0x4f,0xeb,0x2e, + 0x94,0x81,0x4b,0x6d,0xf2,0x55,0x43,0x65,0xaf,0x73, + 0x30,0x0a,0xbc,0x93,0x3a,0xf5,0x21,0x32,0x35,0xb8, + 0xfa,0x89,0xc9,0x6e,0xbf,0xbf,0xd1,0x96,0xc9,0x5e, + 0x02,0x21,0x12,0x04,0xcd,0xc9,0x3d,0x5b,0x86,0xa5, + 0xd6,0x4a,0xc5,0xfa,0xda,0x6d,0x0d,0x55,0x7a,0xc3, + 0xab,0xd6,0x1c,0xa7,0xe1,0xcf,0xa3,0x02,0x44,0x8e, + 0xf0,0xbe,0x63,0x76,0xa8,0x7e,0xa9,0x55,0x38,0x8c, + 0x85,0xf1,0x17,0x12,0xc7,0xe4,0x4b,0x8e,0x4e,0xaa}, + .key_len = 100, + .data = {0x42,0x65,0x7c,0x63,0x16,0xfb,0xc1,0xbc,0xd6,0x9a, + 0x87,0xc7,0xdf,0x3a,0xb0,0x6d,0xcc,0x1e,0x47,0x1e, + 0x97,0x64,0xc1,0x0a,0x00,0xdb,0x83,0x94,0x33,0x14, + 0xa5,0x03,0xa5,0xbc,0xf6,0x7b,0x3f,0x28,0x40,0x2d, + 0xbe,0x32,0xcd,0xca,0x5a,0x44,0x29,0x3d,0xa5,0xb2, + 0x2a,0x99,0xb7,0x4d,0x2e,0x50,0x88,0x35,0xa4,0xa7, + 0x9d,0xee,0xce,0x66,0xe7,0xb6,0xc4,0xd4,0xe8,0x16, + 0xbd,0xe2,0x17,0xb8,0x8a,0xa7,0x86,0x78,0x63,0x0c, + 0xc2,0xbd,0xe6,0xc9,0xfa,0x0a,0x5d,0x90,0x64,0xd0, + 0x40,0x87,0xdd,0x87,0xfb,0xfc,0xd0,0xfc,0xf0,0x55, + 0x58,0xed,0xc0,0x45,0xa9,0xd3,0xc6,0x46,0xac,0xff, + 0xe5,0x43,0xe9,0xe8,0x84,0x94,0xaa,0xc4,0xd6,0x30, + 0x5d,0x55,0x5f,0x1e,0x3b,0x06,0xb4,0x2d}, + .data_len = 128, + .mac = {0x0e,0x9b,0x3a,0xfa,0xb5,0x07,0x82,0xf1,0x75,0x1c, + 0x80,0xb4,0x6c,0xed,0x53,0x1c,0x07,0xc9,0xae,0x4a, + 0xf5,0x0c,0x77,0xa0,0x58,0xa2,0xdb,0x31,0xda,0xbb, + 0x01,0x3b,0x71,0x9c,0x4c,0x22,0xf5,0xe5,0xad,0xea, + 0xfa,0xb7,0x21,0x54,0xcf,0x1f,0xbd,0x21}, + .mac_len = 48, + }, { // 6 (45) + .key = {0x2c,0xa6,0x7a,0xe3,0xea,0x3c,0x84,0xa2,0x54,0x4c, + 0xa8,0x79,0x44,0x57,0x34,0x0e,0x1e,0x42,0x4a,0x8a, + 0xb3,0xaa,0xe2,0x92,0x65,0x77,0x12,0x79,0x8b,0xb4, + 0x8e,0xb4,0x17,0x9e,0x6b,0x8e,0x76,0xfa,0x28,0x1d, + 0xb7,0xac,0xee,0x74,0xf0,0x86,0x17,0x1a,0xdd,0x5e, + 0xee,0xbb,0xcb,0x63,0xb5,0x1e,0xb4,0xb1,0xed,0x57, + 0xac,0x22,0xd1,0x3e,0x7b,0x67,0x24,0x1f,0x8c,0x58, + 0x2c,0xb3,0x06,0x89,0xff,0x4f,0x38,0x1e,0xfd,0x5c, + 0x3a,0xe0,0x9e,0x07,0xd1,0x90,0x6e,0x39,0x94,0x7b, + 0x55,0xca,0x4d,0x4e,0x1c,0xf2,0xa2,0x2c,0x2d,0x00}, + .key_len = 100, + .data = {0x84,0x37,0x1c,0x9f,0xf4,0x0b,0x74,0x5a,0xb5,0x30, + 0x0b,0xc9,0x14,0x51,0x2c,0x14,0x68,0xf9,0x8b,0x33, + 0x97,0x04,0xe2,0x04,0xdb,0x54,0xdd,0x9a,0xc6,0xc5, + 0x34,0xd8,0x84,0x62,0x16,0x3f,0x61,0xd9,0xce,0x05, + 0x8a,0x2c,0xa1,0x67,0x18,0xaa,0xf5,0x40,0x4a,0x1e, + 0xb9,0xd9,0x12,0x46,0x00,0x03,0xd4,0x86,0xef,0x63, + 0x6a,0xde,0xda,0x0e,0x6b,0x1a,0xaa,0x56,0xad,0x48, + 0x82,0xe3,0x08,0x6f,0xa2,0x05,0x5d,0x7e,0x8b,0x48, + 0xd7,0x83,0x63,0x49,0x71,0x1d,0x9c,0xc9,0xb9,0x34, + 0xd1,0x00,0xd3,0xe7,0xf0,0x33,0xc0,0xc6,0x9e,0x89, + 0xe1,0x42,0xd7,0x1b,0xb6,0x61,0xd5,0x4a,0xec,0xb7, + 0x34,0x55,0x97,0x91,0x53,0x2b,0xbc,0x73,0xfd,0x7d, + 0x12,0xc5,0x49,0x18,0x09,0xc9,0xbe,0x72}, + .data_len = 128, + .mac = {0xea,0xa9,0xb6,0x97,0xc8,0x3b,0xc5,0x71,0xa0,0x29, + 0xa6,0xdf,0x1f,0x44,0x0e,0x8c,0x64,0x6a,0xc7,0x63, + 0x33,0x3d,0x5f,0x7a,0x57,0xa6,0xff,0xe7,0xcf,0xda, + 0x7f,0x90,0x47,0x50,0xee,0x4c,0x3a,0xe8,0x87,0xe1, + 0xc2,0x94,0x29,0x01,0x2d,0x0a,0xa7,0x36,0xa8,0x32, + 0x6b,0xa5,0xc9,0x74,0xfc,0xe2}, + .mac_len = 56, + }, { //7 (46) + .key = {0xa8,0xce,0xfe,0xfa,0x10,0x9f,0xac,0xc8,0x5c,0xd6, + 0xf6,0x5b,0x91,0xb4,0x2a,0x98,0x8a,0xf5,0x1f,0xce, + 0xed,0xfb,0xc5,0xf7,0x5d,0x28,0x00,0x3b,0xf1,0x8c, + 0xb7,0xb6,0xe5,0xc0,0x28,0x7b,0x90,0x11,0x7e,0xd9, + 0x96,0xe1,0xa5,0xdd,0x5f,0x4b,0x5d,0x17,0xc8,0x06, + 0x8d,0xa1,0x18,0x8c,0xda,0x5e,0x35,0x7b,0x79,0x80, + 0x18,0x3b,0x41,0x4d,0x7e,0xe1,0x05,0x22,0xe0,0x53, + 0x20,0xb8,0xa6,0xad,0x51,0xa6,0x98,0xe4,0xca,0x27, + 0x95,0xaa,0x83,0x1e,0x87,0x91,0xd4,0x57,0x96,0x72, + 0x43,0x10,0x9c,0x10,0x9b,0xb8,0xd9,0xf9,0x3e,0xf6}, + .key_len = 100, + .data = {0x6b,0x8b,0xc0,0x97,0x1c,0x1c,0x64,0xe8,0xb8,0xdf, + 0x91,0x39,0x7a,0xb8,0xf0,0xa1,0xf2,0x82,0x3c,0x00, + 0x4d,0x48,0xa4,0xd8,0xd6,0xb8,0x70,0x5f,0xbd,0xd4, + 0xe8,0xd2,0x17,0xeb,0x71,0x0b,0x27,0xc8,0xfa,0x56, + 0xdc,0x29,0x96,0x81,0x9a,0x73,0x6a,0x32,0x3e,0xa3, + 0xca,0x7d,0x5c,0x88,0x9f,0xb6,0xca,0x30,0x0c,0x84, + 0x63,0xa0,0x51,0x37,0x05,0xc7,0xef,0x5c,0xdc,0xb5, + 0x0d,0x8e,0xe3,0x09,0x1a,0x8f,0xa7,0xa8,0xb4,0x97, + 0x4f,0xb5,0xc8,0xeb,0xd9,0xbd,0xfb,0xb2,0xa6,0x31, + 0x49,0x04,0x39,0x1a,0xec,0x45,0x3c,0x08,0x80,0xb1, + 0xc3,0x4b,0x64,0x37,0xd5,0x66,0x63,0x8b,0x29,0xc1, + 0x94,0x77,0x2d,0x9e,0x7e,0x72,0x4c,0x4e,0x80,0x73, + 0x71,0xa5,0x71,0x07,0xc7,0xab,0x83,0xa2}, + .data_len = 128, + .mac = {0x9c,0xd0,0x0b,0x99,0xf7,0x3c,0xa0,0xe8,0xca,0xbb, + 0xa5,0x51,0x3b,0x57,0x56,0x98,0xfc,0xf7,0xa2,0x7a, + 0x39,0x6d,0xc3,0x3a,0xfb,0xab,0x98,0x72,0x58,0x9e, + 0xfa,0x82,0x6b,0x2c,0xb2,0xeb,0x66,0x1a,0xd8,0xc3, + 0x6f,0x7b,0x99,0xd6,0x23,0xf4,0x40,0xa0,0x4f,0x07, + 0x67,0xc2,0x50,0x0b,0x05,0x98}, + .mac_len = 56, + }, { //8 (60) + .key = {0x57,0xc2,0xeb,0x67,0x7b,0x50,0x93,0xb9,0xe8,0x29, + 0xea,0x4b,0xab,0xb5,0x0b,0xde,0x55,0xd0,0xad,0x59, + 0xfe,0xc3,0x4a,0x61,0x89,0x73,0x80,0x2b,0x2a,0xd9, + 0xb7,0x8e,0x26,0xb2,0x04,0x5d,0xda,0x78,0x4d,0xf3, + 0xff,0x90,0xae,0x0f,0x2c,0xc5,0x1c,0xe3,0x9c,0xf5, + 0x48,0x67,0x32,0x0a,0xc6,0xf3,0xba,0x2c,0x6f,0x0d, + 0x72,0x36,0x04,0x80,0xc9,0x66,0x14,0xae,0x66,0x58, + 0x1f,0x26,0x6c,0x35,0xfb,0x79,0xfd,0x28,0x77,0x4a, + 0xfd,0x11,0x3f,0xa5,0x18,0x7e,0xff,0x92,0x06,0xd7, + 0xcb,0xe9,0x0d,0xd8,0xbf,0x67,0xc8,0x44,0xe2,0x02}, + .key_len = 100, + .data = {0x24,0x23,0xdf,0xf4,0x8b,0x31,0x2b,0xe8,0x64,0xcb, + 0x34,0x90,0x64,0x1f,0x79,0x3d,0x2b,0x9f,0xb6,0x8a, + 0x77,0x63,0xb8,0xe2,0x98,0xc8,0x6f,0x42,0x24,0x5e, + 0x45,0x40,0xeb,0x01,0xae,0x4d,0x2d,0x45,0x00,0x37, + 0x0b,0x18,0x86,0xf2,0x3c,0xa2,0xcf,0x97,0x01,0x70, + 0x4c,0xad,0x5b,0xd2,0x1b,0xa8,0x7b,0x81,0x1d,0xaf, + 0x7a,0x85,0x4e,0xa2,0x4a,0x56,0x56,0x5c,0xed,0x42, + 0x5b,0x35,0xe4,0x0e,0x1a,0xcb,0xeb,0xe0,0x36,0x03, + 0xe3,0x5d,0xcf,0x4a,0x10,0x0e,0x57,0x21,0x84,0x08, + 0xa1,0xd8,0xdb,0xcc,0x3b,0x99,0x29,0x6c,0xfe,0xa9, + 0x31,0xef,0xe3,0xeb,0xd8,0xf7,0x19,0xa6,0xd9,0xa1, + 0x54,0x87,0xb9,0xad,0x67,0xea,0xfe,0xdf,0x15,0x55, + 0x9c,0xa4,0x24,0x45,0xb0,0xf9,0xb4,0x2e}, + .data_len = 128, + .mac = {0x33,0xc5,0x11,0xe9,0xbc,0x23,0x07,0xc6,0x27,0x58, + 0xdf,0x61,0x12,0x5a,0x98,0x0e,0xe6,0x4c,0xef,0xeb, + 0xd9,0x09,0x31,0xcb,0x91,0xc1,0x37,0x42,0xd4,0x71, + 0x4c,0x06,0xde,0x40,0x03,0xfa,0xf3,0xc4,0x1c,0x06, + 0xae,0xfc,0x63,0x8a,0xd4,0x7b,0x21,0x90,0x6e,0x6b, + 0x10,0x48,0x16,0xb7,0x2d,0xe6,0x26,0x9e,0x04,0x5a, + 0x1f,0x44,0x29,0xd4}, + .mac_len = 64, + }, { //9 (61) + .key = {0x7c,0x98,0x91,0x2c,0x74,0x42,0x13,0x62,0xe1,0x12, + 0xa2,0xf9,0x8f,0xed,0x9b,0xab,0xe0,0x05,0x7f,0xc7, + 0x78,0xb4,0x45,0x32,0x39,0xaa,0xf5,0xac,0x72,0x4b, + 0x72,0x55,0x53,0x53,0x97,0x70,0xa5,0xbc,0x86,0x66, + 0xb8,0xe1,0x3d,0x0e,0x9c,0xe3,0x6b,0x2b,0x93,0x4c, + 0x81,0x37,0xc7,0xf2,0x0b,0x5f,0x39,0x1f,0x41,0xce, + 0xfa,0xee,0xd9,0x2e,0x9d,0xf8,0x20,0x6c,0xec,0x30, + 0x49,0xbc,0xda,0x0c,0x05,0xde,0xb9,0xe6,0x54,0x9f, + 0xad,0xa1,0x9a,0xa2,0x61,0x8f,0xf5,0x60,0xf8,0x92, + 0xce,0x6e,0x47,0x82,0xae,0xff,0x41,0xcf,0x53,0xa9}, + .key_len = 100, + .data = {0x74,0xe8,0x93,0x6d,0x83,0xbf,0x3f,0x16,0xb8,0xd0, + 0x3f,0xb7,0x33,0x84,0xed,0x8f,0x46,0xbd,0x32,0x34, + 0x3f,0x5d,0xf8,0x35,0x81,0x07,0xe2,0xfd,0xda,0x29, + 0x3a,0xfa,0x10,0x3a,0x2b,0xff,0xbd,0x40,0x30,0xe7, + 0x5d,0x96,0xcc,0x7c,0xa6,0xec,0x7c,0x97,0x18,0x8f, + 0xea,0x88,0xd4,0xeb,0x63,0xb7,0xb1,0x4e,0x8b,0x8c, + 0x8d,0xee,0x4f,0x8d,0xe1,0x2e,0x1c,0xc6,0x98,0x1d, + 0x4e,0x6e,0x22,0x3f,0xec,0xc7,0xc4,0x91,0x92,0x46, + 0x32,0xc7,0xae,0xf4,0x5f,0xd8,0xef,0x14,0x94,0xbc, + 0xfb,0x06,0xc0,0x74,0x61,0x6b,0x0f,0x4c,0xce,0x8a, + 0xbd,0x5d,0x83,0xf3,0x2d,0x55,0x06,0x61,0x35,0x7b, + 0x18,0xe5,0xbc,0xed,0xe8,0x41,0x88,0x2c,0x86,0x92, + 0x51,0xdb,0x9a,0x33,0x1a,0xc4,0x56,0xdd}, + .data_len = 128, + .mac = {0x4c,0xc2,0x88,0x18,0x48,0x6b,0xb9,0xb1,0xb5,0x2e, + 0x33,0x3d,0xde,0x71,0xf7,0x3a,0xcc,0x22,0x74,0x88, + 0x45,0x3f,0xd9,0x07,0xc6,0xb5,0x1d,0x34,0x9d,0x67, + 0xaf,0x1d,0xf2,0x9a,0x9f,0x22,0x55,0x32,0xce,0x04, + 0xf5,0x03,0x95,0xfe,0xd5,0x65,0xe9,0x8d,0x78,0x97, + 0x86,0x26,0xdf,0x93,0x46,0x2d,0x3f,0x01,0x2f,0x73, + 0x73,0x34,0x72,0x98}, + .mac_len = 64, + }, { // 10 (75) + .key = {0xfd,0xe1,0x5b,0xa9,0x00,0xe6,0x64,0x8c,0x9d,0x84, + 0x71,0xf0,0x0d,0x9b,0x32,0xd7,0x1e,0x53,0x83,0xb9, + 0x37,0x0c,0x93,0x1c,0x96,0x94,0x45,0x65,0xdd,0x9d, + 0xd6,0xee,0xcd,0x6e,0xc1,0x58,0x51,0xd8,0xdf,0x23, + 0xbe,0x6c,0xd3,0x7b,0x59,0xeb,0xa5,0x55,0x1a,0xfe, + 0xad,0xbb,0xaf,0x27,0xb3,0x64,0xc4,0xf8,0x54,0x88, + 0x82,0x83,0xa7,0xf2,0x55,0x11,0x21,0x57,0xf3,0x17, + 0xb6,0xe6,0x9a,0x65,0x41,0x20,0x98,0xa1,0x26,0xea, + 0x11,0xf4,0x36,0xe1,0xfd,0x03,0xd3,0xed,0x70,0x21, + 0x54,0x19,0x1e,0xc2,0xab,0xa2,0x1e,0x33,0x44,0x4d, + 0xee,0x89,0x31,0xfe,0xb8,0xd8,0x85,0x87,0xd3,0xa5, + 0xfd,0xbe,0x8d,0x9d,0xe6,0xd2,0x28,0x87,0x3a,0xdf, + 0x22,0x77,0x0d,0xbf,0xba}, + .key_len = 125, + .data = {0xcf,0x65,0x95,0x9c,0x76,0x08,0x26,0xbe,0xcc,0x0d, + 0x3c,0x4c,0xf7,0x57,0x40,0xd8,0xc8,0xbe,0xbb,0x98, + 0x35,0xb2,0x6b,0x21,0x0a,0x21,0x97,0x73,0xdb,0x9b, + 0x9f,0x36,0x3d,0xb5,0xd7,0x43,0x36,0xab,0x95,0x66, + 0xf1,0x49,0x89,0x62,0xb6,0x0b,0x4d,0x36,0x1a,0x83, + 0x3d,0x9f,0x73,0xfb,0x89,0xde,0x8f,0x5c,0x89,0xbb, + 0xa6,0x4e,0x50,0xca,0x8c,0xa1,0x83,0xed,0x2b,0xec, + 0x6c,0x1a,0x31,0x73,0x4a,0x5f,0x06,0x4e,0xeb,0x23, + 0x01,0xc8,0x7d,0xae,0xdb,0x06,0xa2,0xec,0x64,0xe9, + 0xc2,0x6d,0x74,0x34,0xa5,0xb1,0x25,0xf2,0x41,0xa3, + 0x3f,0x12,0xd0,0x63,0xf4,0x55,0x26,0x48,0xce,0x6a, + 0x42,0x26,0xe5,0x57,0x23,0xcc,0x55,0x1a,0xdd,0xd1, + 0xef,0x90,0xeb,0x91,0x2f,0x97,0xc7,0x72}, + .data_len = 128, + .mac = {0xb1,0xa9,0x13,0x53,0x11,0xd3,0x2f,0x5b,0xd6,0xb7, + 0x3a,0xbf,0x54,0x08,0x8b,0x65,0xfc,0x1d,0x23,0xe4, + 0xbe,0xd1,0xd3,0x38,0x79,0xa7,0x07,0xc5,0xc9,0x3e, + 0x8f,0xba}, + .mac_len = 32, + }, { // 11 (76) + .key = {0x18,0x51,0x9a,0xce,0x34,0x6e,0x2e,0x99,0x87,0xa2, + 0x50,0x38,0xd7,0x64,0x2b,0x7f,0xbe,0xbd,0x3a,0x49, + 0xb9,0x04,0x00,0x5f,0x7b,0xed,0xfa,0x9c,0x87,0xc2, + 0xd2,0x4f,0xfd,0xef,0xd5,0xe1,0xb4,0xc4,0xa7,0xb8, + 0x8a,0x77,0x35,0x5a,0xf8,0x68,0xec,0xd6,0xea,0xa9, + 0x29,0x60,0xcd,0xbe,0xf0,0x3b,0xe9,0xa1,0xe0,0xdc, + 0xf1,0x0a,0x66,0x4c,0xd8,0xec,0x32,0xce,0xe7,0x43, + 0xe7,0xc2,0x0d,0x0d,0x17,0xc9,0x76,0x96,0x6e,0x2a, + 0x5e,0xf9,0x2d,0x74,0x28,0xe4,0xda,0x65,0xaa,0x9b, + 0x36,0x0b,0xcc,0x40,0x70,0x29,0x51,0x51,0x98,0xdc, + 0xf4,0x72,0x56,0x7e,0xb7,0x6d,0xdc,0xcb,0x78,0x77, + 0x19,0x42,0xc5,0xb5,0x30,0xce,0xf1,0xfe,0x28,0xa6, + 0x67,0xe3,0xe5,0x72,0x3f}, + .key_len = 125, + .data = {0x72,0x10,0x54,0x9b,0x3e,0xdd,0x9a,0x0a,0x70,0x0b, + 0x06,0x1f,0x65,0xce,0x10,0x43,0x74,0x77,0xd9,0xe5, + 0xdc,0x95,0xbb,0xc1,0xfa,0x61,0x25,0x62,0xc0,0x59, + 0xa6,0xe5,0x62,0x2a,0x47,0x01,0x52,0xd3,0x1e,0x44, + 0x6f,0x08,0x20,0x9f,0x7a,0xd4,0x37,0x25,0xc9,0x83, + 0x95,0x10,0x3f,0xbf,0x47,0x05,0x7b,0xf9,0x0d,0x99, + 0x50,0x0b,0x69,0x13,0x75,0x1b,0xf6,0x73,0x7e,0xc2, + 0xfb,0xb4,0x0b,0x6d,0x40,0x4f,0x40,0x04,0x20,0x00, + 0x75,0xca,0xe0,0xcc,0x2e,0x85,0x3f,0x43,0x4d,0xde, + 0x4e,0x03,0x86,0x0a,0x82,0x7d,0x14,0xaa,0x08,0xfc, + 0xaa,0xf0,0x58,0xe3,0xad,0x04,0x0d,0x35,0xa0,0xa6, + 0xf4,0x5b,0xe0,0x14,0x63,0x22,0x91,0x2e,0xcc,0x04, + 0xd8,0xd8,0x91,0xa8,0x4a,0xa0,0x1a,0xac}, + .data_len = 128, + .mac = {0x2b,0x26,0x49,0xc3,0x99,0xf3,0x71,0x6b,0xf3,0x3f, + 0x79,0x37,0x57,0x9d,0xf1,0x2d,0xea,0xa8,0xed,0x00, + 0xf6,0x56,0xf8,0x24,0x04,0x68,0xa3,0xb0,0x22,0xd4, + 0x11,0xfb}, + .mac_len = 32, + }, { // 12 (90) + .key = {0x04,0xe8,0x66,0xda,0x69,0xea,0x09,0x39,0xb0,0x2a, + 0x4e,0x9e,0x29,0x05,0x2f,0xe6,0xcf,0xd7,0xa5,0xf8, + 0x7d,0x65,0x79,0x4a,0x5e,0x78,0x56,0xa7,0xa6,0xcb, + 0x24,0x2f,0x7f,0x27,0x91,0x9f,0x46,0xcd,0xf0,0xd2, + 0xf8,0x14,0x47,0x88,0xe7,0x53,0xa3,0x67,0xb2,0x01, + 0xaf,0x3f,0x73,0x1b,0x85,0x92,0x3a,0xc6,0xc4,0x54, + 0xbb,0x36,0xe3,0xef,0x43,0xce,0xc5,0x8a,0xf1,0x89, + 0x8d,0x8b,0x22,0x98,0xb3,0x5a,0x2d,0x4d,0x58,0x68, + 0x51,0x37,0xd6,0x71,0xeb,0x8f,0x9c,0xfe,0xec,0xd2, + 0x39,0x2d,0x8b,0xb0,0xb6,0xb4,0x37,0x25,0x29,0x24, + 0xd0,0xe6,0x87,0x6b,0x16,0xfe,0xba,0x9d,0x62,0xb9, + 0xf3,0xf4,0x94,0xc1,0x42,0x15,0x4c,0x87,0x64,0x94, + 0x5d,0xe4,0xdc,0xbb,0x7e}, + .key_len = 125, + .data = {0x2f,0x77,0xd8,0x33,0x1b,0x2b,0x92,0xc8,0x56,0xc8, + 0x11,0x88,0x9b,0xab,0x8e,0xdf,0x75,0xc6,0x87,0x5c, + 0x02,0x4d,0xa9,0x0b,0xf6,0xb2,0xf3,0xff,0xe2,0xd4, + 0x19,0x2e,0xb7,0x74,0x26,0x82,0x86,0xe8,0x66,0x2c, + 0x89,0x13,0x83,0x3c,0x67,0x94,0xee,0x6e,0xb4,0x3e, + 0x80,0x47,0xb7,0xc8,0x62,0x61,0x71,0xc6,0x2a,0x04, + 0xda,0xd8,0x46,0xf5,0x6e,0x22,0x9e,0x93,0xe8,0xfc, + 0x75,0x1f,0x4e,0xea,0x90,0x5c,0x2d,0xce,0x9b,0x58, + 0x26,0x5c,0xc8,0x89,0xa9,0xcf,0xb9,0x1b,0x01,0xda, + 0xa0,0x89,0x91,0xe2,0xa5,0x6b,0x5d,0x6a,0x88,0x8f, + 0xcc,0xcf,0x87,0x4a,0xac,0x35,0x82,0x10,0x76,0xc1, + 0x5d,0x43,0xd3,0x09,0xa6,0x49,0x60,0xc8,0x77,0xe1, + 0xae,0xd7,0x9e,0xb7,0x8e,0x58,0xfc,0x36}, + .data_len = 128, + .mac = {0xbf,0x29,0x05,0x1b,0xe9,0x36,0xe6,0xa3,0x24,0xf1, + 0x49,0xda,0x16,0x82,0x36,0xa5,0xaf,0x75,0x84,0xad, + 0x0b,0x8a,0xb1,0xe7,0xc2,0x7c,0xe0,0x3c,0x02,0x76, + 0x88,0x85,0xe2,0x7d,0x06,0x5f,0x26,0x32,0x16,0x67}, + .mac_len = 40, + }, { // 13 (91) + .key = {0xe5,0xcf,0x7e,0xde,0x64,0x0e,0xce,0x05,0xe6,0xe0, + 0x8e,0x64,0x35,0xfa,0x6e,0x75,0x2a,0xde,0xbb,0xe5, + 0x15,0xad,0xe1,0x00,0x5e,0x3c,0x2e,0x6b,0x6d,0x69, + 0xd8,0x11,0xc8,0xb0,0x42,0x5f,0x7b,0xf9,0x7b,0xb4, + 0xbd,0xb4,0x07,0x13,0xd0,0x28,0xe3,0x1c,0x29,0x08, + 0xc3,0x3a,0xd1,0x48,0x9e,0x1d,0x0b,0x2e,0x6c,0x6b, + 0x37,0xac,0x2f,0xb2,0xf6,0xed,0x30,0xa2,0x8f,0x2e, + 0x8b,0x79,0x92,0xcf,0xed,0xbe,0xbb,0xaa,0x9d,0x32, + 0x18,0xa3,0xb9,0x04,0x6e,0x80,0xc3,0x44,0xda,0xfc, + 0x5c,0x9a,0xb4,0x16,0x4e,0x38,0xb8,0xaf,0xd0,0x0d, + 0x68,0x54,0x06,0x3b,0xac,0x59,0xc8,0xcc,0xbc,0x27, + 0xa4,0xa0,0x3f,0xd6,0x26,0xaa,0xb5,0xff,0x56,0x5d, + 0x12,0xcb,0x83,0x60,0xab}, + .key_len = 125, + .data = {0x0c,0x36,0xca,0x43,0xe7,0xc1,0x13,0xed,0x9f,0xb7, + 0x16,0x70,0xb3,0xea,0x73,0xbf,0xd6,0x92,0x8c,0x83, + 0x9f,0x36,0xdb,0x1a,0x82,0xd0,0x8a,0xe0,0xff,0x2c, + 0x3d,0xae,0x19,0x91,0x33,0xa1,0x0a,0xa3,0x8d,0x1d, + 0x35,0x88,0xed,0x11,0x5c,0x4a,0x43,0x7c,0x13,0x7c, + 0xe4,0x30,0x74,0x21,0xdd,0xd6,0x15,0xc9,0x86,0x32, + 0x37,0xfd,0x5a,0xa8,0x40,0xdd,0x05,0xff,0x6c,0x08, + 0xbf,0x66,0xbf,0xbc,0xd9,0xb4,0x3e,0x3f,0x95,0xf4, + 0x5e,0x7d,0x3b,0x21,0xbd,0xf2,0x69,0x2e,0x10,0xca, + 0xab,0x49,0x5c,0x47,0x4b,0x61,0x6a,0x64,0x6b,0xe6, + 0x75,0xb8,0x50,0xd0,0x25,0x9c,0x01,0xe2,0xc1,0x90, + 0x11,0x30,0xa0,0xdb,0xb9,0xdf,0xe0,0x72,0x2a,0x2c, + 0x5b,0x1b,0x20,0xaf,0xd7,0xd2,0xbb,0xe1}, + .data_len = 128, + .mac = {0x71,0x9d,0xd7,0x99,0x84,0xd1,0xa7,0x4b,0xce,0xa4, + 0x6c,0xcb,0xba,0x7a,0xe0,0x9f,0xe2,0x46,0xa4,0x77, + 0x09,0xd9,0x93,0xd3,0x15,0x55,0xa2,0x0d,0x57,0xdb, + 0xd5,0xb1,0xbe,0x9f,0x8f,0xe5,0x54,0x73,0xdd,0xbf}, + .mac_len = 40, + }, { // 14 (105) + .key = {0xa6,0x19,0x89,0x53,0x52,0x2d,0x47,0x66,0x73,0x02, + 0x62,0x8c,0xdc,0x70,0x5e,0x09,0x59,0x61,0x8c,0xb7, + 0xe6,0x36,0xde,0x92,0x1f,0x66,0xf9,0x7a,0xf8,0x68, + 0x8c,0x35,0xae,0xd4,0xe0,0xb4,0xfe,0xc5,0xb1,0x97, + 0x94,0x81,0x3d,0xf3,0xc6,0x5c,0x9a,0x52,0x82,0xd9, + 0x4c,0xfb,0x85,0x13,0x17,0x74,0xce,0x5b,0x12,0x46, + 0x53,0x23,0xfd,0x00,0xf2,0x1b,0xd4,0x7e,0xaa,0x99, + 0xa4,0x6b,0x0b,0x3e,0x9e,0x05,0xeb,0xd7,0x6a,0x20, + 0x5b,0x81,0xbe,0x6e,0xda,0x11,0x2e,0xfd,0xc8,0xb2, + 0x46,0x01,0x1d,0xd0,0xd6,0xd4,0x5a,0x35,0x8d,0x3b, + 0xc0,0x72,0xc9,0xeb,0xc0,0x81,0xae,0x4c,0xb4,0xa8, + 0x76,0x7c,0xcc,0xa0,0x07,0x97,0x4b,0xf7,0xcb,0x36, + 0xf3,0xb3,0xbc,0x35,0xbd}, + .key_len = 125, + .data = {0x29,0x09,0x53,0x25,0x50,0xdb,0x49,0x40,0x48,0x5a, + 0xd5,0xc1,0x90,0x5a,0x88,0xc7,0x60,0x84,0x80,0xca, + 0xe0,0xb0,0x38,0x21,0x97,0x96,0xa4,0xc7,0x26,0xa6, + 0x7e,0x5e,0x36,0x34,0xdb,0x74,0xaf,0xd8,0x01,0x06, + 0x2a,0x15,0x7c,0x42,0xaa,0x38,0x6f,0x91,0x86,0x83, + 0x29,0xd5,0xaa,0x8b,0xf8,0xef,0x00,0xdf,0x42,0x85, + 0x28,0xea,0xd1,0x02,0x6f,0x1b,0x6f,0xde,0xff,0x43, + 0xb3,0x1f,0x53,0x3e,0x1a,0x20,0xee,0xd5,0x59,0x91, + 0x4d,0xe3,0xf2,0xbf,0x1a,0xb7,0x06,0x15,0xa2,0xba, + 0x6a,0xe3,0x89,0x51,0xfd,0x5f,0xbc,0x05,0x38,0xea, + 0xa8,0xe2,0x06,0x94,0xaa,0x1c,0xd6,0xe1,0xc6,0xf9, + 0xef,0xce,0x9b,0xea,0x04,0x0f,0x96,0xfb,0x09,0x9b, + 0x67,0x6e,0x45,0x6a,0xb1,0xa3,0xa7,0x7d}, + .data_len = 128, + .mac = {0x9b,0x31,0x71,0x4d,0xf3,0x8d,0x74,0xda,0x1d,0x31, + 0xc2,0x01,0x01,0x82,0x3a,0x7a,0x51,0x12,0x95,0x95, + 0xe9,0x68,0x85,0xfe,0x4a,0x3c,0xfb,0x31,0xd5,0xe3, + 0x2c,0x63,0x2b,0x2f,0x0e,0x83,0x18,0xc2,0x33,0x92, + 0xc4,0xe1,0xf8,0x3f,0x18,0x0a,0xa9,0xf0}, + .mac_len = 48, + }, { // 15 (106) + .key = {0x91,0xf9,0xe6,0x9e,0x2b,0xd3,0xa0,0xdc,0x72,0x40, + 0xd5,0x09,0xc7,0xec,0x14,0xc8,0x54,0x27,0xf7,0x9c, + 0xa0,0x30,0x57,0x4d,0x60,0xb4,0xbc,0x8d,0x91,0x92, + 0x17,0xdb,0xc3,0xe1,0xb4,0xa8,0xb8,0x34,0x6a,0xb8, + 0x2d,0x1c,0x15,0xcc,0xf8,0xef,0x46,0x7e,0x53,0xc8, + 0x38,0x6c,0x78,0xcf,0x06,0x98,0x6e,0xbb,0x1c,0x0f, + 0x22,0x95,0xeb,0xc9,0xb9,0xbe,0xe2,0xd1,0x25,0x33, + 0x99,0xa5,0xf6,0x10,0x4f,0xe0,0x73,0x53,0x96,0x16, + 0xea,0xe3,0x4d,0x00,0x44,0xd1,0xcf,0xd9,0xdc,0xdd, + 0x6a,0x07,0x92,0x3c,0x13,0xfe,0x1b,0x98,0x57,0x62, + 0x9b,0x59,0x95,0x6b,0x75,0x23,0x6b,0x8e,0x61,0x9f, + 0x6e,0x5a,0xc0,0x7f,0x1e,0xa0,0x2d,0xbc,0x19,0xd6, + 0x55,0x22,0x8e,0xbd,0x08}, + .key_len = 125, + .data = {0x8e,0x9b,0x8a,0x2a,0xf5,0xbf,0x4d,0x8e,0xfd,0x51, + 0xe3,0x32,0x23,0xe3,0x5e,0x69,0xc3,0x72,0x9c,0x2d, + 0x3c,0xf6,0x84,0x59,0x50,0x38,0x8c,0x19,0xc9,0xe4, + 0x7e,0x9e,0x62,0xdf,0x7d,0x16,0xe4,0xda,0x43,0xdb, + 0x90,0x28,0xac,0xea,0xbd,0xcc,0x78,0x98,0xc2,0xd7, + 0x4c,0x80,0x16,0xf1,0xfb,0xc0,0xb6,0x35,0x04,0x65, + 0xc7,0x42,0x5c,0x23,0x7d,0x8e,0x6d,0x4a,0x3b,0xfe, + 0x5e,0xf5,0xfc,0xb4,0x95,0x84,0xf1,0x29,0x7a,0x4d, + 0x6b,0x7b,0x7e,0x8f,0xfc,0x08,0x5d,0xa7,0xd9,0x3b, + 0x9f,0x87,0x83,0xa6,0x65,0x63,0xa7,0x51,0x62,0xad, + 0x42,0x52,0x28,0x44,0x08,0x9e,0xa5,0xe9,0x07,0x1f, + 0xed,0xf2,0x88,0x07,0x3a,0x42,0x36,0x63,0x30,0x78, + 0x82,0xf3,0x66,0x67,0x45,0x39,0x23,0xc7}, + .data_len = 128, + .mac = {0xb7,0x71,0xf3,0x9b,0x76,0xea,0x76,0x4e,0x7e,0x3b, + 0x48,0x8c,0xff,0x14,0xea,0x8e,0x33,0x7c,0xdb,0x17, + 0x3b,0xe0,0xd8,0x60,0x0d,0x2f,0x56,0x5f,0xb0,0x4c, + 0xee,0x85,0x01,0x1a,0x26,0xb5,0xb9,0x22,0x4b,0x30, + 0x16,0x2d,0xc3,0xba,0x48,0xc9,0xb1,0x21}, + .mac_len = 48, + }, { // 16 (121) + .key = {0x2d,0x0c,0xb6,0xd4,0x5a,0x95,0x2e,0x76,0x96,0xba, + 0x75,0xba,0xba,0xc0,0x52,0xa0,0xd4,0x4c,0x5f,0xa7, + 0x7a,0x6d,0x01,0xed,0x5e,0xdc,0x9d,0x97,0x23,0x83, + 0x09,0x73,0x6f,0x3d,0x41,0xdc,0x42,0xdd,0x5c,0xdf, + 0x86,0x71,0xbe,0x9c,0xe7,0xc8,0x8e,0xee,0xe4,0x31, + 0x6b,0x4e,0x26,0x86,0x5a,0xf4,0x11,0x69,0x03,0x40, + 0x9a,0xce,0x1e,0x59,0x58,0xba,0x28,0x14,0xdd,0x49, + 0x5a,0x17,0x46,0xf6,0xdb,0x3e,0x11,0x17,0x35,0x3d, + 0x2f,0xa7,0x06,0x87,0x5a,0x48,0xf8,0x6f,0xa9,0x88, + 0xf2,0x8d,0x62,0x64,0x90,0x64,0x0f,0x0b,0xd1,0x41, + 0xd4,0xe4,0x10,0x66,0xff,0xd1,0x36,0x68,0xe1,0xb6, + 0x2d,0xd6,0xdd,0x35,0x98,0x1b,0xbe,0xbc,0xc1,0xa6, + 0x4d,0xc2,0xd2,0x48,0x24}, + .key_len = 125, + .data = {0x74,0x15,0xf6,0x37,0x3b,0x8a,0x79,0x48,0x77,0xc6, + 0x39,0xf0,0x09,0xb3,0xc4,0x91,0x97,0xf3,0x88,0xf9, + 0x8b,0xd3,0xf0,0xee,0x5f,0x7a,0xd0,0x0a,0x19,0x67, + 0x03,0xca,0x11,0x1a,0x53,0xe1,0xfa,0x10,0x98,0xd2, + 0x20,0xf5,0x24,0xbd,0xef,0x16,0x5f,0x79,0xb5,0x15, + 0xaf,0xe4,0xa9,0xe0,0x9b,0x77,0x2b,0xe3,0x2f,0x1e, + 0x4d,0x7d,0xa2,0x46,0x93,0xb1,0x36,0x37,0xf7,0x1f, + 0x60,0xa4,0x30,0x32,0x29,0x80,0x34,0x9a,0xd4,0x14, + 0xfc,0xfd,0xc1,0x4f,0x87,0xe9,0x91,0x5d,0x21,0x0e, + 0x8b,0x7b,0xe5,0xaa,0x3e,0x09,0x81,0x44,0x68,0xe0, + 0x39,0x9d,0x17,0xe7,0x2f,0xe4,0x0e,0xe1,0xe1,0x29, + 0x6a,0x89,0xf3,0x14,0x86,0xe1,0x2f,0xd7,0x1b,0xc7, + 0xca,0x61,0xac,0xc9,0xe8,0xd4,0x21,0x3a}, + .data_len = 128, + .mac = {0x76,0x91,0x2f,0xf0,0xf1,0x80,0xd6,0x2a,0x86,0xa2, + 0xbb,0xf8,0xe1,0xf8,0xd4,0x43,0x8e,0xd5,0xde,0xd0, + 0xcf,0xd3,0xbb,0xbb,0x43,0x03,0x84,0xa6,0x0f,0x18, + 0xd9,0xe9,0xcd,0xeb,0x7e,0x49,0xec,0x43,0xa6,0x13, + 0x67,0x68,0x6b,0x34,0x63,0x36,0x01,0xa5,0xae,0xdf, + 0x8e,0x3d,0x66,0x9b,0xe2,0x82}, + .mac_len = 56, + }, { // 17 (122) + .key = {0x6e,0x1d,0x5f,0x58,0x1e,0xee,0x88,0x4d,0x33,0x0e, + 0x4c,0xd2,0x6b,0x51,0x00,0x7f,0x4e,0x30,0x09,0xb0, + 0x11,0x1c,0xe5,0x81,0xbb,0x12,0x6b,0xf6,0x86,0x70, + 0x53,0x79,0x88,0x07,0xf8,0x8a,0x92,0x71,0x5d,0xb2, + 0x59,0xa4,0x6e,0xb8,0xd3,0xc8,0x89,0x18,0xe4,0x46, + 0x3d,0xb1,0x3a,0x22,0x52,0xbe,0x76,0x8a,0x09,0x07, + 0x8c,0xaf,0xa4,0x59,0x6c,0xd3,0x29,0x33,0xe2,0xa3, + 0x64,0xc2,0xba,0xc8,0x2b,0x0f,0x29,0xb9,0xe6,0x78, + 0x68,0xd3,0x4e,0x5d,0xa2,0xab,0x74,0x1b,0x10,0xa3, + 0x05,0x3e,0x63,0xbb,0xcd,0xf2,0x62,0xaa,0x7b,0xbb, + 0xd4,0x2e,0xa4,0x66,0xa0,0xa0,0x0a,0x40,0x33,0xcb, + 0x1d,0x85,0x22,0xfe,0xc2,0x1b,0x10,0x60,0x54,0x80, + 0xd3,0x84,0xe8,0x02,0xd2}, + .key_len = 125, + .data = {0x0b,0x8c,0xdd,0x9b,0xc2,0xde,0xc6,0x87,0x48,0xa7, + 0x99,0xc1,0xc1,0x0a,0x41,0x99,0x07,0x0e,0xf5,0x7b, + 0xa7,0x97,0x5d,0x7f,0x2d,0x95,0xf6,0x3b,0xa2,0x7b, + 0xb7,0xdc,0x52,0xf3,0xf5,0x75,0xd3,0xcf,0x84,0x96, + 0x42,0x43,0x1f,0x21,0xd0,0x52,0x09,0x59,0x7d,0x87, + 0xf5,0x3c,0x24,0xe5,0x24,0x13,0xb8,0x20,0xcd,0x47, + 0xcd,0x0e,0xc1,0x76,0x5a,0x58,0x4f,0xc6,0xbd,0x75, + 0x65,0x79,0xff,0xd9,0xf9,0xc2,0x5a,0x69,0xa7,0xd7, + 0xf8,0x33,0x9c,0x48,0xfe,0x5c,0xb2,0x8f,0xc9,0x59, + 0xdc,0xe8,0x77,0x62,0xc5,0x63,0xaa,0x24,0xb4,0x37, + 0x88,0xb7,0xb3,0x59,0x07,0xcf,0xf0,0x4d,0x67,0x36, + 0x63,0x3d,0x00,0x7a,0xb1,0x48,0x3d,0xe3,0x51,0x1c, + 0xe9,0xa7,0xed,0xc7,0xa9,0x61,0x0b,0xca}, + .data_len = 128, + .mac = {0x29,0x3f,0xab,0xbc,0xfd,0xb8,0x55,0x28,0x93,0x77, + 0xf5,0x12,0xef,0xbc,0x37,0x01,0x52,0xcb,0x87,0x19, + 0x7d,0x12,0xf6,0x61,0xb6,0xca,0xe1,0x8b,0x8d,0x24, + 0x2c,0xbc,0x76,0x7a,0x6f,0x66,0x33,0x77,0x08,0x55, + 0x25,0xf0,0xf2,0x7b,0x39,0x00,0x57,0xdf,0xb9,0x9b, + 0x57,0xb7,0x3f,0x52,0xaa,0x2d}, + .mac_len = 56, + }, { // 18 (135) + .key = {0x13,0xfb,0x1e,0xd6,0x38,0x9f,0x32,0xd1,0xde,0x31, + 0x39,0xcb,0x04,0xbc,0xdd,0x53,0x52,0x5c,0x98,0x89, + 0xb8,0x53,0x79,0xd3,0x53,0x5a,0x25,0xd2,0x90,0x35, + 0x1c,0x95,0x93,0x8a,0x3d,0x0c,0xda,0xf3,0x8d,0xbf, + 0x1d,0x52,0x34,0xbf,0x79,0x65,0xc8,0xdd,0xce,0x9a, + 0xce,0x1b,0x66,0x24,0x7e,0x60,0xd7,0x4e,0xc7,0x70, + 0x2a,0x0f,0x93,0x1a,0x3c,0xdf,0x4c,0xb4,0x65,0xca, + 0x9f,0xc4,0x58,0xc3,0x80,0x00,0x4a,0x3a,0x6e,0x79, + 0x57,0xf1,0xf8,0x13,0x21,0x0b,0x80,0x38,0xba,0x66, + 0x3f,0xcd,0xc4,0x2a,0x89,0x65,0xd6,0xa2,0x52,0xb5, + 0x22,0x4b,0xf2,0x49,0x55,0x2b,0x25,0x75,0xbf,0x64, + 0x56,0x8d,0xb4,0x09,0x1d,0x58,0x32,0x30,0x06,0xc3, + 0xc3,0x49,0x94,0xd3,0xa5}, + .key_len = 125, + .data = {0x88,0xad,0x81,0x2f,0xd3,0x4e,0x55,0xc8,0x09,0xe8, + 0x17,0x19,0x96,0x04,0xb4,0xa7,0xf7,0xfe,0xae,0x42, + 0xcd,0xc4,0xc9,0xe9,0x30,0xdb,0x08,0xe8,0x45,0xa3, + 0xd7,0x43,0x13,0xdb,0x8a,0x57,0x92,0x67,0x06,0xbf, + 0x05,0x51,0xbe,0x75,0x8a,0x0f,0xe2,0x39,0xf0,0x04, + 0xd2,0x37,0xc8,0x49,0xd9,0xe4,0xbf,0xac,0x18,0x29, + 0x2b,0xf9,0xc0,0xc3,0xe3,0x79,0x85,0xea,0x54,0xb9, + 0x4f,0x30,0xd1,0x8c,0x32,0xad,0x2b,0x53,0xa0,0x59, + 0x82,0x7c,0xdd,0xb9,0x5a,0x49,0xb4,0xbe,0xf1,0xd3, + 0x69,0xea,0xd1,0x4e,0xee,0xb4,0xa1,0x8e,0x59,0x2e, + 0x40,0xca,0x96,0xe5,0x15,0xa1,0x59,0x08,0xa0,0x5a, + 0x57,0xcd,0x55,0x70,0xb6,0x11,0xab,0x4e,0xc2,0x3f, + 0x70,0x57,0xe1,0x72,0x5f,0x29,0xc9,0xde}, + .data_len = 128, + .mac = {0xa4,0x81,0xe7,0x13,0xcd,0xc8,0x1c,0xa5,0xaf,0xa0, + 0xef,0xcb,0x16,0xe3,0x5c,0xd2,0x0d,0x01,0xaa,0x44, + 0x99,0x58,0xfd,0x2e,0xae,0xde,0x2e,0x25,0xa5,0xba, + 0x54,0x0b,0xea,0xfb,0xa2,0xfa,0xb4,0xad,0xfe,0xf2, + 0xe1,0x46,0xb4,0xc1,0xb2,0xa1,0x83,0x2e,0x93,0xdd, + 0x37,0x3d,0x63,0xfa,0x90,0xbb,0x61,0x49,0x0f,0x65, + 0x68,0x19,0x1f,0x65}, + .mac_len = 64, + }, { // 19 (136) + .key = {0xfd,0x50,0x70,0x36,0x22,0x96,0xc4,0x0d,0x65,0xb1, + 0x05,0xd5,0xab,0x46,0x53,0xfe,0x34,0xe0,0x20,0x05, + 0x16,0x93,0x3f,0x3e,0xea,0xe0,0x3e,0xd0,0xc5,0xd9, + 0xf6,0x01,0x6a,0x85,0x60,0xb4,0xbd,0x86,0xab,0x2f, + 0x7b,0xf9,0x8b,0x22,0x29,0x9e,0xd3,0xe5,0x4a,0x39, + 0x46,0x02,0xd5,0x38,0xaa,0xf3,0xe6,0x95,0x1f,0x2d, + 0xb4,0xfe,0xaf,0x5d,0xc3,0x34,0x26,0xf1,0x5b,0xb1, + 0x24,0xda,0x38,0x8d,0x70,0x90,0x83,0xa2,0x8f,0x57, + 0x01,0xef,0x96,0xc2,0x8b,0x3a,0x3c,0x75,0xbe,0xf9, + 0x33,0x2e,0xf3,0x73,0xb9,0x07,0x71,0x23,0x6a,0xf5, + 0xe2,0x5d,0x58,0x95,0x04,0x34,0x5d,0x28,0xa1,0x9a, + 0xb0,0xdb,0xc1,0xc9,0xb7,0x4d,0x1e,0xe2,0x1c,0x4b, + 0xd8,0xd4,0x23,0xde,0x6a}, + .key_len = 125, + .data = {0x8d,0x2e,0x68,0xd7,0xe9,0x84,0x6c,0xfa,0x30,0xd9, + 0x31,0xa3,0x8e,0xfb,0x59,0xbc,0xce,0xd5,0x3a,0x14, + 0x16,0x4b,0x31,0x63,0xd2,0x65,0x38,0x88,0xee,0xb0, + 0xbb,0x14,0x48,0xe1,0xa8,0x0c,0x65,0xbc,0xc6,0xeb, + 0x63,0x34,0x47,0xe7,0x2e,0xd4,0xa0,0x75,0xf7,0x5d, + 0x98,0x0f,0xe2,0xb1,0x9f,0x35,0xff,0xef,0x62,0xb2, + 0x7c,0xe0,0x9c,0x20,0x19,0x92,0x2f,0xae,0xdb,0x42, + 0x73,0x21,0x05,0x7f,0xce,0x19,0x44,0x8d,0x85,0x96, + 0x2a,0x08,0xd1,0xba,0xdd,0xc9,0x36,0xd1,0x11,0x0e, + 0x10,0x8e,0x33,0xd4,0x6f,0x97,0xe7,0x88,0x24,0x45, + 0xb5,0xdf,0x1c,0xa4,0xff,0x03,0xed,0xc2,0x37,0xef, + 0xaf,0x26,0x4f,0x1c,0x0d,0x9e,0x70,0x5d,0x9b,0x3e, + 0xee,0x07,0x6b,0xa5,0x7c,0x56,0xdb,0x82}, + .data_len = 128, + .mac = {0xb6,0xca,0xd1,0xca,0x5b,0xa5,0x05,0x49,0x8a,0x8f, + 0x66,0xa9,0x42,0x2b,0xf5,0x39,0x42,0x6a,0x8a,0x55, + 0x33,0x4f,0xab,0x9c,0x6b,0x9e,0x08,0xe3,0xa5,0x17, + 0x9d,0x15,0x7d,0x1e,0xfa,0x0f,0x91,0xd5,0xc5,0xe2, + 0x6f,0xfa,0x43,0xf5,0xc1,0xcb,0x7c,0xa5,0xf9,0x06, + 0xce,0x4f,0x0e,0xfc,0xf4,0xe8,0x71,0x82,0x0b,0x83, + 0x53,0xe8,0x90,0xe4}, + .mac_len = 64, + }, { // 20 (150) + .key = {0x39,0xca,0xde,0x38,0x95,0xb0,0x7a,0xbb,0x4c,0x10, + 0x0d,0x2a,0xc9,0x75,0x86,0x06,0x9e,0xfd,0x1c,0xfb, + 0xd3,0x5c,0x41,0x09,0x7e,0x23,0xd1,0xe1,0x94,0x43, + 0x90,0x92,0xff,0xcc,0xd3,0x64,0xf1,0xfb,0x7d,0x04, + 0x77,0x74,0x2d,0xe2,0x51,0xcc,0xb6,0xd8,0x01,0x4a, + 0xd0,0x0c,0x22,0xef,0x0d,0x17,0xfb,0xb3,0x0e,0x67, + 0x54,0x12,0xf6,0xe1,0x88,0xc7,0x1f,0xcb,0xdc,0xd8, + 0x0c,0xea,0x0f,0xd2,0x9f,0xe7,0x33,0x56,0x8c,0xf8, + 0xbb,0xd4,0x0e,0xbc,0xd4,0x97,0xd9,0x66,0xf9,0x02, + 0x4f,0x1d,0xc1,0x19,0xf6,0xa3,0xfc,0x43,0x2a,0x35, + 0xff,0x4d,0x0f,0xb3,0x3c,0xb3,0xca,0x01,0x16,0x1b, + 0xf1,0xad,0xf3,0x23,0x3f,0xd2,0x92,0x5c,0x8d,0x3c, + 0x9f,0x96,0xfd,0xcc,0x84,0x5f,0x79,0x1e}, + .key_len = 128, + .data = {0xff,0xb6,0xb2,0x07,0x1a,0xde,0x0e,0xbb,0xec,0xdf, + 0xe6,0xdc,0xc8,0xcc,0xd5,0x2f,0xae,0xbb,0x66,0xa1, + 0x28,0x1b,0x1c,0x39,0x72,0x48,0xb6,0x4c,0xdd,0x5d, + 0xb0,0xf0,0x75,0x4a,0x0d,0xb2,0xe2,0x26,0x54,0x8c, + 0x8c,0xc6,0xd9,0x11,0x03,0x8e,0x3d,0xeb,0x9d,0x87, + 0x38,0x87,0x61,0xb2,0x96,0x0f,0x23,0x9c,0x80,0x99, + 0xf1,0x33,0xfd,0x9e,0xae,0xd8,0xb9,0xad,0xfd,0xb5, + 0x04,0x60,0x61,0x51,0x1d,0x90,0xa2,0x61,0xb1,0xc5, + 0x72,0xe2,0x9f,0xf0,0x50,0x64,0xfe,0x5d,0xad,0xa9, + 0x61,0xe3,0x4d,0x6e,0x59,0x5e,0xf1,0x89,0x3c,0x5f, + 0x33,0x34,0x25,0x21,0xb1,0xa9,0x3c,0xbf,0x6d,0xef, + 0x38,0xa5,0x74,0xf3,0x22,0x44,0xbe,0xda,0x5b,0x0b, + 0x56,0x96,0xe0,0x92,0xba,0xb7,0xcd,0x18}, + .data_len = 128, + .mac = {0xd4,0x08,0x0a,0xb3,0x7e,0x75,0x98,0xc7,0x8f,0xb4, + 0xc5,0xe4,0x3e,0x95,0x48,0x30,0x78,0xc1,0xe1,0x5e, + 0x2b,0x01,0x5e,0xdb,0x30,0xa5,0xdf,0xe3,0xc7,0x39, + 0xe5,0xa9}, + .mac_len = 32, + }, { // 21 (151) + .key = {0x12,0xdd,0x35,0x38,0x7a,0x7d,0x0c,0xcb,0xb9,0x1f, + 0x4f,0xc9,0xaf,0xb0,0x87,0xa3,0xd8,0x49,0xb4,0x6b, + 0xd2,0xaa,0xef,0xe7,0x19,0xe4,0x4e,0xe4,0x16,0x55, + 0x08,0xcc,0x58,0xd9,0xd9,0x7b,0x21,0x3f,0xa8,0x4f, + 0x24,0xfa,0x68,0x7e,0x8d,0x19,0x3c,0xad,0x42,0x7a, + 0xde,0xbe,0x68,0x3a,0x41,0xe9,0x2a,0x6f,0x75,0x0e, + 0xb5,0x1a,0xcc,0x49,0x87,0x57,0x3b,0xc8,0xea,0xd7, + 0x02,0xd9,0xbb,0x90,0x8f,0x47,0x70,0xb3,0xa0,0xe7, + 0x5a,0xdf,0xa9,0x6e,0x26,0x94,0x75,0x85,0xaa,0xea, + 0x0f,0x20,0xdf,0x83,0xe3,0x0b,0x29,0xbe,0x21,0xc5, + 0xdf,0x2d,0x62,0x92,0x07,0x4a,0x8e,0xcc,0x61,0x65, + 0xfd,0x7a,0xa8,0xe1,0xdc,0x24,0x14,0xa0,0xd3,0xe5, + 0x23,0xbc,0xe4,0xc1,0x99,0x78,0x97,0x39}, + .key_len = 128, + .data = {0xfd,0x64,0xd1,0xd0,0x6d,0x7b,0x92,0xb7,0x7e,0x33, + 0xe3,0x99,0x97,0xec,0xf3,0xfc,0xf6,0x74,0xa5,0x45, + 0x3d,0x7d,0x36,0xce,0x2d,0x4e,0x21,0x38,0xb1,0xb8, + 0x3f,0x03,0x1e,0x4c,0x33,0x5b,0xb9,0xcb,0x05,0x35, + 0x7a,0xde,0x0d,0x9b,0x0f,0x07,0x13,0x44,0x24,0xd8, + 0xb4,0x68,0xe2,0x63,0x07,0xd2,0xb5,0xf1,0x81,0x37, + 0x53,0xf7,0x16,0xc6,0xfa,0x45,0xa1,0x00,0xf8,0x81, + 0x86,0xca,0x71,0xd4,0x96,0xc1,0x5d,0xe3,0x33,0xcd, + 0xd0,0x01,0xb4,0xf9,0x7e,0xa2,0x0b,0x82,0x7e,0x13, + 0xa4,0x2d,0x4e,0x69,0x91,0xde,0x18,0xb8,0xe5,0x67, + 0x33,0x85,0x5d,0x9e,0xed,0x7d,0x46,0xb2,0x88,0x67, + 0x9a,0xbf,0x82,0x57,0x6d,0x9f,0x1a,0x24,0x87,0x04, + 0x0f,0x1d,0x53,0xc3,0xab,0xf8,0xf8,0x73}, + .data_len = 128, + .mac = {0x30,0x87,0x11,0x76,0xe1,0x7a,0x7e,0x99,0xa6,0xfe, + 0x06,0xed,0x5d,0x67,0x9f,0x1f,0x07,0x04,0x9a,0xd4, + 0x45,0xea,0x91,0x22,0xf7,0x36,0xe4,0xf6,0x71,0x51, + 0xaa,0x6a}, + .mac_len = 32, + }, { // 22 (165) + .key = {0xd8,0x6f,0x48,0x54,0x18,0x03,0xcd,0x41,0x1f,0xc3, + 0x4a,0xce,0xab,0xc7,0x8c,0x66,0x0c,0x6c,0x83,0x06, + 0xd8,0x42,0x99,0x44,0xdf,0x25,0x42,0x91,0x61,0xa9, + 0xd4,0xbb,0x7f,0xbc,0x9a,0xb6,0xf0,0x86,0x23,0x9b, + 0xf5,0x94,0xe0,0xf1,0x8f,0x36,0xef,0x2c,0xef,0x25, + 0x31,0x73,0x2e,0x69,0xa2,0xa6,0x3e,0x7a,0xea,0xa0, + 0x21,0xa6,0x2f,0xb9,0x58,0xb2,0x2e,0x8f,0x9f,0xc4, + 0x8a,0x07,0xd7,0x81,0x63,0x8e,0x44,0x72,0x2b,0xa5, + 0xf8,0xac,0xb5,0x9c,0x8f,0xb0,0x8f,0x9d,0x1d,0x90, + 0x92,0xed,0x65,0x53,0xb7,0x6f,0x4c,0x9b,0x2d,0x6a, + 0x8d,0x85,0xa8,0x8b,0xad,0xd1,0xfb,0x2e,0x32,0x43, + 0xe9,0xd9,0x10,0x48,0x38,0x09,0x64,0xdd,0x08,0x32, + 0x64,0xad,0x63,0x01,0x96,0x79,0x15,0xe4}, + .key_len = 128, + .data = {0x3c,0x28,0x3b,0xad,0xcb,0xc4,0xcc,0x09,0xc1,0x00, + 0xff,0x01,0x6d,0x7e,0x3c,0x65,0x2f,0xb2,0x78,0x6a, + 0x37,0x96,0x14,0xfc,0x8f,0x9f,0x01,0x55,0x5c,0xf0, + 0x29,0xcf,0x61,0xcf,0x0a,0xf6,0xc4,0x55,0xa4,0xe2, + 0x15,0x69,0x96,0xc4,0x8c,0xef,0x84,0xbe,0x92,0x3c, + 0xbb,0xf8,0x83,0xcd,0x18,0xf0,0xb3,0x39,0x26,0x11, + 0xaf,0x65,0x86,0x88,0xc5,0xf7,0x94,0x53,0xc6,0x0d, + 0x47,0x9a,0x0a,0x2e,0x59,0x43,0xb5,0x81,0xa8,0xc1, + 0x39,0x3c,0xdd,0x2c,0x1c,0x60,0x4b,0x97,0xfc,0xa4, + 0x1a,0x9e,0xd0,0xae,0xa4,0x3e,0x70,0x89,0x1f,0xea, + 0x58,0x54,0x7d,0xda,0xa8,0x37,0x90,0xa7,0x70,0x9c, + 0x72,0x15,0x2b,0x9b,0x24,0x2f,0x89,0xb5,0x75,0x9a, + 0x72,0xc6,0x25,0x23,0x47,0x35,0x4b,0x9a}, + .data_len = 128, + .mac = {0xc0,0x1a,0x4e,0x9e,0x33,0x17,0x74,0xe5,0x49,0xa5, + 0x6d,0x23,0xce,0x49,0x59,0x24,0x9d,0x6a,0x0d,0xb0, + 0x6d,0x8c,0x42,0xa0,0x41,0x5a,0x99,0x69,0x7c,0x96, + 0xc2,0x37,0x98,0xf8,0xc1,0xd9,0x78,0xfd,0xce,0xaa}, + .mac_len = 40, + }, { // 23 (166) + .key = {0x04,0x17,0xb7,0xfd,0xaf,0x3b,0x20,0x80,0x27,0x14, + 0x15,0x68,0x5f,0xd8,0xbf,0xc4,0x7c,0x2c,0x05,0x71, + 0x37,0xf2,0x0c,0x8e,0x83,0x62,0xfe,0x31,0x70,0x5c, + 0x0b,0x58,0x50,0xfc,0xae,0x23,0x18,0x70,0x32,0x40, + 0x09,0x06,0x74,0xa6,0x8f,0x89,0xea,0x86,0x69,0xce, + 0xe4,0x7e,0x0a,0x8a,0x12,0x11,0x3f,0x66,0x47,0x54, + 0x13,0x56,0x7c,0xe9,0xf0,0x26,0x18,0x31,0x06,0x56, + 0x6f,0xbe,0xf0,0x27,0x88,0x07,0x95,0xf6,0x23,0x60, + 0x4d,0xc9,0xfa,0x29,0x46,0x28,0x48,0x45,0x25,0x2e, + 0x88,0xce,0xf0,0xdf,0x7f,0x06,0x2b,0xbc,0x7c,0x91, + 0x41,0x95,0xdf,0xe2,0x26,0x9f,0xd8,0xf4,0x3b,0xc6, + 0x71,0x3a,0x72,0x44,0xcf,0xd8,0xb2,0x73,0xb4,0x13, + 0x7d,0xdf,0x49,0x06,0xd0,0xa0,0x1b,0x97}, + .key_len = 128, + .data = {0xbd,0xb0,0xcf,0x79,0x96,0x62,0x48,0xa6,0x8d,0x3f, + 0xa4,0xf9,0xa1,0x22,0xe4,0xc1,0xf1,0x78,0x4e,0x7c, + 0x16,0x47,0x62,0xf7,0xb6,0x70,0x11,0xb7,0x56,0x31, + 0x2a,0x98,0x70,0xed,0x15,0xb4,0xc6,0x30,0xc3,0x86, + 0xf5,0xee,0xe5,0x50,0x4d,0x0b,0x5c,0xb9,0xe0,0x20, + 0xf1,0xbb,0xd9,0x7d,0x47,0xbc,0x10,0x6a,0x0d,0xfb, + 0xdb,0xb3,0x78,0x2e,0x26,0x63,0xf1,0x6a,0xc6,0xcf, + 0x0b,0x42,0x0a,0xd6,0xb7,0x33,0x93,0x68,0xbb,0x40, + 0x66,0x45,0x60,0xd9,0x40,0x07,0x6b,0x01,0x2a,0x63, + 0x4f,0xb0,0x4c,0xac,0xa1,0x76,0x06,0x98,0xcc,0x62, + 0x3d,0x47,0x06,0x22,0xf3,0x81,0x83,0x6b,0x1b,0x40, + 0xe8,0x9c,0xab,0x6e,0x02,0x9e,0xf2,0xef,0xb8,0x0e, + 0x2c,0xe2,0x3e,0x9e,0x54,0x24,0x8c,0xb8}, + .data_len = 128, + .mac = {0x4f,0x88,0x23,0xe7,0x6c,0xf5,0x77,0x7c,0x21,0xdc, + 0x05,0xeb,0xe4,0x07,0x17,0xfe,0x55,0x9f,0xbf,0x9c, + 0xfa,0x82,0x74,0xcc,0x34,0xf7,0x42,0x96,0x2f,0x65, + 0x83,0xc7,0xa9,0x2b,0x26,0x8e,0x5f,0x6d,0x76,0xf3}, + .mac_len = 40, + }, { // 24 (180) + .key = {0x3d,0x8e,0x7d,0x7e,0xc3,0x0c,0x16,0xb7,0x47,0x2e, + 0xe0,0x07,0x8b,0x04,0xbe,0x96,0xa9,0x8c,0xbe,0x06, + 0x49,0x1e,0xf0,0xf8,0x17,0x07,0x79,0xd1,0x75,0x75, + 0xe3,0xbe,0x6c,0x93,0xb7,0xf5,0xe9,0xf4,0x4e,0x3e, + 0x26,0x35,0xe4,0xb2,0x66,0xde,0xee,0xc3,0xe5,0x8a, + 0xad,0x7d,0x0f,0x48,0x04,0x0c,0xf0,0x40,0x87,0x7d, + 0xec,0x9a,0xd4,0xc9,0xb0,0x9b,0x26,0x0f,0x68,0x11, + 0x27,0x21,0x32,0xf2,0x06,0x42,0xd3,0x40,0xca,0x2e, + 0xaa,0x2f,0xe6,0x5b,0xe2,0x8a,0x0d,0x7f,0xeb,0x53, + 0x47,0x52,0x2a,0xaa,0x45,0x95,0xef,0xef,0xf1,0x53, + 0xa8,0x2b,0x4a,0x67,0x55,0xac,0x6f,0x3e,0x3c,0xf0, + 0xf9,0xde,0xde,0xc5,0x8e,0x27,0x29,0xad,0xb4,0x59, + 0xef,0x87,0xe2,0xd7,0x97,0x6c,0xdd,0x2b}, + .key_len = 128, + .data = {0x1d,0x00,0xe4,0x40,0x02,0x6f,0x7e,0xfd,0x6d,0x88, + 0x64,0xfb,0xa4,0x8a,0xa6,0x97,0xe6,0xc9,0x1c,0xe0, + 0x4e,0x01,0x5f,0x93,0xfb,0xea,0x19,0x4a,0x6e,0x0c, + 0x7f,0xf0,0x33,0xd5,0x1b,0x78,0xc4,0xe9,0xcf,0xce, + 0xaa,0xb9,0x17,0x0e,0xe5,0x57,0x8e,0xf5,0x8e,0x89, + 0xb4,0x95,0xbb,0x1c,0xee,0x4c,0xa3,0x7a,0xce,0xf6, + 0x03,0x7f,0x95,0x62,0xc0,0x89,0xf6,0x03,0xcd,0xce, + 0x1d,0xe8,0x4f,0xf3,0xf0,0xee,0xff,0xda,0x95,0x35, + 0xd0,0xbb,0x34,0xd0,0xd3,0x76,0xfe,0xc1,0x57,0x27, + 0x6e,0x24,0x54,0xfb,0xce,0xaa,0x0a,0x43,0xfe,0x49, + 0xe5,0xc7,0x71,0x32,0xa4,0x5d,0x78,0x04,0xba,0xba, + 0xc3,0x3f,0xf4,0x87,0x24,0xfb,0x5d,0xb8,0x97,0xda, + 0x5f,0x19,0x80,0x3b,0x2a,0x29,0x33,0xb0}, + .data_len = 128, + .mac = {0x3c,0x27,0x0d,0xf9,0x9f,0x8b,0x2a,0xb1,0x66,0xfd, + 0x29,0xd5,0xfb,0x34,0x7c,0x7a,0xe5,0xda,0xef,0x69, + 0x7f,0xc2,0x0b,0x40,0x8d,0xd6,0xf0,0x1b,0x15,0xc7, + 0x13,0xf1,0xc6,0x26,0x44,0x2d,0xbe,0x5d,0xaf,0xe3, + 0x28,0x7f,0x2e,0x2c,0x86,0x51,0xc3,0x32}, + .mac_len = 48, + }, { // 25 (181) + .key = {0xed,0x8f,0xe5,0x23,0xdd,0xc1,0x93,0x92,0x62,0xfa, + 0xcd,0x6d,0x72,0x2b,0x56,0xbf,0xf6,0x67,0x83,0xd4, + 0x22,0xe8,0x37,0x56,0x02,0x53,0x11,0xb6,0x56,0x3c, + 0xe4,0xcd,0xa0,0xed,0x68,0xc4,0x7b,0x63,0x2f,0x31, + 0x2e,0x9a,0xda,0x82,0x81,0x0b,0x8c,0x9f,0xd0,0x72, + 0x9f,0xcb,0x5d,0xd4,0x96,0xcb,0xea,0xc1,0x53,0x4b, + 0x88,0xd7,0x8b,0x7d,0xaa,0x87,0x76,0x03,0x7d,0x1c, + 0xcb,0x0f,0x7c,0xf8,0xeb,0xc9,0x3f,0x21,0x5c,0xf1, + 0x93,0xfd,0x7a,0xc5,0xd0,0x5a,0x69,0x25,0x67,0xb1, + 0x4e,0xf5,0xbb,0xac,0xbf,0xc3,0x32,0xe5,0x78,0xa9, + 0x8b,0xf1,0x4f,0x75,0x72,0x9d,0x6a,0x08,0x51,0x77, + 0xaf,0xfc,0x6a,0x91,0x7c,0x8a,0x23,0x81,0x98,0xaa, + 0xa0,0xac,0x6a,0x7b,0x97,0xc5,0x69,0xe6}, + .key_len = 128, + .data = {0xc0,0xff,0xbe,0x82,0xe2,0xaa,0xc8,0x7b,0xf2,0xcb, + 0xaf,0x24,0x16,0x43,0xe0,0x0b,0x34,0xac,0x99,0x41, + 0xaa,0x3f,0x43,0x5f,0x40,0xf4,0x02,0xc7,0x5a,0xea, + 0x8a,0x2c,0x73,0x0a,0x34,0x55,0xc6,0xe8,0x51,0x1d, + 0x4e,0xe9,0xbe,0xbf,0xf1,0xab,0xb9,0x50,0xf9,0xa1, + 0xf2,0x8d,0xc3,0xfe,0xe5,0xd7,0xbb,0xd5,0x68,0x7c, + 0x88,0x7e,0x80,0x38,0x83,0x3b,0x79,0xfc,0x6e,0x1b, + 0x36,0xed,0x63,0x1f,0xc5,0xb0,0x0a,0x9c,0x36,0xe5, + 0x0f,0xe0,0xae,0xf1,0xd3,0x18,0xb7,0x01,0x62,0x72, + 0xda,0x4c,0xa6,0x7e,0x70,0x98,0xda,0xda,0xb5,0xff, + 0x40,0x0e,0x1e,0xf3,0x17,0xb5,0xed,0x80,0xc8,0xde, + 0x02,0xd1,0x60,0xb1,0xf4,0xf6,0x42,0x56,0x60,0xe4, + 0x1e,0x12,0x81,0xbd,0x1d,0xb3,0x01,0x52}, + .data_len = 128, + .mac = {0xb9,0x4c,0xd9,0x4b,0x82,0xf7,0xcb,0xc2,0xa9,0x92, + 0xb4,0x13,0x49,0x9e,0x94,0x1c,0x03,0x01,0xed,0x87, + 0x14,0xc5,0xe0,0x7b,0x3b,0xad,0xec,0x2b,0xe1,0x79, + 0x75,0x6f,0x99,0x6e,0x33,0x80,0x25,0xfb,0x35,0xdc, + 0x72,0x9f,0x96,0x71,0x7c,0x5e,0xf8,0xb3}, + .mac_len = 48, + }, { // 26 (195) + .key = {0xfc,0x58,0x50,0xb2,0x5c,0xdb,0x1b,0x94,0x31,0x2f, + 0xe0,0x3f,0x7c,0xa6,0xbb,0x31,0x59,0x35,0xda,0xb4, + 0x79,0x1c,0x8b,0xa5,0xd2,0xc9,0x99,0x7a,0x95,0xfa, + 0xd9,0x84,0x61,0x23,0x00,0x70,0xb6,0x0f,0xb7,0x14, + 0xac,0xc9,0xf2,0x69,0xe5,0xbd,0x7d,0xd3,0xc0,0x1b, + 0xd7,0xa9,0xcf,0x7c,0x44,0xf1,0x8c,0xc8,0x1e,0x6b, + 0x47,0x57,0x6c,0xd2,0x63,0x56,0xb6,0x5e,0xc2,0x6d, + 0x17,0x8d,0x7e,0x9e,0x93,0x23,0xda,0x71,0xab,0x6f, + 0x78,0x4e,0x2f,0xd1,0xcc,0x2a,0x54,0x79,0xd0,0x66, + 0x06,0x71,0xf9,0xf3,0x7f,0xde,0x6a,0xbb,0x19,0x83, + 0x69,0x3c,0x60,0x86,0x0f,0x76,0x6c,0x77,0x43,0x08, + 0x6e,0x8e,0xe9,0x96,0x88,0x34,0x56,0x6d,0xe2,0xc5, + 0x07,0x6a,0xfa,0x95,0x93,0x18,0x3b,0x31}, + .key_len = 128, + .data = {0x85,0xd0,0x9b,0xe1,0x0a,0xd0,0x30,0xa5,0x76,0xa8, + 0x96,0xeb,0x7c,0x4c,0xbf,0x6d,0x3f,0x6a,0x74,0x60, + 0x6f,0xfb,0x9a,0xa7,0xb5,0x19,0xb3,0x47,0x52,0x10, + 0xa8,0x1b,0x03,0xb7,0xc5,0xc9,0x27,0x01,0x05,0xf4, + 0x23,0xcf,0x90,0xb3,0x06,0x08,0x82,0x42,0x69,0xec, + 0xee,0xf8,0x9a,0xa5,0x23,0x79,0xf9,0x1f,0x2d,0x2d, + 0xa1,0x1a,0x9f,0xf1,0x4b,0x7e,0x90,0x0c,0x70,0xee, + 0xe4,0x64,0xae,0x9f,0xcd,0xf2,0x6d,0x6b,0x90,0x73, + 0xc2,0x21,0x8d,0x60,0x94,0x20,0x7a,0x21,0xfd,0x24, + 0xef,0x7e,0xf2,0x5f,0x27,0x56,0x27,0xcc,0x05,0x93, + 0x2d,0xc0,0x55,0x5d,0xdd,0xc2,0x55,0x8e,0xfa,0x9c, + 0x73,0x66,0x12,0xb2,0x59,0x81,0xa5,0x93,0x27,0x05, + 0x8a,0xce,0xff,0x20,0x8d,0x07,0xc7,0xb2}, + .data_len = 128, + .mac = {0x7a,0x90,0xa3,0xf4,0xa4,0x7d,0xd2,0x62,0xf3,0x02, + 0xd2,0x57,0xd6,0xac,0xb9,0x16,0xff,0x81,0x92,0xb8, + 0xd2,0xd4,0x53,0x91,0x19,0xfd,0x72,0xc2,0xb7,0x81, + 0x21,0x94,0xcf,0xee,0xf3,0x4a,0x8c,0x3c,0xbd,0x32, + 0x05,0x7a,0x74,0x77,0x08,0x5c,0xaf,0x72,0x91,0xff, + 0x7f,0x83,0xac,0xdc,0x1d,0x7b}, + .mac_len = 56, + }, { // 27 (196) + .key = {0xb1,0xa8,0x5a,0xae,0xe5,0x5a,0x9b,0x2b,0xf4,0xe2, + 0x28,0x4e,0x66,0x32,0x82,0xa9,0x5c,0x7e,0x56,0x44, + 0x89,0x38,0xa1,0x35,0x7f,0x3f,0x17,0x71,0x2c,0x54, + 0xc6,0xe2,0xa4,0xcd,0xf7,0xba,0x21,0x8d,0x55,0x06, + 0x47,0x33,0x51,0x86,0xad,0x92,0xc4,0xbc,0x9a,0x62, + 0xd6,0x43,0x0c,0x34,0x20,0x62,0xff,0xac,0x0d,0xe1, + 0xeb,0xea,0x86,0x1b,0x8f,0x49,0xce,0x55,0xed,0x4c, + 0xaa,0x4e,0x96,0xd5,0xc6,0x17,0x27,0x98,0x54,0x25, + 0x14,0xd0,0xf6,0xa5,0xa4,0x30,0xde,0x0f,0x3d,0x1d, + 0x33,0xfe,0xe2,0x1a,0xb7,0x3f,0xfa,0x84,0xa8,0x28, + 0x53,0x7f,0xe4,0x2b,0x66,0x30,0x50,0xab,0xdd,0x2d, + 0x79,0x0d,0x52,0x31,0x7c,0x13,0x5a,0x15,0x24,0x65, + 0xc2,0xfb,0x53,0x71,0x18,0xcd,0xa3,0x75}, + .key_len = 128, + .data = {0x7f,0xd1,0x2b,0x61,0x60,0x30,0x47,0x9e,0x30,0x66, + 0xee,0x0a,0x0f,0xa6,0xdc,0x7d,0x40,0xb5,0x0b,0x1a, + 0x2c,0xe6,0xd6,0xdf,0xaa,0x48,0x5e,0x7a,0x7d,0x1e, + 0x2d,0x5e,0x1e,0x8f,0x19,0x17,0xbd,0x9f,0x6b,0xda, + 0x82,0x5e,0x41,0x61,0x18,0x5f,0x31,0xf6,0x6c,0x6c, + 0x2f,0xcd,0xb2,0x78,0xb1,0x96,0xaa,0xd5,0x11,0x53, + 0x21,0xa8,0x32,0x67,0xba,0x99,0x66,0xf0,0xee,0xcf, + 0x8f,0x57,0x52,0x1b,0x85,0x26,0x18,0x73,0xb8,0x19, + 0xd9,0xa3,0x17,0x77,0x92,0x3f,0x30,0xa2,0xec,0xdc, + 0x98,0xed,0xc0,0x7f,0x8d,0xaf,0xda,0x56,0xda,0x96, + 0xfd,0xa6,0xfb,0x3d,0x28,0x05,0x82,0x00,0x18,0xc9, + 0xb9,0x0f,0x0e,0xc0,0x89,0xc1,0xd2,0x22,0x9a,0x2b, + 0xf8,0xc3,0xbc,0xf2,0x62,0x8d,0x86,0x5d}, + .data_len = 128, + .mac = {0xdf,0x5c,0x22,0x8b,0xeb,0xab,0xdd,0x4d,0x48,0xcd, + 0xa2,0x0a,0x86,0x9f,0x12,0xe6,0xd4,0x4f,0x1c,0x88, + 0x1a,0x28,0x83,0x2e,0xd4,0xd5,0xe4,0x04,0xd9,0x18, + 0x17,0xe3,0x96,0x9a,0x36,0x13,0x7f,0x6c,0x06,0x2e, + 0x4c,0x97,0x50,0x2f,0xd8,0x7f,0x48,0x94,0x48,0x08, + 0xa6,0x6b,0xe3,0xbe,0x39,0x23}, + .mac_len = 56, + }, { // 28 (210) + .key = {0xe9,0xe4,0x48,0x0d,0x1c,0x4a,0x62,0x1e,0x0c,0x4e, + 0x15,0x05,0x99,0x25,0x56,0x34,0x7a,0x7a,0xb3,0x4f, + 0xd2,0xb2,0x89,0x91,0x04,0x74,0x76,0x6c,0xc9,0x69, + 0x11,0x6f,0x80,0x40,0xd9,0x6d,0xc5,0xf6,0x6c,0xdc, + 0x44,0x54,0xfa,0x7b,0xcf,0xb9,0xf8,0x38,0xaf,0x19, + 0x19,0x50,0x38,0x46,0x7a,0xb8,0xa1,0x6e,0x1c,0xbc, + 0x12,0xe5,0x98,0xe6,0xfd,0x25,0x0e,0x21,0xb2,0x14, + 0x5f,0x1e,0x2e,0x85,0x9c,0xf7,0x34,0x00,0xbe,0x12, + 0xa0,0xc6,0x97,0x49,0xf7,0x10,0x08,0x47,0x42,0x98, + 0x75,0x35,0x1d,0x5a,0x76,0x97,0x0b,0x9c,0xcf,0x70, + 0x0c,0x2c,0xa3,0xad,0x72,0xe9,0xe4,0xc0,0xf0,0x84, + 0x0e,0x8c,0xf4,0x88,0x15,0x81,0x36,0x98,0x9b,0x08, + 0x91,0xf8,0x67,0x21,0x13,0x50,0x13,0x4a}, + .key_len = 128, + .data = {0xb8,0x2e,0xef,0xb2,0x08,0x1b,0xd1,0x4d,0xab,0x0e, + 0x9e,0x34,0x52,0x48,0xa3,0x4a,0xde,0x73,0xf3,0x29, + 0x18,0x86,0xb9,0x1e,0xa3,0xe8,0xcc,0x74,0x2f,0xd8, + 0x84,0xf6,0xee,0x0c,0xcd,0xaf,0x4c,0x98,0x79,0xf4, + 0xdb,0x12,0xdb,0xa5,0x8c,0xf4,0x91,0xaf,0x25,0x41, + 0xa1,0xd5,0xef,0x6c,0xc8,0xb1,0xaf,0x75,0x0e,0xf5, + 0xd8,0x55,0x9e,0xf7,0xff,0x9c,0xd5,0x6d,0x8f,0x59, + 0x99,0x74,0xbe,0x3a,0xec,0xd8,0xc0,0xf4,0xc0,0x8f, + 0x3a,0xe5,0x0d,0x86,0xf9,0xf8,0x22,0xa1,0xe4,0xca, + 0x39,0xfd,0x2f,0x0b,0x4d,0x78,0xd2,0x26,0x30,0x73, + 0x3a,0x24,0xd8,0xd6,0x3e,0xcd,0xf9,0x55,0x54,0x11, + 0xda,0xf2,0x05,0xa7,0x61,0xc3,0x9e,0xf4,0x6f,0xf6, + 0x29,0x2e,0x74,0x12,0x9b,0xc1,0x3a,0x7f}, + .data_len = 128, + .mac = {0x90,0x09,0x3b,0xdc,0xc4,0x5d,0xa7,0x33,0x8b,0xd2, + 0xef,0xe9,0x2e,0x30,0x93,0x3b,0x14,0xf7,0x55,0x82, + 0x73,0x9c,0x74,0x7f,0x75,0x72,0xb3,0x27,0x0b,0x10, + 0x4f,0x33,0xaf,0x0c,0x93,0x9e,0x3c,0x8a,0xe5,0x3b, + 0x20,0x66,0xfc,0x8c,0x97,0xcc,0xf3,0x87,0x85,0xcd, + 0x2e,0xc3,0xd7,0x9e,0x69,0x46,0x49,0x9d,0x36,0x12, + 0x1e,0x44,0xa3,0xe7}, + .mac_len = 64, + }, { // 29 (211) + .key = {0xd3,0xfb,0xd6,0xfe,0x4e,0x35,0x6a,0xc1,0xc8,0xc1, + 0x20,0xd4,0x32,0xd7,0x20,0x4d,0x9d,0x57,0x9b,0x2a, + 0x5a,0x5d,0x0c,0x8b,0x60,0x16,0xbd,0x1e,0xef,0xd3, + 0x8d,0xda,0x73,0x5c,0xf2,0xf0,0xab,0x87,0x3a,0xfe, + 0x0a,0x09,0x16,0x86,0x5e,0x8b,0x58,0xa0,0xaf,0x01, + 0xfc,0xeb,0x6a,0x37,0x65,0xc9,0xbf,0xac,0xea,0xcc, + 0x47,0xa4,0x91,0x6b,0xea,0x79,0x1a,0xfa,0x00,0x32, + 0x40,0xd9,0xb6,0x56,0x3b,0xeb,0xb3,0x03,0x89,0x49, + 0xfc,0x3a,0xee,0x38,0x15,0x7d,0xba,0x59,0x6a,0x9c, + 0x4a,0x20,0xed,0xcc,0xd1,0x87,0xff,0xf9,0x59,0x04, + 0x94,0x5d,0x04,0xb8,0x92,0x52,0x98,0xe9,0x7b,0x64, + 0x3a,0xb2,0x4c,0xab,0x7a,0xf9,0xa5,0x58,0x90,0xa2, + 0x29,0x8d,0xe5,0x02,0x28,0x72,0xd6,0x97}, + .key_len = 128, + .data = {0xb9,0x67,0xc7,0xd9,0xc0,0xa9,0x41,0xf0,0x2e,0x87, + 0x72,0x3c,0xf2,0x82,0xea,0xda,0x43,0x47,0xb2,0x81, + 0x93,0xd3,0xe0,0xbf,0xbe,0xda,0x69,0x85,0x88,0x6a, + 0x37,0xe6,0x46,0xcc,0x7b,0x1c,0xdb,0xab,0x45,0xcc, + 0xe6,0x77,0x52,0x8b,0x3a,0x0c,0x24,0xa0,0x8f,0x8f, + 0x58,0x0b,0x77,0x99,0x35,0xc7,0x93,0x98,0x81,0x4d, + 0x06,0x72,0x98,0x59,0x2a,0x6b,0xbf,0xf0,0x82,0x48, + 0xb5,0xa2,0xf0,0xb4,0x8b,0x0d,0x28,0xe4,0xb6,0xa2, + 0x65,0x77,0x63,0xac,0x5b,0xa0,0x0a,0x8d,0x6c,0x86, + 0x46,0x4b,0x1e,0xeb,0xe4,0x4c,0xcd,0x0c,0x39,0x5e, + 0x9d,0xc9,0xb9,0xfb,0xb3,0x06,0xc6,0xca,0xa5,0x51, + 0xc6,0x68,0x2e,0xc5,0x78,0x69,0x27,0x2e,0x88,0x9a, + 0xb2,0x6e,0x61,0x89,0xb9,0x1f,0x42,0x48}, + .data_len = 128, + .mac = {0xbc,0x9a,0x83,0xd7,0x82,0xe5,0x0b,0xa5,0xa8,0x01, + 0x14,0x6f,0x8d,0xa3,0x90,0x95,0xd9,0x23,0x87,0xd7, + 0x59,0xeb,0x4a,0xd5,0x2b,0xbd,0x9e,0x99,0xd9,0xf6, + 0x8f,0x4a,0x0f,0x6f,0x64,0x70,0xc6,0x53,0xc4,0x59, + 0x79,0xc2,0xe1,0x95,0x43,0x80,0x4c,0xed,0x59,0x2e, + 0xe9,0xc5,0x3e,0xb6,0x8a,0x5b,0x1b,0x77,0x46,0xed, + 0x40,0x3e,0xbe,0x67}, + .mac_len = 64, + }, { // 30 (225) + .key = {0x9c,0xe6,0x6b,0xe0,0xe1,0x6f,0x03,0xba,0xae,0x35, + 0x67,0xae,0xb7,0xae,0x84,0x00,0xfe,0x60,0x14,0x99, + 0x99,0x9c,0x7b,0x5a,0xb6,0x68,0xef,0xb0,0xdc,0xbd, + 0xdc,0x69,0x74,0xf3,0x87,0xc6,0x87,0x79,0xf1,0xd1, + 0xc9,0xc9,0xfe,0xf0,0xd7,0x9b,0xd6,0xbb,0xbd,0x59, + 0x8c,0x0b,0xbb,0xd4,0xfe,0x53,0x49,0x35,0xfc,0x34, + 0x58,0x36,0xac,0x4b,0xdb,0x92,0x2c,0x4e,0x86,0xb9, + 0x7a,0x57,0xd5,0xc9,0x91,0x7f,0x51,0xba,0xd5,0xaf, + 0x0f,0xd8,0xb1,0xb3,0x79,0x77,0x7f,0x90,0x50,0xe2, + 0xa8,0x18,0xf2,0x94,0x0c,0xbb,0xd9,0xab,0xa4,0xa0, + 0x65,0x99,0x65,0xf5,0xdb,0x1d,0x68,0x83,0xad,0x72, + 0x49,0x85,0xfc,0xc6,0xcd,0xba,0x5b,0xed,0xc7,0xb9, + 0xd6,0x57,0x3c,0x85,0x33,0x3f,0xc5,0x61,0x77,0x26, + 0x35,0xe5,0xac,0x80,0x7c,0x52,0xe2,0xad,0xcb}, + .key_len = 139, + .data = {0x64,0x56,0x64,0x3e,0x93,0x19,0x66,0x95,0xb4,0x84, + 0xf8,0xa3,0x81,0x79,0x48,0x6c,0x3e,0x3b,0x57,0x7a, + 0x9c,0xc8,0x00,0xd2,0xdc,0x69,0x36,0x28,0x37,0x87, + 0x8d,0x4f,0x7e,0xc0,0xfb,0xf3,0xfe,0x3a,0xe0,0x8a, + 0xa6,0x37,0x45,0x88,0x6c,0xea,0x61,0xd2,0xec,0x8a, + 0x62,0x76,0x52,0xa4,0x6a,0x99,0x7b,0xb5,0xd7,0xb1, + 0x57,0xf8,0xc7,0xf4,0x92,0x7d,0xdb,0x0f,0x73,0x7b, + 0x3c,0x1c,0x04,0xe7,0xdc,0xce,0x73,0x45,0xff,0xef, + 0xb8,0xbf,0xf9,0x0d,0x78,0x74,0x39,0x70,0x29,0x12, + 0x86,0x4f,0x78,0xa7,0x89,0x43,0xe7,0xb4,0x8c,0xfb, + 0xbb,0x84,0x81,0x32,0x15,0xbb,0x46,0xde,0x5f,0x32, + 0x27,0xaa,0xe9,0x02,0xa5,0xa7,0xd4,0xdf,0x75,0x3e, + 0x30,0xa8,0xcc,0x6a,0x61,0x3b,0xda,0x24}, + .data_len = 128, + .mac = {0x27,0x97,0x3b,0x34,0x57,0xc6,0xbd,0x41,0x36,0xa3, + 0x3a,0xc6,0x1d,0x41,0xd5,0xdd,0x43,0x95,0xdb,0xd0, + 0x48,0x7d,0xa6,0x5a,0x0e,0x4e,0xb3,0x69,0xd9,0x48, + 0x2d,0x2b}, + .mac_len = 32, + }, { // 31 (226) + .key = {0x86,0x47,0x45,0x38,0x89,0x47,0x6b,0x94,0x4e,0xaf, + 0x55,0xb9,0x7b,0x9a,0x7b,0xcc,0xec,0x87,0x36,0x57, + 0x55,0x67,0x80,0xfa,0x29,0xf4,0xfb,0x5e,0xbb,0x45, + 0x36,0x6b,0xa4,0x9f,0x2b,0xbb,0x64,0x8f,0x0c,0x4e, + 0x4c,0x35,0x3f,0x7f,0x9b,0xe3,0xa7,0x36,0xe7,0xe7, + 0x25,0x60,0xbe,0xa4,0x5e,0x9c,0x8e,0xe8,0xbf,0x37, + 0xc2,0x79,0xbf,0x5b,0x2e,0xf1,0x64,0x83,0xad,0xcc, + 0x09,0x32,0x08,0xc0,0x5e,0xe5,0x1a,0x4d,0xb0,0x46, + 0x32,0x94,0x6b,0xa2,0xb9,0x6c,0xdd,0x9d,0x15,0xb3, + 0x3c,0x25,0xcc,0xe2,0xeb,0xa4,0xed,0xe4,0xf9,0x7a, + 0xac,0x29,0xeb,0xaa,0x4c,0xf6,0xbb,0xd3,0x42,0xff, + 0x20,0x63,0x97,0x37,0x10,0x07,0x8e,0xe7,0x83,0x66, + 0x87,0xfd,0x7b,0x0e,0x23,0xa7,0x41,0xae,0xa9,0x21, + 0xf1,0x87,0xa8,0xcc,0x38,0x1d,0xde,0x7f,0x5d}, + .key_len = 139, + .data = {0x8d,0x4f,0x4a,0x89,0x6a,0x5d,0x6f,0x68,0x1c,0x95, + 0x1d,0xa1,0xee,0xe6,0x14,0x3c,0xd8,0x3a,0x27,0x17, + 0x50,0xfb,0xa8,0x87,0x62,0xd5,0x21,0x42,0x03,0xbe, + 0x44,0x7d,0xa3,0x34,0x25,0x51,0x01,0xc6,0xa7,0x63, + 0x43,0xd6,0x34,0xc4,0x46,0x9d,0xb2,0x16,0x33,0x70, + 0xb2,0xf1,0x53,0x41,0xea,0x85,0x24,0x68,0xe5,0x80, + 0xac,0xa4,0xf9,0x32,0x0d,0x5c,0x7a,0xee,0x5a,0x2b, + 0x2d,0xb4,0xa9,0x9c,0xff,0x0e,0x69,0x32,0xf7,0x38, + 0xf6,0xac,0x6a,0x83,0x6b,0x86,0x6e,0xfb,0xb8,0xc3, + 0x90,0x48,0xf4,0xea,0xca,0xd2,0xf4,0x4f,0xaf,0x29, + 0x1c,0x93,0xe9,0xa3,0x75,0x6e,0xe5,0x47,0x00,0xac, + 0xcd,0xe9,0x4a,0x76,0xb7,0x97,0x41,0xd3,0x1c,0x34, + 0x46,0x6f,0x8b,0x63,0x83,0x9a,0x9e,0xa7}, + .data_len = 128, + .mac = {0x54,0xa6,0xfe,0x35,0x15,0xe8,0x42,0x98,0xc9,0xe3, + 0xb1,0xf2,0xeb,0x6f,0x23,0x8f,0xad,0x2c,0xf6,0x1f, + 0x4e,0x2e,0x96,0x86,0x46,0x4e,0x08,0x7e,0xce,0x45, + 0x67,0xc3}, + .mac_len = 32, + }, { // 32 (240) + .key = {0xf3,0xe8,0x1c,0x3d,0xcf,0xa5,0x30,0x5c,0x9f,0xf1, + 0x5e,0xdf,0x30,0x31,0x03,0xfd,0xed,0xf7,0xfc,0x73, + 0xaf,0x84,0x15,0x25,0xd7,0x8b,0xc4,0x09,0x9b,0x38, + 0x18,0x41,0x9d,0x71,0xec,0x87,0xc2,0x5c,0x60,0xce, + 0x41,0x21,0x8a,0x26,0xfa,0xf1,0x68,0xe1,0x0a,0x47, + 0x19,0xf4,0x9c,0x6d,0x4d,0xa0,0x01,0x43,0xfb,0x51, + 0x04,0x3c,0x52,0xc6,0x77,0xa9,0xf1,0x72,0x12,0x3a, + 0x5a,0x22,0x7e,0xc1,0xa4,0xe1,0xac,0x3a,0x71,0x18, + 0x6b,0x09,0x20,0xfa,0x3a,0x82,0x44,0x1f,0x5a,0xae, + 0x54,0x6f,0x28,0x4c,0xa4,0x42,0xaa,0x17,0x93,0xc6, + 0x68,0x47,0x06,0xa0,0x7d,0x5a,0x16,0xd6,0xed,0x14, + 0x06,0xec,0x39,0xc5,0x78,0x4d,0x31,0xca,0xe0,0xed, + 0x0a,0x56,0x38,0x2d,0xb0,0x73,0xf6,0xff,0x5d,0x43, + 0x3b,0x4a,0x6b,0x8c,0x4d,0x90,0x67,0x73,0x47}, + .key_len = 139, + .data = {0x15,0x5e,0x66,0x93,0x6d,0x31,0x9f,0x16,0x9d,0xb5, + 0x19,0xd5,0x17,0x63,0xf9,0xb4,0x3d,0xe5,0xd5,0x41, + 0x77,0xd5,0x68,0x97,0x83,0xc8,0x8b,0x82,0x0d,0x8b, + 0x61,0xe3,0x80,0xac,0xd1,0x56,0x1b,0x3c,0x39,0x13, + 0x47,0xd4,0x60,0x12,0x28,0xd6,0xad,0x73,0x72,0xf5, + 0x97,0x1c,0x7e,0xf8,0x5d,0xa4,0x9d,0xba,0xf7,0x70, + 0xac,0x76,0x4c,0x1b,0xe8,0x41,0xa5,0x1b,0x04,0xd8, + 0x62,0xa2,0x79,0x9c,0xec,0xc3,0x1e,0xdb,0xea,0xd6, + 0xf8,0x51,0xb8,0x1d,0x53,0xef,0x14,0xa8,0x11,0xdb, + 0x1b,0x75,0x43,0xb7,0x75,0xdc,0xf6,0x26,0xcc,0x2a, + 0x4f,0x8c,0x82,0x8d,0xdb,0x16,0xa3,0x30,0x20,0xfb, + 0x18,0xa6,0x78,0x01,0x1e,0x8c,0x1f,0x42,0xf7,0x6a, + 0x8a,0x30,0xdf,0xdb,0xfa,0xd7,0x42,0xee}, + .data_len = 128, + .mac = {0x62,0x51,0x62,0x8d,0x0e,0x65,0xb0,0xaa,0xc3,0x04, + 0x69,0x5a,0x20,0x59,0xfb,0x7c,0xdd,0x6e,0x78,0x7b, + 0x6d,0x37,0x87,0xea,0x54,0x4a,0x4a,0x53,0xe8,0x61, + 0xbf,0x54,0x67,0xd9,0xd3,0xfa,0xa8,0xcc,0xa1,0x3e}, + .mac_len = 40, + }, { // 33 (241) + .key = {0xfb,0xbb,0xdd,0x42,0xe5,0xfc,0x63,0x19,0x68,0x98, + 0x5c,0x06,0x57,0xec,0x42,0xef,0x0d,0xb1,0x7a,0xf0, + 0x49,0x7e,0xcf,0xfe,0x3d,0x8e,0x1f,0xca,0xe1,0xc4, + 0x54,0xe8,0x8d,0xec,0x96,0x31,0xc7,0x44,0xc0,0x66, + 0x5a,0x3b,0x10,0x16,0xa8,0x78,0x22,0xc1,0x40,0x1e, + 0x1f,0x3d,0xb3,0x4f,0x32,0x59,0xa4,0xef,0x3b,0xc1, + 0x1f,0xaa,0xc8,0x21,0x2c,0x38,0x41,0x8d,0xa3,0xdf, + 0x62,0x21,0x41,0x3a,0xee,0xe4,0xfc,0x3a,0xa2,0xf2, + 0x94,0x6a,0x68,0xdb,0x6b,0x77,0xce,0x46,0x96,0xef, + 0xb6,0xda,0x34,0x49,0x4f,0x5e,0xfe,0x26,0x44,0x1e, + 0x20,0xd6,0x33,0x91,0x48,0x1e,0x60,0x3a,0xfc,0x38, + 0xab,0xcc,0x30,0x1c,0xbf,0x91,0x18,0xfe,0x8d,0x0c, + 0x3b,0x18,0xf9,0xde,0xc9,0xa9,0xd2,0xe6,0x2e,0x3e, + 0x08,0xac,0xe7,0x30,0x19,0x00,0x94,0x6e,0xcd}, + .key_len = 139, + .data = {0x7a,0x03,0xff,0x37,0x37,0xa8,0xb2,0x6d,0xe4,0xf9, + 0xfa,0x29,0x3b,0x94,0x89,0x9c,0xb9,0xd5,0xd9,0xb2, + 0xac,0x9f,0xd5,0xf2,0x8c,0x59,0xd6,0xa7,0x8e,0x36, + 0xd0,0x3d,0x77,0xba,0xce,0xed,0xae,0x7a,0x9b,0x9d, + 0x96,0x23,0xc2,0x01,0x1a,0xbd,0xb9,0x07,0x8a,0x31, + 0x5a,0x72,0xa5,0x09,0x92,0xc4,0xf7,0x78,0x5d,0x62, + 0x65,0x9a,0xf2,0xf3,0x06,0xfc,0x3a,0x09,0x34,0x5f, + 0x87,0x03,0xe3,0xb9,0x83,0x32,0x32,0x7d,0x67,0x3a, + 0x40,0x1c,0x6d,0xbb,0x41,0xcc,0x87,0x31,0xd1,0x88, + 0x51,0x19,0x87,0x58,0x44,0x56,0xce,0xd2,0x2d,0xd2, + 0xf0,0xe1,0xde,0x68,0x74,0xc5,0x24,0x02,0xaa,0x5b, + 0xf9,0xfe,0x84,0x9f,0xfa,0xd7,0xa7,0x6f,0x1b,0x01, + 0xc2,0x92,0x99,0x14,0x1f,0xf8,0x30,0x2d}, + .data_len = 128, + .mac = {0x0f,0x19,0xb0,0x0a,0x7f,0x9c,0x96,0xa0,0xd8,0x8f, + 0xba,0x43,0xcc,0x55,0xcb,0xd0,0x4c,0x0d,0xce,0x84, + 0x4a,0x94,0x53,0x20,0xc0,0x41,0xe3,0x6c,0x3f,0x8c, + 0x5b,0x5a,0xf5,0xeb,0x9f,0x38,0xed,0x7b,0x07,0x1c}, + .mac_len = 40, + }, { // 34 (255) + .key = {0x77,0xb6,0x0a,0x49,0x89,0xc4,0x51,0x60,0xc1,0xe2, + 0xe4,0x19,0x78,0x53,0x0e,0x6b,0x5b,0x62,0xf9,0x9f, + 0x1c,0x48,0x0c,0x57,0x67,0x50,0x76,0xce,0x18,0x39, + 0x0b,0x61,0xab,0xdc,0x50,0x4f,0xf3,0x0f,0xd1,0xbd, + 0x0f,0xc8,0xbb,0xfd,0x9b,0x86,0xa6,0x0f,0x23,0xec, + 0xb3,0x68,0xdd,0xaf,0xd7,0xf3,0x97,0xb3,0x76,0x56, + 0xee,0x71,0x34,0x76,0xc1,0x9c,0x08,0x3d,0xe5,0x04, + 0x92,0x9b,0x1a,0xba,0xae,0xca,0x3e,0x75,0x49,0xd7, + 0xc1,0x34,0x73,0x5e,0x59,0x25,0xb6,0x95,0xf7,0xc6, + 0xa6,0x8b,0xf9,0x4a,0xba,0xb2,0xa1,0x3e,0x5a,0x9c, + 0xc6,0x6c,0x39,0x02,0xc9,0x00,0xe5,0x0a,0xcb,0xe9, + 0x9d,0xc9,0x1d,0x82,0x62,0x07,0xf8,0x72,0x50,0x43, + 0x6f,0xd1,0x2f,0xf7,0xa1,0x8c,0x46,0x1e,0x33,0x0a, + 0x6f,0xf2,0xfe,0x0f,0x71,0xfa,0x04,0xe1,0x89}, + .key_len = 139, + .data = {0x53,0x4c,0x85,0xdd,0x76,0xba,0xf3,0xaa,0x0e,0x3c, + 0xd3,0x1a,0xce,0x04,0x9d,0x93,0x1b,0x39,0xec,0x18, + 0x78,0x9d,0x8d,0x10,0x42,0x6e,0xd6,0x49,0x9d,0x8a, + 0x39,0x3c,0xae,0xd6,0x19,0x93,0x0b,0xdf,0xdb,0xe8, + 0x6f,0xc2,0x41,0xd0,0xb3,0x4a,0xf3,0x18,0xf9,0x59, + 0x5f,0x4e,0x2b,0x89,0xc3,0x83,0xa4,0x12,0x88,0x50, + 0x2c,0xef,0xd2,0x17,0x2a,0x3c,0x55,0x8b,0x15,0xe3, + 0x6a,0x73,0x2c,0x77,0x62,0xab,0x67,0x60,0x1a,0x6b, + 0xad,0x39,0xcf,0xcb,0x47,0x76,0x34,0x87,0x95,0x4a, + 0xc2,0x00,0xff,0xc8,0x50,0x84,0x2f,0x48,0xe3,0xcf, + 0x7d,0x0c,0xc7,0xd2,0xab,0x23,0xdf,0xb3,0xd3,0x8e, + 0x39,0x14,0x9d,0xa2,0xe5,0x98,0xb5,0xad,0x08,0xa3, + 0x7d,0xdc,0x2c,0x62,0xff,0x5c,0xda,0x0c}, + .data_len = 128, + .mac = {0x15,0x77,0x56,0x1f,0x5f,0x3c,0x0b,0xf5,0x23,0xcd, + 0x8c,0xc4,0x70,0xe9,0xc1,0xb9,0x50,0x7b,0xc6,0x99, + 0x1a,0x53,0xdf,0xe2,0x73,0x5f,0x03,0x3b,0xbf,0x88, + 0x1c,0x51,0x3b,0x31,0x53,0x17,0x25,0x02,0xc6,0xcf, + 0x01,0x94,0xfc,0x00,0x98,0x0e,0x1f,0xdc}, + .mac_len = 48, + }, { // 35 (256) + .key = {0xa1,0x8a,0x27,0x74,0x8e,0xf3,0x9b,0x49,0xbe,0x98, + 0x4e,0x8d,0x18,0x52,0x01,0x10,0x00,0x8b,0xc8,0xa1, + 0xd5,0xae,0xb4,0x24,0xbe,0xdc,0xae,0xe5,0xa7,0xe1, + 0xa6,0x2c,0x86,0x66,0xee,0x12,0xe3,0x67,0xe0,0x92, + 0x97,0xe8,0xc7,0xe3,0xd4,0xe4,0xfd,0x05,0x65,0x87, + 0x50,0x9b,0x37,0x9d,0xaa,0xf8,0x19,0x49,0xf2,0x7c, + 0xc0,0xfa,0x2d,0x21,0x0e,0x9b,0xe9,0x51,0x94,0x0a, + 0xdb,0xfb,0x55,0xcc,0xc7,0xe5,0xcc,0xff,0xa0,0x44, + 0x31,0x8f,0xf1,0x8a,0xf9,0xad,0x7b,0x7f,0x9c,0x7d, + 0x1f,0x93,0x9a,0x0f,0xff,0x72,0xc0,0x91,0xe1,0xda, + 0xa7,0xc3,0xd4,0xa9,0x7f,0xab,0x15,0x3b,0x0a,0x89, + 0x33,0xf2,0xeb,0x0d,0x72,0x16,0x21,0xc8,0x6d,0xe0, + 0xcf,0xe1,0x00,0xd1,0x3e,0x09,0x65,0x48,0x24,0xb0, + 0x9d,0x54,0x27,0x79,0x12,0xc7,0x9d,0xec,0x7a}, + .key_len = 139, + .data = {0x29,0xc4,0xae,0x34,0x84,0xdc,0x27,0xc0,0x36,0x03, + 0x43,0xfd,0x0b,0x20,0x58,0xba,0x26,0x1a,0xc3,0xac, + 0xf6,0xf8,0x7f,0xb5,0x66,0x47,0xf6,0x65,0x54,0xbc, + 0x16,0xc2,0x45,0x1b,0xa8,0x44,0x57,0x57,0xdd,0x24, + 0x77,0xfb,0x2a,0xd7,0xd3,0xc8,0x56,0xd5,0x92,0xa0, + 0xd2,0x9e,0xc3,0xa3,0x48,0xff,0x94,0x97,0x76,0x91, + 0xc5,0x8d,0x3d,0x84,0x5c,0xc1,0xf5,0x9a,0x99,0xc3, + 0x04,0x76,0x2c,0xd4,0xaf,0x17,0xa6,0x93,0x30,0xa0, + 0x2e,0xd9,0x08,0x5a,0x75,0xe1,0x96,0xfb,0xec,0xac, + 0xe9,0x29,0x34,0xa3,0xd3,0x3a,0xd5,0x7f,0x3e,0x3e, + 0x34,0x66,0xc3,0x3f,0xbf,0x56,0x79,0xc7,0x6b,0xc7, + 0x0b,0xa3,0x60,0x8c,0x0e,0xe7,0xf2,0xfb,0x91,0x32, + 0xd4,0x4d,0xf5,0x33,0x88,0x48,0xff,0x6c}, + .data_len = 128, + .mac = {0x26,0xa3,0x7c,0x97,0xb7,0xc1,0x30,0x97,0xc5,0x73, + 0x5b,0xc3,0x1f,0x8b,0xdc,0xdc,0x27,0xdf,0xa9,0x6e, + 0x99,0x12,0x19,0xe7,0x08,0xc2,0x3d,0x1b,0x32,0xc0, + 0x4d,0x88,0xa8,0x9a,0x86,0xa1,0xc2,0x17,0x72,0x4f, + 0x4c,0xe5,0xbb,0x58,0x0a,0x1a,0x71,0xc0}, + .mac_len = 48, + }, { // 36 (270) + .key = {0xa0,0x8e,0x14,0xc2,0x67,0x1e,0xf7,0x9f,0x81,0xf7, + 0x32,0xdf,0x2d,0xf3,0x83,0x5a,0xb0,0xcd,0x0d,0xb9, + 0xe1,0x90,0xfb,0x88,0xeb,0x4f,0x66,0x8c,0x4f,0x17, + 0x78,0x56,0x28,0x22,0xd2,0x18,0xb3,0x4d,0x2c,0xb8, + 0x0e,0xcc,0x3b,0x23,0x40,0x1d,0xd8,0xe4,0x7a,0x3a, + 0x5e,0xf5,0x9d,0x13,0x54,0xd4,0xfb,0x3b,0x4c,0xda, + 0x62,0xe2,0x0a,0xc9,0x57,0x03,0xe9,0xa4,0x9f,0xde, + 0x7b,0xc3,0x04,0xa9,0x70,0x26,0x55,0x83,0xb9,0x0a, + 0xaf,0xa9,0xed,0xba,0xfb,0xec,0xeb,0xa8,0xb8,0x63, + 0xc1,0xbc,0xfb,0x5d,0xcc,0xec,0xb3,0x99,0x21,0x0d, + 0x32,0xba,0x2c,0xe8,0xe9,0xf5,0x97,0x91,0x73,0x0d, + 0x6d,0xf4,0xd6,0x81,0x80,0xb1,0x05,0x04,0x08,0x2a, + 0xa9,0x2d,0x8c,0xd9,0x20,0x70,0x06,0xe8,0xc6,0x4d, + 0x42,0xfb,0x74,0xc7,0x87,0x51,0x47,0x18,0x79}, + .key_len = 139, + .data = {0x0f,0xd5,0xe5,0x3b,0x97,0x97,0xcc,0x3e,0xa7,0x5f, + 0xcb,0x7e,0x70,0xa9,0x3b,0x80,0xb5,0x40,0x91,0x76, + 0x2b,0x0b,0xdf,0xb7,0x25,0x2a,0x9e,0x6d,0x70,0x42, + 0xaa,0x8d,0x7c,0x14,0x8e,0x0d,0xbd,0x55,0x02,0x51, + 0x51,0xb9,0xb2,0xe6,0xe3,0x52,0x41,0x72,0xcf,0x18, + 0x8e,0xeb,0x87,0xc9,0x36,0x08,0x35,0xf3,0x5a,0xf5, + 0xa2,0x4e,0xa2,0x4b,0x56,0x50,0x81,0x3f,0x01,0xfc, + 0xbb,0x1a,0x19,0xfb,0x25,0xe9,0xc5,0xed,0xac,0x75, + 0xfa,0x01,0x99,0x75,0xe3,0xc3,0x14,0x03,0x87,0x36, + 0xe6,0x4d,0xa6,0x23,0x83,0x8d,0xe3,0xb0,0x47,0x3b, + 0x29,0x34,0x00,0x80,0x47,0x4a,0xad,0xef,0xdd,0x25, + 0x85,0x70,0x7c,0x23,0x3b,0x7c,0x09,0xa4,0x81,0x90, + 0x62,0x1c,0xcb,0xdb,0x44,0x67,0x55,0x3a}, + .data_len = 128, + .mac = {0xb0,0x7d,0x4e,0x89,0xd7,0xfb,0xca,0x2d,0xb3,0x35, + 0xe8,0x07,0xf9,0xec,0x13,0x1d,0xbc,0x75,0xb8,0x78, + 0xc5,0x13,0xf6,0xcf,0x65,0x95,0xd7,0x54,0x55,0x71, + 0xfd,0x13,0x61,0xd8,0x22,0x9d,0xfa,0x69,0x49,0xcd, + 0x97,0xde,0x56,0x44,0x62,0x93,0x7b,0x35,0xb9,0x23, + 0x20,0xe3,0xab,0x30,0xd9,0xd9}, + .mac_len = 56, + }, { // 37 (271) + .key = {0xec,0x46,0x98,0xb6,0x8d,0x26,0xf2,0xfc,0x04,0x28, + 0xf4,0x13,0xa0,0xef,0x0d,0xc4,0xd6,0xb0,0xe6,0x23, + 0x3e,0x2e,0x8b,0x1c,0xde,0xe8,0xcb,0x4f,0xab,0x90, + 0xe1,0x1e,0x4d,0xc0,0x54,0x03,0x23,0xe9,0x1b,0x27, + 0x87,0x8c,0x05,0x31,0x53,0xac,0x58,0x5c,0xa3,0x83, + 0xb8,0xcd,0xdd,0x74,0x4b,0x23,0xef,0x41,0x1b,0x4f, + 0xd8,0x7e,0xbc,0xa6,0x6a,0x45,0x2e,0x34,0x4e,0x2c, + 0x04,0x54,0x48,0x74,0xc6,0x7e,0xbc,0x83,0x95,0x5f, + 0x72,0x94,0x0d,0x2f,0x96,0xae,0x70,0x3f,0x03,0xd2, + 0x00,0xd1,0xc1,0x79,0xac,0x2d,0xcb,0x3e,0xef,0xf1, + 0x16,0xd7,0xf6,0xa9,0xd0,0x49,0x01,0x9f,0xe5,0x5c, + 0x0b,0xf5,0xc8,0x4d,0xad,0xf0,0x70,0xc4,0x40,0x97, + 0xa1,0x05,0x42,0x7d,0x6c,0x6a,0xfa,0xdb,0xf9,0x11, + 0x5f,0xe1,0x84,0xd2,0x37,0x4e,0xa6,0x74,0x7c}, + .key_len = 139, + .data = {0xf1,0x45,0x0e,0x17,0xbe,0xb5,0x7b,0xdc,0x8e,0x2a, + 0xb1,0xb9,0xb6,0xb3,0x55,0x53,0x99,0x36,0x81,0xe8, + 0xcc,0x08,0x0d,0x85,0x78,0xbb,0x0d,0x79,0x00,0x37, + 0x9a,0x09,0xe4,0x0c,0xd6,0x65,0xe6,0x07,0x2a,0xdb, + 0x6b,0x04,0xd2,0x4b,0x23,0x02,0x9c,0xdb,0xec,0x7d, + 0xec,0xeb,0xf4,0xf8,0x04,0x4c,0x1e,0xd9,0x82,0xac, + 0xa8,0x79,0x2a,0x55,0x0a,0x7c,0xe6,0x18,0x21,0x5e, + 0x0b,0x83,0x8c,0x4f,0xde,0x5b,0x57,0x41,0x57,0x46, + 0xd6,0x3f,0x25,0xc7,0xd4,0x00,0xf1,0x6f,0xee,0xbc, + 0xe7,0x52,0x39,0x3e,0x73,0xb9,0x2b,0x3b,0x48,0x16, + 0xb8,0xe2,0xa7,0x3d,0xbb,0xb4,0xde,0xd0,0x98,0x96, + 0x0f,0xfb,0x1f,0x24,0x32,0x62,0xb4,0x49,0x5d,0x58, + 0xad,0x0c,0x43,0x52,0xfc,0xad,0xfc,0x9b}, + .data_len = 128, + .mac = {0x66,0x4a,0x4b,0x28,0x0e,0xde,0xf3,0x00,0x4c,0xa8, + 0x03,0x2a,0x42,0x42,0x06,0x08,0x3b,0xaf,0x4e,0xd3, + 0xf0,0x55,0xf1,0x95,0x8d,0x84,0xd7,0xde,0xb8,0xec, + 0x7e,0xab,0x7f,0x92,0x85,0xa3,0xb0,0xdc,0xe0,0x99, + 0x7c,0x07,0xb3,0x8e,0xae,0xe1,0x85,0x3a,0xa5,0xc6, + 0xde,0x79,0x89,0x33,0x8d,0x5a}, + .mac_len = 56, + }, { // 38 (285) + .key = {0x95,0xaf,0x10,0x92,0x0d,0xc7,0x88,0x26,0x9e,0x70, + 0xb8,0x56,0x0b,0x73,0x13,0x5c,0xf7,0xf6,0xf5,0xb0, + 0x4a,0x50,0x2c,0x7b,0xd6,0x1c,0xb7,0x4f,0x3b,0x8c, + 0xcd,0x16,0x07,0x01,0x22,0x49,0x22,0xd8,0x65,0x63, + 0x6a,0x86,0x0d,0x94,0x9a,0xe7,0x55,0xb9,0x70,0xd3, + 0x85,0x8c,0x0f,0xf3,0x74,0x18,0xa2,0xd2,0x4b,0x71, + 0x42,0x37,0x8b,0xa1,0x1a,0xb3,0x52,0xe5,0xc8,0x76, + 0xda,0x1a,0x07,0x66,0x42,0x72,0x8b,0x73,0x91,0x6b, + 0x2d,0x24,0xf8,0x02,0x48,0x76,0x57,0x23,0x63,0xe7, + 0x03,0x65,0x10,0xce,0xc7,0xf4,0x13,0xed,0x28,0xce, + 0xc7,0x49,0xed,0x33,0xbe,0x3a,0xdf,0x56,0xa8,0xbe, + 0xce,0x59,0x76,0x12,0xd4,0x78,0xbf,0x84,0xde,0x85, + 0x62,0x83,0x67,0x94,0x6d,0xf8,0x87,0xf7,0x3d,0xd9, + 0x2d,0x6d,0xe7,0xfa,0xa8,0x96,0xd7,0x27,0x6d}, + .key_len = 139, + .data = {0x61,0xd9,0x1f,0x31,0x7a,0x90,0x2e,0xa0,0x94,0x4e, + 0x11,0xe9,0x2e,0x66,0x57,0xa5,0x89,0xe1,0x7a,0xbc, + 0x02,0x7f,0xcd,0x86,0x9f,0xf8,0xb0,0x30,0xe8,0x87, + 0x06,0x62,0xf8,0xa9,0xe9,0x1e,0xd3,0x23,0x9c,0xec, + 0xfa,0x42,0xc0,0x34,0x3d,0x66,0xcb,0xeb,0xd1,0xc2, + 0xb7,0x71,0xa2,0x5d,0xf7,0xba,0xea,0x5c,0xaf,0xad, + 0x03,0x84,0x24,0xc9,0x7a,0xfb,0x72,0x0e,0x64,0x4e, + 0x7d,0x1b,0xf5,0xb8,0x29,0x94,0x4e,0xa2,0xce,0xc6, + 0x97,0x66,0xe6,0x8e,0x4e,0x58,0x09,0x76,0xde,0x07, + 0x1c,0x22,0x74,0xc0,0xc5,0xeb,0x0e,0x54,0x21,0xc9, + 0xd5,0x1b,0xba,0x76,0xac,0x39,0xb3,0xd0,0x09,0x20, + 0x46,0x80,0x03,0x57,0x71,0xd9,0xad,0x79,0xeb,0x02, + 0xa3,0x80,0x5d,0x58,0xe2,0x43,0xcf,0x0e}, + .data_len = 128, + .mac = {0x6e,0x98,0x9e,0xc9,0xcb,0xf0,0x10,0xad,0x66,0x91, + 0xa6,0x72,0xff,0x4c,0xa9,0x0a,0x00,0x27,0x5f,0x9b, + 0xa4,0xc8,0x1c,0xd1,0x47,0xcc,0x50,0x6e,0x1d,0xbc, + 0x8b,0xc9,0x3b,0x1d,0x96,0xa3,0x75,0xe4,0x93,0x50, + 0x3c,0x0a,0xc6,0x97,0xf7,0xc4,0x5e,0x4f,0xad,0xf1, + 0x38,0x24,0x2d,0xf7,0xe0,0x6e,0x67,0x7d,0xe2,0x45, + 0xaf,0xa9,0x77,0x80}, + .mac_len = 64, + }, { // 39 (286) + .key = {0x27,0xe6,0xc9,0xf2,0x70,0xb9,0x85,0x5c,0x96,0x58, + 0xad,0x0e,0x3d,0x6c,0x9a,0x11,0x1a,0x62,0x4f,0x66, + 0xfa,0x64,0xa4,0x9a,0x06,0x88,0xa4,0x9b,0x45,0x47, + 0x33,0xca,0x62,0x30,0xf4,0x51,0xb0,0xdd,0x69,0xb7, + 0x6b,0x27,0x5c,0xb2,0x41,0x96,0x7e,0x3c,0x10,0x1b, + 0x4f,0xe8,0xf2,0x02,0x3d,0x77,0x77,0x22,0x10,0xa6, + 0x31,0x57,0x85,0x4b,0x76,0x32,0x39,0xa0,0x61,0xee, + 0xc9,0xdf,0x1a,0xa6,0x38,0x0f,0x57,0xc6,0x91,0x1d, + 0x23,0xc0,0xcd,0x2e,0xdf,0x00,0xf6,0x34,0x86,0x21, + 0x8d,0xbf,0x35,0x61,0x2a,0x17,0xea,0x52,0x62,0x87, + 0x8b,0xd3,0xed,0xfb,0x2b,0x3f,0x08,0xce,0x8a,0xe4, + 0x19,0xdd,0xda,0xb7,0x92,0xe0,0xc9,0x45,0x17,0xfa, + 0xbb,0xed,0xe3,0x8e,0x57,0x4d,0x68,0x55,0x46,0xfa, + 0x35,0xad,0x37,0x74,0x1d,0x34,0x27,0x59,0x96}, + .key_len = 139, + .data = {0xdf,0x24,0x27,0x9b,0xf8,0x27,0x7a,0xd1,0x09,0x19, + 0x72,0xb8,0x25,0x94,0xd8,0x46,0x77,0xe5,0x4f,0xe5, + 0xd6,0x57,0x86,0xd1,0x9a,0xb5,0xb2,0xc1,0xae,0x0a, + 0x3c,0xc9,0xe7,0xab,0xb6,0x7f,0x94,0x77,0x14,0x5d, + 0x57,0x5e,0x19,0x66,0x33,0x20,0x0f,0x0c,0xe5,0x57, + 0xbb,0x52,0x78,0xb8,0x90,0x2e,0x14,0x96,0x23,0x31, + 0x17,0xa7,0xdf,0x69,0x66,0x0b,0xfa,0x87,0x06,0x8a, + 0xa7,0x3d,0xe6,0x1e,0x8e,0xea,0xff,0xb1,0x79,0x79, + 0x9f,0x27,0x50,0x86,0x02,0x9f,0x47,0xc3,0x23,0xf6, + 0x56,0x9b,0xd1,0x8d,0xea,0x15,0x05,0x4d,0xda,0xfa, + 0x73,0xe8,0x9c,0x3a,0x5f,0x61,0xb9,0x8c,0xb2,0xce, + 0x7e,0x55,0x4d,0x5d,0xf4,0xcb,0x9d,0x95,0x13,0x5a, + 0x70,0xde,0x33,0x47,0x07,0x44,0xc3,0x93}, + .data_len = 128, + .mac = {0xe6,0xf6,0x06,0x12,0x75,0xa8,0x93,0x45,0xf5,0x46, + 0x3c,0xfa,0x19,0x8d,0x52,0x8e,0x14,0x04,0x7d,0x47, + 0x8f,0x69,0xad,0x7a,0x73,0x43,0x2f,0x18,0xf8,0x8b, + 0xc6,0x8a,0x1b,0x8a,0xba,0x2c,0x3b,0x02,0x5c,0x93, + 0xb2,0x5d,0xeb,0x8f,0x40,0x37,0x63,0xa5,0x50,0x24, + 0x40,0x8a,0x97,0xa9,0x03,0xe9,0x5f,0x0c,0xb6,0x17, + 0x8e,0x7b,0xe3,0x89}, + .mac_len = 64, + }, { // 40 (300) + .key = {0x1b,0xca,0xf9,0x6d,0xfd,0xba,0xab,0x10,0x28,0x39, + 0x68,0x65,0xbf,0xf3,0xfd,0x9a,0x87,0xa6,0x04,0x6e, + 0x91,0x30,0xaa,0xe9,0x1a,0xed,0xb5,0x4a,0xaf,0x3f, + 0xc5,0x42,0x95,0x6e,0xd9,0x5f,0x67,0xb3,0x16,0xcb, + 0x01,0x8f,0xc4,0x36,0x9d,0x61,0x9a,0x11,0x3c,0x38, + 0x3b,0xfd,0x48,0xe6,0x00,0x83,0x77,0x56,0xf8,0x05, + 0xf2,0x1f,0x2d,0xf4,0xb7,0x58,0x29,0x44,0x3b,0xaf, + 0xb9,0x1d,0x54,0xb5,0xf1,0xd4,0x57,0x7c,0x70,0x19, + 0x7d,0x64,0xe6,0x72,0x8c,0x32,0xd3,0xe8,0xb3,0x62, + 0x91,0xff,0xb5,0xbf,0x94,0xec,0x4a,0x30,0xf1,0x03, + 0xc2,0xd5,0x1d,0x6f,0xeb,0x52,0xf7,0x25,0x35,0x6b, + 0x09,0x1b,0x14,0xd2,0x0b,0xb4,0xa6,0x3c,0xa9,0x7f, + 0x96,0xba,0x87,0x22,0x40,0x47,0x81,0x91,0x15,0x9d, + 0x37,0x84,0x41,0x4e,0xc9,0x27,0x8c,0x0f,0xdf,0x13, + 0x7e,0x57}, + .key_len = 142, + .data = {0x9d,0x1c,0x57,0xb3,0xe6,0x25,0xd6,0xa7,0xf3,0x84, + 0x62,0x45,0x9c,0x44,0x2e,0xfd,0x5d,0x84,0x2c,0x0b, + 0x57,0x6c,0x31,0x04,0x97,0x66,0x54,0xaf,0x9b,0x8a, + 0x97,0x17,0x12,0x59,0xc9,0xde,0xe4,0xaf,0xaa,0xd4, + 0x72,0xf3,0x51,0xc8,0x1f,0x91,0xcb,0x9f,0x0f,0xaa, + 0x05,0xa3,0x2f,0x0a,0xeb,0x1d,0x75,0x5a,0xd2,0x25, + 0x69,0x96,0x13,0xb9,0xe4,0xc2,0xf9,0x0d,0x17,0xd9, + 0xde,0x22,0xd0,0x07,0x90,0x9a,0xf9,0x17,0xfa,0xcb, + 0x61,0x2f,0x00,0x12,0xc0,0xbb,0xaa,0x69,0xf5,0xa7, + 0x85,0x3c,0x91,0xd1,0x46,0x79,0x99,0xbe,0xb1,0xe7, + 0x88,0x8c,0xb9,0xb8,0x94,0x27,0xe9,0x61,0x32,0xc0, + 0x02,0xa9,0xdc,0x7b,0xe6,0x00,0x12,0x68,0xb4,0x13, + 0x9f,0xb5,0x35,0x9d,0x1d,0x22,0x77,0x80}, + .data_len = 128, + .mac = {0xca,0x7f,0x6a,0xbe,0xd1,0xc2,0x25,0x2f,0xb7,0xf0, + 0x87,0x06,0xd1,0x19,0xfe,0xdd,0x83,0xdf,0x9e,0x09, + 0xc1,0x2e,0x48,0x12,0x67,0xef,0x73,0x3b,0xc0,0x53, + 0xf9,0x45}, + .mac_len = 32, + }, { // 41 (301) + .key = {0xf4,0x73,0x20,0x4e,0x11,0x13,0x98,0x1c,0x4b,0xba, + 0xe6,0xab,0x72,0x07,0xfa,0xbb,0x97,0xd6,0x11,0x2a, + 0x71,0x14,0x34,0x68,0x00,0xd2,0x02,0x2b,0x6f,0x97, + 0xb0,0x64,0x3f,0xfb,0x4e,0x71,0xa2,0x71,0x4c,0x94, + 0x25,0x65,0x3c,0xa4,0x92,0x87,0xd9,0x02,0x15,0x66, + 0x49,0xcf,0x9d,0x40,0x9f,0x5c,0x85,0x18,0xa4,0xe2, + 0x74,0x0a,0xd7,0x74,0x82,0xdc,0xb2,0x31,0x9c,0xd5, + 0x2f,0xbe,0x29,0xd2,0x8b,0xf4,0xed,0x96,0x4a,0xd5, + 0x2e,0x62,0x7b,0xc5,0x16,0xc5,0x3d,0xf7,0x59,0xb6, + 0x82,0x25,0x18,0xe0,0x13,0x84,0x04,0x3d,0xd5,0xf7, + 0xc6,0xe6,0x4a,0x82,0x9f,0x2a,0x5a,0x02,0x4b,0xdd, + 0x54,0x1c,0x2c,0xf2,0x30,0x74,0xa4,0x4d,0x17,0x1f, + 0xc3,0xd2,0x25,0x5a,0x22,0xc2,0x6d,0x7c,0x0e,0x47, + 0x3d,0x29,0xe9,0x4d,0xa4,0xc9,0xce,0x94,0x32,0x38, + 0x74,0x03}, + .key_len = 142, + .data = {0x61,0xa9,0xc8,0x34,0x87,0xfd,0xb8,0xdf,0x53,0x6e, + 0x2a,0x79,0xf5,0x77,0x7f,0x71,0x6e,0x2a,0x4c,0x92, + 0xad,0xc7,0xa6,0x34,0xf8,0x8d,0x9d,0xb4,0x8e,0xd0, + 0x06,0x21,0x8b,0x4c,0x7e,0x38,0x0b,0xb9,0xab,0x93, + 0x92,0xa0,0xc5,0x1d,0xac,0x6c,0x55,0xc9,0xd0,0xc4, + 0x3d,0x84,0x8a,0x18,0xf9,0x68,0xda,0x7a,0x24,0x32, + 0xd7,0xb0,0x3e,0xf6,0x97,0x87,0xac,0x11,0x53,0x6a, + 0x00,0x60,0xc7,0x32,0x7b,0xaf,0xd8,0x40,0xd0,0x74, + 0x79,0xc9,0x2b,0xbe,0xcf,0x72,0x72,0x68,0x93,0x1d, + 0xcb,0x92,0xb9,0x02,0x5e,0x51,0x4f,0x01,0x5c,0xa6, + 0xa7,0x36,0x40,0xad,0xb8,0xcf,0x55,0x17,0xc2,0x1a, + 0x78,0xda,0x31,0xe2,0x1f,0x27,0xc4,0xfc,0x9a,0x9d, + 0xee,0x1d,0x99,0xbc,0x7d,0xef,0xef,0x9c}, + .data_len = 128, + .mac = {0x9e,0xf8,0x22,0xb7,0x1d,0x2b,0x1f,0x44,0xc0,0xc4, + 0x78,0xd0,0xa1,0x6e,0x48,0xae,0x10,0x5f,0xc0,0x1e, + 0x4c,0x0c,0xc5,0x2e,0x9d,0xbc,0x68,0x21,0xa1,0xca, + 0x1e,0x3a}, + .mac_len = 32, + }, { // 42 (315) + .key = {0x75,0x0d,0x16,0xba,0x01,0x45,0x22,0xc2,0xab,0x47, + 0x5e,0x86,0x38,0x53,0x5d,0x5e,0x72,0x9f,0xce,0x4a, + 0x28,0x4a,0xa4,0x87,0x77,0x91,0x75,0x60,0x48,0x45, + 0x20,0x47,0x1a,0x7c,0xb3,0x24,0x02,0x88,0x8c,0xed, + 0xef,0x25,0xbe,0x77,0x33,0xf6,0xb6,0x8c,0x3f,0x33, + 0x1e,0x3d,0xae,0x9c,0x01,0x79,0x86,0xb1,0x30,0xdf, + 0xba,0x24,0xe5,0xd1,0xf3,0x8f,0xa7,0xca,0x8f,0x63, + 0x6d,0xf1,0xea,0x20,0x06,0xee,0xdd,0xcc,0xb8,0xfc, + 0x85,0x9e,0x28,0x3f,0x46,0xfa,0x79,0x59,0x0f,0xa2, + 0xb8,0x38,0xdf,0x2a,0x78,0x31,0x88,0xac,0xb9,0x53, + 0xb3,0xbe,0x0f,0xf5,0x24,0xa1,0x00,0x92,0x3f,0xbb, + 0xad,0xd7,0xcb,0x47,0xb5,0xf9,0xf7,0x4c,0x56,0x4c, + 0x9a,0xcb,0xd5,0x12,0xbf,0x3d,0x20,0x90,0x61,0x3d, + 0xb3,0x68,0x73,0x81,0xb8,0x22,0x24,0x0e,0x72,0x0c, + 0x60,0xac}, + .key_len = 142, + .data = {0x6e,0x9a,0xef,0x11,0x39,0x47,0xfa,0xfb,0x96,0x1e, + 0xef,0xef,0x89,0x1e,0xa3,0xf8,0x3a,0xe0,0x18,0xa4, + 0x56,0x70,0xff,0x6f,0xb3,0x5b,0x7b,0x80,0x33,0x09, + 0x28,0x93,0xea,0x4d,0x5c,0x37,0x83,0x3b,0xad,0x39, + 0xdf,0x3a,0xb3,0x60,0x00,0x5a,0x0f,0x5a,0x26,0xe7, + 0xab,0xf7,0x37,0x3e,0x44,0x95,0x64,0xdf,0x26,0xdc, + 0x0a,0xc4,0x37,0xab,0xd6,0xf1,0x37,0x51,0x2d,0x4d, + 0x46,0x01,0xcb,0xb0,0xa7,0x80,0xaa,0x3d,0xc3,0x21, + 0x25,0xf2,0x71,0xf3,0x5d,0x7d,0x74,0x39,0xdc,0x51, + 0x45,0x1a,0x78,0xfa,0x14,0x9a,0x7a,0xad,0x09,0xc9, + 0x00,0x24,0xcf,0x3a,0xa0,0xa9,0x53,0xb7,0x4e,0x70, + 0xc9,0x33,0x80,0x29,0xf1,0x00,0x90,0xd6,0x98,0x43, + 0x61,0xda,0x61,0xa4,0x45,0x53,0xc5,0x4a}, + .data_len = 128, + .mac = {0x90,0x78,0x1f,0xaa,0x01,0x46,0x87,0x9a,0x36,0x45, + 0x31,0x9c,0x53,0x90,0xba,0xe2,0xd0,0xad,0x06,0x12, + 0xbf,0x2e,0x6e,0x7d,0xc7,0x41,0xe7,0xc7,0x4b,0x2a, + 0xb6,0x5c,0x52,0x04,0x03,0x41,0x0f,0x1e,0xca,0x27}, + .mac_len = 40, + }, { // 43 (316) + .key = {0x3f,0x64,0xc8,0x15,0xf2,0x79,0x3e,0xd4,0x93,0x3e, + 0x37,0x49,0x50,0xf7,0x7e,0x68,0x5a,0xe3,0xdc,0x21, + 0xf3,0x09,0xd3,0x40,0xc9,0x35,0x8f,0x92,0x82,0x3d, + 0x1a,0x49,0x98,0x88,0xcf,0xa1,0x67,0xd1,0x11,0xc4, + 0x84,0x29,0x3d,0xeb,0x51,0x3b,0xdc,0xc7,0xce,0xd4, + 0x1e,0x1f,0xb2,0xa3,0x84,0xba,0xbb,0x3d,0xdc,0x7f, + 0x42,0x63,0x72,0xdb,0x12,0x88,0x85,0x63,0x7a,0x8e, + 0xf8,0xbb,0xa1,0xd1,0x4a,0xb6,0x1a,0x66,0xc8,0xbe, + 0xb8,0xa5,0x01,0x77,0xa4,0xe4,0x7b,0x9f,0xac,0x86, + 0xa4,0x39,0xde,0x35,0x0b,0xea,0x56,0x6b,0xd0,0xa3, + 0x54,0x37,0x5a,0x80,0x92,0x3e,0x47,0xf0,0xd4,0x00, + 0xa9,0x17,0xc0,0x5c,0x6f,0x70,0xf0,0x56,0x21,0xb7, + 0x46,0x19,0xd1,0x06,0x7f,0x38,0x4e,0x3e,0x0b,0x39, + 0x9a,0xa8,0x1c,0x54,0x9e,0xdc,0xfe,0x78,0x1d,0xe2, + 0xa6,0x8f}, + .key_len = 142, + .data = {0xfe,0x7a,0xe0,0xcc,0x9e,0x99,0xc1,0xb0,0xa2,0xbb, + 0x11,0xd7,0x1d,0xb4,0x29,0xcf,0xba,0x95,0x9e,0x65, + 0x5b,0xc8,0x08,0x60,0xff,0x5c,0x08,0x6f,0xe9,0x9d, + 0x89,0x5f,0xff,0xe8,0x45,0x91,0x70,0xbd,0x8b,0xac, + 0x99,0x16,0x40,0x8f,0x2a,0xf7,0x25,0x8a,0x84,0x47, + 0x57,0xcd,0x66,0xde,0x1c,0x20,0xc9,0xdf,0xdc,0xd5, + 0x08,0x48,0x6e,0xfb,0x44,0xc7,0x96,0xd5,0x07,0xd0, + 0xcb,0x8b,0x27,0xec,0x3d,0x1e,0xee,0x54,0x16,0xa1, + 0x77,0xbe,0x00,0xa7,0x5b,0x77,0xe8,0xf8,0x8e,0xb2, + 0x02,0x88,0x83,0x20,0x0e,0xa9,0x97,0xc0,0xd9,0x7f, + 0xac,0xf9,0x06,0xb4,0x14,0xe6,0x0e,0x6e,0xb2,0xf1, + 0x86,0x7e,0x5b,0xa3,0xa1,0xdb,0x82,0xba,0xf5,0x4e, + 0x15,0x7c,0x82,0x6e,0xa2,0x4c,0xf0,0xcf}, + .data_len = 128, + .mac = {0x4b,0xbb,0xa9,0xca,0x72,0xb7,0x20,0x35,0x6a,0x2c, + 0xe8,0x0f,0x32,0xed,0x65,0xf6,0x98,0x8b,0x87,0x69, + 0x72,0x14,0x13,0xae,0x44,0x01,0x4a,0x72,0xcf,0x34, + 0xef,0xc9,0x65,0xcf,0xae,0xb4,0x4b,0x29,0x44,0x45}, + .mac_len = 40, + }, { // 44 (330) + .key = {0xf0,0x1a,0xaa,0x41,0x52,0x8e,0xbf,0xec,0xdb,0x9f, + 0xcd,0x42,0x94,0x80,0x47,0xbf,0x9c,0x23,0x66,0x86, + 0x1e,0x5d,0xc0,0xa4,0x80,0x45,0x1c,0x95,0xdd,0xdd, + 0x85,0x09,0xb6,0xf4,0x9d,0xe8,0xe4,0x4a,0x34,0x93, + 0xd1,0xf6,0x19,0x6d,0xe8,0x05,0x30,0x9a,0x4a,0x64, + 0xc5,0x06,0xc3,0x00,0x20,0xa9,0xfc,0x2b,0x5a,0x0a, + 0xf2,0x42,0x6f,0x02,0xa6,0x8c,0x93,0xc3,0x17,0x66, + 0xca,0x18,0x6d,0x9d,0xb3,0xef,0x77,0x1c,0xa4,0x14, + 0x57,0xc7,0xfc,0x3f,0x7c,0xa6,0xb5,0x51,0xd1,0x46, + 0x39,0xdb,0x34,0x5c,0x77,0xe0,0x2a,0xac,0x35,0xdc, + 0xd1,0x29,0xa8,0x04,0x16,0x5e,0x42,0xd0,0x27,0x0c, + 0xcb,0xb7,0x2c,0x15,0xb3,0x39,0x32,0x98,0xa7,0x23, + 0x67,0x5e,0x62,0x0f,0x8d,0x75,0xc6,0x2a,0xa9,0x1a, + 0x2b,0x3a,0xfb,0xdd,0xf7,0xdf,0x33,0xff,0x6e,0x18, + 0xe2,0x1f}, + .key_len = 142, + .data = {0x7b,0xda,0x43,0xe9,0x04,0x79,0xf8,0x52,0x71,0x7f, + 0x47,0x86,0xb2,0x67,0xca,0x87,0x4f,0xed,0x63,0x80, + 0x5a,0x2b,0xd0,0x07,0xa2,0x02,0x7f,0x9f,0x29,0xbb, + 0xa3,0x81,0xd8,0xee,0x87,0x9c,0x72,0xa3,0x22,0xda, + 0xc7,0xb8,0xed,0xa5,0x2a,0x83,0xf1,0xaa,0x24,0xb7, + 0x24,0xdc,0x6a,0x8c,0xf5,0xbc,0x0d,0x1a,0x26,0xd8, + 0xf1,0x06,0xda,0x92,0x80,0x61,0xef,0x23,0x9f,0xcd, + 0x8d,0xe0,0xe1,0xe2,0xff,0xbb,0xfb,0xd0,0xc2,0x0c, + 0x79,0x45,0xdc,0x92,0xaf,0x91,0x6f,0xb4,0xf1,0x08, + 0x8e,0x0d,0x07,0xa7,0x4f,0x28,0xdb,0xfb,0x22,0x88, + 0x75,0x3f,0x61,0xec,0x29,0xc5,0x28,0xd1,0x0f,0x97, + 0x66,0x37,0xb4,0x5d,0x34,0xa8,0x0f,0x81,0x66,0x77, + 0xb7,0x92,0x60,0x46,0x53,0xe6,0x2c,0xca}, + .data_len = 128, + .mac = {0x02,0x01,0xdb,0xe5,0xef,0x40,0x95,0xf4,0xd4,0xb3, + 0x30,0x6d,0x9b,0x2d,0x75,0x52,0xe0,0xd6,0x8c,0x59, + 0x1e,0xa8,0x83,0x68,0x19,0x5f,0x66,0x28,0x0b,0x80, + 0xba,0x0f,0x2f,0x6a,0xe4,0x36,0xc4,0x23,0xc5,0xc9, + 0x39,0x3a,0xa9,0xf4,0x58,0x8b,0x01,0x07}, + .mac_len = 48, + }, { // 45 (331) + .key = {0x93,0x1b,0x7d,0x98,0xf5,0x80,0xe6,0xd2,0x27,0x8d, + 0x1b,0x67,0x11,0x17,0xe6,0x04,0x7a,0x59,0xed,0xcc, + 0xcd,0xa1,0x91,0xa8,0x1c,0x49,0x17,0xde,0x65,0xe9, + 0x05,0xe6,0x14,0xcb,0xcf,0x79,0xca,0x9f,0xb3,0xea, + 0x5d,0x70,0xe2,0xb9,0x20,0xd7,0xe0,0x66,0x64,0x6f, + 0x2d,0x83,0x3e,0x88,0x25,0x0d,0x8b,0x20,0x25,0xfc, + 0x32,0x0f,0xef,0x19,0xa9,0x81,0x50,0x10,0xbb,0xa9, + 0x00,0xc6,0x88,0xb4,0xc9,0xec,0xcd,0xfc,0xeb,0xd5, + 0x65,0x7f,0xc0,0x84,0x10,0x8f,0x9c,0x0a,0x74,0xcb, + 0xf7,0x0f,0x61,0x4d,0xce,0xae,0x59,0x25,0x46,0x86, + 0x50,0x06,0x93,0x0d,0xb0,0x40,0x18,0x28,0xa0,0xee, + 0xcf,0xf9,0x86,0x71,0xec,0xf8,0xca,0x1d,0xbd,0x46, + 0xde,0x31,0xd5,0x3e,0x7b,0x0d,0x69,0x4c,0x2d,0x9f, + 0xfa,0x02,0x11,0x1f,0x34,0x68,0xdd,0xfc,0x17,0x94, + 0x22,0x16}, + .key_len = 142, + .data = {0x9f,0x84,0x8c,0xbe,0xf3,0xe2,0x9e,0x43,0x76,0x68, + 0x25,0xa1,0xc3,0x8d,0xcc,0xa8,0xf8,0x4e,0xad,0xda, + 0x22,0xd0,0x67,0x2b,0xf5,0x47,0x71,0x05,0xc1,0x16, + 0xae,0x8f,0xa1,0x38,0x41,0x2f,0xf6,0xde,0xa2,0x4e, + 0x13,0x59,0xf1,0x5b,0x3a,0x3b,0x8b,0x12,0xc8,0xb9, + 0xdc,0xfe,0xac,0x54,0x74,0x3c,0x1d,0xb9,0x5c,0x83, + 0x8d,0xe5,0xaa,0x61,0xd8,0x8c,0x53,0xc7,0xc2,0xbc, + 0x41,0xc8,0xa0,0xbe,0xa5,0x9e,0x55,0x3d,0x8f,0xee, + 0x80,0xa9,0xbc,0x4d,0xf4,0xde,0xae,0x02,0x69,0x01, + 0x02,0x0d,0x71,0xab,0xff,0x69,0xad,0x4a,0x6b,0x8f, + 0x40,0xc4,0xa2,0x3b,0x84,0x5d,0xe9,0x72,0xfc,0xda, + 0xff,0xc4,0x8a,0xe6,0xf5,0xcf,0xe2,0xb6,0x40,0x04, + 0x3f,0xe9,0x0d,0xae,0x55,0xb2,0xd4,0x2f}, + .data_len = 128, + .mac = {0x95,0x75,0xd5,0x42,0xbc,0x82,0xea,0x5d,0xef,0xa5, + 0x06,0x98,0xa7,0xe7,0x7c,0x4b,0xc6,0x8f,0x47,0xfd, + 0x33,0x2c,0xb3,0xeb,0x52,0xf0,0x09,0x98,0x7a,0x7b, + 0xd2,0x89,0xad,0x38,0x37,0xee,0x50,0x36,0x02,0x64, + 0xc9,0x54,0x67,0xc7,0x6c,0x0e,0x8a,0xc3}, + .mac_len = 48, + }, { // 46 (345) + .key = {0xc9,0x37,0xc7,0x38,0x77,0x38,0xe5,0xbe,0x87,0x61, + 0xa4,0x16,0x03,0xa2,0x04,0xcd,0x93,0x12,0x8f,0xda, + 0xa1,0x86,0x98,0xd3,0xbc,0x62,0xc1,0x61,0x3a,0xaf, + 0xc0,0xf2,0x22,0x6e,0x62,0xad,0x49,0x2c,0xcf,0xab, + 0xba,0xd7,0x11,0x64,0x5b,0xd0,0xd0,0x67,0xce,0x41, + 0x5f,0x4f,0x96,0xb1,0xfd,0xf2,0x7b,0xd6,0x54,0xdb, + 0x2f,0xaa,0x46,0xfb,0x31,0xc1,0xe9,0x9b,0xf2,0xd9, + 0xd0,0x95,0x37,0xb3,0x8d,0xc4,0xbe,0x21,0x73,0xb9, + 0x24,0x61,0xa1,0xaf,0x06,0xa9,0x3c,0xc1,0x67,0x03, + 0xfb,0x5b,0x51,0x5b,0xe9,0xef,0xbf,0xd6,0x66,0xe9, + 0xbb,0x66,0x6f,0xe4,0xc4,0x9c,0x20,0x1e,0x72,0xbd, + 0x77,0x29,0x5d,0x17,0x5b,0xe4,0x3a,0x95,0xdd,0xaa, + 0x47,0x92,0xbd,0xc9,0xea,0xeb,0x30,0x36,0x94,0x58, + 0xe0,0x7f,0xec,0xfc,0x35,0x00,0x2a,0x3a,0xd3,0x5a, + 0xc0,0xcb}, + .key_len = 142, + .data = {0x92,0xcf,0x37,0x16,0xe2,0x2f,0x68,0xd3,0x02,0x11, + 0x40,0x10,0x34,0xfc,0x38,0x39,0xc9,0x4f,0x47,0x36, + 0x95,0xe0,0xf8,0x36,0xa0,0xe4,0xbf,0xab,0x1e,0x0f, + 0x8d,0x95,0xa2,0xfc,0xa2,0x04,0x8e,0xce,0xa3,0xd8, + 0xce,0x18,0xec,0xcc,0xc6,0xfa,0x27,0xb3,0x88,0x8d, + 0x1d,0x01,0x4b,0x81,0xcd,0x8c,0x19,0x05,0xbb,0x94, + 0xc7,0xe7,0x8b,0x01,0x2a,0xfd,0xce,0xed,0x88,0xc3, + 0x1c,0x62,0x4d,0x45,0x63,0x65,0xff,0x40,0x7e,0x33, + 0x74,0x84,0x0a,0xca,0x43,0x9c,0x75,0xab,0x78,0xb1, + 0x57,0xdf,0x8c,0xac,0x06,0x38,0x94,0x9b,0x65,0xd9, + 0xb8,0x56,0xfc,0xf8,0xe7,0x62,0x4e,0xe3,0xc9,0x15, + 0x66,0x41,0xf5,0xfb,0xb4,0x9b,0x65,0x79,0x17,0x1b, + 0x26,0xb0,0x3b,0x93,0x54,0xa4,0x25,0xc0}, + .data_len = 128, + .mac = {0x49,0x04,0x50,0x77,0x2d,0x57,0xcd,0xe7,0xf8,0x6f, + 0x9d,0x68,0x5d,0x07,0x0c,0x23,0x79,0x4c,0xed,0xc1, + 0x13,0x14,0x3c,0x44,0x1d,0xbf,0x5b,0x4d,0x78,0x7f, + 0xe6,0xe6,0x19,0xb6,0xe6,0xa2,0x86,0xa3,0x91,0x3e, + 0x1d,0x71,0x3f,0x4b,0x28,0xaf,0x24,0x77,0xcf,0x34, + 0x53,0xc4,0x15,0x29,0xc2,0xec}, + .mac_len = 56, + }, { // 47 (346) + .key = {0x49,0xa7,0x5f,0xaf,0x82,0x32,0x54,0x4d,0x78,0x23, + 0x4c,0x3f,0x4f,0xd9,0xbd,0x7b,0x35,0x99,0x62,0x17, + 0xf5,0xd5,0x79,0xb2,0xc9,0xae,0x2f,0x10,0x70,0xb7, + 0x59,0x04,0x81,0xfc,0x64,0x93,0xff,0x43,0x8f,0x56, + 0x2d,0x91,0x57,0x20,0xa4,0xf0,0x33,0xe1,0xa2,0x70, + 0x82,0xca,0xa5,0x6c,0xc2,0xb2,0x39,0x0e,0x02,0xb9, + 0x0e,0x15,0x9a,0x2b,0x4d,0xd6,0x19,0xa7,0x2c,0x81, + 0x7f,0x80,0xc1,0xa6,0xad,0x63,0x13,0xf8,0x19,0x3a, + 0x77,0x50,0xc6,0x51,0x1a,0xf5,0x74,0xb7,0xda,0x1a, + 0x14,0xe8,0x5a,0xa8,0x7e,0xa8,0x55,0x3e,0x66,0x32, + 0x32,0x76,0x8c,0x92,0xd9,0x6b,0x34,0x50,0xc6,0x78, + 0xd6,0x4e,0x5b,0x42,0x16,0xf3,0x7b,0xf8,0xf6,0x89, + 0x54,0xd9,0x4b,0xe4,0x7c,0xf7,0x6e,0x45,0x40,0x3b, + 0x33,0x7e,0x39,0xaa,0x1f,0x56,0x20,0xe6,0xd5,0x2e, + 0xe2,0xf8}, + .key_len = 142, + .data = {0xe4,0x43,0x7f,0xae,0xaa,0x8e,0x07,0x1f,0x7f,0xd7, + 0x1b,0x5d,0x9b,0x42,0xdb,0x56,0x43,0xd0,0xd7,0xad, + 0x9e,0xe1,0x7f,0x5f,0xc5,0xf8,0xdc,0xa6,0x19,0xbf, + 0x7e,0x1d,0xd9,0x4b,0xb6,0x25,0xf4,0xa0,0x05,0x88, + 0x1b,0x78,0xd3,0x5d,0x1b,0x40,0x64,0x2c,0x6a,0x64, + 0x09,0x52,0xff,0xcc,0x93,0xa6,0x67,0xa7,0x0d,0x5c, + 0x16,0x67,0xab,0x2a,0xfb,0x0c,0xfd,0xaa,0x57,0xa6, + 0x68,0x00,0xce,0x15,0xd7,0xbc,0xbf,0x14,0xae,0x02, + 0xd1,0x76,0x00,0xe8,0xce,0xae,0x01,0x1f,0xb5,0x95, + 0xbe,0xd6,0x0a,0x68,0x0b,0xdb,0x71,0x10,0xbd,0x03, + 0x7b,0xa7,0x1a,0xcd,0xc0,0x37,0x8e,0x42,0x2e,0xc5, + 0xa0,0x1f,0xa0,0x8e,0x23,0x36,0xb2,0x90,0xb1,0x12, + 0xd4,0x4c,0x55,0xda,0x9e,0xcb,0x88,0x77}, + .data_len = 128, + .mac = {0xa0,0x93,0xdf,0x05,0xd8,0xdf,0x35,0xbb,0x12,0xde, + 0x09,0xc9,0xae,0xdb,0x23,0xdc,0xfc,0xd5,0x17,0xdf, + 0x6f,0x0c,0xdd,0x18,0x86,0xd4,0xc7,0x36,0xc8,0x50, + 0x68,0xf9,0xf1,0x94,0x86,0x05,0x1d,0x22,0x3d,0xf4, + 0x85,0x09,0xa2,0xa6,0xe1,0xb5,0x0c,0xe2,0x24,0x29, + 0xef,0xb8,0xf0,0x79,0x78,0x23}, + .mac_len = 56, + }, { // 48 (360) + .key = {0x01,0xb9,0x5a,0x88,0x79,0x27,0xce,0x31,0xb1,0x24, + 0x23,0x91,0xbb,0xd0,0x09,0x65,0xeb,0x77,0xa9,0x03, + 0xd4,0xb8,0x39,0x9b,0x72,0xe6,0xce,0xbd,0xa9,0xae, + 0x72,0x1b,0xee,0xfa,0x77,0x91,0x45,0x16,0x0b,0x62, + 0x6b,0x11,0x0c,0xc5,0x54,0x67,0x1d,0xa0,0xd8,0xdc, + 0xf9,0x93,0xa9,0xab,0x07,0x38,0x88,0xe0,0x2f,0xa9, + 0xb8,0x03,0xed,0x43,0xb3,0xf6,0xa3,0xaa,0x1d,0x20, + 0x34,0x0d,0xf6,0xcc,0xce,0xac,0x13,0xcb,0x07,0x97, + 0xcf,0x61,0x2c,0xb8,0xfe,0x5f,0xd5,0x13,0x22,0x8c, + 0xbd,0x4d,0xe2,0x49,0xd1,0x6b,0xb7,0x75,0x87,0xdd, + 0xe9,0x8f,0x71,0xbb,0xba,0x1a,0x12,0x4e,0xe0,0x46, + 0xf0,0xd2,0x39,0xcc,0xea,0x7a,0xbb,0x1a,0xcc,0xb5, + 0xaa,0xb0,0x21,0xb0,0x0d,0xca,0x49,0x1c,0x62,0x3f, + 0xcb,0x31,0x91,0xa9,0xec,0xf3,0x1f,0xc6,0x80,0xb4, + 0xa4,0x1e}, + .key_len = 142, + .data = {0x63,0x2a,0xfa,0x8e,0x79,0xb1,0x4b,0x2a,0x36,0x04, + 0xf5,0x85,0x5d,0x2b,0xf1,0x82,0xd3,0xc5,0x6d,0x68, + 0x53,0xf2,0x1f,0xe4,0x62,0x71,0xda,0x52,0x86,0x06, + 0x5f,0x38,0xb3,0x1f,0x75,0x13,0x06,0xb6,0x3c,0x57, + 0xb6,0x79,0xbe,0xb1,0x47,0x29,0xc7,0x8f,0x00,0x40, + 0xf7,0xe2,0xa0,0xd6,0x15,0x22,0x4d,0xc5,0xa6,0x93, + 0xcd,0x0c,0xbe,0xc8,0xf8,0x71,0x17,0x65,0x6d,0x6b, + 0x60,0x29,0x85,0x3e,0xd7,0x2b,0x85,0x68,0x1a,0x63, + 0x18,0x3c,0x3a,0x6d,0xfc,0xcd,0x12,0x8a,0xfb,0x0d, + 0xd7,0xe8,0x1d,0x36,0xf0,0x23,0x1c,0x69,0x07,0x0b, + 0x18,0x95,0x60,0xa8,0x8c,0x9b,0x69,0x7b,0x81,0xb0, + 0x93,0x07,0x01,0x02,0x61,0x90,0xcf,0x9e,0xbe,0x23, + 0x55,0x91,0x94,0xd6,0xde,0x4d,0x9a,0x51}, + .data_len = 128, + .mac = {0x21,0x0a,0xd4,0x5c,0xa2,0xfd,0x1f,0x10,0x5c,0x0a, + 0x18,0xf9,0x93,0x77,0x4f,0x93,0x3e,0xce,0x57,0xac, + 0xe4,0xda,0x61,0x96,0x89,0xe1,0xcb,0x8b,0x49,0x1a, + 0x18,0x9c,0xc6,0xe4,0xee,0x19,0x54,0xa3,0x22,0x01, + 0x07,0x2e,0x70,0xf9,0x34,0x83,0x7c,0x0f,0xb6,0xe2, + 0x39,0xb4,0xfd,0xfb,0xd2,0x6e,0xbf,0x11,0xb9,0xa9, + 0x19,0xea,0xfd,0x09}, + .mac_len = 64, + }, { // 49 (361) + .key = {0x61,0x09,0x6f,0x4f,0xe5,0x34,0x04,0x88,0x91,0x6d, + 0xe2,0x93,0xbe,0x38,0xcc,0x3a,0xe0,0xc8,0x77,0x67, + 0x0c,0x71,0x36,0x37,0xb7,0x60,0xd7,0x4f,0xc1,0x8a, + 0xc7,0x73,0xb2,0xe2,0x7d,0x55,0x43,0xcf,0x16,0xaa, + 0x20,0xdd,0x3d,0x83,0xec,0xb3,0x4e,0xdb,0x85,0x45, + 0xbb,0x6c,0x8a,0x4a,0xae,0xc8,0x1b,0xf1,0xf0,0xa4, + 0xe0,0xcf,0x09,0x77,0x4d,0x1c,0xa9,0x44,0x24,0x20, + 0x46,0xb3,0x3b,0xe8,0x07,0x67,0x7f,0x3d,0xe1,0x8c, + 0x39,0xd7,0x00,0xaf,0x90,0xcd,0x68,0xd3,0x4f,0x50, + 0xdc,0xc1,0xe9,0x99,0xfe,0x9f,0xbb,0x20,0xb9,0xc4, + 0x90,0x0f,0xdc,0xcb,0x6a,0xf6,0x07,0xe6,0x80,0xc0, + 0xcb,0x75,0x83,0xe6,0x0d,0xd8,0x25,0xe2,0xab,0x81, + 0xdc,0xe7,0x63,0x4d,0xe3,0xcf,0xf0,0x14,0x83,0x55, + 0x75,0x7f,0x90,0x84,0x1f,0x19,0x36,0x6f,0x06,0xa9, + 0xf6,0x23}, + .key_len = 142, + .data = {0x67,0xe7,0x04,0x04,0x6f,0x98,0xcb,0x5a,0xa9,0x7d, + 0xa9,0x5b,0x19,0x14,0x73,0x91,0xf0,0x57,0x88,0xf8, + 0x11,0x36,0x6b,0x0e,0xce,0x44,0xb1,0x2a,0xf2,0xb1, + 0x1e,0x0e,0x05,0x78,0x0b,0xbf,0xcb,0xd9,0x0a,0x95, + 0x0e,0x0a,0xcd,0x8e,0x9d,0x2a,0x44,0xe7,0x95,0x76, + 0x06,0xee,0xdf,0xbf,0xf2,0x12,0xfa,0x1c,0x16,0x3c, + 0xfb,0xdc,0xd0,0x62,0xd2,0xbe,0x32,0x59,0xce,0x65, + 0xab,0xea,0x64,0x06,0xe4,0x29,0x2c,0x64,0xe9,0x02, + 0x2c,0xfe,0x89,0x15,0x59,0x86,0xff,0xc4,0x5b,0x96, + 0xd2,0x89,0x91,0x9f,0xf9,0x8d,0x55,0x22,0x43,0x77, + 0x81,0x22,0xf6,0x82,0x31,0xd9,0xb6,0xd3,0xcb,0xaa, + 0xa9,0x09,0x3d,0x57,0xd9,0x15,0x86,0x74,0xda,0x4c, + 0x78,0x1b,0xac,0xba,0xbc,0xe2,0xe2,0xba}, + .data_len = 128, + .mac = {0x9a,0x2d,0x14,0x7e,0x50,0x82,0x71,0x57,0xf3,0x86, + 0x6e,0x86,0x8c,0x1c,0xca,0x9f,0x08,0x15,0x79,0xc9, + 0x2f,0x25,0xda,0x8c,0xeb,0xc9,0xed,0x24,0x99,0x28, + 0xc8,0x2b,0xea,0xd3,0x9d,0x48,0x0e,0xcb,0xb5,0xb5, + 0xd0,0xe0,0x75,0x50,0x29,0xae,0xbf,0x3e,0x02,0x06, + 0x98,0x4f,0x3e,0xa8,0x3f,0x4d,0x63,0x72,0xf4,0x45, + 0x33,0x90,0xe0,0x70}, + .mac_len = 64, + }, +}; + +struct HMAC_TEST_SUITE_INFO { + const char *name; + unsigned int tvcount; + struct HMAC_TEST_VECTOR *tv; + CK_MECHANISM mech; +}; + +#define NUM_OF_FIPS_HMAC_TEST_SUITES 5 +struct HMAC_TEST_SUITE_INFO fips_hmac_test_suites[] = { + { + .name = "SHA-1 HMAC", + .tvcount = 10, + .tv = fips_sha1_hmac_test_vector, + .mech = { CKM_SHA_1_HMAC, 0, 0 }, + }, { + .name = "SHA-224 HMAC", + .tvcount = 10, + .tv = fips_sha224_hmac_test_vector, + .mech = { CKM_SHA224_HMAC, 0, 0 }, + }, { + .name = "SHA-256 HMAC", + .tvcount = 10, + .tv = fips_sha256_hmac_test_vector, + .mech = { CKM_SHA256_HMAC, 0, 0 }, + }, { + .name = "SHA-384-HMAC", + .tvcount = 10, + .tv = fips_sha384_hmac_test_vector, + .mech = {CKM_SHA384_HMAC, 0, 0 }, + }, { + .name = "SHA-512-HMAC", + .tvcount = 10, + .tv = fips_sha512_hmac_test_vector, + .mech = {CKM_SHA512_HMAC, 0, 0 }, + } +}; + +#define NUM_OF_FIPS_HMAC_GENERAL_TEST_SUITES 5 +struct HMAC_TEST_SUITE_INFO fips_hmac_general_test_suites[] = { + { + .name = "SHA-1 HMAC GENERAL", + .tvcount = 40, + .tv = fips_sha1_hmac_general_test_vector, + .mech = { CKM_SHA_1_HMAC_GENERAL, 0, 0 }, + }, + { + .name = "SHA-224 HMAC GENERAL", + .tvcount = 30, + .tv = fips_sha224_hmac_general_test_vector, + .mech = { CKM_SHA224_HMAC_GENERAL, 0, 0 }, + }, + { + .name = "SHA-256 HMAC GENERAL", + .tvcount = 30, + .tv = fips_sha256_hmac_general_test_vector, + .mech = { CKM_SHA256_HMAC_GENERAL, 0, 0 }, + }, + { + .name = "SHA-384 HMAC GENERAL", + .tvcount = 40, + .tv = fips_sha384_hmac_general_test_vector, + .mech = { CKM_SHA384_HMAC_GENERAL, 0, 0 }, + }, + { + .name = "SHA-512 HMAC GENERAL", + .tvcount = 50, + .tv = fips_sha512_hmac_general_test_vector, + .mech = { CKM_SHA512_HMAC_GENERAL, 0, 0 }, + } +}; + +#define NUM_OF_HMAC_TEST_SUITES 16 +struct HMAC_TEST_SUITE_INFO hmac_test_suites[] = { + { + .name = "SHA-1 HMAC", + .tvcount = 7, + .tv = sha1_hmac_test_vector, + .mech = { CKM_SHA_1_HMAC, 0, 0 }, + }, + { + .name = "SHA-224 HMAC", + .tvcount = 6, + .tv = sha224_hmac_test_vector, + .mech = { CKM_SHA224_HMAC, 0, 0 }, + }, + { + .name = "SHA-256 HMAC", + .tvcount = 6, + .tv = sha256_hmac_test_vector, + .mech = { CKM_SHA256_HMAC, 0, 0 }, + }, + { + .name = "SHA-384 HMAC", + .tvcount = 6, + .tv = sha384_hmac_test_vector, + .mech = { CKM_SHA384_HMAC, 0, 0 }, + }, + { + .name = "SHA-512 HMAC", + .tvcount = 6, + .tv = sha512_hmac_test_vector, + .mech = { CKM_SHA512_HMAC, 0, 0 }, + }, + { + .name = "MD5 HMAC", + .tvcount = 7, + .tv = md5_hmac_test_vector, + .mech = { CKM_MD5_HMAC, 0, 0 }, + }, + { + .name = "SHA-1 HMAC General", + .tvcount = 7, + .tv = sha1_hmac_general_test_vector, + .mech = { CKM_SHA_1_HMAC_GENERAL, &ten, sizeof(CK_ULONG) }, + }, + { + .name = "SHA-224 HMAC General", + .tvcount = 4, + .tv = sha224_hmac_general_test_vector, + .mech = { CKM_SHA224_HMAC_GENERAL, &sixteen, sizeof(CK_ULONG) }, + }, + { + .name = "SHA-256 HMAC General", + .tvcount = 4, + .tv = sha256_hmac_general_test_vector, + .mech = { CKM_SHA256_HMAC_GENERAL, &sixteen, sizeof(CK_ULONG) }, + }, + { + .name = "SHA-384 HMAC General", + .tvcount = 4, + .tv = sha384_hmac_general_test_vector, + .mech = {CKM_SHA384_HMAC_GENERAL,&twentyfour,sizeof(CK_ULONG)}, + }, + { + .name = "SHA-512 HMAC General", + .tvcount = 4, + .tv = sha512_hmac_general_test_vector, + .mech = { CKM_SHA512_HMAC_GENERAL,&thirtytwo,sizeof(CK_ULONG) }, + }, + { + .name = "MD5 HMAC General", + .tvcount = 7, + .tv = md5_hmac_general_test_vector, + .mech = { CKM_MD5_HMAC_GENERAL, &four, sizeof(CK_ULONG) }, + }, + { + .name = "IBM-SHA3-224 HMAC", + .tvcount = 6, + .tv = sha3_224_hmac_test_vector, + .mech = { CKM_IBM_SHA3_224_HMAC, 0, 0 }, + }, + { + .name = "IBM-SHA3-256 HMAC", + .tvcount = 6, + .tv = sha3_256_hmac_test_vector, + .mech = { CKM_IBM_SHA3_256_HMAC, 0, 0 }, + }, + { + .name = "IBM-SHA3-384 HMAC", + .tvcount = 6, + .tv = sha3_384_hmac_test_vector, + .mech = { CKM_IBM_SHA3_384_HMAC, 0, 0 }, + }, + { + .name = "IBM-SHA3-512 HMAC", + .tvcount = 6, + .tv = sha3_512_hmac_test_vector, + .mech = { CKM_IBM_SHA3_512_HMAC, 0, 0 }, + }, + +}; diff --git a/testcases/crypto/digest_func.c b/testcases/crypto/digest_func.c new file mode 100644 index 0000000..1a4bd7e --- /dev/null +++ b/testcases/crypto/digest_func.c @@ -0,0 +1,1653 @@ +/* + * 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 + */ + +#include +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "digest.h" +#include "common.c" + +#define DIGEST_UPDATE_SIZE 32 + +/** Tests messge digest with published test vectors. **/ +CK_RV do_Digest(struct digest_test_suite_info *tsuite) +{ + unsigned int i; + CK_BYTE data[MAX_DATA_SIZE]; + CK_ULONG data_len; + CK_BYTE actual[MAX_HASH_SIZE]; + CK_ULONG actual_len; + CK_BYTE expected[MAX_HASH_SIZE]; + CK_ULONG expected_len; + CK_MECHANISM mech; + + CK_SESSION_HANDLE session; + CK_SLOT_ID slot_id = SLOT_ID; + CK_ULONG flags; + CK_RV rc; + + + /** begin test suite **/ + testsuite_begin("%s Digest.", tsuite->name); + testcase_rw_session(); + + /** skip test if mech is not supported with this slot **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "mechanism %s is not supported with slot %ld", + tsuite->name, slot_id); + goto testcase_cleanup; + } + + /** iterate over test vectors **/ + for (i = 0; i < tsuite->tvcount; i++) { + + /** begin test **/ + testcase_begin("Starting %s Digest with test vector %d.", + tsuite->name, i); + + rc = CKR_OK; // set rc + + /** clear buffers **/ + memset(data, 0, sizeof(data)); + memset(actual, 0, sizeof(actual)); + memset(expected, 0, sizeof(expected)); + + /** get test vector info **/ + data_len = tsuite->tv[i].data_len; + expected_len = tsuite->tv[i].hash_len; + memcpy(data, tsuite->tv[i].data, data_len); + memcpy(expected, tsuite->tv[i].hash, expected_len); + + /** get mech **/ + mech = tsuite->mech; + + /** initialize single digest **/ + rc = funcs->C_DigestInit(session, &mech); + if (rc != CKR_OK) { + testcase_error("C_DigestInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + actual_len = sizeof(actual); // set digest buffer size + + /** do single digest **/ + rc = funcs->C_Digest(session, data, data_len, actual, &actual_len); + if (rc != CKR_OK) { + testcase_error("C_Digest rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** compare digest results with expected results **/ + testcase_new_assertion(); + + if (actual_len != expected_len) { + testcase_fail("hashed data length does not match test " + "vector's hashed data length.\n expected" + " length=%ld, found length=%ld.", + expected_len, actual_len); + } else if (memcmp(actual, expected, expected_len)) { + testcase_fail("hashed data does not match test vector's" + " hashed data."); + } else { + testcase_pass("%s Digest with test vector %d passed.", + tsuite->name, i); + } + } + +testcase_cleanup: + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Tests multipart message digest with published test vectors. **/ +CK_RV do_DigestUpdate(struct digest_test_suite_info * tsuite) +{ + unsigned int i; + CK_BYTE data[MAX_DATA_SIZE]; + CK_ULONG data_len, data_done; + CK_BYTE actual[MAX_HASH_SIZE]; + CK_ULONG actual_len; + CK_BYTE expected[MAX_HASH_SIZE]; + CK_ULONG len, expected_len; + CK_MECHANISM mech; + + CK_SESSION_HANDLE session; + CK_SLOT_ID slot_id = SLOT_ID; + CK_ULONG flags; + CK_RV rc; + + /** begin test **/ + testsuite_begin("Starting %s Multipart Digest.", tsuite->name); + testcase_rw_session(); + + /** skip test if mech is not supported with this slot **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "mechanism %s is not supported with slot %ld", + tsuite->name, slot_id); + goto testcase_cleanup; + } + + /** iterate over test vectors **/ + for (i = 0; i < tsuite->tvcount; i++) { + + /** begin test **/ + testcase_begin("Starting %s Multipart Digest with test vector %d.", + tsuite->name, i); + + rc = CKR_OK; // set rc + + /** clear buffers **/ + memset(data, 0, sizeof(data)); + memset(actual, 0, sizeof(actual)); + memset(expected, 0, sizeof(expected)); + + /** get test vector info **/ + data_done = 0; + data_len = tsuite->tv[i].data_len; + expected_len = tsuite->tv[i].hash_len; + memcpy(data, tsuite->tv[i].data, data_len); + memcpy(expected, tsuite->tv[i].hash, expected_len); + + /** get mechanism **/ + mech = tsuite->mech; + + /** initialize multipart digest **/ + rc = funcs->C_DigestInit(session, &mech); + if (rc != CKR_OK) { + testcase_error("C_DigestInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + actual_len = sizeof(actual); + + /* do multipart digest + * if test vector contains chunks, use that. + * Otherwise, just call update on entire data. + * + * Note: for chunks, -1 is NULL, and 0 is empty string, + * and a value > 0 is amount of data from test vector's + * plaintext data. This way we test chunks that + * are NULL or empty string when updating. + */ + if (tsuite->tv[i].num_chunks) { + int j; + CK_BYTE *data_chunk = NULL; + + for (j = 0; j < tsuite->tv[i].num_chunks; j++) { + if (tsuite->tv[i].chunks[j] == -1) { + len = 0; + data_chunk = NULL; + } else if (tsuite->tv[i].chunks[j] == 0) { + len = 0; + data_chunk = (CK_BYTE *) ""; + } else { + len = tsuite->tv[i].chunks[j]; + data_chunk = data + data_done; + } + + rc = funcs->C_DigestUpdate(session, data_chunk, len); + if (rc != CKR_OK) { + testcase_error("C_DigestUpdate rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + data_done += len; + } + } else { + rc = funcs->C_DigestUpdate(session, data, data_len); + if (rc != CKR_OK) { + testcase_error("C_DigestUpdate rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + + /** finalize multipart digest **/ + rc = funcs->C_DigestFinal(session, actual, &actual_len); + if (rc != CKR_OK) { + testcase_error("C_DigestFinal rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** compare multipart digest results with expected results **/ + testcase_new_assertion(); + + if (actual_len != expected_len) { + testcase_fail("hashed multipart data length does not " + "match test vector's hashed data length.\n"); + } else if (memcmp(actual, expected, expected_len)) { + testcase_fail("hashed multipart data does not match " + "test vector's hashed data.\n"); + } else { + testcase_pass("%s Multipart Digest with test vector " + "%d passed.", tsuite->name, i); + } + + } + +testcase_cleanup: + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Tests signature verification with published test vectors. **/ +CK_RV do_Sign_FIPS_HMAC_GENERAL(struct HMAC_TEST_SUITE_INFO * tsuite) +{ + unsigned int i; + CK_MECHANISM mech; + CK_BYTE key[MAX_KEY_SIZE], data[MAX_DATA_SIZE]; + CK_ULONG key_len, data_len, actual_mac_len, expected_mac_len, mac_size; + CK_BYTE actual_mac[MAX_HASH_SIZE], expected_mac[MAX_HASH_SIZE]; + CK_SESSION_HANDLE session; + CK_SLOT_ID slot_id = SLOT_ID; + CK_ULONG flags; + CK_RV rc; + CK_OBJECT_HANDLE h_key; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + /** begin testsuite **/ + testsuite_begin("%s Sign.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + rc = CKR_OK; // set rc + + /** skip test if mech is not supported with this slot **/ + if (!mech_supported(SLOT_ID, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "mechanism %s is not supported with slot %ld", + tsuite->name, slot_id); + goto testcase_cleanup; + } + + /** iterate over test vectors **/ + for (i = 0; i < tsuite->tvcount; i++) { + + /** begin test **/ + testcase_begin("Sign %s with test vector %d.", tsuite->name, i); + + /** get mechanism and set parameter **/ + mech = tsuite->mech; + mac_size = tsuite->tv[i].mac_len; + + mech.ulParameterLen = sizeof(CK_ULONG); + mech.pParameter = &mac_size; + + /** clear buffers **/ + memset(key, 0, sizeof(key)); + memset(data, 0, sizeof(data)); + memset(actual_mac, 0, sizeof(actual_mac)); + memset(expected_mac, 0, sizeof(expected_mac)); + + /** get test vector info **/ + data_len = tsuite->tv[i].data_len; + actual_mac_len = sizeof(actual_mac); + expected_mac_len = tsuite->tv[i].mac_len; + key_len = tsuite->tv[i].key_len; + memcpy(key, tsuite->tv[i].key, key_len); + memcpy(data, tsuite->tv[i].data, data_len); + memcpy(expected_mac, tsuite->tv[i].mac, expected_mac_len); + + /** create key object **/ + rc = create_GenericSecretKey(session, key, key_len, &h_key); + if (rc != CKR_OK) { + testcase_error("create_GenericSecretKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** initialize signing **/ + rc = funcs->C_SignInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do signing **/ + rc = funcs->C_Sign(session, data, data_len, actual_mac, + &actual_mac_len); + if (rc != CKR_OK) { + testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare sign/verify results with expected results **/ + testcase_new_assertion(); + + if (actual_mac_len != expected_mac_len) { + testcase_fail("hashed data length does not match test " + "vector's hashed data length\nexpected " + "length=%ld, found length=%ld", + expected_mac_len, actual_mac_len); + goto error; + } else if (memcmp(actual_mac, expected_mac, expected_mac_len)) { + testcase_fail("hashed data does not match test " + "vector's hashed data"); + goto error; + } else { + testcase_pass("%s Sign with test vector %d passed", + tsuite->name, i); + } +error: + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Tests signature verification with published test vectors. **/ +CK_RV do_Verify_FIPS_HMAC_GENERAL(struct HMAC_TEST_SUITE_INFO * tsuite) +{ + unsigned int i; + CK_MECHANISM mech; + CK_BYTE key[MAX_KEY_SIZE], data[MAX_DATA_SIZE]; + CK_ULONG key_len, data_len, expected_mac_len, mac_size; + CK_BYTE expected_mac[MAX_HASH_SIZE]; + CK_SESSION_HANDLE session; + CK_SLOT_ID slot_id = SLOT_ID; + CK_ULONG flags; + CK_RV rc; + CK_OBJECT_HANDLE h_key; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + /** begin testsuite **/ + testsuite_begin("%s Verify.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + rc = CKR_OK; // set rc + + /** skip test if mech is not supported with this slot **/ + if (!mech_supported(SLOT_ID, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "mechanism %s is not supported with slot %ld", + tsuite->name, slot_id); + goto testcase_cleanup; + } + + /** iterate over test vectors **/ + for (i = 0; i < tsuite->tvcount; i++) { + + /** begin test **/ + testcase_begin("Verify %s with test vector %d.", tsuite->name, i); + + /** get mechanism and set parameter **/ + mech = tsuite->mech; + mac_size = tsuite->tv[i].mac_len; + + mech.ulParameterLen = sizeof(CK_ULONG); + mech.pParameter = &mac_size; + + /** clear buffers **/ + memset(key, 0, sizeof(key)); + memset(data, 0, sizeof(data)); + memset(expected_mac, 0, sizeof(expected_mac)); + + /** get test vector info **/ + data_len = tsuite->tv[i].data_len; + expected_mac_len = tsuite->tv[i].mac_len; + key_len = tsuite->tv[i].key_len; + memcpy(key, tsuite->tv[i].key, key_len); + memcpy(data, tsuite->tv[i].data, data_len); + memcpy(expected_mac, tsuite->tv[i].mac, expected_mac_len); + + /** create key object **/ + rc = create_GenericSecretKey(session, key, key_len, &h_key); + if (rc != CKR_OK) { + testcase_error("create_GenericSecretKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** initilaize verification **/ + rc = funcs->C_VerifyInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** see if signature verifies **/ + testcase_new_assertion(); + + /** do verification **/ + rc = funcs->C_Verify(session, data, data_len, expected_mac, + expected_mac_len); + if (rc != CKR_OK) + testcase_fail("C_Verify rc=%s", p11_get_ckr(rc)); + else + testcase_pass("%s C_Verify with test vector %d passed", + tsuite->name, i); + +error: + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + + +/** Tests signature generation with published test vectors. **/ +CK_RV do_Sign_FIPS_HMAC(struct HMAC_TEST_SUITE_INFO * tsuite) +{ + unsigned int i; + CK_MECHANISM mech; + CK_BYTE key[MAX_KEY_SIZE], data[MAX_DATA_SIZE]; + CK_ULONG key_len, data_len, actual_mac_len, expected_mac_len; + CK_BYTE actual_mac[MAX_HASH_SIZE], expected_mac[MAX_HASH_SIZE]; + CK_SESSION_HANDLE session; + CK_SLOT_ID slot_id = SLOT_ID; + CK_ULONG flags; + CK_RV rc; + CK_OBJECT_HANDLE h_key; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + /** begin testsuite **/ + testsuite_begin("%s Sign.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + rc = CKR_OK; // set rc + + /** skip test if mech is not supported with this slot **/ + if (!mech_supported(SLOT_ID, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "mechanism %s is not supported with slot %ld", + tsuite->name, slot_id); + goto testcase_cleanup; + } + + /** iterate over test vectors **/ + for (i = 0; i < tsuite->tvcount; i++) { + + /** begin test **/ + testcase_begin("Sign %s with test vector %d.", tsuite->name, i); + + /** get mechanism **/ + mech = tsuite->mech; + + /* only run hmac testcases with appropriate mac length */ + switch (mech.mechanism) { + case CKM_SHA_1_HMAC: + if (tsuite->tv[i].mac_len != 20) { + testcase_skip("Skip, this testcase is not" " for SHA1 HMAC"); + continue; + } + break; + case CKM_SHA224_HMAC: + if (tsuite->tv[i].mac_len != 28) { + testcase_skip("Skip, this testcase is not" " for SHA224 HMAC"); + continue; + } + break; + case CKM_SHA256_HMAC: + if (tsuite->tv[i].mac_len != 32) { + testcase_skip("Skip, this testcase is not" " for SHA256 HMAC"); + continue; + } + break; + case CKM_SHA384_HMAC: + if (tsuite->tv[i].mac_len != 48) { + testcase_skip("Skip, this testcase is not" " for SHA384 HMAC"); + continue; + } + break; + case CKM_SHA512_HMAC: + if (tsuite->tv[i].mac_len != 64) { + testcase_skip("Skip, this testcase is not" " for SHA512 HMAC"); + continue; + } + break; + default: + testcase_error("Invalid Mechanism\n"); + goto testcase_cleanup; + } + + /** clear buffers **/ + memset(key, 0, sizeof(key)); + memset(data, 0, sizeof(data)); + memset(actual_mac, 0, sizeof(actual_mac)); + memset(expected_mac, 0, sizeof(expected_mac)); + + /** get test vector info **/ + data_len = tsuite->tv[i].data_len; + actual_mac_len = sizeof(actual_mac); + expected_mac_len = tsuite->tv[i].mac_len; + key_len = tsuite->tv[i].key_len; + memcpy(key, tsuite->tv[i].key, key_len); + memcpy(data, tsuite->tv[i].data, data_len); + memcpy(expected_mac, tsuite->tv[i].mac, expected_mac_len); + + /** create key object **/ + rc = create_GenericSecretKey(session, key, key_len, &h_key); + if (rc != CKR_OK) { + testcase_error("create_GenericSecretKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** initialize signing **/ + rc = funcs->C_SignInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do signing **/ + rc = funcs->C_Sign(session, data, data_len, actual_mac, + &actual_mac_len); + if (rc != CKR_OK) { + testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); + goto error; + } + /** compare sign results with expected results **/ + testcase_new_assertion(); + + if (actual_mac_len != expected_mac_len) { + testcase_fail("hashed data length does not match test " + "vector's hashed data length\nexpected " + "length=%ld, found length=%ld", + expected_mac_len, actual_mac_len); + } else if (memcmp(actual_mac, expected_mac, expected_mac_len)) { + testcase_fail("hashed data does not match test " + "vector's hashed data"); + } else { + testcase_pass("%s C_Sign with test vector %d passed.", + tsuite->name, i); + } +error: + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + return rc; +} + + +/** Tests signature generation with published test vectors. **/ +CK_RV do_Verify_FIPS_HMAC(struct HMAC_TEST_SUITE_INFO * tsuite) +{ + unsigned int i; + CK_MECHANISM mech; + CK_BYTE key[MAX_KEY_SIZE], data[MAX_DATA_SIZE]; + CK_ULONG key_len, data_len, expected_mac_len; + CK_BYTE expected_mac[MAX_HASH_SIZE]; + CK_SESSION_HANDLE session; + CK_SLOT_ID slot_id = SLOT_ID; + CK_ULONG flags; + CK_RV rc; + CK_OBJECT_HANDLE h_key; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + /** begin testsuite **/ + testsuite_begin("%s Verify.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + rc = CKR_OK; // set rc + + /** skip test if mech is not supported with this slot **/ + if (!mech_supported(SLOT_ID, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "mechanism %s is not supported with slot %ld", + tsuite->name, slot_id); + goto testcase_cleanup; + } + + /** iterate over test vectors **/ + for (i = 0; i < tsuite->tvcount; i++) { + + /** begin test **/ + testcase_begin("Verify %s with test vector %d.", tsuite->name, i); + + /** get mechanism **/ + mech = tsuite->mech; + + /* only run hmac testcases with appropriate mac length */ + switch (mech.mechanism) { + case CKM_SHA_1_HMAC: + if (tsuite->tv[i].mac_len != 20) { + testcase_skip("Skip, this testcase is not" " for SHA1 HMAC"); + continue; + } + break; + case CKM_SHA224_HMAC: + if (tsuite->tv[i].mac_len != 28) { + testcase_skip("Skip, this testcase is not" " for SHA224 HMAC"); + continue; + } + break; + case CKM_SHA256_HMAC: + if (tsuite->tv[i].mac_len != 32) { + testcase_skip("Skip, this testcase is not" " for SHA256 HMAC"); + continue; + } + break; + case CKM_SHA384_HMAC: + if (tsuite->tv[i].mac_len != 48) { + testcase_skip("Skip, this testcase is not" " for SHA384 HMAC"); + continue; + } + break; + case CKM_SHA512_HMAC: + if (tsuite->tv[i].mac_len != 64) { + testcase_skip("Skip, this testcase is not" " for SHA512 HMAC"); + continue; + } + break; + default: + testcase_error("Invalid Mechanism\n"); + goto testcase_cleanup; + } + + /** clear buffers **/ + memset(key, 0, sizeof(key)); + memset(data, 0, sizeof(data)); + memset(expected_mac, 0, sizeof(expected_mac)); + + /** get test vector info **/ + data_len = tsuite->tv[i].data_len; + expected_mac_len = tsuite->tv[i].mac_len; + key_len = tsuite->tv[i].key_len; + memcpy(key, tsuite->tv[i].key, key_len); + memcpy(data, tsuite->tv[i].data, data_len); + memcpy(expected_mac, tsuite->tv[i].mac, expected_mac_len); + + /** create key object **/ + rc = create_GenericSecretKey(session, key, key_len, &h_key); + if (rc != CKR_OK) { + testcase_error("create_GenericSecretKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** initilaize verification **/ + rc = funcs->C_VerifyInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + testcase_new_assertion(); + + /** do verification **/ + rc = funcs->C_Verify(session, data, data_len, expected_mac, + expected_mac_len); + if (rc != CKR_OK) + testcase_fail("C_Verify rc=%s", p11_get_ckr(rc)); + + else + testcase_pass("%s C_Verify with test vector %d passed.", + tsuite->name, i); +error: + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + + +/** Tests signature generation with published test vectors. **/ +CK_RV do_SignUpdate_FIPS_HMAC(struct HMAC_TEST_SUITE_INFO * tsuite) +{ + unsigned int i; + CK_MECHANISM mech; + CK_BYTE key[MAX_KEY_SIZE], data[MAX_DATA_SIZE]; + CK_ULONG key_len, data_len, actual_mac_len, expected_mac_len; + CK_BYTE actual_mac[MAX_HASH_SIZE], expected_mac[MAX_HASH_SIZE]; + CK_SESSION_HANDLE session; + CK_SLOT_ID slot_id = SLOT_ID; + CK_ULONG flags; + CK_RV rc; + CK_OBJECT_HANDLE h_key; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + /** begin testsuite **/ + testsuite_begin("%s SignUpdate.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + rc = CKR_OK; // set rc + + /** skip test if mech is not supported with this slot **/ + if (!mech_supported(SLOT_ID, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "mechanism %s is not supported with slot %ld", + tsuite->name, slot_id); + goto testcase_cleanup; + } + + /** iterate over test vectors **/ + for (i = 0; i < tsuite->tvcount; i++) { + + /** begin test **/ + testcase_begin("Multipart SignUpdate %s with test vector %d.", + tsuite->name, i); + + /** get mechanism and set parameter **/ + mech = tsuite->mech; + + /* only run hmac testcases with appropriate mac length */ + switch (mech.mechanism) { + case CKM_SHA_1_HMAC: + if (tsuite->tv[i].mac_len != 20) { + testcase_skip("Skip, testcase not applicable" " to SHA1 HMAC"); + continue; + } + break; + case CKM_SHA224_HMAC: + if (tsuite->tv[i].mac_len != 28) { + testcase_skip("Skip, testcase not applicable" + " to SHA224 HMAC"); + continue; + } + break; + case CKM_SHA256_HMAC: + if (tsuite->tv[i].mac_len != 32) { + testcase_skip("Skip, testcase not applicable" + " to SHA256 HMAC"); + continue; + } + break; + case CKM_SHA384_HMAC: + if (tsuite->tv[i].mac_len != 48) { + testcase_skip("Skip, testcase not applicable" + " to SHA384 HMAC"); + continue; + } + break; + case CKM_SHA512_HMAC: + if (tsuite->tv[i].mac_len != 64) { + testcase_skip("Skip, testcase not applicable" + " to SHA512 HMAC"); + continue; + } + break; + default: + testcase_error("Invalid Mechanism\n"); + goto testcase_cleanup; + } + + /** clear buffers **/ + memset(key, 0, sizeof(key)); + memset(data, 0, sizeof(data)); + memset(actual_mac, 0, sizeof(actual_mac)); + memset(expected_mac, 0, sizeof(expected_mac)); + + /** get test vector info **/ + data_len = tsuite->tv[i].data_len; + actual_mac_len = sizeof(actual_mac); + expected_mac_len = tsuite->tv[i].mac_len; + key_len = tsuite->tv[i].key_len; + memcpy(key, tsuite->tv[i].key, key_len); + memcpy(data, tsuite->tv[i].data, data_len); + memcpy(expected_mac, tsuite->tv[i].mac, expected_mac_len); + + /** create key object **/ + rc = create_GenericSecretKey(session, key, key_len, &h_key); + if (rc != CKR_OK) { + testcase_error("create_GenericSecretKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** initialize signing **/ + rc = funcs->C_SignInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /* for chunks, -1 is NULL, and 0 is empty string, + * and a value > 0 is amount of data from test vector's + * plaintext data. This way we test vary-sized chunks. + */ + if (tsuite->tv[i].num_chunks) { + int j, k = 0; + CK_ULONG len; + CK_BYTE *data_chunk = NULL; + + for (j = 0; j < tsuite->tv[i].num_chunks; j++) { + if (tsuite->tv[i].chunks[j] == -1) { + len = 0; + data_chunk = NULL; + } else if (tsuite->tv[i].chunks[j] == 0) { + len = 0; + data_chunk = (CK_BYTE *) ""; + } else { + len = tsuite->tv[i].chunks[j]; + data_chunk = data + k; + } + + rc = funcs->C_SignUpdate(session, data_chunk, len); + if (rc != CKR_OK) { + testcase_error("C_SignUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + k += len; + } + } else { + rc = funcs->C_SignUpdate(session, data, data_len); + if (rc != CKR_OK) { + testcase_error("C_SignUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + } + + rc = funcs->C_SignFinal(session, actual_mac, &actual_mac_len); + if (rc != CKR_OK) { + testcase_error("C_SignFinal rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare results with expected results **/ + testcase_new_assertion(); + if (actual_mac_len != expected_mac_len) { + testcase_fail("hashed data length does not match test " + "vector's hashed data length\nexpected " + "length=%ld, found length=%ld", + expected_mac_len, actual_mac_len); + } else if (memcmp(actual_mac, expected_mac, expected_mac_len)) { + testcase_fail("hashed data does not match test " + "vector's hashed data"); + } else { + testcase_pass("%s Sign with test vector %d passed.", + tsuite->name, i); + } + +error: + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + + return rc; +} + +/** Tests signature verification with published test vectors. **/ +CK_RV do_VerifyUpdate_FIPS_HMAC(struct HMAC_TEST_SUITE_INFO * tsuite) +{ + unsigned int i; + CK_MECHANISM mech; + CK_BYTE key[MAX_KEY_SIZE], data[MAX_DATA_SIZE]; + CK_ULONG key_len, data_len, expected_mac_len; + CK_BYTE expected_mac[MAX_HASH_SIZE]; + CK_SESSION_HANDLE session; + CK_SLOT_ID slot_id = SLOT_ID; + CK_ULONG flags; + CK_RV rc; + CK_OBJECT_HANDLE h_key; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + /** begin testsuite **/ + testsuite_begin("%s VerifyUpdate.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + rc = CKR_OK; // set rc + + /** skip test if mech is not supported with this slot **/ + if (!mech_supported(SLOT_ID, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "mechanism %s is not supported with slot %ld", + tsuite->name, slot_id); + goto testcase_cleanup; + } + + /** iterate over test vectors **/ + for (i = 0; i < tsuite->tvcount; i++) { + + /** begin test **/ + testcase_begin("Multipart VerifyUpdate %s with test vector %d.", + tsuite->name, i); + + /** get mechanism and set parameter **/ + mech = tsuite->mech; + + /* only run hmac testcases with appropriate mac length */ + switch (mech.mechanism) { + case CKM_SHA_1_HMAC: + if (tsuite->tv[i].mac_len != 20) { + testcase_skip("Skip, testcase not applicable" " to SHA1 HMAC"); + continue; + } + break; + case CKM_SHA224_HMAC: + if (tsuite->tv[i].mac_len != 28) { + testcase_skip("Skip, testcase not applicable" + " to SHA224 HMAC"); + continue; + } + break; + case CKM_SHA256_HMAC: + if (tsuite->tv[i].mac_len != 32) { + testcase_skip("Skip, testcase not applicable" + " to SHA256 HMAC"); + continue; + } + break; + case CKM_SHA384_HMAC: + if (tsuite->tv[i].mac_len != 48) { + testcase_skip("Skip, testcase not applicable" + " to SHA384 HMAC"); + continue; + } + break; + case CKM_SHA512_HMAC: + if (tsuite->tv[i].mac_len != 64) { + testcase_skip("Skip, testcase not applicable" + " to SHA512 HMAC"); + continue; + } + break; + default: + testcase_error("Invalid Mechanism\n"); + goto testcase_cleanup; + } + + /** clear buffers **/ + memset(key, 0, sizeof(key)); + memset(data, 0, sizeof(data)); + memset(expected_mac, 0, sizeof(expected_mac)); + + /** get test vector info **/ + data_len = tsuite->tv[i].data_len; + expected_mac_len = tsuite->tv[i].mac_len; + key_len = tsuite->tv[i].key_len; + memcpy(key, tsuite->tv[i].key, key_len); + memcpy(data, tsuite->tv[i].data, data_len); + memcpy(expected_mac, tsuite->tv[i].mac, expected_mac_len); + + /** create key object **/ + rc = create_GenericSecretKey(session, key, key_len, &h_key); + if (rc != CKR_OK) { + testcase_error("create_GenericSecretKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** initialize signing **/ + rc = funcs->C_VerifyInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /* for chunks, -1 is NULL, and 0 is empty string, + * and a value > 0 is amount of data from test vector's + * plaintext data. This way we test vary-sized chunks. + */ + if (tsuite->tv[i].num_chunks) { + int j, k = 0; + CK_ULONG len; + CK_BYTE *data_chunk = NULL; + + for (j = 0; j < tsuite->tv[i].num_chunks; j++) { + if (tsuite->tv[i].chunks[j] == -1) { + len = 0; + data_chunk = NULL; + } else if (tsuite->tv[i].chunks[j] == 0) { + len = 0; + data_chunk = (CK_BYTE *) ""; + } else { + len = tsuite->tv[i].chunks[j]; + data_chunk = data + k; + } + + rc = funcs->C_VerifyUpdate(session, data_chunk, len); + if (rc != CKR_OK) { + testcase_error("C_VerifyUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + k += len; + } + } else { + rc = funcs->C_VerifyUpdate(session, data, data_len); + if (rc != CKR_OK) { + testcase_error("C_SignUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + } + + testcase_new_assertion(); + + rc = funcs->C_VerifyFinal(session, expected_mac, expected_mac_len); + if (rc != CKR_OK) + testcase_fail("C_VerifyFinal rc=%s", p11_get_ckr(rc)); + else + testcase_pass("%s Verfied with test vector %d passed.", + tsuite->name, i); +error: + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + + return rc; +} + +/** Tests signature verification with published test vectors. **/ +CK_RV do_SignVerify_HMAC(struct HMAC_TEST_SUITE_INFO * tsuite) +{ + unsigned int i; + CK_MECHANISM mech; + CK_BYTE key[MAX_KEY_SIZE]; + CK_ULONG key_len; + CK_BYTE data[MAX_DATA_SIZE]; + CK_ULONG data_len; + CK_BYTE actual[MAX_HASH_SIZE]; + CK_ULONG actual_len; + CK_BYTE expected[MAX_HASH_SIZE]; + CK_ULONG expected_len; + + CK_SESSION_HANDLE session; + CK_SLOT_ID slot_id = SLOT_ID; + CK_ULONG flags; + CK_RV rc; + CK_OBJECT_HANDLE h_key; + + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + /** begin testsuite **/ + testsuite_begin("%s Sign Verify.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + rc = CKR_OK; // set rc + + /** skip test if mech is not supported with this slot **/ + if (!mech_supported(SLOT_ID, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "mechanism %s is not supported with slot %ld", + tsuite->name, slot_id); + goto testcase_cleanup; + } + + /** iterate over test vectors **/ + for (i = 0; i < tsuite->tvcount; i++) { + + /** begin test **/ + testcase_begin("Sign Verify %s with test vector %d.", tsuite->name, i); + + /** get mechanism **/ + mech = tsuite->mech; + + /* for ep11, check if key len is supported */ + key_len = tsuite->tv[i].key_len; + + if ((is_ep11_token(SLOT_ID) || is_cca_token(SLOT_ID)) && + (!check_supp_keysize(SLOT_ID, mech.mechanism, key_len * 8))) { + testcase_skip("keysize %d is not supported in slot %ld", + (unsigned int) key_len, slot_id); + continue; + } + + /** clear buffers **/ + memset(key, 0, sizeof(key)); + memset(data, 0, sizeof(data)); + memset(actual, 0, sizeof(actual)); + memset(expected, 0, sizeof(expected)); + + /** get test vector info **/ + data_len = tsuite->tv[i].data_len; + actual_len = sizeof(actual); + expected_len = tsuite->tv[i].mac_len; + memcpy(key, tsuite->tv[i].key, key_len); + memcpy(data, tsuite->tv[i].data, data_len); + memcpy(expected, tsuite->tv[i].mac, expected_len); + + /** create key object **/ + rc = create_GenericSecretKey(session, key, key_len, &h_key); + if (rc != CKR_OK) { + testcase_error("create_GenericSecretKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** initialize signing **/ + rc = funcs->C_SignInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do signing **/ + rc = funcs->C_Sign(session, data, data_len, actual, &actual_len); + if (rc != CKR_OK) { + testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** initilaize verification **/ + rc = funcs->C_VerifyInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do verification **/ + rc = funcs->C_Verify(session, data, data_len, actual, actual_len); + if (rc != CKR_OK) { + testcase_error("C_Verify rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare sign/verify results with expected results **/ + testcase_new_assertion(); + + if (actual_len != expected_len) { + testcase_fail("hashed data length does not match test " + "vector's hashed data length\nexpected length=" + "%ld, found length=%ld", expected_len, actual_len); + } else if (memcmp(actual, expected, expected_len)) { + testcase_fail("hashed data does not match test " + "vector's hashed data"); + } else { + testcase_pass("%s Sign Verify with test vector %d " + "passed.", tsuite->name, i); + } + +error: + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/** Tests signature verification with published test vectors. **/ +CK_RV do_SignVerify_HMAC_Update(struct HMAC_TEST_SUITE_INFO * tsuite) +{ + int len1 = 0, len2 = 0; + unsigned int i; + CK_MECHANISM mech; + CK_BYTE key[MAX_KEY_SIZE]; + CK_ULONG key_len; + CK_BYTE data[MAX_DATA_SIZE]; + CK_ULONG data_len; + CK_BYTE actual[MAX_HASH_SIZE]; + CK_ULONG actual_len; + CK_BYTE expected[MAX_HASH_SIZE]; + CK_ULONG expected_len; + + CK_SESSION_HANDLE session; + CK_SLOT_ID slot_id = SLOT_ID; + CK_ULONG flags; + CK_RV rc; + CK_OBJECT_HANDLE h_key; + + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + /** begin testsuite **/ + testsuite_begin("%s Sign Verify.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + rc = CKR_OK; // set rc + + /** skip test if mech is not supported with this slot **/ + if (!mech_supported(SLOT_ID, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "mechanism %s is not supported with slot %ld", + tsuite->name, slot_id); + goto testcase_cleanup; + } + + /** iterate over test vectors **/ + for (i = 0; i < tsuite->tvcount; i++) { + + /** begin test **/ + testcase_begin("Multipart Sign Verify %s with test vector %d.", + tsuite->name, i); + + /** get mechanism **/ + mech = tsuite->mech; + + /* for ep11, check if key len is supported */ + key_len = tsuite->tv[i].key_len; + + if ((is_ep11_token(SLOT_ID) || is_cca_token(SLOT_ID)) && + (!check_supp_keysize(SLOT_ID, mech.mechanism, key_len * 8))) { + testcase_skip("keysize %d is not supported in slot %ld", + (unsigned int) key_len, slot_id); + continue; + } + + /** clear buffers **/ + memset(key, 0, sizeof(key)); + memset(data, 0, sizeof(data)); + memset(actual, 0, sizeof(actual)); + memset(expected, 0, sizeof(expected)); + + /** get test vector info **/ + data_len = tsuite->tv[i].data_len; + actual_len = sizeof(actual); + expected_len = tsuite->tv[i].mac_len; + memcpy(key, tsuite->tv[i].key, key_len); + memcpy(data, tsuite->tv[i].data, data_len); + memcpy(expected, tsuite->tv[i].mac, expected_len); + + /** create key object **/ + rc = create_GenericSecretKey(session, key, key_len, &h_key); + if (rc != CKR_OK) { + testcase_error("create_GenericSecretKey rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** initialize signing **/ + rc = funcs->C_SignInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do multipart signing **/ + if (data_len > 0) { + /* do in 2 parts */ + if (data_len < 20) { + len1 = data_len; + } else { + len1 = data_len - 20; + len2 = 20; + } + + rc = funcs->C_SignUpdate(session, data, len1); + if (rc != CKR_OK) { + testcase_error("C_SignUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + + if (len2) { + rc = funcs->C_SignUpdate(session, data + len1, len2); + if (rc != CKR_OK) { + testcase_error("C_SignUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + } + } + rc = funcs->C_SignFinal(session, actual, &actual_len); + if (rc != CKR_OK) { + testcase_error("C_SignFinal rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** initilaize verification **/ + rc = funcs->C_VerifyInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do verification **/ + if (data_len > 0) { + rc = funcs->C_VerifyUpdate(session, data, len1); + if (rc != CKR_OK) { + testcase_error("C_VerifyUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + + if (len2) { + rc = funcs->C_VerifyUpdate(session, data + len1, len2); + if (rc != CKR_OK) { + testcase_error("C_VerifyUpdate rc=%s", p11_get_ckr(rc)); + goto error; + } + } + } + rc = funcs->C_VerifyFinal(session, actual, actual_len); + if (rc != CKR_OK) { + testcase_error("C_VerifyFinal rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** compare sign/verify results with expected results **/ + testcase_new_assertion(); + + if (actual_len != expected_len) { + testcase_fail("hashed data length does not match test " + "vector's hashed data length\nexpected length=" + "%ld, found length=%ld", expected_len, actual_len); + } else if (memcmp(actual, expected, expected_len)) { + testcase_fail("hashed data does not match test " + "vector's hashed data"); + } else { + testcase_pass("%s Sign Verify Multipart with test vector %d " + "passed.", tsuite->name, i); + } + +error: + /** clean up **/ + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + + +/* This function tests generating a generic secret key to be used + * with hmac sign and verify. + */ +CK_RV do_HMAC_SignVerify_WithGenKey(void) +{ + CK_MECHANISM secret_mech = { CKM_GENERIC_SECRET_KEY_GEN, 0, 0 }; + CK_MECHANISM hash_mech = { CKM_SHA_1_HMAC, 0, 0 }; + CK_ULONG key_len = 20; + CK_BYTE data[] = { "Hi There" }; + CK_ULONG data_len = 8; + CK_BYTE actual[MAX_HASH_SIZE]; + CK_ULONG actual_len; + CK_SESSION_HANDLE session; + CK_SLOT_ID slot_id = SLOT_ID; + CK_ULONG flags; + CK_RV rc; + CK_OBJECT_HANDLE h_key; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + /** begin test **/ + testsuite_begin("do_HMAC_SignVerify_WithGenKey"); + testcase_begin("Generate Generic Secret Key And Sign/Verify with it."); + testcase_rw_session(); + testcase_user_login(); + + rc = CKR_OK; // set rc + + /* skip test if mech is not supported with this slot, + * checking for generic secret key mechanism + * and also sha1-hmac mechanism + */ + if (!mech_supported(SLOT_ID, secret_mech.mechanism)) { + testsuite_skip(1, "mechanism %ld not supported with slot %ld", + secret_mech.mechanism, slot_id); + goto testcase_cleanup; + } + if (!mech_supported(SLOT_ID, hash_mech.mechanism)) { + testsuite_skip(1, "mechanism %ld not supported with slot %ld", + hash_mech.mechanism, slot_id); + goto testcase_cleanup; + } + + /** clear buffers **/ + memset(actual, 0, sizeof(actual)); + + /** get test vector info **/ + actual_len = sizeof(actual); + + /** generate key object **/ + rc = generate_SecretKey(session, key_len, &secret_mech, &h_key); + if (rc != CKR_OK) { + testcase_error("generate_SecretKey rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /** initialize signing **/ + rc = funcs->C_SignInit(session, &hash_mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do signing **/ + rc = funcs->C_Sign(session, data, data_len, actual, &actual_len); + if (rc != CKR_OK) { + testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); + goto error; + } + + /* Ensure the generated key can verify what it signed */ + testcase_new_assertion(); + + /** initilaize verification **/ + rc = funcs->C_VerifyInit(session, &hash_mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc)); + goto error; + } + + /** do verification **/ + rc = funcs->C_Verify(session, data, data_len, actual, actual_len); + if (rc != CKR_OK) + testcase_fail("C_Verify rc=%s", p11_get_ckr(rc)); + else + testcase_pass("Sign Verify with generated generic secret key " + "passed."); + +error: + if (funcs->C_DestroyObject(session, h_key) != CKR_OK) + testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc)); + +testcase_cleanup: + testcase_user_logout(); + if (funcs->C_CloseAllSessions(slot_id) != CKR_OK) + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + + return rc; +} + +CK_RV digest_funcs() +{ + CK_RV rc; + unsigned int i; + + /** Digest tests **/ + for (i = 0; i < NUM_DIGEST_TEST_SUITES; i++) { + rc = do_Digest(&digest_test_suites[i]); + if (rc && !no_stop) { + return rc; + } + } + + /** Multipart Digest tests **/ + for (i = 0; i < NUM_DIGEST_TEST_SUITES; i++) { + rc = do_DigestUpdate(&digest_test_suites[i]); + if (rc && !no_stop) { + return rc; + } + } + + + /** RFC HMAC tests **/ + for (i = 0; i < NUM_OF_HMAC_TEST_SUITES; i++) { + rc = do_SignVerify_HMAC(&hmac_test_suites[i]); + if (rc && !no_stop) + return rc; + } + + /** FIPS HMAC tests **/ + for (i = 0; i < NUM_OF_FIPS_HMAC_TEST_SUITES; i++) { + rc = do_Sign_FIPS_HMAC(&fips_hmac_test_suites[i]); + if (rc && !no_stop) + break; + + rc = do_Verify_FIPS_HMAC(&fips_hmac_test_suites[i]); + if (rc && !no_stop) + break; + + rc = do_Sign_FIPS_HMAC_GENERAL(&fips_hmac_general_test_suites[i]); + if (rc && !no_stop) + break; + + rc = do_Verify_FIPS_HMAC_GENERAL(&fips_hmac_general_test_suites[i]); + if (rc && !no_stop) + break; + } + + /** HMAC Multipart tests **/ + /* ica and tpm tokens do not yet support multipart hmac right now. */ + if (!(is_ica_token(SLOT_ID)) && !(is_tpm_token(SLOT_ID))) { + for (i = 0; i < NUM_OF_FIPS_HMAC_TEST_SUITES; i++) { + rc = do_SignUpdate_FIPS_HMAC(&fips_hmac_test_suites[i]); + if (rc && !no_stop) + break; + + rc = do_VerifyUpdate_FIPS_HMAC(&fips_hmac_test_suites[i]); + if (rc && !no_stop) + break; + } + } + + /* HMAC test with a generated generic secret key */ + rc = do_HMAC_SignVerify_WithGenKey(); + + return rc; +} + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + int rc; + CK_BBOOL no_init; + CK_RV rv; + + SLOT_ID = 0; + no_init = FALSE; + + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: no_init: %d\n", no_init); + + rc = do_GetFunctionList(); + if (!rc) { + PRINT_ERR("ERROR do_GetFunctionList() Failed , rc = 0x%0x\n", rc); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + // SAB Add calls to ALL functions before the C_Initialize gets hit + + funcs->C_Initialize(&cinit_args); + + { + CK_SESSION_HANDLE hsess = 0; + + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + } + testcase_setup(0); //TODO + rv = digest_funcs(); + testcase_print_result(); + + funcs->C_Finalize(NULL); + + /* make sure we return non-zero if rv is non-zero */ + return ((rv == 0) || (rv % 256) ? (int)rv : -1); +} diff --git a/testcases/crypto/dilithium.h b/testcases/crypto/dilithium.h new file mode 100644 index 0000000..24962d3 --- /dev/null +++ b/testcases/crypto/dilithium.h @@ -0,0 +1,1459 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2019 + * + * 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 + */ + +/** + * Experimental Support for Dilithium keys and signatures + * with oid = 1.3.6.1.4.1.2.267.1.6.5 + * + * Public-key encoding; raw public-key field. See RFC 3279 for + * subjectPublicKeyInfo (SPKI) structures. + * + * DilithiumPublicKey ::= BIT STRING { + * SEQUENCE { + * rho BIT STRING, [2] -- nonce + * t1 BIT STRING [3] -- from vector(L) + * } + * } + * + * Private-key encoding; see RFC 5959 for PKCS#8 structure definitions. + * + * DilithiumPrivateKey ::= SEQUENCE { + * version INTEGER, -- v0, reserved 0 + * rho BIT STRING, -- nonce + * key BIT STRING, -- key/seed/D + * tr BIT STRING, -- PRF bytes ('CRH' in spec) + * s1 BIT STRING, -- vector(L) + * s2 BIT STRING, -- vector(K) + * t0 BIT STRING -- low bits(vector L) + * t1 [0] IMPLICIT OPTIONAL { + * t1 BIT STRING -- high bits(vector L) -- see also public key + * } + * } + */ + +struct DILITHIUM_TEST_VECTOR { + char *name; + int version; + CK_ULONG rho_len; + CK_BYTE rho[32]; + CK_ULONG seed_len; + CK_BYTE seed[32]; + CK_ULONG tr_len; + CK_BYTE tr[48]; + CK_ULONG s1_len; + CK_BYTE s1[480]; + CK_ULONG s2_len; + CK_BYTE s2[576]; + CK_ULONG t0_len; + CK_BYTE t0[2688]; + CK_ULONG t1_len; + CK_BYTE t1[1728]; + CK_ULONG msg_len; + CK_BYTE msg[4096]; // adjust to max msg len + CK_ULONG sig_len; + CK_BYTE sig[3366]; +}; + +/** + * test vectors from: https://csrc.nist.gov/Projects/post-quantum-cryptography/round-2-submissions + */ +struct DILITHIUM_TEST_VECTOR dilithium_tv[] = { + { + .name = "Dilithium 6-5 KAT 0", + .version = 0, + .rho_len = 32, + .rho = { 0x7C, 0x99, 0x35, 0xA0, 0xB0, 0x76, 0x94, 0xAA, 0x0C, 0x6D, 0x10, 0xE4, 0xDB, 0x6B, 0x1A, 0xDD, 0x2F, 0xD8, 0x1A, 0x25, 0xCC, 0xB1, 0x48, 0x03, 0x2D, 0xCD, 0x73, 0x99, 0x36, 0x73, 0x7F, 0x2D }, + .seed_len = 32, + .seed = { 0x3E, 0x78, 0x4C, 0xCB, 0x7E, 0xBC, 0xDC, 0xFD, 0x45, 0x54, 0x2B, 0x7F, 0x6A, 0xF7, 0x78, 0x74, 0x2E, 0x0F, 0x44, 0x79, 0x17, 0x50, 0x84, 0xAA, 0x48, 0x8B, 0x3B, 0x74, 0x34, 0x06, 0x78, 0xAA }, + .tr_len = 48, + .tr = { 0x73, 0xFD, 0x5E, 0x3F, 0xE6, 0xFB, 0x80, 0xFA, 0x84, 0x71, 0xC0, 0x8C, 0x68, 0x82, 0xF7, 0x1D, 0x86, 0x21, 0x84, 0xC3, 0x5F, 0x55, 0x76, 0xC0, 0x65, 0x97, 0xD8, 0xDC, 0xFA, 0x36, 0xA8, 0x0B, + 0x2C, 0x25, 0x5A, 0x59, 0x9A, 0x55, 0xB0, 0x74, 0xAF, 0x36, 0xE8, 0xDB, 0x79, 0x23, 0xF7, 0x68 }, + .s1_len = 480, + .s1 = { 0x91, 0xB4, 0x79, 0x09, 0xC5, 0x15, 0x4E, 0x10, 0xB2, 0x0D, 0x12, 0x0D, 0x98, 0x66, 0x0B, 0x08, 0xAB, 0x6C, 0xE8, 0xEA, 0x09, 0xA6, 0x36, 0x14, 0xAC, 0xE0, 0xC0, 0x41, 0x38, 0x13, 0x11, 0xC9, + 0xD5, 0x14, 0x6A, 0x71, 0xC0, 0xDA, 0x41, 0xA2, 0x49, 0x91, 0x6E, 0x6D, 0x12, 0xF2, 0xC2, 0x6A, 0xD2, 0x4C, 0x55, 0x8C, 0x86, 0x61, 0x62, 0x01, 0xD8, 0x32, 0x12, 0xC3, 0x04, 0x24, 0x26, 0x4B, + 0xB2, 0xA2, 0xAD, 0xE6, 0xDA, 0x2E, 0x36, 0xA9, 0xE8, 0x28, 0x8E, 0x2C, 0xD3, 0xCD, 0x5D, 0x22, 0x6D, 0x66, 0xC6, 0xBA, 0x02, 0x0C, 0x31, 0x19, 0x69, 0x43, 0xE4, 0x04, 0x6E, 0x71, 0x67, 0x89, + 0x13, 0x14, 0x74, 0x4A, 0x47, 0xB0, 0x50, 0xC3, 0x61, 0x8D, 0x01, 0x22, 0x2A, 0x5A, 0x6B, 0x6A, 0x34, 0x60, 0x26, 0x00, 0x01, 0x68, 0xA6, 0x89, 0x0D, 0x95, 0x10, 0x20, 0x04, 0x82, 0x0C, 0x6B, + 0x70, 0x94, 0x89, 0x50, 0x73, 0x26, 0xD4, 0xB5, 0x0B, 0x40, 0x48, 0x82, 0x31, 0x12, 0xC2, 0x02, 0x0D, 0xE2, 0x78, 0xD0, 0x20, 0x2E, 0x4A, 0x07, 0x41, 0x58, 0x2C, 0x47, 0x9C, 0xBB, 0x15, 0x2E, + 0x8D, 0x24, 0x73, 0x10, 0xD6, 0xE8, 0x66, 0x01, 0xB3, 0x1C, 0xA5, 0x75, 0xB9, 0xD4, 0xD5, 0x84, 0x4E, 0x08, 0xB9, 0xC9, 0x46, 0xC4, 0x84, 0x26, 0xE9, 0x9A, 0xAE, 0x6B, 0x33, 0x94, 0x20, 0x79, + 0x35, 0x16, 0x90, 0x58, 0xD4, 0xB2, 0x5E, 0x46, 0xC7, 0x29, 0x09, 0x47, 0xA0, 0x19, 0xB0, 0x16, 0x2A, 0xC6, 0xE1, 0xC0, 0x42, 0x70, 0x04, 0x62, 0x43, 0xE1, 0xCD, 0x6E, 0x52, 0x25, 0x86, 0xCA, + 0x8A, 0x15, 0x51, 0x2C, 0x69, 0xB1, 0x62, 0x12, 0x89, 0xC9, 0x89, 0x15, 0x2C, 0x8D, 0xB1, 0x01, 0x2C, 0x1C, 0xB2, 0x14, 0x05, 0x5B, 0x1B, 0x95, 0xCC, 0x41, 0x29, 0x27, 0xC3, 0x4A, 0xC8, 0x51, + 0xCC, 0x65, 0x19, 0x52, 0x13, 0x5E, 0x38, 0x44, 0x80, 0x8C, 0x32, 0x2B, 0x56, 0xCF, 0x1A, 0x68, 0x0D, 0x80, 0xD3, 0xDA, 0x6D, 0xB1, 0xD5, 0xF5, 0x98, 0x50, 0x85, 0x38, 0x30, 0x42, 0x6A, 0x73, + 0x9A, 0x4B, 0xCD, 0x50, 0x35, 0x0D, 0x5B, 0x4B, 0x86, 0x90, 0x22, 0xD8, 0x4E, 0x55, 0xA8, 0x23, 0x9D, 0x15, 0x25, 0x50, 0x35, 0x08, 0x91, 0x31, 0xDA, 0x08, 0xCF, 0x2A, 0xB3, 0x15, 0x43, 0x33, + 0xC8, 0x5D, 0x41, 0x59, 0x43, 0xD4, 0x99, 0x30, 0x94, 0x45, 0xD4, 0x3C, 0x60, 0x16, 0xB2, 0x14, 0x45, 0xAB, 0xD1, 0xD5, 0x14, 0x7B, 0x85, 0xC8, 0x8A, 0x1B, 0x6C, 0x66, 0x40, 0x49, 0x02, 0x69, + 0xAA, 0x45, 0x83, 0xB2, 0x66, 0x74, 0x81, 0x68, 0x95, 0x2D, 0x51, 0x19, 0x6B, 0x90, 0xAB, 0x22, 0x84, 0x55, 0xC9, 0x71, 0xAA, 0x44, 0x00, 0x1C, 0x43, 0xA9, 0x62, 0x47, 0x93, 0x0E, 0xA6, 0xD2, + 0xA2, 0xC6, 0x38, 0xA5, 0x17, 0x2F, 0x4A, 0x25, 0x3A, 0x04, 0xB7, 0x54, 0x91, 0x38, 0x07, 0x42, 0x94, 0x45, 0xF3, 0xA2, 0x45, 0xE8, 0x36, 0xC6, 0x48, 0x8A, 0x08, 0x82, 0x4D, 0x97, 0x1B, 0xDD, + 0x36, 0xAC, 0x43, 0x85, 0xD6, 0xD2, 0x4D, 0x5D, 0x88, 0x69, 0x9B, 0xD4, 0x4E, 0x8C, 0x0C, 0xC3, 0xA5, 0x56, 0xB3, 0x54, 0x0A, 0x26, 0x6C, 0x21, 0x6B, 0x5D, 0x3D, 0x52, 0x9E, 0x5D, 0x0D, 0x9A, + 0x00, 0x14, 0x4D, 0x32, 0x08, 0x58, 0x09, 0xD3, 0xD9, 0x38, 0x35, 0x1D, 0xD0, 0xB1, 0x69, 0x29, 0x57, 0x1A, 0x43, 0xC9, 0x32, 0xD3, 0x85, 0xA8, 0x90, 0x0C, 0x6D, 0x1A, 0x2B, 0x74, 0x3A, 0xB9 }, + .s2_len = 576, + .s2 = { 0x16, 0xA7, 0x65, 0x55, 0x1C, 0x11, 0x1E, 0x95, 0x6C, 0x90, 0x30, 0x79, 0x8B, 0x67, 0x8E, 0x0A, 0x36, 0x72, 0xCA, 0x50, 0x27, 0x98, 0xE5, 0x46, 0x6C, 0xA2, 0x14, 0x16, 0x33, 0x02, 0x11, 0x2C, + 0xC3, 0xA9, 0x6D, 0xA3, 0x86, 0xA9, 0xAE, 0xA1, 0x10, 0x27, 0x50, 0x08, 0xD9, 0xB3, 0xB9, 0xC0, 0x51, 0x1D, 0x13, 0x9E, 0x5A, 0x66, 0xE0, 0x0C, 0x76, 0x76, 0x85, 0xA6, 0x0B, 0x12, 0x8F, 0x93, + 0xD0, 0x48, 0x02, 0x28, 0x2C, 0x1E, 0x9D, 0x8C, 0x5B, 0x01, 0x14, 0x74, 0x60, 0x66, 0x43, 0xC2, 0x0D, 0x42, 0x1B, 0xA3, 0x8A, 0x44, 0x25, 0x92, 0x44, 0x90, 0x41, 0x06, 0x8A, 0xA9, 0x24, 0x41, + 0xA6, 0x81, 0xD5, 0x05, 0x3A, 0xD4, 0x6C, 0x93, 0x45, 0x5D, 0x8C, 0x18, 0x88, 0xD4, 0x5A, 0x20, 0x3D, 0xAA, 0xCD, 0xA0, 0xA6, 0xAC, 0x54, 0x45, 0xB3, 0x0B, 0x13, 0xB1, 0x61, 0x1A, 0x08, 0x56, + 0x6D, 0x6D, 0x8D, 0xA6, 0xDA, 0xC0, 0x8D, 0x0D, 0x33, 0xCE, 0x99, 0x96, 0xB4, 0x8B, 0xDB, 0x8D, 0xC8, 0x8C, 0x85, 0x6E, 0x03, 0xB2, 0xC1, 0x2C, 0xAA, 0x43, 0x60, 0x27, 0x60, 0xC1, 0x95, 0x54, + 0xCA, 0x2E, 0x8D, 0x02, 0x19, 0x83, 0x80, 0x3A, 0x43, 0x1D, 0xCC, 0xD1, 0x82, 0x39, 0x81, 0x90, 0xD1, 0xC2, 0x40, 0xC6, 0x28, 0x6C, 0xB5, 0x8C, 0x6A, 0x15, 0xEA, 0xC8, 0x18, 0x42, 0x6A, 0x6B, + 0x01, 0x05, 0x93, 0xB1, 0x53, 0x15, 0xAA, 0xCD, 0x96, 0xCD, 0xC4, 0x79, 0x00, 0x64, 0x8A, 0x24, 0xB6, 0x2E, 0xC6, 0x10, 0xB0, 0x32, 0x38, 0xBA, 0x66, 0xA2, 0x6A, 0xD9, 0x12, 0x2C, 0x74, 0xC9, + 0x15, 0x58, 0x44, 0xD1, 0x45, 0xD4, 0xC9, 0x84, 0x6D, 0x97, 0x55, 0x5C, 0x39, 0xDC, 0x40, 0xC2, 0x83, 0xDA, 0x46, 0x82, 0x48, 0x33, 0x14, 0x02, 0xA6, 0xB1, 0x58, 0x78, 0xA3, 0x65, 0x53, 0x8D, + 0x25, 0x07, 0xDC, 0x14, 0x5B, 0x73, 0x39, 0xB2, 0x28, 0xB6, 0xD1, 0xB6, 0x54, 0x02, 0x85, 0x9C, 0x00, 0x95, 0x37, 0xD1, 0x6B, 0xB4, 0xA9, 0x32, 0xB9, 0xD5, 0x0B, 0x44, 0xB4, 0x03, 0x6A, 0x0C, + 0xA9, 0x21, 0x4E, 0x81, 0x95, 0x36, 0x0C, 0xC0, 0x72, 0x65, 0x59, 0xC4, 0x09, 0x42, 0x39, 0x93, 0x48, 0xD2, 0x03, 0x44, 0x9B, 0xA5, 0x42, 0xA4, 0xD9, 0x9A, 0x19, 0xE4, 0x6C, 0x1A, 0xAA, 0xC4, + 0x11, 0x1B, 0x41, 0x2D, 0xF3, 0xB0, 0xCC, 0xAC, 0x39, 0xA5, 0x19, 0x05, 0x47, 0xA0, 0x51, 0x56, 0x51, 0x57, 0x8C, 0x5B, 0xED, 0xD6, 0x62, 0xDA, 0x5A, 0x75, 0x50, 0x6C, 0x13, 0x11, 0x63, 0x34, + 0x52, 0x23, 0x25, 0x46, 0x78, 0x2C, 0x93, 0xC5, 0x20, 0x20, 0x80, 0x59, 0x2A, 0xC2, 0xA4, 0xE6, 0x7A, 0x4E, 0x9C, 0x70, 0xCE, 0xA4, 0x8E, 0x86, 0x5D, 0x73, 0x61, 0xCA, 0xD1, 0x13, 0xD2, 0xC5, + 0xF6, 0xEA, 0x95, 0x2A, 0xB8, 0x6C, 0x90, 0x69, 0x23, 0xAB, 0xD5, 0x59, 0x00, 0x52, 0x93, 0x51, 0x59, 0x37, 0x34, 0x2B, 0xBA, 0xB0, 0xB4, 0x14, 0x93, 0xE1, 0xAA, 0xA8, 0x20, 0x08, 0x0E, 0xA9, + 0xCA, 0x30, 0x51, 0xB1, 0x60, 0xAA, 0xA8, 0x40, 0xC1, 0x3A, 0x5A, 0xC5, 0xB0, 0x02, 0x1A, 0xAE, 0x1E, 0x2C, 0x9B, 0x6C, 0xD7, 0x0E, 0x32, 0x39, 0x06, 0x50, 0x92, 0xA9, 0x71, 0x92, 0x56, 0x02, + 0x26, 0xCE, 0x9C, 0x41, 0x6E, 0x50, 0x1C, 0x96, 0x4C, 0xA0, 0x7A, 0x13, 0x61, 0x99, 0x01, 0x0B, 0x72, 0x81, 0x45, 0x45, 0x52, 0x1A, 0x0A, 0x6C, 0x31, 0x57, 0x13, 0x6A, 0x71, 0x42, 0x8D, 0x92, + 0xE5, 0x60, 0xC8, 0x99, 0x92, 0x42, 0x9A, 0x91, 0xA6, 0xE9, 0x4A, 0x94, 0xA2, 0x58, 0x33, 0x8E, 0x8A, 0xAA, 0x80, 0xC8, 0x89, 0x23, 0x31, 0x3B, 0x6E, 0x33, 0x76, 0x44, 0x1B, 0x57, 0x12, 0x10, + 0x37, 0xAD, 0xA6, 0x36, 0x0E, 0x43, 0xD6, 0x19, 0xBB, 0x58, 0xED, 0xE2, 0x91, 0x83, 0x1A, 0x10, 0x0A, 0xB7, 0xB9, 0x0B, 0xD3, 0x2A, 0x43, 0x5C, 0x4F, 0x34, 0x18, 0x53, 0xE4, 0xE2, 0x94, 0xDE, + 0xE4, 0xC1, 0x8A, 0xA5, 0x0A, 0xA5, 0x91, 0x4E, 0x45, 0xB9, 0x6C, 0xE4, 0xC6, 0x4C, 0xAA, 0x64, 0x00, 0x63, 0xDD, 0x1A, 0x33, 0xDC, 0x81, 0x42, 0xC7, 0x0D, 0x4B, 0x80, 0x82, 0x58, 0x29, 0x93 }, + .t0_len = 2688, + .t0 = { 0x78, 0x81, 0x96, 0x2F, 0x23, 0xE6, 0x5B, 0x5C, 0x42, 0xDD, 0xCE, 0x0B, 0x7D, 0x97, 0xD3, 0x53, 0x6B, 0xA3, 0xD9, 0x0B, 0xB3, 0x6F, 0x47, 0xDB, 0x3F, 0xB1, 0x38, 0xA0, 0x3A, 0x8D, 0xCE, 0x07, + 0x90, 0x71, 0x65, 0x8B, 0xBB, 0xF2, 0x55, 0x7E, 0x54, 0xD6, 0xFD, 0x7C, 0x88, 0xFB, 0xBD, 0xBD, 0x73, 0x71, 0x03, 0x3C, 0x86, 0x5F, 0x24, 0x82, 0x1C, 0xB6, 0x86, 0xC7, 0x24, 0xA0, 0x75, 0xF2, + 0x34, 0xEB, 0xAF, 0x37, 0xAB, 0x7C, 0xDC, 0x57, 0xAB, 0xFB, 0xE3, 0x7A, 0xA6, 0x0A, 0x44, 0x29, 0x1C, 0x66, 0x00, 0x8F, 0x22, 0x4E, 0x3B, 0x1A, 0x0E, 0x5E, 0x17, 0xC5, 0xF3, 0xEC, 0xE3, 0x11, + 0x23, 0x44, 0x49, 0x90, 0x31, 0xB2, 0x1F, 0x50, 0xED, 0x5B, 0xB5, 0xFF, 0x84, 0x0C, 0x13, 0x16, 0x45, 0x6B, 0xDC, 0x82, 0x5E, 0xB9, 0x03, 0x9A, 0x8F, 0x62, 0x7E, 0x81, 0xA3, 0xBC, 0x39, 0x54, + 0xF4, 0xA4, 0xFF, 0xF5, 0x73, 0x71, 0xB4, 0x6B, 0x17, 0xF5, 0xB6, 0x84, 0x53, 0x2C, 0xFD, 0xFA, 0x64, 0x7C, 0x73, 0x24, 0x2C, 0x82, 0xC1, 0x24, 0x4C, 0xC1, 0x41, 0xD3, 0x97, 0x2B, 0x2C, 0xAD, + 0x88, 0x14, 0xFE, 0x61, 0xEC, 0x80, 0xF0, 0x78, 0x3C, 0xE0, 0xC4, 0x19, 0xB6, 0x73, 0x6E, 0xA6, 0xD7, 0xFA, 0xB2, 0x18, 0x95, 0x01, 0xFF, 0x37, 0x78, 0x11, 0x56, 0x03, 0xD9, 0x4A, 0xBF, 0xFF, + 0x5D, 0x61, 0xE2, 0x81, 0xD8, 0xC1, 0xAF, 0x33, 0x2B, 0x63, 0xF9, 0xCA, 0x13, 0x4C, 0xD0, 0x0B, 0xB9, 0x4F, 0x6B, 0x33, 0x67, 0x2E, 0x92, 0xD4, 0x21, 0xEF, 0xDA, 0x70, 0x6E, 0x47, 0x04, 0xD3, + 0x89, 0x76, 0xE3, 0x39, 0x12, 0x4A, 0x7B, 0xFC, 0x21, 0x85, 0x61, 0xD3, 0xB9, 0x32, 0x5C, 0x09, 0x69, 0xEA, 0x0D, 0x0F, 0xD8, 0x3C, 0x38, 0xD8, 0xF9, 0x84, 0x16, 0xDB, 0x58, 0x5B, 0xF1, 0x6C, + 0xAA, 0x1E, 0x11, 0xD8, 0xCF, 0x2B, 0x9A, 0x91, 0x47, 0xA1, 0x14, 0x34, 0x2D, 0x6A, 0x40, 0xAF, 0x35, 0xCB, 0x14, 0x5C, 0xF6, 0x28, 0x55, 0xAD, 0x31, 0x96, 0xBE, 0x6C, 0xA9, 0xB8, 0x8C, 0x88, + 0xE3, 0x03, 0x6B, 0x33, 0x00, 0x7B, 0x83, 0x10, 0x67, 0xEE, 0x46, 0x08, 0xFD, 0x38, 0xF1, 0x1F, 0x10, 0x2A, 0xCB, 0x30, 0x90, 0xFE, 0x7C, 0x11, 0x24, 0xF8, 0x16, 0x4F, 0x99, 0xE7, 0x5F, 0xF9, + 0x7E, 0xA0, 0xDB, 0xAA, 0x20, 0x78, 0xF5, 0x90, 0x58, 0xDD, 0x9F, 0x4D, 0x15, 0x73, 0xFE, 0xA0, 0xE7, 0x28, 0x60, 0x0A, 0xBB, 0x63, 0xA9, 0xB9, 0x99, 0xD1, 0xD9, 0x15, 0x27, 0x1C, 0xE7, 0x5B, + 0x12, 0x05, 0xA6, 0x20, 0x25, 0x69, 0x1F, 0xA4, 0xF8, 0xAD, 0x8A, 0x83, 0x74, 0x94, 0x65, 0x25, 0x81, 0x34, 0x13, 0x1C, 0x01, 0xBF, 0x3D, 0x43, 0x6A, 0x82, 0x9E, 0xA4, 0xFF, 0x36, 0xA4, 0x06, + 0xA8, 0x91, 0x2A, 0xB6, 0x04, 0x13, 0xCB, 0x67, 0xE1, 0x27, 0xE6, 0xA1, 0xF3, 0xB6, 0xCF, 0x3D, 0x8C, 0x70, 0xF2, 0xB5, 0x6F, 0xE4, 0x57, 0x81, 0x6E, 0x17, 0x30, 0x8C, 0x60, 0x05, 0x37, 0x24, + 0xD0, 0x97, 0x0F, 0x7F, 0x41, 0xCD, 0x4C, 0xB4, 0xF4, 0x40, 0xBF, 0xE4, 0xE6, 0x0D, 0xF6, 0x88, 0xB5, 0x36, 0xCA, 0x57, 0xC8, 0xF0, 0x15, 0xD8, 0xFD, 0x8D, 0xFD, 0xC4, 0x56, 0x4B, 0xF1, 0x79, + 0x40, 0x71, 0x1D, 0xA7, 0x24, 0xA9, 0xB9, 0x86, 0x53, 0x00, 0x58, 0xC4, 0x21, 0x37, 0xD5, 0xCE, 0x52, 0x40, 0x1C, 0x26, 0xFA, 0x59, 0x92, 0x93, 0x96, 0x60, 0xDC, 0x65, 0x2D, 0xF1, 0xDD, 0x91, + 0x99, 0x59, 0xC7, 0xD1, 0x15, 0xCD, 0x19, 0x64, 0xB0, 0x4E, 0xF0, 0x3C, 0x30, 0xD1, 0xEA, 0x29, 0x47, 0xDC, 0x2E, 0x94, 0x5D, 0xB8, 0x78, 0xB4, 0xD7, 0x30, 0x27, 0x98, 0xAF, 0xB9, 0x3F, 0x26, + 0xEA, 0x9A, 0x95, 0xBF, 0x20, 0xEF, 0x05, 0x83, 0x7D, 0xF6, 0xDC, 0xC0, 0xD9, 0x62, 0x4B, 0xF0, 0xD4, 0xDF, 0x28, 0xE0, 0xB6, 0xAF, 0x9D, 0x98, 0xC2, 0x21, 0x96, 0x1A, 0xFE, 0x1E, 0x72, 0x8C, + 0x35, 0xAF, 0x7C, 0x6B, 0x42, 0xCC, 0x18, 0x70, 0xAC, 0x27, 0xAE, 0x90, 0xDB, 0x78, 0xCB, 0x48, 0x85, 0x07, 0xE8, 0x56, 0x1E, 0x13, 0xD5, 0xB1, 0x72, 0xB2, 0xDE, 0x08, 0x66, 0x44, 0xB3, 0x9C, + 0x19, 0x44, 0x71, 0x5D, 0x26, 0x31, 0x8E, 0x72, 0xF3, 0x21, 0x91, 0x79, 0x18, 0x6A, 0x9F, 0xE0, 0x2E, 0x41, 0xFE, 0x64, 0xA9, 0x55, 0xCA, 0x04, 0x4D, 0x1D, 0xC7, 0x97, 0xD4, 0x8A, 0x8F, 0x74, + 0xDF, 0xF4, 0x17, 0x75, 0x39, 0x02, 0x0E, 0x52, 0x20, 0x7F, 0x01, 0x8D, 0x07, 0xA5, 0xED, 0x88, 0xD7, 0x2D, 0xC6, 0xF1, 0xE9, 0x2B, 0x36, 0x72, 0x59, 0x4A, 0xEE, 0xF3, 0x7E, 0xAE, 0x5E, 0xF5, + 0xE1, 0xBF, 0xC8, 0x7F, 0x4A, 0x98, 0x36, 0xB2, 0x64, 0x2A, 0x4C, 0x8A, 0xDE, 0xDC, 0xC5, 0x1C, 0xF0, 0x70, 0xEA, 0x4F, 0xF8, 0xBF, 0xD8, 0x12, 0x1B, 0x5D, 0x43, 0xAD, 0xE5, 0xE1, 0x7E, 0xAF, + 0x2C, 0x60, 0xB2, 0x0D, 0x36, 0x11, 0xFD, 0xC3, 0xDF, 0xFF, 0x32, 0x14, 0xE3, 0xC6, 0x54, 0xAC, 0xB9, 0x7E, 0x0E, 0xE7, 0x2F, 0x41, 0x6A, 0x50, 0x83, 0xA3, 0x4C, 0x44, 0xB6, 0xE6, 0xC4, 0x4B, + 0xC1, 0x0E, 0x92, 0x5F, 0x61, 0x37, 0x0F, 0x18, 0x06, 0xDF, 0x77, 0xCF, 0xC6, 0x8D, 0x40, 0x80, 0x28, 0x52, 0x29, 0x08, 0x7A, 0xB6, 0xB1, 0x11, 0x5C, 0xAB, 0xDE, 0x98, 0x2F, 0x11, 0x63, 0xA0, + 0xB2, 0x40, 0xAF, 0x6A, 0x5B, 0x94, 0x57, 0xCC, 0xED, 0x75, 0xD2, 0x1B, 0x72, 0xC7, 0x28, 0xBA, 0x90, 0x4D, 0x07, 0x39, 0x41, 0x93, 0xDD, 0x59, 0x6D, 0x75, 0xE3, 0x21, 0x33, 0xDF, 0x3E, 0xAF, + 0x89, 0xDA, 0x68, 0xAD, 0x8A, 0xD1, 0x16, 0xC0, 0x0F, 0x54, 0xD5, 0x51, 0xBE, 0x76, 0x29, 0x82, 0xA2, 0x2A, 0x3D, 0xEA, 0xE6, 0x2D, 0x34, 0xD2, 0x04, 0xD2, 0xCB, 0x06, 0xC1, 0xA8, 0x4E, 0xB4, + 0x7A, 0xC9, 0x49, 0x55, 0x13, 0xC1, 0x72, 0x60, 0x20, 0xD8, 0x82, 0x13, 0x50, 0x9C, 0xC8, 0xF0, 0x12, 0xFA, 0x70, 0x4D, 0x2F, 0xFB, 0xE6, 0xFC, 0xB8, 0xD8, 0x0D, 0x94, 0x7C, 0xFB, 0xD2, 0x0F, + 0xEF, 0x29, 0x0A, 0xD6, 0x27, 0x18, 0x54, 0x37, 0xD0, 0x24, 0xA9, 0xA1, 0x5E, 0x43, 0x66, 0x24, 0x96, 0x10, 0xBB, 0x75, 0x2D, 0x4A, 0x86, 0xF5, 0x47, 0x2C, 0x23, 0x46, 0x78, 0x95, 0xF3, 0xAD, + 0x79, 0xF2, 0x37, 0x17, 0xD1, 0x2F, 0xA1, 0xAF, 0xE1, 0x69, 0x4D, 0x6A, 0x4B, 0x51, 0x8E, 0x7E, 0x03, 0x0A, 0x21, 0x44, 0xD8, 0x2C, 0xAC, 0x65, 0x03, 0xBE, 0x53, 0x56, 0x06, 0x48, 0xD6, 0xEA, + 0xC3, 0xAA, 0x19, 0x47, 0x01, 0x76, 0x5B, 0x2B, 0xD9, 0xEE, 0x9B, 0x2A, 0xAA, 0x53, 0x62, 0xBC, 0x79, 0xA0, 0x2C, 0x2B, 0xF7, 0x3A, 0xA5, 0x41, 0x1C, 0xBD, 0x04, 0xB9, 0x16, 0xB1, 0x38, 0xFC, + 0x7B, 0x0D, 0x55, 0x0E, 0x70, 0x5E, 0x50, 0x3A, 0x42, 0xD3, 0x0B, 0x22, 0x0D, 0x60, 0x8C, 0x83, 0xCF, 0x2E, 0xEF, 0x62, 0x79, 0x50, 0xB8, 0x29, 0xDF, 0x33, 0x44, 0xA6, 0xA9, 0x57, 0xB2, 0x97, + 0x18, 0x4B, 0xA6, 0x69, 0xC2, 0x25, 0x0A, 0xD4, 0x29, 0x38, 0xE4, 0xF9, 0x22, 0x92, 0x5F, 0x22, 0x88, 0x7D, 0xF7, 0x9E, 0x95, 0x43, 0x36, 0xA3, 0xC0, 0xB7, 0x46, 0x22, 0x84, 0xB4, 0xF3, 0x80, + 0x11, 0x5C, 0xE7, 0xC3, 0x25, 0x37, 0x64, 0x47, 0x89, 0xF4, 0x2A, 0x31, 0xDB, 0x5C, 0x84, 0x7C, 0xC0, 0x65, 0xA3, 0xDF, 0x03, 0x54, 0x78, 0x9A, 0x2E, 0x18, 0x49, 0x75, 0x15, 0x1D, 0xFB, 0x96, + 0xA9, 0x59, 0x26, 0x97, 0xDE, 0xC9, 0xF9, 0xA8, 0xDD, 0xDE, 0x89, 0x51, 0x63, 0xBC, 0xFA, 0x48, 0x31, 0x48, 0x5D, 0x2C, 0x98, 0xFD, 0xA5, 0xC8, 0x3C, 0x7E, 0xEA, 0xED, 0xC1, 0xBB, 0x1C, 0x03, + 0x81, 0x27, 0xE7, 0x92, 0x91, 0x5A, 0xC5, 0x3D, 0x47, 0x62, 0x8A, 0xF3, 0x8B, 0x30, 0xFC, 0x3B, 0xB9, 0x14, 0xFD, 0x7A, 0x4C, 0x29, 0x83, 0x3C, 0x94, 0x9E, 0xF1, 0xC0, 0xAC, 0x5F, 0xF3, 0xBF, + 0x3C, 0x76, 0xC9, 0xF6, 0x59, 0x35, 0x96, 0x52, 0x14, 0x5A, 0xBC, 0xBE, 0xD4, 0x7B, 0xCF, 0x3B, 0xD5, 0x4F, 0xF6, 0x82, 0x45, 0x2E, 0xD7, 0x51, 0xE2, 0x98, 0x62, 0x93, 0x64, 0xD8, 0x63, 0x3D, + 0x24, 0x8B, 0x30, 0x00, 0x96, 0x7C, 0x75, 0x84, 0x7C, 0x61, 0x76, 0x53, 0xCB, 0x44, 0xC5, 0x7C, 0xCF, 0x34, 0xF4, 0xD9, 0xEE, 0xD8, 0x3F, 0xD2, 0x87, 0xA1, 0x1A, 0xB8, 0x6F, 0xFB, 0x4C, 0xA0, + 0x1F, 0xD8, 0x2B, 0x04, 0x96, 0xE6, 0xFC, 0xED, 0x8D, 0xC6, 0xD1, 0xF6, 0xC7, 0xDD, 0x1E, 0x2A, 0x8F, 0xF3, 0xC3, 0x1A, 0x36, 0x1C, 0x77, 0x9D, 0xE7, 0x6F, 0x00, 0x9D, 0x18, 0xEF, 0x19, 0x74, + 0x3F, 0x1F, 0xFF, 0xA6, 0x04, 0x92, 0xBE, 0x1D, 0x01, 0x46, 0xE6, 0xAD, 0x13, 0xC3, 0x81, 0x87, 0x0E, 0x6C, 0xDB, 0xDE, 0x7E, 0x5E, 0x71, 0x12, 0x1A, 0x89, 0x26, 0x26, 0xE2, 0xEB, 0xB8, 0x9F, + 0x6F, 0x0C, 0x55, 0xC0, 0x4F, 0x9B, 0xCB, 0xAF, 0xB3, 0xF9, 0x05, 0xD4, 0x6D, 0x05, 0x44, 0x10, 0x8C, 0x58, 0x49, 0x7D, 0x44, 0xC6, 0x40, 0xBC, 0xBF, 0xE3, 0x91, 0xDC, 0xDF, 0xEE, 0xEE, 0x3D, + 0x81, 0x59, 0xE9, 0x73, 0x53, 0xFE, 0x1B, 0x42, 0xF8, 0xD7, 0x09, 0x9E, 0x16, 0xD7, 0x3A, 0x44, 0xF3, 0xA7, 0x07, 0xD0, 0x48, 0xB1, 0x9C, 0x6F, 0x84, 0xB3, 0x70, 0x44, 0x13, 0x14, 0x56, 0xF6, + 0xCF, 0x52, 0x69, 0x4C, 0x5F, 0x39, 0x1E, 0xE3, 0xDD, 0xFD, 0x7C, 0xBE, 0x36, 0x0B, 0x72, 0x99, 0xBC, 0x99, 0xFA, 0xDF, 0xF6, 0x92, 0xBE, 0xAD, 0xBB, 0x31, 0x39, 0x43, 0x33, 0xC1, 0xFA, 0x8D, + 0xEB, 0x49, 0x0F, 0xB6, 0x54, 0xEA, 0x0C, 0x0E, 0xA9, 0xCA, 0x79, 0x8D, 0xF2, 0x86, 0x56, 0xED, 0x4C, 0x60, 0xF6, 0xBD, 0x0C, 0xB2, 0x41, 0x9B, 0x87, 0xA9, 0x14, 0x9F, 0xC8, 0xEA, 0x23, 0x6D, + 0xB0, 0x8D, 0x5C, 0xB5, 0xB7, 0xDC, 0x6E, 0x61, 0xA9, 0xEC, 0xB0, 0x00, 0x06, 0x02, 0xAF, 0x03, 0xB4, 0x49, 0xE7, 0xAB, 0xD9, 0x2A, 0x9D, 0xF6, 0x42, 0x0C, 0x04, 0x91, 0x24, 0xD7, 0x64, 0x84, + 0xC9, 0x22, 0x92, 0x68, 0x91, 0x05, 0x71, 0x74, 0xFC, 0xDE, 0xEA, 0x07, 0x2F, 0x7D, 0xE3, 0x8E, 0xA3, 0xCF, 0xAB, 0x50, 0xAC, 0x5B, 0xD4, 0xAA, 0xD7, 0xCA, 0xC3, 0x58, 0x97, 0x72, 0xA1, 0x32, + 0xB2, 0x51, 0x0B, 0x62, 0x7A, 0x9E, 0xE1, 0x60, 0xAC, 0xB7, 0xA3, 0x55, 0x24, 0xDE, 0xE9, 0x49, 0x8B, 0x71, 0xFF, 0x65, 0xE9, 0x62, 0x93, 0x06, 0x93, 0xAB, 0x8C, 0xD2, 0x54, 0x84, 0xA5, 0x08, + 0x43, 0xFE, 0xE4, 0x84, 0xD6, 0xB6, 0xC1, 0xCA, 0x9D, 0x85, 0xF9, 0x7D, 0x80, 0x7D, 0xFE, 0x9E, 0x39, 0x62, 0xC1, 0xF0, 0xEE, 0xFC, 0x00, 0x17, 0x07, 0x64, 0x4B, 0xE2, 0x52, 0x2C, 0xFA, 0x04, + 0x26, 0x73, 0x73, 0x93, 0x93, 0x6D, 0x2F, 0xE1, 0xE2, 0x89, 0x75, 0x79, 0xA0, 0x68, 0xFE, 0x29, 0x65, 0xDE, 0x40, 0x21, 0x4B, 0x94, 0xA5, 0x16, 0x08, 0xFF, 0xF6, 0xDF, 0x2D, 0x15, 0xDC, 0xE9, + 0xA5, 0xB3, 0x0A, 0x11, 0x01, 0x4E, 0xD9, 0x0C, 0x44, 0x46, 0x6F, 0xDF, 0xE0, 0x5C, 0x08, 0x4C, 0x3C, 0x72, 0x47, 0xDF, 0x2C, 0x72, 0x74, 0xF1, 0x87, 0x9F, 0x39, 0x11, 0x1F, 0x61, 0xBB, 0x98, + 0xBB, 0xDB, 0x03, 0x45, 0x8D, 0xFA, 0xBA, 0x7D, 0xEB, 0xC7, 0x44, 0xDB, 0x04, 0xCD, 0x84, 0xE8, 0x79, 0xBB, 0xB0, 0xC0, 0x70, 0xE5, 0x4B, 0x62, 0x96, 0xAB, 0x48, 0xD5, 0x11, 0x7F, 0x91, 0x70, + 0x01, 0x28, 0xC7, 0x86, 0xB0, 0x1C, 0x89, 0x1C, 0xC0, 0x81, 0x89, 0x6D, 0x40, 0xBF, 0x87, 0x6A, 0x5D, 0x18, 0x22, 0xDD, 0xC3, 0xF0, 0x6B, 0xCA, 0x94, 0x2D, 0x46, 0xD8, 0x49, 0x38, 0x96, 0x55, + 0xC8, 0xDE, 0xC2, 0xAA, 0xC2, 0xEA, 0xF6, 0x1D, 0x11, 0xC7, 0xF7, 0x15, 0x23, 0x36, 0x7E, 0xD4, 0x56, 0x4C, 0x0F, 0x98, 0xD5, 0xB0, 0x38, 0x66, 0x61, 0x8C, 0x3D, 0xE3, 0x7D, 0x56, 0x6E, 0x8C, + 0x0F, 0x8F, 0x7A, 0x56, 0x65, 0x68, 0x87, 0x39, 0x86, 0x1F, 0x78, 0x42, 0x92, 0x57, 0x8B, 0x72, 0x80, 0x3F, 0x7A, 0x4B, 0x8D, 0x03, 0x18, 0x30, 0xE0, 0xEF, 0x94, 0x47, 0x00, 0x9C, 0x83, 0x9F, + 0xD6, 0x94, 0xEB, 0x4F, 0x2B, 0x49, 0x08, 0xB8, 0x4D, 0x11, 0xCC, 0x2D, 0xF4, 0x47, 0xA1, 0xC7, 0xB4, 0x84, 0xA6, 0x14, 0x25, 0x34, 0xD5, 0x62, 0x3E, 0x86, 0xE6, 0xFA, 0xD1, 0x78, 0xA4, 0xA6, + 0x0D, 0x4C, 0x8F, 0xE1, 0x1E, 0xE1, 0x53, 0x85, 0xAC, 0x79, 0x1B, 0x69, 0x08, 0x48, 0x96, 0xC1, 0xF1, 0x50, 0xD5, 0x0C, 0x24, 0xF5, 0x07, 0x8F, 0x80, 0xFE, 0xAD, 0x9B, 0x4F, 0x51, 0x86, 0x49, + 0xB6, 0xB4, 0x09, 0x50, 0x2B, 0x38, 0xE0, 0x7B, 0xEF, 0x58, 0x77, 0x35, 0xE8, 0xCB, 0xA9, 0xFF, 0x4D, 0x96, 0x85, 0x07, 0x63, 0xA4, 0x74, 0x37, 0xB2, 0xDA, 0x8F, 0x40, 0x72, 0x5E, 0xC6, 0x46, + 0xDE, 0xC7, 0x27, 0xA8, 0x81, 0x1D, 0x4E, 0x66, 0x8E, 0xA9, 0x7B, 0xC0, 0x23, 0x7F, 0x4E, 0x4A, 0x25, 0xA2, 0xFA, 0x19, 0x8C, 0x3A, 0x77, 0x4B, 0x57, 0x91, 0x7B, 0x72, 0x07, 0x5A, 0x42, 0x1A, + 0x73, 0x90, 0x0B, 0x75, 0x61, 0xEE, 0x43, 0x6F, 0x07, 0x75, 0x31, 0x09, 0xF9, 0x22, 0xC0, 0x55, 0x1F, 0x59, 0x1F, 0xB5, 0x46, 0xA8, 0x81, 0xB1, 0x1C, 0x8C, 0x83, 0x6B, 0xF8, 0x3E, 0xC4, 0x2F, + 0xF7, 0x45, 0x1B, 0xF3, 0xE0, 0xCB, 0xC8, 0x7C, 0x97, 0x29, 0x7D, 0x8F, 0xD1, 0x1E, 0x53, 0x44, 0x1E, 0x4B, 0x74, 0x4A, 0xFE, 0xE4, 0xAA, 0x0B, 0x72, 0x3B, 0x80, 0x6C, 0x34, 0x85, 0xBB, 0xFB, + 0x67, 0x31, 0x06, 0x92, 0x05, 0x10, 0x1C, 0xFF, 0xCC, 0x2C, 0xE2, 0x63, 0xF3, 0xEC, 0xFE, 0x8D, 0x93, 0x0B, 0xF4, 0x9A, 0xD2, 0x8A, 0x7E, 0x6C, 0xEA, 0x75, 0xC5, 0x69, 0x90, 0x6B, 0x5F, 0x93, + 0x55, 0x97, 0x1D, 0xF4, 0x03, 0x3D, 0x00, 0x86, 0x65, 0xDD, 0xD0, 0x62, 0x88, 0x11, 0x99, 0x0B, 0x13, 0x04, 0x7A, 0x6B, 0x2E, 0xEC, 0xE1, 0x8C, 0x62, 0x55, 0x82, 0xD6, 0x0E, 0x08, 0x7B, 0x13, + 0x47, 0x37, 0xBB, 0xC9, 0x26, 0x03, 0x9C, 0xFA, 0x9C, 0xAB, 0xAB, 0x8E, 0x3B, 0xD6, 0x31, 0x90, 0x7A, 0x33, 0x1F, 0x1B, 0x08, 0xC0, 0x9D, 0xCA, 0x05, 0xCE, 0xB1, 0x49, 0xA0, 0xDF, 0x0E, 0x9A, + 0x43, 0x06, 0xA0, 0x49, 0xC9, 0x06, 0x47, 0xC0, 0xEE, 0xE7, 0xBF, 0x84, 0xCA, 0xF9, 0x1C, 0x1B, 0xE7, 0x1D, 0xF4, 0xA3, 0x23, 0x69, 0x89, 0x6D, 0xF8, 0xBB, 0x3D, 0xA8, 0xE8, 0x54, 0x4D, 0xD5, + 0xC1, 0xD5, 0xCB, 0xA1, 0x34, 0x0B, 0x56, 0xB6, 0xB5, 0x18, 0xAA, 0x62, 0xF9, 0x83, 0xA2, 0x71, 0xBA, 0x38, 0x92, 0x04, 0xE1, 0x95, 0x36, 0xAC, 0x98, 0x86, 0x87, 0xA2, 0xDC, 0x0C, 0x5D, 0xEC, + 0xC1, 0xF0, 0x14, 0x33, 0xB7, 0x01, 0xCE, 0x27, 0xB5, 0xCA, 0x70, 0x27, 0x38, 0x22, 0xFC, 0x8A, 0x3F, 0x58, 0xE5, 0x22, 0xEE, 0x8B, 0x8B, 0xD0, 0xB7, 0x56, 0x42, 0x72, 0x9D, 0x9D, 0x4C, 0xEE, + 0xDB, 0xE3, 0xE8, 0xF9, 0x00, 0x69, 0x1A, 0xCA, 0x09, 0x6C, 0x92, 0x7A, 0xC3, 0x4E, 0x94, 0xE2, 0xC7, 0xB8, 0x5D, 0x18, 0x74, 0x5E, 0x42, 0x63, 0xA1, 0x60, 0xFC, 0xC7, 0x87, 0x36, 0x81, 0xF0, + 0xDC, 0xC0, 0x36, 0xC1, 0x8D, 0xD0, 0x0F, 0x52, 0x1A, 0x8B, 0x88, 0xD4, 0x8F, 0x71, 0xD2, 0xC5, 0xE7, 0x69, 0xD6, 0xE4, 0x44, 0x35, 0x70, 0xE9, 0x8C, 0x8C, 0xF6, 0x70, 0xC6, 0xAF, 0x97, 0x46, + 0xA8, 0xC2, 0x87, 0xF7, 0x5C, 0xC2, 0x6B, 0xD3, 0x36, 0xBE, 0xEC, 0x5A, 0xD8, 0xCA, 0x35, 0xD1, 0x67, 0x70, 0xCF, 0x09, 0x3F, 0xAC, 0x78, 0x81, 0xE8, 0x22, 0xAF, 0x2D, 0xAD, 0xB7, 0x27, 0x79, + 0xAB, 0x3E, 0xD8, 0xBC, 0x79, 0x99, 0x95, 0x7C, 0x0D, 0x8A, 0xBD, 0x71, 0xB2, 0x04, 0xF0, 0xFD, 0xBB, 0xAC, 0x65, 0x82, 0x17, 0xE8, 0x83, 0xCA, 0xBB, 0x6A, 0xBA, 0xC8, 0x0C, 0xF4, 0xBA, 0x09, + 0x0B, 0x05, 0x71, 0x1B, 0xB3, 0x7B, 0x14, 0x0D, 0xBB, 0x37, 0x4D, 0xA2, 0x89, 0xD7, 0xA9, 0x34, 0x34, 0x49, 0x7D, 0xA9, 0xF8, 0x16, 0x71, 0x34, 0x57, 0x04, 0xEC, 0x03, 0xBB, 0x86, 0x82, 0x52, + 0x89, 0x37, 0x3F, 0x72, 0x3C, 0x83, 0x83, 0x13, 0xC8, 0x78, 0x7C, 0x1F, 0xAD, 0x57, 0x29, 0xB9, 0xE6, 0x6D, 0xDA, 0x71, 0x0D, 0xD9, 0xFE, 0xB8, 0xB5, 0xBA, 0x24, 0x1A, 0x0B, 0xC4, 0x02, 0xDD, + 0x9C, 0x30, 0x00, 0x68, 0xF5, 0x0F, 0x94, 0x47, 0x5E, 0xF2, 0xF4, 0xAD, 0xD6, 0x67, 0x11, 0x92, 0x07, 0x5A, 0xD2, 0x42, 0x02, 0xF8, 0xD7, 0x73, 0x66, 0x5C, 0xDA, 0x7D, 0x29, 0x79, 0x65, 0x6E, + 0xFC, 0x48, 0x94, 0x18, 0xFD, 0x67, 0x99, 0x29, 0xD5, 0xEB, 0x58, 0x4A, 0x6C, 0x18, 0x4D, 0xFF, 0xE3, 0xF9, 0x9F, 0x26, 0x71, 0xD5, 0x4E, 0xC3, 0x48, 0x32, 0x2F, 0xA1, 0xAE, 0xC4, 0x67, 0xF5, + 0x57, 0x91, 0x22, 0x9F, 0x03, 0x03, 0x53, 0xAF, 0x0F, 0x63, 0x3A, 0x34, 0x59, 0x6E, 0xC0, 0x4C, 0xEC, 0x58, 0xC2, 0x50, 0xE0, 0x99, 0x40, 0xD4, 0x89, 0xEF, 0x4B, 0xB5, 0x47, 0x34, 0xF7, 0x64, + 0x69, 0x9A, 0x45, 0x3C, 0x43, 0x76, 0x4D, 0x1C, 0xFD, 0x4A, 0x61, 0x8F, 0xC9, 0xED, 0xE9, 0xE3, 0x45, 0x66, 0x3E, 0x9B, 0x20, 0x89, 0x54, 0xB5, 0x91, 0x8C, 0x61, 0x0D, 0xB7, 0xF5, 0xBA, 0xD1, + 0xC5, 0xDB, 0x8A, 0x4B, 0xCC, 0xA1, 0xD6, 0x43, 0x92, 0xC7, 0x38, 0x05, 0x36, 0xF0, 0x9C, 0x0A, 0xCC, 0x61, 0xAA, 0xC4, 0x62, 0x99, 0x44, 0xDC, 0x64, 0x42, 0xE2, 0x30, 0x8C, 0x5A, 0xD7, 0x42, + 0x6E, 0x1F, 0xAE, 0x75, 0xE8, 0xA3, 0xA0, 0xBB, 0xB7, 0xF3, 0x4F, 0xB4, 0x0F, 0x41, 0x4A, 0xC7, 0x97, 0xE0, 0xB7, 0x0F, 0x69, 0x65, 0xFC, 0xD3, 0xE0, 0xED, 0x07, 0xDA, 0x8B, 0x75, 0x2F, 0x99, + 0x2D, 0x3C, 0xD2, 0xC0, 0x58, 0x87, 0x84, 0x85, 0x77, 0xA0, 0x28, 0x12, 0x72, 0x28, 0x69, 0x4A, 0x8D, 0xD5, 0x57, 0x3A, 0x73, 0x6E, 0xA7, 0xF8, 0x75, 0x06, 0xF9, 0x32, 0xB2, 0xF1, 0x4B, 0x53, + 0x86, 0xBD, 0x07, 0x17, 0x04, 0x30, 0x54, 0x82, 0x81, 0x3C, 0xF1, 0x1A, 0xD4, 0x25, 0x0E, 0xC5, 0x79, 0xE8, 0xFF, 0x73, 0x4E, 0x07, 0x95, 0xC5, 0x03, 0xB6, 0x2D, 0x6E, 0x44, 0x7B, 0xED, 0xFD, + 0xD1, 0x43, 0x44, 0xE1, 0x8D, 0xD3, 0xFB, 0x95, 0xF0, 0x72, 0xEC, 0xF7, 0xC0, 0xE5, 0x51, 0x7C, 0x18, 0xC0, 0xA6, 0x35, 0x26, 0xDA, 0xDD, 0xC9, 0xBC, 0xAF, 0x8B, 0x8B, 0x6A, 0x26, 0x75, 0x58, + 0x1B, 0x9D, 0x46, 0x56, 0x3A, 0xDA, 0x1C, 0x93, 0xAA, 0x27, 0xF7, 0xA2, 0xF2, 0xC4, 0xB5, 0xEE, 0x8A, 0xED, 0x3D, 0x92, 0x5C, 0x6A, 0x65, 0x47, 0xF6, 0x67, 0x2C, 0x05, 0x8E, 0x5D, 0x95, 0x9B, + 0x6B, 0x9E, 0x32, 0x6A, 0xFC, 0x36, 0xE8, 0x9C, 0x14, 0xE6, 0x81, 0x2B, 0x5C, 0xDD, 0xAB, 0x38, 0x6B, 0x13, 0xF5, 0xD1, 0x44, 0x1A, 0x78, 0x98, 0x7B, 0xD1, 0x9E, 0xBE, 0xEA, 0x91, 0xEF, 0xE4, + 0x72, 0xC2, 0xF8, 0xC2, 0x0D, 0xE2, 0x11, 0x73, 0xAD, 0xB5, 0xAA, 0xF9, 0x17, 0xC6, 0x03, 0x76, 0xC2, 0x77, 0x6D, 0xD0, 0xC6, 0x58, 0xE9, 0x48, 0xF3, 0x46, 0xC2, 0xCA, 0x2B, 0x77, 0xDC, 0x6B, + 0x8B, 0x84, 0xC3, 0x96, 0x78, 0x7E, 0x62, 0xDF, 0x47, 0x0E, 0x94, 0xD8, 0xAB, 0x87, 0xCA, 0x45, 0x37, 0xCE, 0x65, 0x07, 0x0D, 0xA5, 0xA1, 0xBA, 0x4D, 0x22, 0x4D, 0x21, 0x07, 0xFF, 0x60, 0x4B, + 0x1D, 0x14, 0x25, 0x45, 0x95, 0x8C, 0x11, 0xA3, 0xFF, 0xEF, 0x36, 0x85, 0x54, 0x69, 0x4F, 0x2B, 0xFA, 0x6B, 0xFF, 0x57, 0xF5, 0x49, 0x98, 0x8C, 0xA9, 0x1E, 0x87, 0xC9, 0xDF, 0xC4, 0x74, 0x76 }, + .t1_len = 1728, + .t1 = { 0x68, 0x59, 0xF6, 0x4C, 0x66, 0x39, 0x16, 0x79, 0x5E, 0x9D, 0x42, 0xA6, 0x28, 0xF7, 0xA1, 0x1F, 0xB6, 0xCA, 0xD6, 0xBE, 0x5A, 0x22, 0x92, 0x06, 0xF3, 0x8E, 0xC3, 0xE8, 0x7E, 0x74, 0x87, 0xC6, + 0x51, 0x27, 0x45, 0xFE, 0xD6, 0xD0, 0xB6, 0x4F, 0x60, 0x55, 0x07, 0xC0, 0x43, 0xE2, 0x5D, 0x10, 0x3D, 0x19, 0x67, 0x34, 0x93, 0x73, 0x04, 0x73, 0xCD, 0xC0, 0xEF, 0x78, 0x0A, 0x83, 0xF2, 0x3A, + 0x5C, 0x6C, 0x38, 0x75, 0xBC, 0x10, 0xB6, 0xA0, 0x53, 0xB1, 0x3A, 0xAD, 0x6F, 0xD7, 0xFF, 0x1E, 0xCF, 0x8F, 0x72, 0x5F, 0x46, 0x01, 0x81, 0x46, 0x0C, 0x5C, 0x75, 0xE0, 0x50, 0x52, 0xFE, 0xA0, + 0xDB, 0xC4, 0x99, 0x2E, 0xE0, 0x43, 0x22, 0xBB, 0x21, 0xAF, 0x25, 0xD7, 0x84, 0xCB, 0xD4, 0x34, 0xDF, 0x2A, 0x87, 0xAA, 0x48, 0x6A, 0xE7, 0x05, 0x7F, 0xA0, 0x42, 0x87, 0xDA, 0x5F, 0xC0, 0xD0, + 0x08, 0x8C, 0x16, 0x82, 0xE0, 0x9E, 0x47, 0xAB, 0xF3, 0x08, 0x36, 0xC3, 0x82, 0x42, 0xC8, 0xA4, 0xBA, 0x58, 0xFA, 0x4B, 0x7A, 0x17, 0x2D, 0x3B, 0x00, 0x32, 0x51, 0x65, 0x63, 0xFE, 0x46, 0xB7, + 0x2E, 0x49, 0xDF, 0xAC, 0xD0, 0x03, 0x3E, 0x44, 0x4F, 0x5C, 0xEF, 0x0F, 0xF4, 0x97, 0xD4, 0xD9, 0xD9, 0xE5, 0xB9, 0x88, 0x6F, 0x4B, 0x47, 0x29, 0x9D, 0x63, 0x52, 0x41, 0xA6, 0xDC, 0xF0, 0x69, + 0xF1, 0xED, 0x1C, 0x81, 0x5A, 0x51, 0xA6, 0xF7, 0xC7, 0x55, 0xD3, 0xFB, 0x2C, 0xF0, 0xD6, 0x19, 0xF8, 0x48, 0xC3, 0x5C, 0x5A, 0x61, 0x41, 0x9A, 0x53, 0xCB, 0xA5, 0x19, 0x30, 0x97, 0x43, 0x83, + 0x82, 0x8D, 0xAD, 0x66, 0x7C, 0x4B, 0x89, 0x01, 0xF7, 0xDF, 0x68, 0xF4, 0x9F, 0x7F, 0xA2, 0x06, 0x9F, 0x2A, 0xA5, 0xC7, 0xFD, 0xC8, 0x5D, 0x37, 0xD0, 0x66, 0x35, 0x65, 0x71, 0x1D, 0xD1, 0xC5, + 0xE6, 0x53, 0x56, 0xDD, 0xFB, 0xE3, 0x4A, 0x67, 0x5C, 0x6F, 0x55, 0xA1, 0x85, 0xCB, 0xEC, 0x69, 0x74, 0x7D, 0x3F, 0x24, 0x8C, 0xC8, 0x1D, 0x1F, 0xB7, 0xD4, 0xBC, 0x6E, 0x3F, 0x78, 0x5A, 0xD0, + 0x21, 0x70, 0x01, 0x7D, 0x2A, 0x98, 0x5C, 0x5C, 0xC9, 0xE1, 0x05, 0xCB, 0x5D, 0xFB, 0x87, 0x86, 0xD4, 0x57, 0x80, 0x13, 0xE7, 0x93, 0xB0, 0xAF, 0x05, 0x75, 0x65, 0xB5, 0xFA, 0xA4, 0xF4, 0x1C, + 0x3E, 0xA7, 0x10, 0xC0, 0x19, 0xF8, 0x7D, 0x7E, 0x39, 0xBB, 0xBC, 0x09, 0x32, 0x01, 0xF7, 0x6E, 0xCB, 0x19, 0xB4, 0xE4, 0xBE, 0x14, 0x90, 0x86, 0x39, 0xE4, 0x46, 0xC3, 0xD1, 0xB1, 0x35, 0x04, + 0x8B, 0x72, 0xD3, 0x86, 0x30, 0x93, 0x92, 0x1C, 0xE6, 0x0C, 0x51, 0xC7, 0x08, 0x13, 0xF6, 0xE8, 0xF0, 0xB0, 0x69, 0x38, 0xB4, 0xAF, 0xA7, 0x96, 0xD1, 0x6F, 0xB6, 0x5F, 0x0C, 0x1B, 0xE6, 0xF2, + 0x15, 0xA4, 0xE3, 0xF0, 0x84, 0x6F, 0xC3, 0x9B, 0xD6, 0xD2, 0xC3, 0x3B, 0xCA, 0xDF, 0xFF, 0x2A, 0x9E, 0xCD, 0x96, 0x40, 0xDC, 0x3C, 0xBF, 0xEE, 0x6F, 0x25, 0x1F, 0xC5, 0x3A, 0x53, 0x50, 0xBF, + 0x1B, 0xBC, 0x12, 0xC9, 0x4B, 0x26, 0x3C, 0xD5, 0x89, 0xB5, 0x6A, 0xEE, 0x8A, 0xED, 0x89, 0x1D, 0x34, 0x2B, 0x76, 0xBD, 0x62, 0x15, 0xD9, 0x32, 0x11, 0xEF, 0xED, 0x7C, 0x4A, 0x86, 0xBA, 0xEC, + 0x77, 0xBB, 0xE1, 0x18, 0xCA, 0xC7, 0x4D, 0xB9, 0xBA, 0x42, 0x41, 0xF1, 0x19, 0xFB, 0x7F, 0x11, 0x15, 0xDD, 0x0A, 0xEA, 0x46, 0x5A, 0x83, 0xBF, 0xB0, 0x7D, 0x7F, 0x59, 0x5B, 0x66, 0xA7, 0xEB, + 0x25, 0x7B, 0x39, 0x5E, 0x80, 0x45, 0x81, 0xC2, 0x58, 0x85, 0x4B, 0xF7, 0x64, 0x3F, 0x2B, 0xBC, 0x4A, 0xC2, 0xD2, 0x11, 0x20, 0x70, 0xC3, 0xE6, 0x7B, 0xAB, 0x0D, 0x40, 0x67, 0x59, 0xEA, 0xE6, + 0xEB, 0x90, 0xBE, 0x54, 0xEF, 0x92, 0x27, 0xD4, 0xB1, 0x66, 0xAD, 0x28, 0x83, 0x42, 0x22, 0x68, 0x57, 0x65, 0x71, 0x18, 0x77, 0xA7, 0x82, 0x7B, 0x2B, 0xDB, 0xD7, 0xF5, 0xF8, 0xF2, 0x19, 0x92, + 0x4A, 0xDD, 0x54, 0xCC, 0x30, 0x24, 0x92, 0x41, 0x82, 0xC5, 0x42, 0xC8, 0x10, 0x11, 0x02, 0x1D, 0x85, 0x1B, 0x39, 0x72, 0x86, 0xF5, 0x21, 0x1C, 0x82, 0xDE, 0xF9, 0xB5, 0x20, 0xF5, 0x64, 0x64, + 0x80, 0x5A, 0xD6, 0x5D, 0xBD, 0x8C, 0x60, 0x39, 0xBE, 0x94, 0x86, 0xC0, 0x72, 0xC0, 0x43, 0x08, 0x05, 0x13, 0x1B, 0xE1, 0xC1, 0xEA, 0x43, 0xCC, 0x08, 0xE6, 0xBE, 0x9C, 0xEB, 0x94, 0xAB, 0xEB, + 0x48, 0xC8, 0xDD, 0x39, 0xA9, 0xDE, 0x0B, 0xF0, 0xA3, 0x32, 0xCC, 0x25, 0xEF, 0x1B, 0x36, 0xA3, 0x6B, 0x06, 0xF8, 0x0D, 0x55, 0x9B, 0x46, 0xE2, 0x4D, 0x03, 0x02, 0xE8, 0x2B, 0x81, 0xF1, 0xAD, + 0xD4, 0x88, 0x49, 0xEE, 0xD8, 0x7C, 0x3E, 0x3B, 0xEE, 0x7A, 0xF5, 0xCB, 0xCC, 0x96, 0x01, 0x7E, 0x32, 0xE8, 0xBE, 0x0C, 0x3E, 0xBC, 0x6F, 0x19, 0x87, 0x43, 0x58, 0xCE, 0x70, 0xC8, 0x51, 0xAD, + 0xA6, 0xBA, 0x86, 0x85, 0x39, 0x2C, 0x69, 0xB9, 0x06, 0x2C, 0xF7, 0x4D, 0xB3, 0xC5, 0x3C, 0xBB, 0xE8, 0xE7, 0x78, 0x2B, 0xE7, 0x9E, 0x09, 0x10, 0x0D, 0xE3, 0x21, 0x1D, 0xF2, 0xA5, 0x72, 0x08, + 0x31, 0x4B, 0x63, 0x2E, 0xD8, 0x79, 0x9E, 0x42, 0x26, 0xF7, 0xBD, 0x08, 0x79, 0x02, 0xAB, 0xFD, 0x1F, 0x3B, 0xE7, 0x29, 0xF8, 0x60, 0x85, 0x13, 0x32, 0x6F, 0x3F, 0x41, 0x42, 0xD5, 0xA9, 0xCF, + 0x3C, 0x19, 0x61, 0x80, 0xA2, 0x3C, 0xBB, 0xBD, 0x37, 0xDE, 0x01, 0xC6, 0x06, 0x4A, 0x75, 0xCB, 0xAC, 0x5D, 0xC7, 0x73, 0x15, 0x76, 0x36, 0x6F, 0x3C, 0x70, 0x6E, 0xC2, 0x9E, 0x0E, 0x15, 0xBE, + 0xC3, 0x48, 0xA6, 0x07, 0xE2, 0xCF, 0xD4, 0x2A, 0x39, 0x2A, 0xF0, 0xE8, 0xC4, 0x9D, 0x4B, 0x89, 0xCE, 0x05, 0x79, 0xD1, 0x86, 0xF0, 0xC2, 0x2D, 0x84, 0xC5, 0x06, 0x6F, 0x1A, 0x3D, 0xF6, 0x0E, + 0xED, 0x66, 0x3D, 0xFA, 0xF6, 0xA3, 0x5A, 0x74, 0x40, 0xD4, 0xC7, 0x68, 0x53, 0xD7, 0x44, 0xFE, 0x18, 0x6D, 0x98, 0x9F, 0x27, 0x1F, 0x15, 0xC7, 0x0A, 0xD7, 0xA8, 0x60, 0x91, 0xB7, 0x78, 0x67, + 0xDD, 0x2C, 0x4F, 0xE5, 0xE2, 0xAD, 0x84, 0x3D, 0x7C, 0x99, 0xA6, 0x0B, 0x70, 0x76, 0x8F, 0x38, 0x44, 0xF5, 0xCC, 0x35, 0x55, 0xF8, 0x19, 0x1B, 0x56, 0xC8, 0xB5, 0xC6, 0x2D, 0x54, 0xD3, 0xDE, + 0x7B, 0xED, 0x98, 0x01, 0x34, 0xF1, 0x51, 0xD7, 0xE2, 0xCE, 0x98, 0x2F, 0x19, 0x2C, 0x01, 0x08, 0x42, 0xBD, 0x4A, 0xB4, 0x40, 0xEE, 0xE9, 0x83, 0x6E, 0x87, 0x2C, 0x8A, 0xEF, 0x5E, 0x2B, 0x86, + 0x57, 0x8B, 0x36, 0x8C, 0xDE, 0x15, 0x96, 0x86, 0x14, 0xEA, 0xDE, 0xCC, 0xED, 0xE7, 0x21, 0x79, 0xD4, 0xCC, 0x12, 0x72, 0xEA, 0x35, 0xBB, 0x7C, 0xB0, 0x92, 0x50, 0x8C, 0x72, 0x2D, 0x6D, 0xB8, + 0xE8, 0xCC, 0x9E, 0x52, 0xC0, 0xE7, 0x07, 0xE4, 0x4A, 0xA0, 0x23, 0x71, 0x53, 0xAE, 0x20, 0xDE, 0x9D, 0x7E, 0xD5, 0x79, 0x80, 0xC1, 0xB8, 0x19, 0xF7, 0xB3, 0xA8, 0x59, 0x40, 0x2B, 0x1C, 0xDD, + 0xFD, 0x0C, 0x49, 0x18, 0x4B, 0x9A, 0x12, 0x04, 0xA1, 0xD3, 0xDB, 0x63, 0xFF, 0x9D, 0x6A, 0xB7, 0x9B, 0x18, 0xCF, 0xED, 0x0B, 0xDB, 0x76, 0xCC, 0xAA, 0x24, 0xA3, 0xF7, 0xB6, 0xE7, 0x7C, 0xA7, + 0x3D, 0x63, 0xF1, 0x5B, 0x2E, 0x98, 0x67, 0x65, 0xD8, 0x68, 0x55, 0xBC, 0xEF, 0x5D, 0x45, 0x3D, 0xEA, 0xDA, 0x48, 0xC3, 0x0F, 0x48, 0xBD, 0x33, 0xE8, 0xE1, 0x35, 0x11, 0x27, 0x98, 0xFE, 0xC7, + 0x44, 0xEA, 0xD8, 0x33, 0x8A, 0x77, 0x87, 0xFE, 0x59, 0xE3, 0xB9, 0x08, 0x89, 0xED, 0x89, 0x63, 0x50, 0x9F, 0x68, 0x02, 0x0F, 0x43, 0x61, 0x92, 0xE9, 0x54, 0x41, 0x12, 0x7E, 0x03, 0xF7, 0x64, + 0x32, 0x84, 0x54, 0x76, 0xFF, 0x28, 0x4E, 0xE6, 0xF1, 0x62, 0x8C, 0x0F, 0xEC, 0x65, 0xEB, 0xBD, 0x9B, 0x48, 0xF2, 0x02, 0x5F, 0x14, 0x34, 0xE5, 0xA2, 0x23, 0x5F, 0x8F, 0xCE, 0x87, 0x3D, 0x8C, + 0xCA, 0xEF, 0x94, 0xC3, 0xBA, 0xEB, 0x20, 0x0A, 0x08, 0x00, 0xA6, 0x0B, 0x9B, 0x1F, 0xFE, 0x72, 0x78, 0xFD, 0x5A, 0x3A, 0xE3, 0x0C, 0x89, 0x34, 0x36, 0xC9, 0xAF, 0x57, 0xD7, 0xE0, 0xD6, 0x25, + 0x80, 0xD4, 0x5F, 0x2D, 0xA7, 0x77, 0x0E, 0x49, 0x94, 0xA1, 0x03, 0x1E, 0x7B, 0xA1, 0xF3, 0x3C, 0xAA, 0x2E, 0x20, 0xEC, 0x83, 0x96, 0x60, 0x5F, 0xBD, 0x4C, 0x7B, 0x32, 0xA1, 0xD4, 0x60, 0xB8, + 0x7B, 0xBD, 0xC1, 0x93, 0x46, 0x98, 0xE7, 0xF5, 0x71, 0xDA, 0x56, 0x08, 0xDC, 0x1D, 0xA5, 0x80, 0x54, 0xBA, 0xA0, 0xB9, 0x83, 0xE0, 0x34, 0x84, 0xCF, 0xBC, 0x32, 0xD0, 0x1C, 0xCA, 0x13, 0xBC, + 0xF0, 0xCA, 0x0C, 0xEF, 0xB7, 0x48, 0x03, 0xB9, 0xFD, 0xBE, 0xCA, 0x4C, 0x70, 0x42, 0xB7, 0x28, 0xD2, 0xB7, 0xB3, 0xF4, 0x3C, 0x47, 0xB0, 0xA4, 0x2A, 0xD0, 0xC6, 0xD5, 0x26, 0x2B, 0xC3, 0x98, + 0xE7, 0x16, 0x44, 0x8B, 0xB6, 0x8F, 0xAE, 0x54, 0x2A, 0x0D, 0x5F, 0x46, 0x82, 0x0B, 0xD7, 0x8A, 0x61, 0xC3, 0xE8, 0x33, 0xFD, 0x7B, 0xEE, 0x3E, 0x39, 0x8F, 0x7C, 0x91, 0xB8, 0x9F, 0x89, 0xE5, + 0xEB, 0x12, 0x29, 0x8E, 0xCC, 0x7B, 0xCA, 0x64, 0xF9, 0x9F, 0x0A, 0x5F, 0x48, 0xF5, 0x3F, 0x16, 0x77, 0xEE, 0x13, 0xA1, 0xE1, 0xF3, 0x7C, 0x1A, 0x8D, 0xD2, 0x85, 0x58, 0x16, 0x45, 0x9B, 0x3F, + 0x14, 0xA1, 0x0C, 0xAE, 0x3D, 0x7F, 0x19, 0xE0, 0x41, 0x2A, 0xEE, 0xA5, 0x3B, 0x43, 0x05, 0xF0, 0xD0, 0x22, 0x88, 0x50, 0x60, 0xDA, 0x5F, 0x2B, 0x46, 0x65, 0x2D, 0xE2, 0xF5, 0xAF, 0xA8, 0xBF, + 0x7E, 0x6C, 0xE5, 0xA6, 0xE4, 0x04, 0x66, 0xC7, 0x92, 0xD3, 0x17, 0x50, 0xAD, 0x28, 0x40, 0x65, 0x1A, 0x44, 0x2B, 0x67, 0x35, 0x37, 0xA7, 0x6E, 0xF4, 0x5F, 0xA1, 0xD3, 0x8F, 0xF7, 0x7E, 0x47, + 0x05, 0x21, 0x77, 0x39, 0x92, 0xD5, 0x69, 0x94, 0x12, 0x6E, 0xC9, 0xEC, 0x78, 0x04, 0x73, 0xA0, 0xFD, 0x5A, 0x7E, 0xC9, 0xF3, 0xCF, 0x78, 0x12, 0x56, 0xF4, 0xF1, 0xA9, 0x69, 0x30, 0x15, 0x22, + 0x19, 0x3F, 0xD8, 0xCB, 0x8C, 0xCD, 0x5F, 0x94, 0x12, 0x4F, 0x2C, 0x39, 0xCA, 0xE4, 0x55, 0x74, 0x76, 0x1B, 0xD7, 0x6F, 0x64, 0x15, 0x39, 0x34, 0xBD, 0x22, 0x0B, 0x48, 0xFB, 0xD0, 0xFC, 0xB5, + 0xD7, 0x39, 0x83, 0x3B, 0x20, 0x3D, 0x55, 0x43, 0x57, 0xC8, 0xB1, 0x91, 0x9A, 0x46, 0xFD, 0x84, 0xFA, 0x39, 0x64, 0x3F, 0x5E, 0x05, 0x9E, 0xB7, 0x4D, 0x13, 0xF8, 0xB9, 0xD0, 0xE7, 0x73, 0x28, + 0x5F, 0xE9, 0xDB, 0x5D, 0x98, 0x56, 0xC1, 0x4D, 0x76, 0xE2, 0x85, 0xCF, 0xB7, 0xF1, 0xE0, 0x0C, 0xB2, 0x16, 0xCF, 0xDA, 0xA9, 0x1F, 0x68, 0x44, 0xDC, 0x08, 0x13, 0xF3, 0xEC, 0xB5, 0x36, 0x31, + 0xB1, 0xCD, 0x94, 0x19, 0x4A, 0x69, 0x26, 0xB0, 0x1B, 0x35, 0xA3, 0x16, 0x16, 0x9A, 0x67, 0x2B, 0xCB, 0x96, 0xF3, 0xD3, 0x50, 0x4C, 0xAA, 0xF4, 0xC0, 0x81, 0x32, 0xC1, 0x77, 0xFD, 0x47, 0x38, + 0x51, 0x28, 0x23, 0x84, 0x91, 0x47, 0x19, 0x7C, 0x87, 0x3D, 0xF3, 0xC6, 0xDD, 0x2A, 0xCB, 0xCC, 0xD2, 0x55, 0x7D, 0xD9, 0x64, 0x34, 0x4A, 0xA1, 0x15, 0xC9, 0x47, 0x2F, 0x38, 0xBD, 0x98, 0x96, + 0x4A, 0x42, 0x26, 0xEF, 0x91, 0x3B, 0x64, 0xB5, 0x40, 0x5D, 0xEF, 0xCA, 0x1F, 0x00, 0x8C, 0xBA, 0xCE, 0xDE, 0x3F, 0x63, 0x26, 0xBF, 0x43, 0x66, 0x3E, 0xDD, 0xB7, 0xE5, 0xFC, 0xCA, 0x8E, 0xAD, + 0xA8, 0x86, 0xBC, 0x9D, 0xF4, 0x2E, 0xDE, 0x4C, 0xC1, 0x42, 0x9C, 0xD7, 0xFF, 0x4C, 0x9E, 0xED, 0xB2, 0xA2, 0x10, 0xBC, 0x28, 0xAE, 0x73, 0xD6, 0x23, 0x3F, 0x6F, 0x65, 0x70, 0x73, 0x9A, 0x0C, + 0x53, 0x72, 0x6C, 0x32, 0xE2, 0xE9, 0x5F, 0xCA, 0x8C, 0x34, 0xE3, 0x60, 0x93, 0x72, 0x6A, 0x87, 0x01, 0x3A, 0x35, 0x12, 0xD8, 0x8E, 0xA9, 0x2A, 0x6B, 0x95, 0x7B, 0xF1, 0x0A, 0x6A, 0xEE, 0x6E, + 0x97, 0x6A, 0xBC, 0xC9, 0x5C, 0x14, 0xA8, 0xEF, 0xE6, 0x0A, 0x2C, 0x1A, 0xF0, 0xAB, 0xBE, 0x6B, 0xF7, 0x89, 0xD4, 0xF6, 0x97, 0x38, 0x09, 0x2A, 0xE3, 0xE6, 0x2A, 0xF1, 0x77, 0x3E, 0xD6, 0xA4, + 0x2F, 0x1A, 0xAA, 0xBC, 0xFB, 0x98, 0x73, 0x1C, 0xE2, 0x70, 0x1F, 0x42, 0xE4, 0xBA, 0x9E, 0x12, 0x8B, 0x67, 0x26, 0x1C, 0x59, 0x8D, 0x31, 0x89, 0xD0, 0x60, 0x24, 0xF0, 0x1E, 0x25, 0x35, 0x4D, + 0x60, 0x32, 0x7F, 0xB6, 0x57, 0x0B, 0xF7, 0xE1, 0x63, 0xFA, 0x04, 0x32, 0x4B, 0x32, 0xE7, 0xEB, 0xF8, 0xB7, 0x8A, 0xC2, 0xEC, 0xFA, 0x3D, 0x36, 0xB1, 0x3A, 0x59, 0xA3, 0xA7, 0x27, 0x02, 0x9B }, + .msg_len = 33, + .msg = { 0xD8, 0x1C, 0x4D, 0x8D, 0x73, 0x4F, 0xCB, 0xFB, 0xEA, 0xDE, 0x3D, 0x3F, 0x8A, 0x03, 0x9F, 0xAA, 0x2A, 0x2C, 0x99, 0x57, 0xE8, 0x35, 0xAD, 0x55, 0xB2, 0x2E, 0x75, 0xBF, 0x57, 0xBB, 0x55, 0x6A, + 0xC8 }, + .sig_len = 3366, + .sig = { + 0xD7, 0x87, 0x58, 0xC8, 0x99, 0x2B, 0x2D, 0x0F, 0xC5, 0x1A, 0x03, 0xD7, 0x6B, 0x07, 0x17, 0x96, 0xF9, 0x15, 0xD6, 0xB2, 0x41, 0x5F, 0x61, 0x07, 0x58, 0xD1, 0x88, 0xAC, 0x94, 0x04, 0x8C, 0x53, + 0x0D, 0x81, 0xB2, 0xC1, 0xBC, 0x7B, 0x95, 0x19, 0xB3, 0xEB, 0x4F, 0x0C, 0xFA, 0x97, 0xDA, 0x66, 0xB8, 0xD1, 0x44, 0x70, 0x71, 0x1D, 0x1A, 0x85, 0x1A, 0x52, 0xB3, 0x72, 0xC2, 0xBE, 0xB4, 0xA3, + 0xFE, 0xA3, 0x3A, 0x29, 0x3B, 0xC1, 0x83, 0x47, 0xD1, 0x51, 0x47, 0x7D, 0x19, 0x7B, 0xD9, 0x39, 0x7A, 0xB2, 0x74, 0x1A, 0xA6, 0x5E, 0x37, 0xC1, 0x72, 0xEF, 0x29, 0xDD, 0xA2, 0x70, 0x0E, 0xCF, + 0xB9, 0xDF, 0x47, 0x8F, 0xF9, 0x4C, 0xAC, 0x21, 0x6B, 0xDD, 0xD6, 0x7E, 0x2A, 0x52, 0xA2, 0x83, 0x31, 0x2A, 0x2B, 0x09, 0x92, 0x7B, 0xA1, 0x73, 0x7F, 0xBD, 0xEC, 0x13, 0x85, 0x97, 0x83, 0x71, + 0xA1, 0xA1, 0x99, 0x54, 0x3B, 0x8B, 0x36, 0x91, 0x10, 0xEB, 0xE2, 0xB6, 0xDF, 0x44, 0x1A, 0xEE, 0x27, 0xB5, 0x20, 0x7C, 0xDD, 0x3A, 0xF2, 0xF7, 0x71, 0x09, 0xF2, 0xA3, 0xDB, 0x89, 0xD3, 0x00, + 0xE2, 0x7D, 0x9A, 0x48, 0x47, 0x33, 0xF6, 0x08, 0x5D, 0x21, 0xA3, 0xC4, 0xD7, 0xD2, 0x7F, 0x24, 0x37, 0x89, 0xFE, 0xBE, 0x36, 0x1D, 0xE4, 0x82, 0x9C, 0x20, 0x44, 0x1C, 0xD1, 0x93, 0x8E, 0xD9, + 0xF2, 0x83, 0xAC, 0x3C, 0x9A, 0x2D, 0x1F, 0xE8, 0xFE, 0x60, 0x55, 0xED, 0x3C, 0x51, 0x1C, 0x83, 0x07, 0x41, 0x1B, 0x65, 0xDE, 0xCD, 0xFC, 0x6D, 0xDF, 0xB5, 0xEB, 0x0E, 0x1B, 0xDF, 0xC7, 0x0A, + 0xD9, 0x09, 0xEB, 0x11, 0xB3, 0x89, 0x7D, 0xF7, 0x0E, 0x40, 0x65, 0x6E, 0x8D, 0x86, 0x9C, 0x24, 0xC4, 0x39, 0x31, 0x53, 0xF3, 0x8C, 0x7F, 0x58, 0x51, 0xEF, 0xDB, 0x40, 0xD8, 0x02, 0x3F, 0x6D, + 0x37, 0x51, 0x8F, 0xBA, 0xFE, 0x34, 0x44, 0xA8, 0x84, 0xD6, 0xD7, 0x6E, 0x8E, 0x99, 0x54, 0x22, 0xA2, 0x8C, 0xA1, 0x3C, 0x22, 0x32, 0x00, 0xF3, 0xB5, 0x1D, 0xD4, 0xA0, 0x62, 0x34, 0xA6, 0x9F, + 0xAB, 0x90, 0xF3, 0x38, 0x0A, 0x12, 0x5A, 0x63, 0x24, 0x59, 0xE4, 0x89, 0xD9, 0x21, 0x4E, 0x83, 0x7A, 0x16, 0xA8, 0x2D, 0x5F, 0x28, 0x9D, 0xD6, 0x00, 0x06, 0x03, 0x4A, 0xD2, 0xC2, 0xA8, 0x2C, + 0x7E, 0x68, 0x4E, 0xCE, 0xD1, 0x58, 0x4E, 0x95, 0xE6, 0x62, 0x55, 0x07, 0xB1, 0xA6, 0x59, 0xC0, 0xB3, 0x46, 0x3B, 0x9A, 0x11, 0xBB, 0x7C, 0x0A, 0xB6, 0x04, 0x33, 0xA7, 0x85, 0xC9, 0xCC, 0xB7, + 0x94, 0x1D, 0xEA, 0xCB, 0x0B, 0xEB, 0x51, 0x0B, 0x39, 0x50, 0x0A, 0x4C, 0x6E, 0x36, 0xDF, 0x96, 0x4C, 0x82, 0x36, 0x48, 0x1E, 0x73, 0xBD, 0x56, 0x42, 0xCB, 0x10, 0x12, 0xDD, 0x5E, 0x91, 0xD2, + 0xDA, 0x28, 0xBD, 0x29, 0x30, 0x58, 0xB8, 0xC4, 0x9E, 0x81, 0x68, 0xAA, 0x9F, 0x16, 0xEA, 0x45, 0x93, 0x87, 0x31, 0x4C, 0xB6, 0x16, 0x65, 0xCA, 0x62, 0x1D, 0x42, 0xD6, 0x82, 0xA3, 0x48, 0x93, + 0x23, 0xF4, 0x72, 0x84, 0x4B, 0xE5, 0xEB, 0x6D, 0xD1, 0x7A, 0x0B, 0xE4, 0xA1, 0x18, 0x1B, 0x55, 0x57, 0xB3, 0xB4, 0x2F, 0x90, 0x20, 0xDC, 0x3A, 0x7D, 0x1E, 0x55, 0x0C, 0x85, 0xB1, 0xB2, 0xA8, + 0x5F, 0x02, 0x31, 0x2C, 0x01, 0x03, 0xBA, 0x75, 0xB7, 0x09, 0x2C, 0xC1, 0x3A, 0x9C, 0xA6, 0x8A, 0x7B, 0x56, 0xA5, 0x58, 0x28, 0xFD, 0x70, 0x35, 0x64, 0x81, 0xD4, 0xBA, 0x15, 0x6B, 0xAF, 0xFC, + 0xE3, 0xEA, 0x26, 0xC5, 0x91, 0x48, 0x82, 0xF5, 0x5A, 0xB3, 0xFA, 0x73, 0xB4, 0xBF, 0x18, 0x33, 0x0D, 0xB5, 0x48, 0x20, 0x0D, 0x7D, 0xFE, 0x0F, 0xE7, 0xE8, 0x4F, 0xBE, 0x50, 0xB9, 0x9B, 0x37, + 0xEA, 0xBE, 0x32, 0x50, 0xB9, 0x45, 0x8A, 0xBB, 0xA6, 0x01, 0x9E, 0xA5, 0x4A, 0x49, 0x19, 0x0D, 0xCA, 0x0B, 0x62, 0x7C, 0x3D, 0x4F, 0xE4, 0x43, 0xCE, 0xFD, 0x85, 0x28, 0xE4, 0x93, 0xAA, 0xBF, + 0xF8, 0x49, 0x32, 0x67, 0x58, 0x1F, 0xEC, 0xF8, 0x02, 0x74, 0xBE, 0xE4, 0xDC, 0x5B, 0xDF, 0x95, 0x4F, 0xB0, 0x3E, 0xA8, 0xF0, 0x96, 0x3F, 0xED, 0xA3, 0xD1, 0xA1, 0xAE, 0xAE, 0x11, 0x5F, 0xA2, + 0x97, 0x57, 0x6A, 0x12, 0xF9, 0xF2, 0x39, 0x0C, 0x9C, 0xAB, 0x86, 0x9B, 0x22, 0x54, 0x37, 0x64, 0x23, 0x60, 0x72, 0x4F, 0x3F, 0x0A, 0x9F, 0x71, 0x97, 0x9A, 0xE4, 0xE3, 0x03, 0x1E, 0x83, 0xB2, + 0x76, 0x52, 0x63, 0xF4, 0x91, 0x40, 0x0E, 0x9B, 0x90, 0x88, 0x54, 0xB9, 0x16, 0xA1, 0x2F, 0x67, 0x46, 0x5A, 0x46, 0x01, 0xF4, 0x93, 0x2F, 0xA7, 0x11, 0xF1, 0xB0, 0x97, 0xC1, 0x3B, 0x88, 0x6E, + 0x0D, 0xDE, 0xD9, 0xE7, 0xAA, 0xEE, 0x74, 0xFA, 0xDC, 0xDD, 0xF3, 0x8D, 0x61, 0x06, 0x49, 0x55, 0x5E, 0x7A, 0x13, 0xA4, 0xDD, 0x02, 0x84, 0x70, 0x3A, 0x6D, 0x14, 0x7F, 0xDC, 0xE8, 0x6F, 0xC1, + 0xF3, 0x5D, 0xD7, 0x0D, 0xF9, 0xB6, 0x9B, 0xB4, 0xC3, 0xA0, 0x76, 0xBF, 0xA4, 0x6B, 0x05, 0x74, 0x3D, 0xE6, 0x3D, 0xB3, 0x37, 0xD2, 0x0C, 0x14, 0x3C, 0x64, 0x7B, 0x86, 0xCF, 0x8F, 0xF2, 0xE2, + 0x26, 0x7C, 0xC9, 0x5E, 0x0A, 0xC5, 0x57, 0x5D, 0xEF, 0xCD, 0xD2, 0xA5, 0x69, 0x2E, 0xB8, 0x84, 0x50, 0xB3, 0x49, 0x87, 0x78, 0xCA, 0x1F, 0x48, 0xFA, 0x2A, 0x59, 0x03, 0x21, 0xD5, 0x7B, 0x76, + 0xD5, 0x3C, 0x2A, 0x11, 0x29, 0xA3, 0xF2, 0x0B, 0x42, 0xB3, 0xDD, 0xC7, 0xB5, 0xDC, 0x5F, 0xFC, 0xB4, 0xC5, 0xEE, 0xE0, 0xE3, 0xDD, 0x62, 0x9E, 0x38, 0x1C, 0xE8, 0xA9, 0x5A, 0x65, 0xD8, 0xC5, + 0xAD, 0x29, 0xE7, 0x86, 0xDA, 0xA5, 0x8E, 0xA2, 0xC1, 0x29, 0x05, 0xEA, 0xD9, 0xC1, 0x04, 0x06, 0xEC, 0x50, 0xE9, 0xEB, 0x9F, 0xB3, 0x68, 0x2F, 0x1C, 0x33, 0xAD, 0x48, 0x73, 0x0C, 0xDB, 0x6D, + 0x47, 0x73, 0xDE, 0xFE, 0x7D, 0x07, 0xD3, 0xC9, 0xAC, 0xF7, 0xB4, 0x0F, 0x0E, 0x3D, 0x57, 0x2C, 0x0A, 0x10, 0x2D, 0x28, 0xB5, 0x2D, 0xBE, 0xBB, 0xAF, 0x40, 0x3A, 0x25, 0x41, 0x19, 0x64, 0xF3, + 0x55, 0x52, 0xB0, 0xDA, 0x42, 0x80, 0xEA, 0x60, 0xA6, 0x8C, 0x29, 0xA3, 0x1F, 0xD4, 0x99, 0xFF, 0x48, 0x98, 0x7B, 0xD8, 0x32, 0x8E, 0x84, 0x3D, 0xEB, 0xEA, 0x22, 0x21, 0x9B, 0xAB, 0x08, 0x07, + 0xD1, 0x4F, 0x78, 0x34, 0x60, 0x84, 0x70, 0x34, 0xF4, 0xAC, 0x38, 0x81, 0xCA, 0x7C, 0xA6, 0x74, 0xD4, 0x49, 0x98, 0xE0, 0xAC, 0x04, 0xE9, 0x04, 0x2A, 0xAA, 0x1F, 0xA6, 0x74, 0x49, 0x5F, 0xA0, + 0x8B, 0x0D, 0x43, 0xE0, 0x35, 0xCD, 0x6F, 0x18, 0x98, 0x1D, 0x7B, 0x96, 0xBE, 0x61, 0x7C, 0x2F, 0xFF, 0x3F, 0x3B, 0x77, 0x50, 0x74, 0x94, 0x60, 0xA4, 0xBA, 0x17, 0x52, 0xFB, 0x71, 0x37, 0x5B, + 0x10, 0xD9, 0xBE, 0xA5, 0x5B, 0xBE, 0x86, 0xAD, 0x9D, 0x9D, 0xE2, 0x54, 0xDB, 0x42, 0xD7, 0x68, 0x38, 0xFA, 0x81, 0x3A, 0x4D, 0x76, 0x5D, 0x1A, 0x6F, 0x29, 0x02, 0x4D, 0xFC, 0xA6, 0x13, 0xF6, + 0x18, 0xBA, 0x26, 0x3E, 0x97, 0xDB, 0xD0, 0xF4, 0x72, 0xFA, 0x5C, 0x01, 0x14, 0xBE, 0x0E, 0x57, 0xBA, 0x50, 0x58, 0x6D, 0xB3, 0x1B, 0x68, 0x58, 0xA6, 0x26, 0x1E, 0x11, 0xEB, 0x08, 0xAE, 0x66, + 0xEC, 0x3B, 0xF9, 0x70, 0x07, 0xD6, 0x0B, 0x37, 0x31, 0xA1, 0x3A, 0x60, 0xE6, 0xBA, 0xB1, 0x49, 0xC1, 0xFD, 0x1F, 0xD6, 0x60, 0xBB, 0x11, 0x3C, 0x50, 0x2E, 0xCF, 0x67, 0x65, 0x3D, 0xB1, 0xE2, + 0x80, 0xEB, 0xCB, 0x15, 0x22, 0x1C, 0xED, 0x2C, 0x2E, 0xCF, 0x94, 0xC2, 0x29, 0xAD, 0x50, 0x39, 0x4D, 0xD7, 0xCC, 0xFC, 0xE9, 0xB1, 0xF6, 0x40, 0x2D, 0x49, 0xB7, 0xAF, 0xE3, 0x7E, 0xF3, 0x27, + 0x0B, 0x19, 0xA7, 0x28, 0xD4, 0x5B, 0xE7, 0xDB, 0x71, 0x6C, 0x86, 0xA6, 0x84, 0x3F, 0xB9, 0x64, 0xFD, 0xEB, 0xD7, 0xA6, 0xFE, 0x30, 0xE8, 0xF3, 0x0F, 0x1F, 0x3A, 0x79, 0x31, 0xF6, 0x85, 0x29, + 0xC0, 0xCE, 0x9B, 0xA4, 0x75, 0x02, 0x32, 0xE0, 0x52, 0xFE, 0x8B, 0x61, 0x22, 0x1A, 0xED, 0x89, 0x0B, 0xF4, 0x9D, 0x15, 0xBD, 0xA3, 0x36, 0x8F, 0x09, 0x6A, 0x9E, 0x08, 0x8F, 0x94, 0x75, 0xD5, + 0x40, 0x3C, 0xCD, 0x26, 0x7B, 0x9C, 0x5B, 0xE5, 0x2A, 0x54, 0xBA, 0x81, 0x8B, 0xC6, 0xD9, 0x9B, 0x4D, 0x38, 0x3F, 0x1A, 0xDB, 0x58, 0x89, 0xCC, 0xBD, 0x29, 0xE2, 0x26, 0x8C, 0x35, 0x26, 0xE5, + 0x85, 0x31, 0x95, 0xDE, 0x86, 0x11, 0x9F, 0x21, 0x76, 0xEF, 0x1A, 0x25, 0x90, 0x6E, 0x8E, 0x74, 0xB0, 0x46, 0xE6, 0xFA, 0x42, 0xB4, 0x66, 0xBA, 0x0D, 0x5B, 0x21, 0x7C, 0x14, 0x74, 0xF6, 0x75, + 0x6C, 0x8F, 0x87, 0x44, 0x69, 0xCD, 0x9F, 0x1D, 0x41, 0x15, 0x1B, 0xAC, 0x70, 0x62, 0x08, 0x84, 0xD3, 0x35, 0x4F, 0x22, 0xF7, 0x44, 0x14, 0x53, 0x59, 0x0A, 0x6B, 0x93, 0x4F, 0x1B, 0xC6, 0xB5, + 0x61, 0x39, 0x83, 0x0D, 0xAB, 0x8E, 0xE9, 0x71, 0xEF, 0xD0, 0xC1, 0x61, 0xA9, 0xD0, 0xF2, 0x83, 0xF3, 0x44, 0xA4, 0x23, 0x27, 0xFA, 0x53, 0x2D, 0x1E, 0x45, 0x23, 0xC5, 0xC2, 0xA1, 0x2A, 0x80, + 0x1E, 0x0F, 0x92, 0x35, 0x13, 0xFD, 0x7C, 0xB7, 0x35, 0xE3, 0xB2, 0xB2, 0x50, 0xCF, 0x54, 0x14, 0x44, 0x51, 0x5E, 0xCE, 0x10, 0xF6, 0xED, 0x7C, 0x3A, 0xA4, 0x1D, 0xBA, 0xB0, 0xF4, 0xE2, 0xD0, + 0x0F, 0x6A, 0x32, 0xB2, 0xB2, 0xFF, 0xD8, 0x6F, 0xD5, 0xF4, 0xFE, 0x1A, 0x10, 0xC7, 0xDD, 0x10, 0xBE, 0xA3, 0x1B, 0xE8, 0xEB, 0x9B, 0x82, 0xCF, 0x72, 0xC2, 0x00, 0x15, 0x6F, 0xE5, 0x37, 0x37, + 0xBF, 0x00, 0x31, 0x74, 0xFF, 0xBC, 0x72, 0xA0, 0x9C, 0x10, 0xB4, 0xA4, 0x35, 0x13, 0x5D, 0xCD, 0xE5, 0x75, 0xB0, 0x56, 0x22, 0x9C, 0xCB, 0xD2, 0x6A, 0x11, 0x1A, 0xB4, 0x5E, 0x3F, 0x86, 0x4A, + 0xBF, 0xEF, 0x43, 0x14, 0x86, 0xC8, 0xA4, 0x71, 0xA2, 0x27, 0xF5, 0x14, 0x81, 0x9B, 0x0B, 0x13, 0x9C, 0x4C, 0x72, 0x98, 0xB5, 0xD8, 0x07, 0x95, 0x3E, 0x86, 0x40, 0xFE, 0xDE, 0x28, 0x4F, 0x1A, + 0x96, 0xA8, 0x32, 0xAB, 0xA1, 0x10, 0x00, 0xAB, 0x72, 0x6D, 0x30, 0xD3, 0xCB, 0x0C, 0xB7, 0x79, 0xE5, 0x50, 0x45, 0x72, 0xF2, 0xDA, 0xFA, 0xF8, 0x2E, 0x59, 0xB8, 0x19, 0x38, 0x0B, 0x4C, 0xEC, + 0xD1, 0x7B, 0xC7, 0xC3, 0x3B, 0xBA, 0x1E, 0x64, 0x52, 0x1D, 0xB2, 0xD2, 0x38, 0x74, 0x3C, 0x5A, 0x63, 0x75, 0x81, 0x78, 0x29, 0x41, 0x5B, 0x97, 0xDA, 0xD1, 0x34, 0xAC, 0x40, 0x0A, 0xA0, 0xE4, + 0x1B, 0x8B, 0x27, 0x36, 0x47, 0x56, 0xAE, 0xF8, 0x32, 0xE8, 0x8E, 0x5A, 0x29, 0x71, 0xDB, 0x85, 0x79, 0x28, 0x52, 0xDF, 0x55, 0xA7, 0xE8, 0x52, 0x7D, 0x42, 0xB4, 0xC1, 0xAB, 0x8F, 0x80, 0xA3, + 0x84, 0xA8, 0xF3, 0x7C, 0x09, 0x50, 0x41, 0x5B, 0xE7, 0x15, 0x79, 0x5C, 0x88, 0x4C, 0x88, 0x2F, 0xDE, 0xA1, 0x11, 0xF6, 0x67, 0xD4, 0x65, 0x6C, 0x10, 0xA5, 0xCF, 0x5A, 0xF6, 0xBE, 0xB5, 0xBE, + 0x27, 0xFA, 0xB2, 0xD6, 0xDD, 0xC4, 0x81, 0xEF, 0xA7, 0x4A, 0xA7, 0x8F, 0xA5, 0x66, 0xE8, 0x37, 0xEF, 0xDE, 0x77, 0xBC, 0xCF, 0x78, 0x5E, 0xD7, 0xCA, 0xD6, 0x4B, 0x1E, 0x1F, 0xD5, 0x19, 0xF3, + 0x82, 0x60, 0x74, 0xB4, 0xD2, 0x86, 0x77, 0xB0, 0xB1, 0xB9, 0x9A, 0x1D, 0x46, 0xE7, 0xFF, 0x70, 0x75, 0xD2, 0x44, 0x78, 0xD3, 0x7E, 0xA5, 0x43, 0x0C, 0x6E, 0xE8, 0xC5, 0x01, 0xBF, 0xF4, 0xE8, + 0x70, 0x3F, 0x06, 0x5B, 0x83, 0x60, 0x1B, 0x31, 0xB9, 0x0D, 0xE5, 0x01, 0x4A, 0xD4, 0x55, 0x8B, 0xF8, 0x80, 0x69, 0x90, 0xED, 0xDC, 0xC8, 0x50, 0x84, 0xA0, 0xAC, 0xCD, 0xC1, 0x49, 0x7C, 0x8C, + 0x69, 0x9F, 0x8B, 0x0C, 0x75, 0x74, 0x3B, 0x66, 0xFB, 0x4E, 0x2A, 0xE7, 0x99, 0xA0, 0xBD, 0x3A, 0x9C, 0x3F, 0x22, 0x97, 0x48, 0x7B, 0x86, 0x33, 0x4A, 0x73, 0xA9, 0x09, 0xFD, 0xD7, 0x88, 0xE9, + 0xCC, 0x02, 0xFA, 0xAB, 0x77, 0x57, 0xEE, 0xE5, 0x97, 0x89, 0x6C, 0x9C, 0xD3, 0x10, 0xBE, 0x5F, 0x3E, 0x4F, 0xFD, 0xA8, 0x04, 0x47, 0xEB, 0x4C, 0x4E, 0x58, 0xEF, 0xCB, 0x00, 0x90, 0x8B, 0xAA, + 0xB3, 0xF3, 0x64, 0x52, 0x23, 0x19, 0x69, 0x73, 0x43, 0x9A, 0xFA, 0xAF, 0x53, 0x39, 0x85, 0xAB, 0x81, 0x3B, 0x2E, 0x19, 0x78, 0xB3, 0xAD, 0x7A, 0x19, 0x00, 0xD9, 0xCB, 0x64, 0x4F, 0x7E, 0x28, + 0x99, 0x5D, 0xCE, 0x47, 0xC8, 0x79, 0xBA, 0x1D, 0xC2, 0x7B, 0x3B, 0x14, 0x83, 0x22, 0x88, 0xC9, 0x08, 0xCA, 0x10, 0xD7, 0x25, 0x99, 0x17, 0x6B, 0x15, 0x58, 0xC8, 0xCA, 0x1A, 0xF9, 0x51, 0x44, + 0x16, 0xA7, 0x60, 0xF3, 0xF7, 0x46, 0x21, 0x59, 0xEF, 0x95, 0x79, 0x56, 0x3E, 0xF6, 0xE3, 0xBE, 0x10, 0xB8, 0x54, 0xCD, 0xD7, 0xE8, 0x24, 0xDA, 0xE1, 0x3C, 0xEE, 0x70, 0xC8, 0x71, 0xFB, 0x6F, + 0x9B, 0xCC, 0x2C, 0x62, 0xAA, 0x41, 0x6F, 0xCF, 0x57, 0xA4, 0xDC, 0x22, 0xCA, 0xC3, 0x19, 0x8A, 0xE5, 0xAD, 0xF6, 0xE9, 0x57, 0x63, 0x5C, 0x95, 0xA8, 0xC1, 0xF8, 0xED, 0xE8, 0xF5, 0xB5, 0x14, + 0xD6, 0x81, 0xCA, 0x9B, 0xF9, 0x64, 0x43, 0x95, 0x8D, 0xDC, 0x00, 0xF0, 0x6E, 0x38, 0xD8, 0xB4, 0x95, 0x86, 0x4D, 0x5D, 0xF5, 0x6C, 0x32, 0xD2, 0x3E, 0xA9, 0x3D, 0x72, 0x1C, 0x66, 0xE6, 0x49, + 0xB2, 0x5F, 0x5B, 0x02, 0x44, 0x68, 0x4B, 0x58, 0xB1, 0x01, 0x26, 0x05, 0x55, 0x08, 0x94, 0xA2, 0x8D, 0xAD, 0x18, 0x92, 0x96, 0x6A, 0x56, 0x0E, 0x89, 0xAD, 0x7C, 0x1E, 0x4B, 0xD1, 0x76, 0x6E, + 0x63, 0x7A, 0x4F, 0xFF, 0x64, 0x2C, 0x8B, 0x14, 0xFE, 0xB7, 0xAE, 0x52, 0x41, 0xAA, 0x4C, 0x90, 0x35, 0xEC, 0x02, 0xF1, 0x78, 0x88, 0x73, 0x7A, 0xDE, 0x49, 0x0F, 0xA7, 0x92, 0xE7, 0xF7, 0x62, + 0x5E, 0x14, 0x1F, 0x95, 0x95, 0xE9, 0xF2, 0x62, 0xAD, 0xF4, 0x18, 0xAB, 0x6B, 0x31, 0xFB, 0xFE, 0x3B, 0x2E, 0x97, 0x4A, 0xB6, 0xF5, 0x2C, 0x96, 0x0B, 0x8F, 0x72, 0x9C, 0xF5, 0xE8, 0x49, 0x78, + 0x60, 0x12, 0x5C, 0xA6, 0x22, 0x99, 0x52, 0xC0, 0x71, 0xDB, 0x25, 0x8E, 0xFA, 0xDC, 0x6D, 0xBA, 0x70, 0xA1, 0x02, 0xD5, 0xB0, 0x84, 0x7B, 0x16, 0x6F, 0x21, 0x46, 0x6E, 0xBA, 0xAC, 0xF5, 0x19, + 0x9A, 0x8A, 0x9B, 0x68, 0x93, 0x3D, 0xED, 0x39, 0xB6, 0x44, 0x87, 0x13, 0x0F, 0x9C, 0x33, 0xB5, 0x1F, 0xA7, 0xBD, 0x53, 0x3A, 0x17, 0x04, 0xE4, 0x83, 0x42, 0xD6, 0xA5, 0xC0, 0xBB, 0x53, 0x97, + 0x2A, 0xD9, 0xF7, 0xE6, 0x3B, 0x53, 0x91, 0x5B, 0x3D, 0x87, 0x94, 0x9E, 0xDC, 0x6C, 0x34, 0x43, 0x38, 0xDA, 0x7B, 0x15, 0xE0, 0x7E, 0x18, 0xFF, 0xF5, 0x5B, 0xE2, 0x5D, 0x8A, 0xBB, 0x06, 0x82, + 0x2C, 0xD9, 0x5F, 0xB1, 0xA3, 0x26, 0xC7, 0xB5, 0xD0, 0xFD, 0x0C, 0x97, 0x10, 0x4B, 0xEF, 0x06, 0x7A, 0xA3, 0x00, 0x16, 0xA1, 0x33, 0x25, 0x4D, 0x02, 0xBA, 0x56, 0x52, 0x3E, 0x80, 0xE3, 0xB6, + 0xBA, 0xF9, 0x21, 0x6E, 0x0B, 0x1C, 0xEF, 0x65, 0xE2, 0xB8, 0xE4, 0x6D, 0x85, 0x69, 0x7F, 0xCA, 0xF0, 0x3E, 0xAB, 0x80, 0xC7, 0x74, 0x45, 0xCB, 0x10, 0x36, 0x6B, 0xD0, 0xB8, 0xB1, 0xC3, 0xB4, + 0xDF, 0x32, 0xED, 0xC0, 0x6C, 0xF3, 0xAF, 0x70, 0xFE, 0x29, 0x95, 0x51, 0x7E, 0x69, 0xFD, 0x2A, 0xE0, 0xBA, 0xF9, 0x58, 0x5F, 0x21, 0xF9, 0x25, 0x50, 0x4A, 0xDF, 0x8E, 0x8C, 0x91, 0xFB, 0xF2, + 0x10, 0x1C, 0xBB, 0xE7, 0x97, 0xA2, 0x66, 0x40, 0xD0, 0x8C, 0xD1, 0xF8, 0xC6, 0x41, 0x81, 0xE3, 0x82, 0x8E, 0xF2, 0xEE, 0x46, 0x20, 0x8B, 0x93, 0x12, 0x35, 0x36, 0xD0, 0x6E, 0xAB, 0x4A, 0x29, + 0xCE, 0x33, 0x4F, 0x43, 0xD4, 0x71, 0xEA, 0x15, 0x7F, 0xF7, 0xA8, 0xF3, 0x1A, 0x38, 0x7A, 0xCD, 0x03, 0xEA, 0x4B, 0x52, 0x96, 0xB4, 0x97, 0x14, 0x20, 0xE1, 0x83, 0x0E, 0xA0, 0xED, 0xE8, 0x1C, + 0x8B, 0x96, 0x54, 0x3A, 0x9F, 0xE2, 0x87, 0x63, 0xFC, 0xF5, 0x6B, 0x9A, 0xF4, 0x3F, 0x77, 0x7B, 0xCA, 0xCB, 0xEC, 0xC8, 0xAE, 0x13, 0xC3, 0xD4, 0x12, 0x66, 0x55, 0x8B, 0xEA, 0x42, 0x8E, 0xAA, + 0x10, 0xBB, 0xAC, 0xDE, 0xA9, 0x44, 0xCD, 0xA5, 0x9A, 0x1A, 0xEF, 0xB4, 0x82, 0x54, 0x81, 0x71, 0xC4, 0x2F, 0xF9, 0xC0, 0xE9, 0xD2, 0x46, 0x93, 0x5B, 0xB8, 0x0B, 0x3E, 0x34, 0x7E, 0xA1, 0xEF, + 0x9D, 0x1C, 0x51, 0xEF, 0x45, 0x5D, 0xA2, 0xDE, 0x90, 0xC8, 0x7C, 0xDB, 0xBC, 0xE1, 0x3D, 0x2F, 0xBA, 0xC8, 0xB4, 0xD4, 0x62, 0x4C, 0x36, 0xF6, 0x13, 0x49, 0x0F, 0xE5, 0xF9, 0x7E, 0x44, 0xF9, + 0x1D, 0xAE, 0x67, 0x4B, 0x09, 0xC2, 0x78, 0xA0, 0x0A, 0x95, 0x25, 0x23, 0x99, 0x3E, 0x92, 0xC6, 0x03, 0x96, 0xE9, 0x9F, 0x91, 0x67, 0x26, 0xA9, 0xB7, 0x11, 0x5F, 0xE9, 0xE2, 0x49, 0x5B, 0xD7, + 0x10, 0x2D, 0x9B, 0x61, 0x96, 0x1A, 0xEE, 0x02, 0x54, 0xB3, 0x27, 0xBF, 0xC0, 0x64, 0x46, 0x55, 0xA8, 0x5D, 0x35, 0x91, 0x8C, 0xA7, 0xD5, 0x66, 0x7E, 0xAF, 0xAE, 0x11, 0x3A, 0x12, 0x12, 0x80, + 0x50, 0x4E, 0xAC, 0x12, 0x2C, 0x04, 0x1D, 0xB2, 0x14, 0x1A, 0xA0, 0x85, 0x38, 0x15, 0xC1, 0x49, 0x96, 0x2B, 0x4D, 0x9C, 0x55, 0x99, 0xAC, 0xC7, 0x2A, 0x9E, 0x15, 0xF0, 0x06, 0xA2, 0x51, 0x96, + 0x09, 0x80, 0x0A, 0xB4, 0xEB, 0x11, 0x6D, 0x7B, 0x36, 0xBE, 0xB2, 0x59, 0x7E, 0x15, 0xA5, 0x54, 0x26, 0x3B, 0xD3, 0xB0, 0xE7, 0x8C, 0xE3, 0x8B, 0x7F, 0x60, 0x83, 0x11, 0xAB, 0x7B, 0xC3, 0xCA, + 0xF4, 0x38, 0xC5, 0x06, 0xB3, 0x23, 0x17, 0x43, 0xFE, 0x3E, 0x29, 0xF9, 0x3D, 0xF3, 0x5B, 0x34, 0x40, 0x10, 0x87, 0x04, 0x1C, 0xEE, 0x3B, 0x75, 0xAE, 0xFA, 0x0A, 0xFE, 0xAF, 0x09, 0xA6, 0xEB, + 0xF6, 0xD2, 0xFE, 0x41, 0x85, 0xBC, 0xC6, 0xB3, 0x9A, 0xED, 0x79, 0xF3, 0x38, 0x92, 0x12, 0xFD, 0xC0, 0x9F, 0xA4, 0x8A, 0x71, 0xFE, 0x6A, 0x2D, 0xE3, 0x3D, 0x40, 0xAC, 0xB6, 0xEB, 0x59, 0xE1, + 0x99, 0xB1, 0xCD, 0x76, 0x19, 0xAF, 0xE9, 0x6E, 0xD5, 0x46, 0xEE, 0xC5, 0x64, 0x39, 0x5F, 0xAC, 0x3B, 0x49, 0xA5, 0xE7, 0xAC, 0x20, 0x60, 0x68, 0x06, 0xF1, 0x91, 0x27, 0xC6, 0x38, 0x1E, 0xE3, + 0x47, 0x93, 0x6B, 0x35, 0xE3, 0x07, 0x4E, 0x23, 0xEB, 0x9E, 0xB0, 0xB0, 0x87, 0x2D, 0x67, 0x30, 0x54, 0xBF, 0x4F, 0xAB, 0x46, 0xD9, 0xC3, 0xC2, 0x75, 0x82, 0x31, 0x8A, 0x05, 0x56, 0xAA, 0x6F, + 0x5D, 0xCF, 0x79, 0x25, 0x9F, 0xF8, 0x47, 0xC0, 0xA6, 0xB5, 0x28, 0xD0, 0x49, 0xEE, 0x85, 0xE5, 0xE2, 0xD0, 0x57, 0x23, 0x49, 0x43, 0x89, 0x12, 0x51, 0x5A, 0xA9, 0x46, 0xCD, 0x2A, 0xD7, 0xF8, + 0x93, 0xA9, 0xC4, 0xD0, 0x16, 0x0A, 0x24, 0xEF, 0xAA, 0xE9, 0xE2, 0x89, 0x1A, 0xD9, 0x62, 0xB9, 0x62, 0x08, 0x0A, 0x06, 0x65, 0xFC, 0xF5, 0x4B, 0xA3, 0xE3, 0x7A, 0x83, 0x0A, 0x1E, 0x59, 0x5E, + 0xCB, 0xD0, 0xE0, 0xAC, 0x37, 0x01, 0x2E, 0x97, 0xDE, 0x3D, 0x4D, 0xAE, 0x2C, 0xA8, 0x42, 0x75, 0x25, 0x99, 0x88, 0xFC, 0x83, 0x9E, 0x0D, 0x59, 0xC1, 0x59, 0xA5, 0x18, 0x53, 0xDF, 0x57, 0xC6, + 0x22, 0xCA, 0x74, 0xCB, 0x71, 0xFD, 0xC2, 0xD5, 0x20, 0x01, 0xD4, 0xF8, 0x04, 0x73, 0x4E, 0xC0, 0x9B, 0x09, 0x0C, 0xDE, 0x83, 0x71, 0xE2, 0x6B, 0xC5, 0x7F, 0x76, 0x8C, 0x5F, 0xA0, 0x2B, 0xC6, + 0x6C, 0x6A, 0xEC, 0xB0, 0x44, 0xDA, 0x59, 0xF2, 0xCF, 0x52, 0x93, 0xB8, 0xD8, 0x6E, 0x61, 0xB8, 0x6E, 0x84, 0xEB, 0x6B, 0xA4, 0xDE, 0x6F, 0x44, 0xAC, 0xC5, 0x66, 0x2E, 0x34, 0x7B, 0xE8, 0x38, + 0xEA, 0xB6, 0xA0, 0x3B, 0x3F, 0x1E, 0xA9, 0x90, 0xA3, 0x22, 0xB0, 0xCB, 0x13, 0x09, 0x22, 0x87, 0xE7, 0xFF, 0x52, 0xF9, 0x35, 0x10, 0x45, 0x5D, 0xD2, 0xAF, 0x81, 0x1F, 0xBA, 0xE2, 0x19, 0x48, + 0x01, 0xA9, 0x0D, 0xCC, 0x2D, 0x69, 0x90, 0x59, 0x1F, 0xF9, 0x0A, 0xF8, 0x17, 0x30, 0xC7, 0xDD, 0x13, 0x91, 0xE7, 0x8D, 0x9B, 0x0E, 0x42, 0x64, 0x61, 0x55, 0xEF, 0x4C, 0x53, 0xFC, 0xF6, 0x23, + 0x9C, 0xAE, 0x7C, 0xAD, 0xEC, 0x2E, 0x8D, 0xB1, 0xFB, 0xAA, 0x91, 0x15, 0x24, 0x45, 0x4C, 0x49, 0x18, 0x4C, 0xC1, 0xA7, 0x7E, 0x57, 0x2A, 0x01, 0x67, 0xE2, 0x91, 0xC0, 0xA1, 0xEC, 0xBD, 0x9D, + 0x31, 0x70, 0x9C, 0x27, 0x7C, 0xE5, 0x41, 0xD3, 0x25, 0x56, 0x3C, 0x2E, 0xC3, 0x1E, 0x0A, 0x8B, 0x54, 0x2C, 0xAE, 0x34, 0xDC, 0x13, 0x4F, 0x66, 0x79, 0x96, 0xD8, 0x27, 0x1C, 0xA6, 0xE9, 0x0B, + 0xB8, 0x44, 0x6F, 0xB6, 0x6D, 0xBE, 0x61, 0xD2, 0x74, 0x2C, 0x38, 0xCA, 0xB4, 0x06, 0x4D, 0x2B, 0x40, 0xB6, 0x53, 0x72, 0x5B, 0x97, 0x6D, 0x37, 0xD2, 0x66, 0xAA, 0x6F, 0xA8, 0xB2, 0x99, 0x63, + 0x05, 0x8E, 0x06, 0xEF, 0xAD, 0x99, 0x07, 0x35, 0x9D, 0xE3, 0xDB, 0xC2, 0x27, 0x05, 0xFE, 0x6A, 0xB7, 0xD5, 0xFD, 0xAE, 0xB9, 0x02, 0x33, 0xEB, 0x94, 0xCB, 0x20, 0x40, 0x0B, 0x5A, 0x68, 0xC9, + 0xCE, 0xAB, 0x1A, 0x16, 0xBB, 0xBD, 0x5F, 0x1B, 0x90, 0x55, 0x6A, 0xC9, 0x38, 0x50, 0xAD, 0xFC, 0xCA, 0x90, 0x58, 0x8A, 0x1A, 0xAD, 0x3E, 0x71, 0x67, 0xEE, 0x26, 0x90, 0xEE, 0x58, 0xC1, 0xDE, + 0x36, 0xD2, 0x7B, 0xDE, 0xEA, 0xB9, 0xD8, 0x19, 0xD6, 0x9D, 0xFA, 0xF9, 0xEA, 0xE5, 0x5E, 0x1C, 0xD3, 0xA9, 0x7A, 0x5F, 0xB3, 0xFD, 0x10, 0xBB, 0xA2, 0x9D, 0x84, 0xC6, 0x9C, 0x14, 0xB2, 0x2E, + 0xDD, 0xD9, 0x91, 0xCD, 0x4E, 0xF2, 0x9F, 0xA3, 0x5D, 0xDB, 0xDE, 0xE6, 0xC9, 0xA0, 0x09, 0x6D, 0x4E, 0x7F, 0xDF, 0xCF, 0x7E, 0x28, 0x3C, 0x89, 0x91, 0x73, 0x10, 0xC8, 0x90, 0xBE, 0xEC, 0x2C, + 0x8C, 0x6C, 0xC0, 0xE6, 0xEE, 0x4A, 0xB5, 0xC2, 0x8F, 0xAA, 0xCB, 0x2E, 0x00, 0xBB, 0x93, 0xD9, 0x7E, 0x5C, 0xFB, 0xFA, 0xF8, 0xF7, 0x8B, 0xDF, 0x90, 0x2D, 0x25, 0xDF, 0xB5, 0x06, 0xA3, 0xB1, + 0x0C, 0x06, 0x48, 0xAA, 0xBB, 0xC5, 0xD4, 0xCA, 0x8B, 0x1A, 0x46, 0x6F, 0x04, 0x1B, 0xF7, 0xE1, 0x0E, 0xF5, 0x1E, 0x0D, 0x7A, 0x3F, 0xF5, 0xB1, 0x80, 0xAC, 0xBA, 0xF2, 0x36, 0xA3, 0x81, 0x51, + 0xB9, 0x56, 0xCB, 0x56, 0x35, 0x75, 0x65, 0xD7, 0x1E, 0x42, 0x60, 0xF2, 0xF6, 0x35, 0x12, 0xDC, 0xDB, 0xD3, 0xC3, 0x5E, 0x54, 0x0F, 0x87, 0x72, 0x63, 0x26, 0xAF, 0x2A, 0x3C, 0xD6, 0xEE, 0xD2, + 0xDA, 0x8E, 0x51, 0x9F, 0x9F, 0x60, 0x58, 0x1A, 0x58, 0x20, 0x13, 0xBC, 0x93, 0xBE, 0x25, 0xA0, 0x13, 0x71, 0xDC, 0x8C, 0x34, 0xBE, 0x1E, 0x88, 0x24, 0xA2, 0xD2, 0x12, 0x03, 0x39, 0xD6, 0xE2, + 0x87, 0xEC, 0x0C, 0xC4, 0x3D, 0x58, 0x6A, 0x04, 0xF8, 0x08, 0x75, 0xB3, 0x76, 0x64, 0x83, 0xB8, 0x84, 0xA9, 0x20, 0x2C, 0x1C, 0xDB, 0x4D, 0xF4, 0xC1, 0x1B, 0x1D, 0x79, 0xB1, 0xE4, 0xF2, 0xAE, + 0x88, 0x6E, 0x81, 0xA1, 0xFF, 0x7B, 0xCA, 0xC8, 0x98, 0x89, 0x53, 0x21, 0x4D, 0xAF, 0xE7, 0x79, 0xA7, 0x9D, 0xF5, 0x1A, 0x65, 0x1A, 0x51, 0x2D, 0xB2, 0x56, 0x2B, 0x7C, 0x1D, 0x46, 0x71, 0xD5, + 0x2C, 0x51, 0x70, 0x81, 0xD5, 0x3A, 0x79, 0x22, 0x70, 0xB1, 0xC3, 0x05, 0x51, 0x5F, 0xB7, 0xB6, 0xC4, 0x61, 0xBD, 0x4C, 0xD0, 0xD7, 0xC3, 0x17, 0x5B, 0x14, 0x6F, 0xE9, 0x62, 0xA4, 0xC9, 0xA9, + 0x08, 0x1E, 0x39, 0x49, 0x60, 0x68, 0x9B, 0xA9, 0xBC, 0xC6, 0xCA, 0xD5, 0xEA, 0xED, 0xF8, 0x1E, 0x34, 0x53, 0x61, 0x64, 0x6E, 0x9E, 0xAF, 0xB8, 0xBA, 0xEC, 0xF1, 0xFC, 0x01, 0x12, 0x1C, 0x29, + 0x3D, 0x58, 0x68, 0x7D, 0x7E, 0x81, 0xA4, 0xA8, 0xAE, 0xC9, 0x0F, 0x16, 0x1D, 0x73, 0x87, 0x97, 0xAC, 0xAE, 0xBE, 0xC1, 0x18, 0x19, 0x58, 0x67, 0x9D, 0xA1, 0xA7, 0xAA, 0xB0, 0xEB, 0xEE, 0xF0, + 0xF1, 0xFF, 0x18, 0x32, 0x3C, 0x47, 0x5D, 0x6A, 0x72, 0x7F, 0x80, 0x82, 0x93, 0xAD, 0xBD, 0xCC, 0xDF, 0xE6, 0xEC, 0xF0, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1C, 0x2A, 0x34, 0x42, 0x55, 0x80, 0x16, + 0x15, 0x00, 0x78, 0x78, 0x2C, 0x25, 0x10, 0x0C, 0x02, 0x01, 0x82, 0x08, 0xD8, 0x80, 0x82, 0x02, 0xC4, 0x02, 0x01, 0x20, 0x27, 0x80, 0x84, 0x4A, 0x00, 0x12, 0x82, 0x02, 0x00, 0x50, 0x64, 0x4A, + 0xB2, 0xB4, 0x16, 0xBF, 0x7C, 0x04 }, + }, + { + .name = "Dilithium 6-5 KAT 1", + .version = 0, + .rho_len = 32, + .rho = { 0xBC, 0x96, 0x2D, 0x97, 0x8F, 0x38, 0x88, 0x10, 0x85, 0xC1, 0xB8, 0x13, 0xBC, 0x90, 0xEE, 0xE4, 0x4A, 0xD9, 0xE7, 0x65, 0x16, 0x81, 0xC2, 0x0B, 0xA4, 0x64, 0x02, 0xF5, 0x57, 0xC4, 0x54, 0xDE }, + .seed_len = 32, + .seed = { 0x05, 0xB6, 0x95, 0xC9, 0x3E, 0x88, 0x78, 0x6B, 0x4C, 0xA4, 0x61, 0xC5, 0x5B, 0xB3, 0x03, 0xBA, 0x50, 0xCD, 0x5E, 0x52, 0xC9, 0xB1, 0xDA, 0x0C, 0x17, 0xF8, 0x6C, 0x19, 0xCD, 0xA7, 0x72, 0xBC }, + .tr_len = 48, + .tr = { 0xB9, 0x10, 0x41, 0x9A, 0x59, 0x33, 0xC9, 0x3C, 0x39, 0x01, 0x68, 0x4D, 0x9D, 0xC5, 0x05, 0xFC, 0xC7, 0xDE, 0x22, 0x89, 0x2C, 0x39, 0x48, 0xEB, 0x58, 0xE9, 0x96, 0xAF, 0x6E, 0x6D, 0xE3, 0x17, + 0x5C, 0x90, 0x2C, 0x33, 0xE2, 0xFB, 0x37, 0x6E, 0x4F, 0x88, 0xE4, 0x90, 0xBC, 0x13, 0x02, 0x8B }, + .s1_len = 480, + .s1 = { 0xAD, 0x65, 0xAB, 0x8D, 0x4C, 0xCC, 0x9A, 0x24, 0x92, 0x53, 0xEB, 0xB0, 0x2A, 0x6B, 0xCB, 0x94, 0x6C, 0x84, 0x52, 0x20, 0x0B, 0x42, 0x80, 0x42, 0x70, 0x97, 0x8D, 0xE5, 0x08, 0x1A, 0x41, 0x4A, + 0x68, 0x58, 0x0B, 0x01, 0x51, 0xE9, 0x49, 0x58, 0xE2, 0x89, 0xA8, 0x3A, 0xBB, 0x32, 0x35, 0xC5, 0x9A, 0x20, 0x27, 0x1D, 0xB5, 0xAE, 0x8A, 0x61, 0x73, 0xEE, 0x44, 0x86, 0x65, 0xAA, 0x10, 0xA5, + 0x02, 0x37, 0x0D, 0x55, 0x1A, 0x41, 0x8B, 0x91, 0xDA, 0xD6, 0x38, 0x94, 0xCA, 0x8C, 0xC4, 0x60, 0x96, 0x1D, 0xBB, 0x4D, 0xC6, 0xD0, 0x31, 0xB0, 0x61, 0xA6, 0x35, 0x3B, 0xA1, 0xF6, 0x2A, 0xB9, + 0x83, 0x19, 0x2B, 0x46, 0xB4, 0x16, 0x24, 0x56, 0x42, 0x18, 0xA2, 0x6A, 0x52, 0x39, 0x81, 0x23, 0xD1, 0xBA, 0x0C, 0x16, 0x25, 0x68, 0xEA, 0x40, 0xDE, 0x5A, 0xCD, 0x0B, 0x40, 0x14, 0x75, 0xC3, + 0xD2, 0x51, 0x82, 0x10, 0xE0, 0x3A, 0x29, 0x31, 0xA3, 0x95, 0xA6, 0x1D, 0x84, 0xEC, 0xB4, 0x39, 0x10, 0x54, 0x90, 0x6E, 0x48, 0x38, 0x9D, 0x57, 0xC1, 0x40, 0x15, 0x0E, 0x74, 0x26, 0x96, 0x24, + 0xC7, 0xD1, 0x12, 0x2D, 0x57, 0xAA, 0xA4, 0x51, 0x0A, 0x69, 0xB2, 0x69, 0x65, 0x54, 0x84, 0x34, 0x38, 0x4C, 0x32, 0xCC, 0x9B, 0xAB, 0x39, 0xF5, 0x3C, 0xA7, 0x64, 0x10, 0x84, 0xC0, 0x38, 0x36, + 0x93, 0x58, 0x13, 0x9E, 0xE1, 0xC0, 0x43, 0xEB, 0x22, 0xEE, 0x80, 0x8D, 0xC2, 0xE0, 0xC8, 0x32, 0xA8, 0x91, 0x49, 0x69, 0x29, 0x2B, 0x5D, 0x03, 0xEC, 0x18, 0x37, 0x48, 0x4B, 0xCB, 0x62, 0x81, + 0x0D, 0x71, 0x16, 0x20, 0xB1, 0x2C, 0xC2, 0x1D, 0x64, 0xD8, 0xF1, 0x44, 0x67, 0x0B, 0x04, 0x97, 0x56, 0xB0, 0x40, 0x35, 0x40, 0x99, 0xB4, 0x6C, 0x56, 0xA9, 0x6B, 0xD4, 0x65, 0xEC, 0x94, 0x34, + 0x96, 0xD5, 0x25, 0xBB, 0xCC, 0x12, 0x38, 0x73, 0x28, 0x63, 0x90, 0xAD, 0xB7, 0x19, 0xAA, 0x9D, 0x6D, 0xDB, 0x46, 0x8B, 0xCB, 0x16, 0x07, 0x32, 0xC2, 0x28, 0xB3, 0xA8, 0x58, 0x30, 0x2C, 0xAD, + 0x81, 0xA3, 0x16, 0x4B, 0xB5, 0x85, 0x4C, 0x11, 0x27, 0xDB, 0x44, 0x39, 0x4E, 0x42, 0x57, 0x09, 0x9A, 0x16, 0x36, 0xC3, 0xCE, 0xA9, 0xC7, 0xD9, 0xC2, 0x04, 0x7A, 0x5D, 0xB2, 0x76, 0x6E, 0xC6, + 0xCE, 0x8A, 0xC0, 0x7A, 0xA4, 0x1C, 0x49, 0x48, 0x68, 0xAE, 0x9B, 0xBB, 0x4A, 0x64, 0x8D, 0x0E, 0x93, 0x22, 0xC8, 0xA3, 0xE0, 0x45, 0x4E, 0x41, 0x2B, 0xD8, 0x40, 0xD6, 0xA3, 0x21, 0x35, 0xA5, + 0x85, 0x94, 0x00, 0x6C, 0xCB, 0x83, 0xA7, 0x79, 0xA5, 0xD9, 0xC0, 0x9A, 0x3B, 0x4D, 0x86, 0x37, 0xD3, 0x54, 0x03, 0x53, 0xAC, 0x35, 0x68, 0x45, 0x4A, 0x72, 0x5E, 0x67, 0x98, 0x60, 0x68, 0x65, + 0xF0, 0x38, 0x10, 0x9C, 0x10, 0x2B, 0x0D, 0x18, 0x0F, 0xB6, 0x1B, 0xB7, 0x28, 0xEB, 0x8A, 0xEC, 0x96, 0x64, 0xAE, 0x17, 0x83, 0xB6, 0x10, 0x59, 0xE4, 0x5C, 0x2B, 0x8A, 0xB7, 0xD6, 0x1D, 0xC1, + 0x94, 0x95, 0xAC, 0xAA, 0xF6, 0xA4, 0x84, 0x41, 0x19, 0x20, 0xA2, 0x33, 0x37, 0x81, 0xC5, 0xAD, 0x95, 0x31, 0xA5, 0x08, 0x31, 0xB8, 0x0C, 0x36, 0xB6, 0x9A, 0xE2, 0xCC, 0x0C, 0xBD, 0x64, 0x2C, + 0xB8, 0x48, 0x14, 0xB3, 0x82, 0x73, 0x68, 0x05, 0xCA, 0x94, 0x15, 0xA6, 0x3C, 0x83, 0x88, 0x2A, 0x51, 0x21, 0x55, 0xA9, 0xAD, 0x2C, 0x33, 0x43, 0xA0, 0xC1, 0xC9, 0x16, 0xAB, 0x14, 0x30, 0x71 }, + .s2_len = 576, + .s2 = { 0x75, 0x97, 0x58, 0x0B, 0xC7, 0x05, 0x2B, 0x3C, 0xAC, 0x09, 0x5C, 0xAD, 0x56, 0x15, 0x93, 0xAA, 0xC5, 0xD5, 0xB2, 0x62, 0x69, 0x5A, 0x5B, 0x67, 0xAB, 0x95, 0x51, 0x35, 0xB6, 0x42, 0x65, 0x15, + 0x40, 0x20, 0xE9, 0xB0, 0xAA, 0x69, 0xB5, 0x83, 0x34, 0x94, 0x58, 0x57, 0x1B, 0xA4, 0x44, 0x32, 0x49, 0x51, 0x92, 0x64, 0x69, 0xA8, 0x0B, 0x11, 0x5B, 0xD4, 0x02, 0x61, 0xB0, 0x59, 0x01, 0x65, + 0xDB, 0x94, 0x32, 0x81, 0x71, 0x1B, 0x41, 0x44, 0xF0, 0x00, 0x8D, 0x03, 0xE2, 0x59, 0xAC, 0x66, 0xAA, 0x5A, 0x2A, 0xB6, 0xA4, 0xC0, 0xD9, 0xCA, 0x5C, 0x97, 0x30, 0x35, 0x23, 0x5C, 0x20, 0x48, + 0xA5, 0x55, 0x2C, 0x69, 0x94, 0xBA, 0x93, 0x07, 0x0D, 0x6C, 0x57, 0xAE, 0xA4, 0x42, 0x31, 0x46, 0xD1, 0x69, 0xC6, 0x04, 0xA1, 0x9D, 0x62, 0xD6, 0x64, 0x5C, 0xA5, 0x20, 0xA2, 0xCA, 0x46, 0xB2, + 0xA6, 0xE5, 0x0C, 0xD1, 0x6E, 0x8A, 0xAD, 0x85, 0x40, 0x6D, 0xB0, 0x3D, 0x9A, 0xF5, 0x2C, 0x01, 0x19, 0x44, 0xB8, 0x42, 0xE2, 0x41, 0x5A, 0xB8, 0x05, 0x2B, 0x5C, 0xC2, 0xB5, 0x64, 0x0C, 0x65, + 0x4A, 0x26, 0xCC, 0x50, 0x66, 0xD4, 0x20, 0x2B, 0xB1, 0xC3, 0x28, 0x36, 0x60, 0x54, 0x30, 0x81, 0x84, 0x71, 0x90, 0x4E, 0x1E, 0x32, 0xCB, 0xEB, 0x66, 0x97, 0xED, 0x1C, 0x6A, 0xB2, 0x40, 0x79, + 0x40, 0x26, 0xC8, 0x91, 0xA8, 0xB9, 0xEA, 0x06, 0xCF, 0x20, 0x96, 0xB6, 0xEE, 0xEC, 0xA5, 0xA3, 0x40, 0x2D, 0x98, 0xD3, 0x9A, 0xF1, 0xD4, 0x16, 0x31, 0xB3, 0x7A, 0x6B, 0x25, 0x93, 0x58, 0x58, + 0x11, 0x55, 0xD0, 0x90, 0x02, 0x1A, 0x79, 0x0C, 0x00, 0xA9, 0xB1, 0x52, 0x66, 0x12, 0x09, 0x61, 0x8C, 0x0C, 0xD0, 0x94, 0x80, 0x3A, 0x50, 0x49, 0x74, 0xB3, 0x3B, 0x61, 0xA8, 0x40, 0xA9, 0x62, + 0x88, 0xB1, 0x13, 0x28, 0xC1, 0x64, 0x59, 0x24, 0x02, 0x3A, 0x28, 0xC3, 0x16, 0x54, 0x93, 0x4C, 0xA3, 0x03, 0xE0, 0xC6, 0x5A, 0x9D, 0x6A, 0x46, 0x61, 0x8B, 0x44, 0x43, 0x17, 0x5C, 0xE8, 0x4E, + 0x43, 0xA6, 0x2A, 0x6E, 0x67, 0x49, 0xAE, 0x32, 0x30, 0x81, 0x01, 0x75, 0x6E, 0x5B, 0x48, 0x5C, 0xD0, 0x45, 0x0B, 0xC7, 0xAA, 0x89, 0x4C, 0x13, 0xC5, 0x64, 0x72, 0x55, 0x1C, 0x2F, 0x09, 0xD5, + 0xD2, 0x8D, 0xCB, 0x24, 0x16, 0x02, 0x6E, 0x30, 0x32, 0x73, 0x6E, 0xBA, 0xC1, 0x01, 0x04, 0x96, 0xC3, 0xEC, 0x02, 0x74, 0xA4, 0xC9, 0x61, 0x65, 0x61, 0x1D, 0x43, 0x92, 0xA0, 0x59, 0xAA, 0xDC, + 0xB4, 0x58, 0x63, 0x35, 0x69, 0xB5, 0x5D, 0x59, 0x90, 0x89, 0xC0, 0x59, 0xC8, 0x68, 0x01, 0x16, 0xCA, 0x2C, 0xA5, 0x95, 0x32, 0xD6, 0xB8, 0x23, 0x17, 0x4D, 0x31, 0x10, 0xB9, 0xA6, 0x18, 0x0A, + 0x93, 0x8A, 0x6C, 0xD1, 0xAC, 0x2D, 0x28, 0x16, 0xB6, 0xB6, 0x4B, 0x17, 0x24, 0xD7, 0xD5, 0xD5, 0x82, 0x95, 0x6D, 0x40, 0x0B, 0x0E, 0x37, 0x84, 0x95, 0xB0, 0x66, 0x65, 0xA6, 0x9A, 0x45, 0x96, + 0x59, 0x5B, 0x80, 0x3A, 0x1A, 0x45, 0x59, 0x5D, 0xD9, 0x1A, 0xAC, 0x19, 0x4C, 0x44, 0x91, 0x25, 0xC8, 0xB4, 0x51, 0x2E, 0xD5, 0x80, 0x0C, 0x49, 0x73, 0xEA, 0xD4, 0x62, 0x53, 0x19, 0x8E, 0xDD, + 0x4C, 0x0C, 0x4B, 0x57, 0x29, 0xE5, 0x14, 0x65, 0xCD, 0xE2, 0x51, 0xEE, 0x54, 0xCA, 0x10, 0x08, 0xAD, 0x15, 0x33, 0x23, 0x05, 0x25, 0x85, 0x04, 0xB8, 0xB4, 0x26, 0x66, 0xD6, 0x5C, 0x48, 0xC4, + 0x15, 0xE7, 0x9A, 0xAB, 0x26, 0xDB, 0xB1, 0xDB, 0x26, 0xCE, 0x16, 0x91, 0x6B, 0x59, 0x9A, 0x8D, 0x18, 0x7B, 0x36, 0xD5, 0x0C, 0x32, 0x13, 0x07, 0x0B, 0x37, 0x53, 0x1A, 0xC4, 0xD9, 0x9B, 0x9B, + 0x50, 0xDE, 0xE2, 0x34, 0x4E, 0xC6, 0x55, 0x43, 0xEC, 0x02, 0x22, 0xC8, 0x34, 0x18, 0xE3, 0x89, 0x11, 0x0A, 0x30, 0xC0, 0x26, 0x37, 0xD2, 0xA2, 0x0C, 0xB4, 0x40, 0x02, 0x99, 0x68, 0xA7, 0x21, + 0x67, 0x57, 0x98, 0x05, 0x88, 0x92, 0xC2, 0x5A, 0xA3, 0x61, 0xB2, 0xE6, 0xB4, 0xC0, 0x94, 0x07, 0x73, 0x4B, 0x2C, 0x14, 0xDD, 0x90, 0xC1, 0x9A, 0x93, 0x9A, 0xB4, 0x04, 0xC3, 0x66, 0x61, 0x8D }, + .t0_len = 2688, + .t0 = { 0x66, 0x0D, 0x72, 0x90, 0x66, 0x47, 0xF1, 0xCE, 0xAD, 0x34, 0x0A, 0x36, 0x0E, 0xEC, 0x45, 0xB3, 0x1C, 0x9F, 0xAF, 0x09, 0x3B, 0x27, 0x51, 0x72, 0xCF, 0xDD, 0x4F, 0x36, 0x22, 0x79, 0x69, 0xF7, + 0x3C, 0xB9, 0xD5, 0xB7, 0x1C, 0x52, 0x5A, 0x14, 0x1B, 0xC8, 0xBF, 0xC0, 0xCC, 0xD8, 0x63, 0xE5, 0x5F, 0x0E, 0x6C, 0x15, 0xD9, 0xFF, 0x31, 0x17, 0xA1, 0x53, 0x2D, 0xCD, 0x90, 0xEB, 0x86, 0xF9, + 0x06, 0xE8, 0xE8, 0x33, 0x59, 0x9C, 0xC9, 0xE7, 0x7D, 0x5A, 0xFA, 0x6A, 0xA3, 0x60, 0x37, 0xF3, 0x16, 0x58, 0x44, 0xA1, 0xDA, 0xB6, 0x32, 0xD6, 0x7D, 0x5C, 0x83, 0xB2, 0xC0, 0xA1, 0xB5, 0xC6, + 0xBF, 0x4D, 0x41, 0x0B, 0x26, 0xD2, 0xDC, 0xDA, 0x47, 0xD2, 0x7D, 0xC9, 0x9B, 0xC2, 0x94, 0xEC, 0x62, 0x8F, 0xAA, 0x5F, 0x6D, 0x2D, 0xAD, 0x0A, 0xC4, 0x9C, 0x97, 0x58, 0xAE, 0xF1, 0x08, 0xA7, + 0xC2, 0x4C, 0xAE, 0x03, 0xA0, 0xED, 0x0F, 0x72, 0x69, 0x8C, 0xD3, 0xDD, 0x03, 0x0F, 0x5E, 0x56, 0xCB, 0xA8, 0xB6, 0xBE, 0xB1, 0x14, 0x4C, 0xA5, 0x89, 0x22, 0x6B, 0x60, 0xA9, 0x97, 0x21, 0x21, + 0x0D, 0xA7, 0x06, 0xD6, 0x88, 0x64, 0x18, 0x0F, 0x71, 0x50, 0xCF, 0xD0, 0x6D, 0x05, 0x87, 0xF1, 0xD4, 0xF6, 0x51, 0xD0, 0xA3, 0x56, 0xD3, 0xD2, 0x86, 0x34, 0x31, 0x64, 0x65, 0x32, 0x93, 0x22, + 0x2D, 0x36, 0xF5, 0x11, 0xB5, 0x3A, 0xD7, 0x0D, 0x09, 0x6D, 0x6A, 0x43, 0x66, 0xE4, 0xFF, 0x02, 0xA3, 0x24, 0x19, 0x03, 0x3A, 0xC5, 0x94, 0xF8, 0x6A, 0x34, 0xB6, 0xFF, 0x6A, 0x24, 0xB8, 0x02, + 0x89, 0x53, 0x0C, 0x49, 0xD6, 0x4F, 0x6F, 0xB5, 0xB0, 0x5F, 0x59, 0x34, 0x4E, 0xAE, 0x9C, 0x5C, 0x9D, 0x2B, 0x62, 0xBC, 0xC3, 0x12, 0x99, 0xC0, 0x14, 0x95, 0xB4, 0x8D, 0x4A, 0x8F, 0xE3, 0xE7, + 0xEB, 0xB1, 0x93, 0x95, 0x4A, 0x94, 0x89, 0x78, 0xC9, 0x3E, 0xA4, 0xA4, 0x7A, 0xBD, 0x50, 0xEE, 0xEA, 0x6E, 0x5B, 0x79, 0xEC, 0x19, 0x78, 0x7F, 0x2E, 0x90, 0xB7, 0xF9, 0x3F, 0x6B, 0x20, 0x2D, + 0x50, 0x20, 0xAB, 0x2D, 0x69, 0x58, 0x9C, 0x43, 0xE9, 0xD2, 0x96, 0xE3, 0x27, 0xC7, 0xF5, 0x6E, 0x24, 0x0A, 0xC4, 0x05, 0x53, 0x88, 0xBD, 0x0D, 0x68, 0x29, 0xDB, 0xD6, 0xF7, 0xEC, 0x3E, 0x06, + 0x92, 0xCD, 0x4C, 0xA7, 0x72, 0x2A, 0x80, 0x3E, 0x50, 0xE8, 0x12, 0xA2, 0x6F, 0x16, 0x83, 0xBF, 0x6F, 0x6C, 0xF3, 0x99, 0xE5, 0xE5, 0x06, 0x96, 0x8A, 0x99, 0x55, 0xAE, 0x43, 0x88, 0x57, 0x7F, + 0x8C, 0x81, 0x7F, 0x75, 0x90, 0xBF, 0x0F, 0x7B, 0x46, 0x5C, 0x6A, 0xF4, 0x81, 0xDA, 0x6F, 0xA4, 0x6D, 0x6A, 0xF4, 0xB1, 0xC2, 0x40, 0x4B, 0xF5, 0xB5, 0x7C, 0x17, 0x8E, 0x53, 0x04, 0x86, 0xB4, + 0xFD, 0x40, 0x8C, 0x18, 0xAC, 0xC1, 0x8E, 0xEE, 0xE1, 0x34, 0x9A, 0x7A, 0x84, 0x5C, 0x82, 0x61, 0xF0, 0xEA, 0x2E, 0xAA, 0xAF, 0xEF, 0x5E, 0x81, 0xA3, 0x6E, 0x13, 0xA2, 0x5D, 0x29, 0x0B, 0xCE, + 0x6D, 0x62, 0xBF, 0xE8, 0xD4, 0x03, 0xCB, 0x52, 0xFE, 0xE8, 0xCF, 0xA9, 0x29, 0x27, 0xDC, 0xC1, 0x4A, 0x64, 0xBB, 0x26, 0x51, 0x7F, 0xF4, 0x11, 0x15, 0xF4, 0x63, 0xCD, 0xE8, 0x01, 0x85, 0x01, + 0x50, 0xE5, 0xCC, 0x1A, 0x28, 0xF3, 0xA6, 0x69, 0xF4, 0x19, 0x31, 0xAD, 0x82, 0xDB, 0xFB, 0xEA, 0xDA, 0xBE, 0x79, 0xF7, 0xD8, 0xC2, 0x3D, 0x50, 0xCC, 0xC0, 0x3A, 0xBC, 0x12, 0x43, 0x72, 0xFA, + 0x47, 0xC1, 0x0C, 0xFC, 0x21, 0xD4, 0x8C, 0xE6, 0x5F, 0x23, 0x6F, 0xAA, 0x80, 0xF3, 0xB4, 0x07, 0x03, 0x70, 0x3D, 0xAE, 0xD0, 0x39, 0x96, 0x5E, 0x0C, 0x5B, 0xD2, 0x65, 0xF9, 0x82, 0x74, 0x8A, + 0x18, 0xEB, 0x41, 0xBB, 0xD4, 0x42, 0xAE, 0xD1, 0x1E, 0x4C, 0x5F, 0x93, 0x3B, 0x5C, 0xE9, 0x5C, 0x11, 0x59, 0x95, 0x81, 0xAA, 0xA7, 0x49, 0x71, 0x98, 0xD8, 0xF3, 0x6A, 0x88, 0x7C, 0xF3, 0x46, + 0xD4, 0xD3, 0x43, 0x34, 0xC3, 0x83, 0x0C, 0xA3, 0x7D, 0x98, 0xD4, 0xB5, 0x3E, 0xA2, 0x8A, 0xD6, 0xA2, 0x88, 0xF6, 0x81, 0x84, 0x16, 0xE9, 0x29, 0xC2, 0x08, 0x44, 0xDC, 0xE6, 0x1E, 0xD2, 0xFF, + 0x81, 0x3B, 0xEB, 0x75, 0xEB, 0x80, 0x5C, 0x58, 0x92, 0x1E, 0x31, 0xB0, 0xD5, 0xC3, 0xF6, 0x19, 0x38, 0xEE, 0x50, 0x3B, 0x5C, 0x98, 0x51, 0xC8, 0xE0, 0x80, 0x0A, 0xE7, 0x2A, 0xF3, 0xF9, 0xF8, + 0x37, 0x49, 0x4A, 0xB0, 0x63, 0xF1, 0x1B, 0x80, 0x46, 0x8E, 0x76, 0x39, 0xAC, 0x20, 0x80, 0x5D, 0x55, 0x30, 0xB0, 0xA4, 0x8D, 0x9A, 0x3F, 0x27, 0x57, 0x5E, 0x5A, 0x71, 0xCD, 0x1F, 0x18, 0x5D, + 0xF2, 0x78, 0x34, 0x33, 0x30, 0xF8, 0x27, 0x6F, 0xC6, 0x37, 0x7E, 0xC3, 0xDE, 0x4C, 0x7D, 0x2D, 0xB0, 0x3A, 0x12, 0x98, 0xF3, 0x07, 0xD8, 0x1E, 0x6C, 0xB8, 0x2F, 0x2B, 0x86, 0xB9, 0x60, 0x56, + 0xEF, 0x92, 0xDD, 0xF9, 0x10, 0x42, 0xB9, 0x4E, 0xD0, 0x1D, 0xB8, 0x75, 0x37, 0xDC, 0xD4, 0xA8, 0xA2, 0x11, 0x97, 0x29, 0x96, 0xA8, 0x16, 0xEA, 0x6A, 0xB1, 0x59, 0x01, 0xE7, 0x86, 0x6A, 0xFB, + 0x20, 0x22, 0xBB, 0x23, 0xE9, 0x37, 0xFE, 0xD4, 0x9B, 0x61, 0x7D, 0x1B, 0xF4, 0xA3, 0xAE, 0x06, 0xE1, 0x87, 0xF4, 0xB0, 0xA7, 0x8F, 0x2D, 0x71, 0x69, 0x9F, 0xF5, 0x1F, 0xE8, 0x23, 0x78, 0x00, + 0xFC, 0xB0, 0xCE, 0xC8, 0xCE, 0x1D, 0xDE, 0xD3, 0xA3, 0xBC, 0x9F, 0x10, 0x84, 0x13, 0xDC, 0xBF, 0x1D, 0xBF, 0xCA, 0x3A, 0x62, 0x9D, 0xD4, 0xCB, 0x2C, 0x6A, 0xF9, 0xEA, 0xFA, 0x16, 0x4B, 0x46, + 0x1D, 0xDB, 0x47, 0xFA, 0xF1, 0xD3, 0xEB, 0x5D, 0x38, 0xE7, 0x9E, 0xFE, 0x97, 0xA7, 0x2E, 0x4F, 0xC5, 0x34, 0x2B, 0xD5, 0xF3, 0x72, 0xF0, 0xD1, 0xCE, 0xAC, 0xE4, 0xA1, 0xBD, 0x04, 0x23, 0xAC, + 0x76, 0x5E, 0x32, 0x80, 0x3B, 0xD2, 0x45, 0x8D, 0x6C, 0x29, 0x05, 0xC5, 0xA0, 0xDD, 0x8C, 0xE3, 0x5D, 0xEC, 0x6E, 0x8F, 0xDD, 0x64, 0x81, 0x95, 0x55, 0x65, 0xE5, 0xCC, 0x9C, 0xD7, 0xE2, 0x72, + 0x8F, 0xBB, 0x06, 0xE4, 0xE5, 0x23, 0x43, 0x17, 0xA2, 0x8F, 0x65, 0x8A, 0x85, 0xD6, 0xA2, 0x9E, 0xDD, 0x51, 0x83, 0xD7, 0xEF, 0x7A, 0x0C, 0xE6, 0xA9, 0x17, 0x01, 0xC3, 0x40, 0xD6, 0xCF, 0xEE, + 0xD2, 0x97, 0x12, 0x83, 0x56, 0xB7, 0x8E, 0x96, 0x00, 0xC6, 0x6C, 0xBE, 0x6A, 0xC3, 0x0B, 0xFC, 0x91, 0xDB, 0x04, 0x4C, 0x5A, 0xBB, 0xC3, 0x94, 0x2E, 0x73, 0x01, 0xFE, 0x7A, 0x01, 0xF2, 0x11, + 0xF6, 0xED, 0xA7, 0x84, 0x37, 0xF7, 0xD4, 0xE0, 0x45, 0xB7, 0x32, 0x57, 0x02, 0xE8, 0x7F, 0x46, 0x5C, 0xB9, 0x80, 0x43, 0xA6, 0x61, 0x38, 0x19, 0x2B, 0x92, 0x73, 0x5B, 0x8E, 0x10, 0xC8, 0x68, + 0x87, 0x9A, 0x92, 0xA8, 0x80, 0x04, 0xFB, 0x79, 0x7C, 0x14, 0x9C, 0x09, 0x4F, 0xFB, 0x6A, 0x02, 0xE5, 0x0D, 0x69, 0x2D, 0x9C, 0x8F, 0x1F, 0xAD, 0xAE, 0x19, 0x4E, 0x14, 0x16, 0x62, 0xEF, 0xE8, + 0xCF, 0x47, 0xD7, 0xE4, 0x14, 0x97, 0x91, 0xFB, 0x28, 0xB6, 0xDB, 0x0A, 0x34, 0x9B, 0x4E, 0x21, 0x7D, 0xA5, 0x58, 0x65, 0x71, 0x75, 0x19, 0x89, 0x07, 0x6E, 0x66, 0x55, 0x15, 0xD3, 0x24, 0xA9, + 0xF6, 0x86, 0xAB, 0x17, 0x61, 0xF2, 0x40, 0x8B, 0xB8, 0x5D, 0x07, 0xA1, 0x0C, 0xE7, 0x9B, 0x43, 0x05, 0xC7, 0x6E, 0x47, 0x59, 0x05, 0x22, 0x35, 0xC3, 0x68, 0x9E, 0x80, 0x8A, 0x05, 0xDD, 0xB4, + 0x28, 0x16, 0x82, 0x61, 0x00, 0x7F, 0x71, 0x37, 0xF8, 0xFE, 0x73, 0x72, 0xCC, 0x86, 0xBE, 0x80, 0x4E, 0xCF, 0x27, 0xB5, 0x44, 0xA5, 0xCA, 0x43, 0x9D, 0xD2, 0x39, 0x13, 0xDF, 0x44, 0x9D, 0x43, + 0x15, 0x99, 0x73, 0x76, 0x7E, 0x32, 0x12, 0xAB, 0x7C, 0x5E, 0x6D, 0x9B, 0xAB, 0xF9, 0xC5, 0x71, 0x47, 0x3E, 0x6B, 0x51, 0xE2, 0xAB, 0xBD, 0x8B, 0xD8, 0x20, 0x69, 0x8D, 0x1E, 0x57, 0xEA, 0x7B, + 0x37, 0x0C, 0xAE, 0x7C, 0xDC, 0xCA, 0x41, 0x81, 0xBD, 0x7F, 0xAC, 0xDD, 0x1D, 0x82, 0xBD, 0x66, 0x6A, 0x9F, 0x6B, 0x5B, 0x68, 0x59, 0x2E, 0x10, 0x1B, 0x13, 0xD5, 0x1B, 0xE7, 0xCD, 0x29, 0x9B, + 0xF1, 0x02, 0x06, 0x7F, 0x76, 0xF7, 0x86, 0x41, 0x68, 0xBD, 0x1C, 0x2A, 0xA4, 0x65, 0xC0, 0x4B, 0x04, 0x52, 0x07, 0x05, 0x9B, 0xF2, 0xD2, 0xDA, 0xEB, 0xDE, 0x73, 0x19, 0x4E, 0x2E, 0x2C, 0xB7, + 0x97, 0x3E, 0xA5, 0x81, 0xF8, 0x0B, 0x83, 0xCC, 0x2D, 0x79, 0x29, 0xCB, 0x23, 0xF2, 0xED, 0xFE, 0x50, 0xCA, 0xDF, 0xA6, 0x72, 0x73, 0x32, 0x9E, 0x22, 0xCD, 0x68, 0x5A, 0x0B, 0x55, 0x5B, 0x11, + 0xAC, 0x20, 0x69, 0x71, 0x78, 0xBE, 0xDF, 0x93, 0x57, 0xCB, 0xD6, 0xD9, 0xB1, 0x19, 0xA4, 0xDF, 0x52, 0x39, 0x49, 0xBB, 0xA3, 0x23, 0x0D, 0x5C, 0x1E, 0x3F, 0xC8, 0x0F, 0xF3, 0x1E, 0x5E, 0xC9, + 0x89, 0x76, 0xEA, 0xC3, 0xFF, 0x8B, 0x78, 0x54, 0x4E, 0xAA, 0xFB, 0xFF, 0x14, 0x11, 0xDE, 0x2C, 0xBF, 0x0E, 0x94, 0xF1, 0x3D, 0x34, 0xDB, 0x8F, 0xAD, 0x36, 0xD5, 0x4D, 0x3C, 0xF0, 0x3D, 0x38, + 0x89, 0xB2, 0x1F, 0xC0, 0xD7, 0xA6, 0x90, 0xF2, 0xFC, 0xAD, 0x0A, 0xA6, 0x87, 0x9A, 0x9E, 0x5A, 0x42, 0xD8, 0x49, 0xA3, 0x6C, 0x60, 0xDA, 0x42, 0x2D, 0x0F, 0x22, 0x2B, 0x57, 0xCD, 0x0E, 0x08, + 0x3A, 0xF6, 0xC8, 0x6C, 0x9C, 0x32, 0xC3, 0x7D, 0xC8, 0x8F, 0x27, 0x36, 0xD6, 0xA5, 0x3D, 0x74, 0xA7, 0xD6, 0xB6, 0xEA, 0x0F, 0x25, 0xA2, 0xBC, 0x61, 0x49, 0xD0, 0x69, 0x8A, 0x77, 0xDD, 0x97, + 0xAA, 0x7F, 0xA1, 0xB8, 0x81, 0x11, 0xEB, 0xC1, 0xB8, 0xF4, 0x81, 0xCD, 0x23, 0x87, 0xB4, 0x88, 0x2A, 0xF9, 0x89, 0xC2, 0x6E, 0x95, 0x67, 0x52, 0x96, 0xD9, 0x6B, 0x15, 0x89, 0x68, 0x34, 0xEF, + 0x7B, 0xDB, 0xD9, 0x9E, 0xDB, 0x5F, 0xB0, 0xC2, 0xCC, 0xAB, 0x53, 0x37, 0x90, 0xB9, 0x95, 0xC0, 0xCD, 0x46, 0x4B, 0xEB, 0x97, 0x54, 0x56, 0x10, 0xD4, 0x90, 0x40, 0xFF, 0xF0, 0x40, 0x44, 0xBF, + 0x1B, 0x99, 0xB1, 0x3B, 0xC6, 0x7C, 0x2C, 0xEB, 0x3F, 0x3B, 0x23, 0x70, 0x61, 0x05, 0x44, 0x3F, 0xC9, 0x72, 0xD8, 0xE2, 0x3E, 0xB9, 0xA6, 0xF4, 0x05, 0xB0, 0x39, 0xC7, 0x68, 0x87, 0xD6, 0x3D, + 0x31, 0x76, 0x6E, 0xE6, 0x03, 0x48, 0xD4, 0x74, 0xC0, 0x1D, 0xFE, 0xEF, 0x14, 0x4B, 0x8D, 0xBF, 0x29, 0x68, 0x75, 0x6B, 0xC4, 0xB3, 0x2F, 0x70, 0xFC, 0xCE, 0xC7, 0x20, 0x36, 0x37, 0x66, 0x47, + 0x05, 0xA0, 0x7C, 0x2E, 0x62, 0x50, 0xEE, 0xA1, 0x14, 0xDF, 0x7B, 0x91, 0xF4, 0xCF, 0x66, 0x11, 0xD0, 0x80, 0x9F, 0x96, 0x48, 0x1A, 0x0F, 0x09, 0x84, 0xC9, 0x7B, 0x3F, 0x55, 0x59, 0x2F, 0x0C, + 0x53, 0xE5, 0x46, 0x7E, 0x3B, 0x4F, 0x3E, 0xCC, 0x8C, 0x34, 0x16, 0x82, 0xD3, 0xE4, 0x7C, 0x8D, 0xEF, 0xEC, 0x79, 0xDC, 0xD0, 0x7F, 0x83, 0xDF, 0x43, 0x32, 0x7F, 0x29, 0xF2, 0xFD, 0x6F, 0x83, + 0x11, 0xD1, 0x0A, 0x9D, 0xC1, 0x26, 0x46, 0xCB, 0x18, 0x58, 0xBB, 0xD0, 0x6D, 0xA7, 0x2A, 0x82, 0xE7, 0xC4, 0xD1, 0x5E, 0x89, 0x69, 0x80, 0x7B, 0xD2, 0x44, 0xBB, 0x15, 0x7A, 0xC4, 0x2E, 0x79, + 0xD3, 0xE9, 0x37, 0x65, 0x18, 0xD3, 0x8B, 0xD6, 0xF9, 0x83, 0xBB, 0x8C, 0xF8, 0x6E, 0xC7, 0xFF, 0x6C, 0xFE, 0xA5, 0x3E, 0xC9, 0xEA, 0x4B, 0xAF, 0xFA, 0xA2, 0x80, 0x29, 0xDF, 0xE6, 0x84, 0xB8, + 0xD3, 0xC8, 0x88, 0x9A, 0x6F, 0xF4, 0x6D, 0x9F, 0xF7, 0x2C, 0xF0, 0xF4, 0xD2, 0xF9, 0xBE, 0xE1, 0xA1, 0xEC, 0xCF, 0x58, 0xAA, 0x83, 0x24, 0xE8, 0x9C, 0xD5, 0xE3, 0xFC, 0xA4, 0x96, 0x05, 0x4A, + 0x4C, 0x5C, 0x41, 0x3A, 0xF2, 0x3A, 0x3D, 0xC1, 0xC2, 0x11, 0x29, 0xAA, 0xDD, 0x20, 0xB0, 0x7D, 0x34, 0x9D, 0x56, 0x16, 0x95, 0x18, 0xEE, 0x7E, 0xE0, 0xB8, 0x89, 0x86, 0xCA, 0xF2, 0xAE, 0x69, + 0x41, 0xF3, 0x85, 0xC9, 0x7C, 0x34, 0x73, 0xC7, 0x1A, 0x69, 0xB0, 0x46, 0xF9, 0xC9, 0xA7, 0xF2, 0xF7, 0xF4, 0xC1, 0xCB, 0xD4, 0xA2, 0xBF, 0x17, 0x33, 0x93, 0x66, 0x74, 0x46, 0xB5, 0xEB, 0xD2, + 0xB6, 0xE7, 0x6E, 0xE5, 0x42, 0x75, 0xD4, 0x8D, 0x47, 0xE3, 0xD3, 0x24, 0x8D, 0xE8, 0x85, 0x6D, 0x90, 0xB4, 0x87, 0x29, 0x08, 0xE2, 0xCE, 0x08, 0xA3, 0xEE, 0x6F, 0xE6, 0x59, 0x19, 0x8A, 0x91, + 0xDD, 0x5A, 0xC7, 0x2A, 0xD7, 0xA5, 0x62, 0x47, 0x36, 0x96, 0xBD, 0x24, 0xEE, 0x11, 0xF2, 0xDC, 0xC2, 0xE8, 0xFA, 0x13, 0x93, 0x4D, 0x78, 0x5C, 0x5F, 0x22, 0x8B, 0x86, 0x73, 0xF1, 0xFF, 0xCF, + 0x30, 0x18, 0x32, 0xA5, 0x66, 0x1D, 0x7B, 0x2A, 0xA8, 0x39, 0xD3, 0xB1, 0x97, 0x2A, 0xB3, 0xD0, 0xC3, 0x2C, 0xE3, 0x40, 0x13, 0xAF, 0x4D, 0xA7, 0xF8, 0x7C, 0xB3, 0x49, 0xE3, 0x54, 0x9F, 0x62, + 0xA2, 0x4C, 0x3C, 0x7D, 0x81, 0x50, 0x30, 0x45, 0x08, 0x7A, 0xAC, 0x30, 0xE3, 0x64, 0xD0, 0x6C, 0xEC, 0xAA, 0xD1, 0xD9, 0x7D, 0xA7, 0x2A, 0xC8, 0x24, 0x6B, 0x39, 0xB3, 0x3C, 0xD8, 0xF1, 0xB7, + 0x66, 0x1D, 0xE1, 0x11, 0xA1, 0x9E, 0xA2, 0x8B, 0x51, 0x58, 0xC7, 0x44, 0xC6, 0x6E, 0x2B, 0xDE, 0x1E, 0x56, 0x8A, 0x83, 0xC7, 0x84, 0xDE, 0xFD, 0x50, 0x6B, 0x60, 0x9A, 0x45, 0x22, 0x1A, 0x79, + 0x70, 0x92, 0xE0, 0xBE, 0xD1, 0x38, 0xE1, 0x53, 0xD2, 0x34, 0xE5, 0x81, 0xDF, 0x5F, 0xD1, 0x0B, 0x28, 0x50, 0x8F, 0x3C, 0x08, 0xE8, 0x3E, 0x95, 0x69, 0xF2, 0x48, 0x89, 0xD3, 0xF7, 0x00, 0x45, + 0xF4, 0xD5, 0x39, 0x5D, 0x97, 0x25, 0x71, 0x00, 0xAB, 0x1B, 0x59, 0x49, 0x9E, 0xD3, 0x50, 0xBF, 0xF7, 0xFB, 0xB4, 0x3E, 0x7B, 0xD1, 0x84, 0x0B, 0x66, 0xC0, 0xFB, 0x91, 0x88, 0xA6, 0x18, 0xD6, + 0x07, 0xCA, 0xA7, 0x65, 0x76, 0xE8, 0x52, 0x0E, 0x26, 0xE5, 0x57, 0x94, 0xB7, 0xD9, 0x62, 0x35, 0x46, 0x0D, 0x02, 0x81, 0x5F, 0xC3, 0x1D, 0x5F, 0xD2, 0x75, 0x9C, 0x4F, 0xF1, 0x9B, 0x9C, 0x2C, + 0xC5, 0xCF, 0x1E, 0x14, 0x3F, 0x51, 0xF7, 0x2B, 0xCF, 0xAA, 0xCB, 0x35, 0x91, 0xD4, 0xF9, 0x48, 0xEA, 0xB1, 0x73, 0x9B, 0x0C, 0x8B, 0xC2, 0x78, 0x2E, 0x48, 0x74, 0xB4, 0xAC, 0x67, 0xAE, 0x50, + 0x25, 0x1C, 0x56, 0x9B, 0x31, 0x5D, 0xC8, 0x6B, 0x97, 0x0E, 0x48, 0x15, 0x65, 0xBF, 0x19, 0x32, 0x0C, 0x80, 0xDC, 0x9D, 0xF1, 0x1C, 0x78, 0x3F, 0xB2, 0xB8, 0x3F, 0x04, 0x62, 0xCB, 0xE6, 0xAB, + 0x15, 0x59, 0x97, 0x47, 0xE6, 0x3C, 0xA8, 0xE7, 0x78, 0x43, 0x66, 0xEE, 0x3D, 0x8C, 0x5E, 0xEF, 0x84, 0x88, 0xA6, 0xD5, 0x7B, 0x47, 0xC8, 0x0A, 0x9E, 0x40, 0xF5, 0xD3, 0xED, 0x98, 0x7F, 0x2A, + 0xB5, 0x4B, 0x49, 0x97, 0xD3, 0x8F, 0x39, 0x2D, 0xF6, 0xD9, 0x9F, 0xCA, 0xFD, 0xEB, 0x89, 0x34, 0x21, 0x0D, 0xF2, 0x8D, 0xAA, 0xB2, 0x68, 0x23, 0x78, 0x6A, 0xE7, 0x27, 0x7E, 0x49, 0x1C, 0x97, + 0xD4, 0x7F, 0x87, 0x41, 0x55, 0x6D, 0x6B, 0xA3, 0xD3, 0x5D, 0x49, 0x99, 0x84, 0x39, 0xCF, 0xF5, 0x96, 0x9C, 0x9E, 0x63, 0x21, 0x55, 0x80, 0xD4, 0x07, 0x10, 0x33, 0x4D, 0x58, 0x99, 0x8A, 0x88, + 0x15, 0x21, 0x4E, 0xED, 0x94, 0xF2, 0x40, 0x47, 0x02, 0xD9, 0xC5, 0x91, 0x73, 0xEF, 0xBD, 0x13, 0xF3, 0x36, 0x77, 0xAB, 0xAE, 0x5A, 0x38, 0xE1, 0xE8, 0xBC, 0x9A, 0x35, 0x23, 0xF4, 0xF9, 0xBF, + 0x9D, 0x82, 0x65, 0x02, 0xA6, 0xE3, 0x44, 0x88, 0xB1, 0x7E, 0x0E, 0xB4, 0x1F, 0x3D, 0x10, 0xA4, 0xD7, 0x52, 0x77, 0xA1, 0xD0, 0x71, 0xCD, 0xE9, 0x21, 0xB1, 0xD4, 0x51, 0x83, 0x24, 0x36, 0xCC, + 0x6E, 0xDC, 0xFA, 0x93, 0x45, 0x86, 0x1F, 0x51, 0xC1, 0xC3, 0xA7, 0x4E, 0x6D, 0x71, 0x11, 0xA2, 0x51, 0xDF, 0xFF, 0x1B, 0xD0, 0xF2, 0x9C, 0x69, 0xC3, 0x26, 0x12, 0x6F, 0x9C, 0x45, 0x5D, 0x6A, + 0xC2, 0x7D, 0x53, 0x44, 0x49, 0x33, 0xDF, 0xFA, 0x3B, 0x66, 0xB9, 0xD1, 0x9B, 0x40, 0xB4, 0x3D, 0x3C, 0x8D, 0xE7, 0x9C, 0xFC, 0xD2, 0x14, 0x52, 0x83, 0x49, 0x48, 0x63, 0x2C, 0xBC, 0x49, 0x49, + 0xB5, 0x5E, 0x23, 0x4B, 0x5A, 0x74, 0xE4, 0x1F, 0x94, 0xB3, 0x9A, 0x9D, 0x97, 0xD2, 0x7C, 0x43, 0x3F, 0xF0, 0xBE, 0x41, 0x62, 0xDB, 0xCE, 0x88, 0xCA, 0x30, 0xF9, 0x2A, 0x2A, 0x5B, 0x43, 0x99, + 0xA0, 0x0C, 0xE1, 0x47, 0x39, 0xBF, 0x49, 0x32, 0xBF, 0xC8, 0x9E, 0x8B, 0xFC, 0xE9, 0x1D, 0x02, 0x25, 0xED, 0xBD, 0xFF, 0xE3, 0x21, 0xA9, 0x94, 0x48, 0xD7, 0xA0, 0xD6, 0x93, 0xD4, 0xC0, 0x99, + 0xA2, 0x4C, 0x57, 0xF8, 0xC8, 0x0A, 0x02, 0xF0, 0x6A, 0x6B, 0x34, 0x90, 0x03, 0x8E, 0x37, 0x4A, 0x85, 0x61, 0x72, 0x91, 0xC8, 0x6B, 0x11, 0xD0, 0x66, 0xA9, 0x70, 0x94, 0x85, 0x63, 0x90, 0x98, + 0x35, 0xCE, 0xD1, 0xB9, 0xE7, 0x85, 0x96, 0xEE, 0xAB, 0x0E, 0xE9, 0xE6, 0x14, 0xE3, 0x40, 0xFD, 0x03, 0x4B, 0xAF, 0x2F, 0x34, 0x51, 0x7C, 0xCE, 0xB5, 0xD1, 0x55, 0x0E, 0xE2, 0xE3, 0xD7, 0xDF, + 0x19, 0xB9, 0xFC, 0x83, 0xD6, 0x4E, 0x7E, 0xB7, 0xA2, 0x59, 0xF3, 0x72, 0xB3, 0xF7, 0xB1, 0xA1, 0x4A, 0x69, 0x66, 0x71, 0x31, 0xDD, 0x06, 0xDD, 0xE3, 0x5C, 0x86, 0x26, 0x23, 0xAF, 0x71, 0xCE, + 0x15, 0xE3, 0xB0, 0x04, 0x0D, 0xCF, 0x78, 0x7E, 0xC8, 0x58, 0x3F, 0xDE, 0xC3, 0x16, 0x60, 0xA8, 0x1C, 0xBC, 0xD1, 0x91, 0xD9, 0xA2, 0xAF, 0x11, 0x35, 0x54, 0xB2, 0x78, 0x79, 0xE3, 0xE3, 0xC7, + 0xC1, 0xE7, 0x71, 0xA4, 0x08, 0x6E, 0x33, 0x9C, 0x61, 0xEC, 0x11, 0x98, 0x50, 0x70, 0x4F, 0xE5, 0xC8, 0x07, 0xB9, 0x35, 0xB0, 0x8D, 0x7F, 0xFB, 0x58, 0xC9, 0x2C, 0xC2, 0x4A, 0xAC, 0xB2, 0x28, + 0xFB, 0xB7, 0x04, 0x45, 0xB4, 0xC2, 0x39, 0x16, 0x44, 0x79, 0x3A, 0xDE, 0x07, 0xEA, 0x1F, 0x29, 0x51, 0x40, 0x6F, 0x10, 0x85, 0xAF, 0xA6, 0xD7, 0x6C, 0xB9, 0x0C, 0xBD, 0x98, 0x8F, 0xFB, 0xFF, + 0x62, 0xA4, 0xAD, 0xB8, 0x3B, 0x0D, 0x13, 0x4F, 0xAD, 0xE4, 0xAE, 0x4B, 0xD5, 0x7D, 0x95, 0xDE, 0x23, 0x16, 0x24, 0x43, 0xD0, 0xAF, 0x2D, 0x59, 0x47, 0x24, 0x4A, 0xE5, 0xF0, 0xDD, 0x56, 0x57, + 0xB7, 0x70, 0x5F, 0x83, 0x69, 0x55, 0x6B, 0x2C, 0xBE, 0x38, 0xD0, 0x47, 0xBC, 0xA9, 0xBB, 0x48, 0x79, 0x2D, 0x47, 0xF2, 0xC7, 0x07, 0x4F, 0xA2, 0x71, 0xFD, 0x87, 0x29, 0x19, 0x0C, 0x3B, 0x2D, + 0x95, 0x72, 0x37, 0x13, 0xB2, 0xD6, 0x8B, 0xD7, 0x71, 0x15, 0xA8, 0x00, 0xF8, 0xF7, 0xB4, 0x43, 0x90, 0xC3, 0x8B, 0xC8, 0x8E, 0x4C, 0x04, 0x73, 0xAC, 0x31, 0x60, 0xA5, 0x84, 0x54, 0xD2, 0x5C, + 0xE2, 0xF7, 0x49, 0x18, 0xD8, 0xA9, 0xA4, 0xBF, 0xAF, 0x1B, 0xFC, 0x44, 0xA6, 0xF5, 0x35, 0xED, 0xC5, 0xCB, 0x40, 0x48, 0x98, 0xC7, 0xA3, 0x48, 0x15, 0x24, 0xCF, 0x0E, 0x60, 0x51, 0x58, 0xFD, + 0x63, 0xB3, 0x0D, 0x26, 0xD6, 0xDA, 0xB3, 0x20, 0x4A, 0x78, 0x30, 0xFC, 0xE0, 0x5B, 0x3F, 0x0B, 0x35, 0x57, 0xA4, 0x31, 0x39, 0xE0, 0x52, 0x46, 0xD2, 0xD4, 0x66, 0x9C, 0xCE, 0x5A, 0x19, 0x54, + 0xE4, 0xDC, 0x06, 0x46, 0xD6, 0xF3, 0xEC, 0x71, 0xD4, 0x20, 0xE7, 0x4E, 0x1A, 0xD3, 0x5A, 0xC9, 0x25, 0x73, 0x56, 0xB5, 0xD3, 0x42, 0x84, 0x0C, 0x59, 0x57, 0x9B, 0xBC, 0xE3, 0xF3, 0xAE, 0x37, + 0x6C, 0xBB, 0x15, 0x77, 0x98, 0x49, 0x39, 0x64, 0x44, 0x94, 0x56, 0xB0, 0x64, 0x36, 0x6C, 0x1F, 0x91, 0xB9, 0x98, 0x16, 0x6F, 0x76, 0xC3, 0xD8, 0x1D, 0x76, 0x2E, 0x72, 0x8A, 0x16, 0x34, 0x2C }, + .t1_len = 1728, + .t1 = { 0x03, 0x86, 0xFF, 0xC6, 0x0A, 0x93, 0x17, 0x0D, 0x76, 0x19, 0x52, 0x69, 0x55, 0x36, 0xD3, 0x08, 0xE6, 0x95, 0xB0, 0x16, 0x51, 0x48, 0xA3, 0x3B, 0x57, 0x07, 0x20, 0x23, 0x3D, 0xBA, 0x3B, 0xBD, + 0x2E, 0xF0, 0x82, 0xEC, 0xDE, 0x3E, 0x51, 0x92, 0xA3, 0xC5, 0x58, 0x5E, 0xFF, 0xD7, 0x7C, 0x74, 0x93, 0x17, 0xCB, 0x34, 0x72, 0x3C, 0x40, 0x3D, 0x06, 0xB9, 0x47, 0x6A, 0xA5, 0x17, 0x6F, 0xD7, + 0x88, 0xBC, 0xD6, 0xB8, 0x0D, 0x6B, 0x97, 0x30, 0x25, 0x0E, 0x7B, 0xE2, 0xDF, 0x4C, 0x19, 0xD6, 0x7B, 0x21, 0x7E, 0xEB, 0xE5, 0x0F, 0x27, 0x84, 0xA4, 0x82, 0x8D, 0x27, 0x2A, 0xDF, 0xC3, 0x59, + 0xB6, 0x44, 0x94, 0x05, 0xF1, 0xBD, 0xDC, 0xA1, 0xB8, 0xEA, 0x42, 0x43, 0x29, 0x14, 0xEE, 0xB7, 0x86, 0x49, 0xBE, 0xEE, 0x3A, 0x87, 0xEC, 0xA7, 0x38, 0xCF, 0x40, 0x42, 0x1B, 0x22, 0x18, 0x13, + 0x56, 0xC4, 0x7F, 0xC0, 0x35, 0x96, 0x9C, 0x1F, 0x1C, 0x94, 0xF4, 0x8A, 0xB5, 0xBE, 0xD4, 0x47, 0x08, 0xA9, 0xE7, 0xBB, 0x13, 0xBA, 0xC9, 0xEC, 0x88, 0xBC, 0x19, 0x1C, 0x1A, 0xAB, 0x53, 0xCE, + 0x31, 0x9A, 0xCF, 0x16, 0x3F, 0x26, 0xCB, 0x5E, 0x6C, 0x91, 0xAB, 0x83, 0x28, 0xA1, 0x81, 0xD2, 0xB7, 0x17, 0xA5, 0xB6, 0x35, 0xB2, 0x87, 0xE8, 0x9D, 0xCE, 0x97, 0xA6, 0x5B, 0x3A, 0x70, 0xAC, + 0xAE, 0xD8, 0x00, 0x56, 0xC8, 0x2A, 0xEE, 0xAE, 0x6B, 0x69, 0x94, 0x15, 0x57, 0x3E, 0x90, 0xCC, 0xB7, 0xEF, 0x3D, 0x8E, 0x3F, 0xA6, 0x6C, 0x9A, 0x8E, 0x13, 0x31, 0x5D, 0xE0, 0x4C, 0x7B, 0x66, + 0x51, 0xDC, 0x10, 0xC4, 0x58, 0x7A, 0x3C, 0xC0, 0x87, 0x32, 0xFE, 0x6D, 0x74, 0x2B, 0x62, 0x58, 0x54, 0x5F, 0x30, 0xEC, 0x7F, 0x60, 0x91, 0xCA, 0xB3, 0xBD, 0xB6, 0xD2, 0x65, 0x1E, 0x68, 0x4A, + 0x0B, 0x26, 0x7F, 0xFA, 0xFF, 0x77, 0xAA, 0xB8, 0xB0, 0x8D, 0x75, 0xFE, 0x38, 0x01, 0x0C, 0xA3, 0xE9, 0x0D, 0x33, 0x3B, 0xED, 0x45, 0x2B, 0xDA, 0xB4, 0x46, 0xB4, 0x9C, 0xD4, 0x47, 0x49, 0x9D, + 0xEF, 0x7B, 0x7F, 0xCD, 0xE6, 0x73, 0x4E, 0x09, 0x22, 0x9A, 0x28, 0x5E, 0x02, 0x24, 0x08, 0x03, 0x25, 0x72, 0x73, 0x50, 0x5A, 0xA5, 0xEF, 0x2C, 0x92, 0xE1, 0x2D, 0x81, 0xBC, 0xC1, 0xA6, 0xC7, + 0x52, 0x6D, 0xA8, 0x45, 0x6D, 0x3F, 0x87, 0xE5, 0xAF, 0x18, 0xA5, 0x6C, 0xBB, 0x0C, 0x99, 0x82, 0xAF, 0x25, 0x29, 0x5D, 0xC0, 0xDA, 0x17, 0x22, 0x08, 0xBB, 0x60, 0x83, 0x3F, 0x33, 0xDD, 0x48, + 0x94, 0x9F, 0x6E, 0x19, 0xB0, 0xB1, 0xFE, 0x70, 0x5F, 0xF8, 0x18, 0x1C, 0xC9, 0xE2, 0xF2, 0x5D, 0xE8, 0x65, 0xFA, 0xD2, 0x71, 0x8A, 0x49, 0x3C, 0x0C, 0x41, 0xC1, 0x4C, 0x2C, 0x24, 0x21, 0x1D, + 0x01, 0x70, 0x6B, 0xDA, 0x53, 0x92, 0x62, 0x74, 0x55, 0x43, 0x43, 0xAE, 0xAB, 0x09, 0x56, 0xA6, 0x48, 0x19, 0xF4, 0x3E, 0xDF, 0xF8, 0xAC, 0xCC, 0x7D, 0xA0, 0x47, 0xC4, 0x59, 0x3C, 0xCB, 0x6E, + 0xD1, 0xA7, 0x2F, 0xE6, 0x06, 0x6C, 0x82, 0x41, 0x44, 0x6E, 0xB5, 0x3D, 0x2D, 0x7D, 0xB5, 0xAC, 0x97, 0x93, 0xB8, 0x2A, 0x42, 0x41, 0xAC, 0xE2, 0x8D, 0xCF, 0xF0, 0x73, 0x86, 0xE6, 0x1B, 0x5F, + 0xAF, 0xA3, 0x04, 0x05, 0xF5, 0xE0, 0x8B, 0x68, 0x1D, 0xE3, 0x47, 0xBE, 0x92, 0x9C, 0xBA, 0x4E, 0x99, 0x7C, 0x1C, 0x5D, 0x5C, 0x09, 0xB8, 0x3B, 0xC0, 0x6B, 0xFC, 0x00, 0x35, 0x16, 0xB6, 0x2D, + 0xB4, 0xD3, 0x57, 0x0B, 0x9A, 0x7B, 0x58, 0x53, 0x33, 0xE6, 0x58, 0x7D, 0xA3, 0x7A, 0x72, 0x76, 0xA3, 0x8C, 0xFA, 0xE5, 0xCC, 0x37, 0xEF, 0x42, 0xA5, 0xD9, 0x7D, 0xD6, 0xFE, 0xB2, 0xBC, 0x48, + 0xDC, 0x7F, 0x24, 0x66, 0x8E, 0x52, 0x5B, 0x2A, 0xF4, 0x1D, 0xB6, 0x7D, 0xC9, 0x9D, 0x7D, 0x8E, 0xFC, 0xA2, 0xAD, 0xB7, 0x90, 0x70, 0x6A, 0x9E, 0x9E, 0x22, 0x18, 0xF3, 0xEE, 0x19, 0xF6, 0x81, + 0x72, 0xA2, 0xC5, 0x1F, 0x92, 0xAF, 0xDB, 0x08, 0x60, 0x92, 0x08, 0x31, 0x3E, 0x41, 0x9B, 0xB5, 0x23, 0x34, 0x77, 0x07, 0xBA, 0x88, 0x75, 0xC0, 0x56, 0xB3, 0xC8, 0x40, 0xDB, 0xC4, 0x68, 0xDD, + 0x9D, 0xD1, 0x17, 0x99, 0x8A, 0x73, 0x64, 0xA9, 0x9A, 0xAA, 0xCB, 0x86, 0x28, 0xB5, 0xA8, 0x26, 0xB5, 0x45, 0xCE, 0xDB, 0x8B, 0x29, 0x34, 0xD0, 0xF5, 0x32, 0xFF, 0xEB, 0xEA, 0xA9, 0x61, 0x44, + 0x3F, 0xD6, 0x96, 0x8C, 0xA6, 0xB0, 0x0D, 0x73, 0x00, 0x38, 0x42, 0x51, 0xA8, 0xC9, 0xEA, 0x44, 0x08, 0x47, 0x01, 0xF8, 0x21, 0x40, 0x7F, 0x17, 0xC8, 0x16, 0xFC, 0xA4, 0xA2, 0x11, 0x32, 0x8A, + 0x97, 0xEA, 0xEF, 0x62, 0xB9, 0xD8, 0xD2, 0xAA, 0x63, 0xDC, 0xA8, 0xAC, 0xFE, 0xB3, 0xA5, 0xA7, 0x03, 0x6A, 0x83, 0x2D, 0x2B, 0xEF, 0x2A, 0x7C, 0x05, 0x6D, 0x10, 0x51, 0x45, 0x4C, 0x58, 0x4A, + 0x1D, 0x38, 0xA9, 0x8A, 0x75, 0xAA, 0x5F, 0xB6, 0xC3, 0x0F, 0x89, 0xD3, 0xDE, 0x1F, 0x8B, 0x11, 0xA8, 0xF9, 0x20, 0xD8, 0x25, 0x09, 0x3C, 0x78, 0x60, 0x19, 0x12, 0x3F, 0x34, 0x85, 0x11, 0xEF, + 0x6D, 0xB5, 0xEF, 0x9F, 0x6B, 0xB7, 0x3A, 0x8C, 0xFF, 0x5B, 0xFC, 0xB4, 0x69, 0x25, 0x87, 0x3B, 0xDE, 0x6D, 0x61, 0x87, 0x6A, 0x02, 0x28, 0x0C, 0x35, 0xD0, 0x3C, 0x5F, 0x09, 0xD8, 0xF4, 0x70, + 0x4E, 0xC0, 0xA5, 0x1A, 0xAD, 0xAE, 0x18, 0x24, 0xA2, 0xDD, 0xC5, 0x3A, 0x51, 0x4D, 0x58, 0x55, 0x93, 0xE8, 0x96, 0x24, 0x1B, 0x8F, 0x0F, 0x14, 0x86, 0xD6, 0xDC, 0x3B, 0x56, 0x51, 0x83, 0x2B, + 0x97, 0x2C, 0x2F, 0x68, 0x18, 0xFE, 0x5B, 0x61, 0xE4, 0x9D, 0x54, 0x3B, 0xEF, 0x38, 0x3B, 0x36, 0xDB, 0x6E, 0xEB, 0x06, 0x3A, 0x34, 0x4D, 0xDA, 0x18, 0x0D, 0x4E, 0x8B, 0xFB, 0x4C, 0x87, 0xA3, + 0xB7, 0x91, 0x1B, 0x91, 0xA0, 0x06, 0xC2, 0x82, 0x0D, 0x11, 0x4D, 0xEF, 0xC7, 0x8D, 0x53, 0x46, 0x90, 0xC7, 0xD0, 0x58, 0xEF, 0x88, 0xF4, 0x3A, 0xE0, 0x1B, 0xFE, 0x16, 0xF5, 0xD9, 0x71, 0x1D, + 0x9A, 0x40, 0xBE, 0x61, 0xDC, 0xC7, 0x11, 0x8E, 0xE9, 0x95, 0x1C, 0xC1, 0x90, 0x13, 0x05, 0x48, 0x51, 0xF3, 0x7D, 0xA9, 0x15, 0x45, 0x38, 0x96, 0xD0, 0x82, 0xEA, 0x8B, 0x38, 0x98, 0x8B, 0x41, + 0x9D, 0x55, 0x1D, 0xE0, 0xEB, 0x3D, 0x6E, 0xD8, 0xD9, 0xC6, 0xC5, 0xE3, 0xCB, 0xC8, 0x5C, 0x64, 0x18, 0x12, 0xD6, 0x7B, 0x31, 0x1F, 0xF8, 0xBF, 0xD4, 0x8C, 0x90, 0xD6, 0x3D, 0x54, 0xB2, 0x37, + 0x4B, 0x0B, 0x1A, 0x3D, 0x1F, 0xE9, 0x3A, 0x28, 0xB8, 0x0C, 0x8B, 0xA0, 0x05, 0x4B, 0x06, 0xE0, 0x37, 0x0C, 0xAE, 0x9E, 0xBB, 0x26, 0x3E, 0x33, 0xAF, 0x44, 0x87, 0x5F, 0x79, 0x03, 0xC5, 0xD1, + 0xE9, 0xA1, 0x0D, 0x7A, 0x43, 0x0A, 0x8B, 0x13, 0x71, 0xC7, 0x5D, 0xAB, 0xA3, 0xE5, 0x74, 0x57, 0xBA, 0x59, 0x34, 0x27, 0x25, 0x74, 0x70, 0x9C, 0x07, 0x4A, 0xB8, 0x06, 0xE1, 0xAC, 0xEB, 0x39, + 0xC5, 0x66, 0x80, 0x67, 0x29, 0x71, 0x8F, 0x2C, 0x96, 0xE6, 0x24, 0x38, 0xF5, 0x19, 0x9B, 0xF7, 0x4C, 0x4D, 0xAF, 0x4E, 0xE7, 0x51, 0xE4, 0x3A, 0xD3, 0x0A, 0x45, 0x2B, 0x1B, 0xDC, 0xA4, 0xA5, + 0xC0, 0x55, 0x83, 0xBE, 0x2B, 0xC3, 0xD5, 0xB3, 0x45, 0xD7, 0xDD, 0xE3, 0xE6, 0xF3, 0x9B, 0x64, 0x9B, 0xDC, 0x40, 0x5A, 0x5B, 0x46, 0xC3, 0x46, 0x4C, 0x03, 0x73, 0xDF, 0x67, 0x0C, 0x23, 0x31, + 0x09, 0x05, 0x00, 0x8B, 0xB0, 0xA3, 0x97, 0x59, 0x1C, 0xF5, 0xBF, 0xE3, 0x20, 0x0A, 0x50, 0x04, 0x9A, 0xA7, 0x04, 0xCA, 0xEB, 0xC5, 0xEF, 0x4F, 0x0A, 0x6B, 0x4C, 0x41, 0x92, 0xD1, 0x04, 0x96, + 0x70, 0x5A, 0xFC, 0x30, 0x02, 0xEB, 0x18, 0x96, 0x3A, 0xCC, 0xAD, 0x59, 0x7B, 0xEE, 0xBB, 0x21, 0x89, 0xBB, 0x8B, 0x6C, 0x43, 0x09, 0xC5, 0xD0, 0x8D, 0xAC, 0xC4, 0x8D, 0xF3, 0xC8, 0xFF, 0x6F, + 0x45, 0xF9, 0x48, 0x26, 0x77, 0xC0, 0xA9, 0xC0, 0xDB, 0x46, 0xC7, 0x20, 0xDD, 0x5B, 0x7B, 0xF2, 0x61, 0x2D, 0xC8, 0xEA, 0x18, 0xC8, 0x14, 0xD7, 0x70, 0x39, 0xD0, 0x39, 0x7E, 0x24, 0x38, 0xB9, + 0x0B, 0xA5, 0xEB, 0xE7, 0x2B, 0xCD, 0xED, 0x47, 0xD7, 0x92, 0xBA, 0x2D, 0x9F, 0xF0, 0xB9, 0x16, 0xDA, 0x01, 0xBA, 0x32, 0xBD, 0xDF, 0xB3, 0x2B, 0x95, 0xC9, 0x02, 0x96, 0x69, 0x56, 0x75, 0xBA, + 0x78, 0x89, 0xB8, 0x61, 0x5F, 0x77, 0xD2, 0x03, 0x72, 0x8E, 0xA7, 0xB7, 0xE5, 0x00, 0xD8, 0xBA, 0x7F, 0xEA, 0x61, 0x37, 0x95, 0xEB, 0x52, 0xB7, 0x11, 0x67, 0x6D, 0xBA, 0xD9, 0x42, 0x7D, 0xB7, + 0xA2, 0xE5, 0x0A, 0xDD, 0x54, 0x1F, 0x63, 0x62, 0xED, 0x14, 0x6F, 0xD7, 0xEC, 0x61, 0x2C, 0xD7, 0x7D, 0xD8, 0x39, 0xCD, 0x89, 0x40, 0xA8, 0x53, 0x31, 0xAA, 0x7D, 0x3D, 0xFA, 0x71, 0xE5, 0xD4, + 0xB7, 0x5B, 0x1D, 0xBF, 0xF8, 0xB6, 0xD4, 0x59, 0x98, 0x45, 0xA3, 0x20, 0x5D, 0x2D, 0x41, 0x17, 0xD0, 0x23, 0x81, 0x4A, 0x0C, 0x80, 0x88, 0xEC, 0x89, 0x1E, 0xD0, 0xA2, 0xFC, 0x3A, 0xE7, 0x60, + 0x54, 0x52, 0x4B, 0x1D, 0x3B, 0x2F, 0x1E, 0x01, 0xA9, 0x03, 0x59, 0x20, 0x56, 0x32, 0x85, 0x3D, 0xC0, 0x35, 0xF2, 0x49, 0x30, 0xEB, 0x7F, 0x8F, 0xAA, 0x62, 0x42, 0x11, 0xB3, 0xF6, 0xC8, 0x46, + 0x09, 0xE9, 0x19, 0x85, 0xE6, 0x9F, 0x12, 0xDE, 0xC1, 0xEC, 0x9F, 0x20, 0x80, 0xBD, 0x24, 0x9B, 0x2F, 0x99, 0xC5, 0x74, 0x78, 0x7B, 0x44, 0xE4, 0x11, 0x31, 0x6C, 0x79, 0x2E, 0xB4, 0x77, 0xD7, + 0xD6, 0x4D, 0x17, 0xB0, 0x3B, 0x6E, 0x7C, 0x40, 0x35, 0xFA, 0x3F, 0xF6, 0x24, 0x2C, 0x29, 0x93, 0xD0, 0x8F, 0x56, 0xEC, 0x16, 0x37, 0xE9, 0x12, 0x91, 0x6D, 0xB0, 0xF5, 0xE1, 0x37, 0xF7, 0x78, + 0x01, 0x83, 0xFA, 0xC3, 0x7F, 0x25, 0xCF, 0x28, 0x7A, 0x17, 0xAF, 0x4D, 0x6A, 0xD4, 0x3F, 0xED, 0x0C, 0x58, 0x4E, 0x6E, 0xA2, 0x57, 0x34, 0xEF, 0xF8, 0xB9, 0x7F, 0x8B, 0x27, 0x75, 0xE0, 0x25, + 0xB3, 0xF4, 0xCA, 0x85, 0xF1, 0x11, 0x16, 0xDC, 0x1E, 0x03, 0xAD, 0xCE, 0x40, 0x32, 0x6E, 0x67, 0x97, 0x4B, 0x8A, 0x6F, 0xA5, 0xC1, 0x74, 0x4A, 0xEC, 0xAC, 0xEA, 0x80, 0xD7, 0x41, 0x4D, 0xCB, + 0xF0, 0xD5, 0x8D, 0x1F, 0x4D, 0x96, 0x59, 0xF7, 0x99, 0x62, 0xFC, 0xA5, 0x64, 0xB4, 0x08, 0x42, 0xD2, 0x18, 0x0C, 0x55, 0x8F, 0x67, 0x27, 0x1C, 0x63, 0xA5, 0x8B, 0x59, 0x1D, 0x11, 0x37, 0xFA, + 0x79, 0x08, 0x7C, 0xBF, 0x1D, 0x98, 0x76, 0xF5, 0xA7, 0x36, 0xA8, 0x62, 0x53, 0xE0, 0xDF, 0x58, 0x7F, 0x92, 0x05, 0x4E, 0x43, 0xB5, 0xDC, 0xD4, 0x4C, 0x9F, 0x5A, 0x92, 0x18, 0x57, 0xCE, 0x4C, + 0x4D, 0x55, 0x1F, 0xD2, 0x38, 0x58, 0x03, 0xE6, 0x9A, 0x1F, 0x26, 0x55, 0x4F, 0x10, 0x00, 0xBA, 0x31, 0x2A, 0xB8, 0x65, 0x4C, 0xC3, 0x1A, 0x63, 0xC6, 0xF9, 0x4A, 0xB9, 0x7A, 0xFC, 0xE5, 0x52, + 0x7C, 0x1F, 0x14, 0xB5, 0xEF, 0x34, 0x88, 0xA8, 0xA1, 0x16, 0x1A, 0x93, 0x58, 0xA7, 0x67, 0xFA, 0x49, 0x2F, 0xFC, 0xA7, 0xEC, 0x94, 0x5F, 0x25, 0xAC, 0x4A, 0xCD, 0x0C, 0x0E, 0x27, 0x27, 0xB0, + 0x82, 0x27, 0xFA, 0x7F, 0x84, 0xC3, 0x39, 0x79, 0xE7, 0x1B, 0x79, 0xBE, 0x77, 0xD9, 0x0C, 0x80, 0xE9, 0x56, 0x54, 0x4B, 0x30, 0x38, 0x6B, 0xBE, 0x2A, 0x88, 0xD7, 0x2B, 0x70, 0x57, 0x25, 0xFA, + 0x49, 0xDD, 0xA9, 0xCF, 0x44, 0x9D, 0x82, 0x21, 0xD5, 0xC4, 0x77, 0xE7, 0xB8, 0x2F, 0x96, 0xB1, 0xF5, 0x70, 0xEF, 0xB8, 0x2E, 0x10, 0x4B, 0x7B, 0x4E, 0x90, 0xAF, 0x7B, 0x5E, 0x33, 0xA5, 0x8E, + 0x85, 0xCA, 0x03, 0x32, 0x9B, 0x9B, 0x31, 0x05, 0x02, 0x21, 0x88, 0x74, 0xFA, 0xF0, 0xE4, 0xA2, 0x4F, 0xD7, 0x97, 0x10, 0x4E, 0x6F, 0xDC, 0xC0, 0xCE, 0xF4, 0xC0, 0x50, 0x86, 0xE9, 0x80, 0x26, + 0x6B, 0x50, 0x20, 0x56, 0x35, 0xCD, 0x16, 0xA5, 0xB4, 0xC2, 0x58, 0xA9, 0xC7, 0x33, 0x15, 0x11, 0x93, 0xE4, 0x1C, 0x73, 0xEA, 0xAD, 0xC8, 0x86, 0x41, 0x76, 0x42, 0x73, 0xDF, 0x00, 0xD6, 0x6F, + 0xE3, 0x84, 0x78, 0x3B, 0x95, 0xD5, 0x30, 0xC6, 0x90, 0x0B, 0x4A, 0x93, 0x84, 0x1D, 0x40, 0x54, 0x3E, 0x56, 0x37, 0x40, 0x75, 0x1A, 0xDE, 0x91, 0x63, 0xBA, 0x9A, 0x28, 0xAE, 0x8C, 0x95, 0xCF, + 0x15, 0x65, 0x34, 0xF9, 0x78, 0x1F, 0x35, 0xE7, 0x5F, 0x1C, 0x0E, 0xD8, 0x78, 0x98, 0xC0, 0xB5, 0x9B, 0x82, 0x13, 0x68, 0x86, 0xA2, 0x20, 0xC3, 0x4F, 0xD4, 0xDD, 0xC3, 0x96, 0x7C, 0xEF, 0x7D }, + .msg_len = 891, + .msg = { 0x30, 0xD6, 0x1C, 0x6F, 0xBD, 0x64, 0x11, 0x3F, 0xCE, 0xD8, 0xC5, 0x20, 0x50, 0x26, 0xEB, 0xAC, 0x0D, 0x9F, 0x35, 0x22, 0x18, 0x26, 0x17, 0xCB, 0x00, 0xB6, 0xE7, 0x0C, 0x8D, 0xA6, 0x2E, 0xCC, + 0x1B, 0xBC, 0x8E, 0x1F, 0xDA, 0xF1, 0x7C, 0xC6, 0x1D, 0xD0, 0x1C, 0xE8, 0x5A, 0x90, 0x72, 0xCC, 0x1D, 0x9D, 0x34, 0xFD, 0xAD, 0xBA, 0x5B, 0x93, 0xE0, 0xAA, 0xB4, 0xC9, 0xC4, 0xC9, 0xE2, 0x6D, + 0x3F, 0x7F, 0x14, 0x5F, 0xCB, 0x23, 0x67, 0x3B, 0x6E, 0x0B, 0x37, 0x3C, 0x0F, 0xD1, 0xA5, 0x8F, 0x52, 0x48, 0x6B, 0x72, 0x62, 0x4E, 0xF9, 0x1A, 0x53, 0x95, 0x19, 0xEE, 0x53, 0x05, 0x77, 0x2A, + 0x00, 0x6E, 0x49, 0x52, 0x17, 0x44, 0x91, 0x2B, 0xCF, 0x3C, 0xDB, 0xAD, 0x42, 0x4F, 0x00, 0x42, 0x8A, 0xA9, 0x6C, 0xCC, 0x21, 0xD0, 0x00, 0xEF, 0xB0, 0x9D, 0xA5, 0xCE, 0x65, 0x2E, 0x36, 0x1A, + 0x6F, 0xB6, 0x49, 0xA0, 0x60, 0x83, 0x5E, 0x3B, 0x9D, 0xC9, 0xCB, 0xEC, 0x66, 0x0C, 0x75, 0x31, 0x62, 0x01, 0x15, 0xEC, 0x90, 0x5D, 0xCA, 0x6E, 0xE2, 0xA1, 0xCE, 0x36, 0x55, 0x4C, 0x0F, 0xC1, + 0xD6, 0xDD, 0x68, 0x63, 0xB8, 0xF3, 0x84, 0x35, 0x08, 0xED, 0x5C, 0x21, 0x4B, 0x69, 0x23, 0xE7, 0xF5, 0xC0, 0x30, 0x4E, 0x9B, 0x0D, 0x5E, 0x5E, 0x43, 0x3B, 0xD0, 0x29, 0x11, 0x6A, 0x33, 0xA6, + 0x0C, 0xB9, 0x80, 0x73, 0x7A, 0xC9, 0x50, 0x57, 0x7D, 0x05, 0x94, 0xBF, 0xE0, 0xAD, 0x22, 0x25, 0xCB, 0x8D, 0x3F, 0xA4, 0x2F, 0x19, 0x2B, 0x0E, 0xC0, 0x5A, 0x49, 0x39, 0x16, 0x32, 0xA3, 0x2F, + 0xA9, 0x31, 0xC0, 0xFB, 0xD8, 0x3A, 0x7B, 0x6E, 0xA2, 0x43, 0x01, 0xAD, 0x09, 0x06, 0xE7, 0x91, 0x1F, 0x9D, 0x90, 0x0D, 0x19, 0xAE, 0x12, 0x47, 0xAB, 0xAB, 0xB1, 0xC0, 0xE9, 0xB9, 0xBD, 0x16, + 0x51, 0x85, 0xD9, 0xD7, 0x41, 0x3E, 0xA0, 0x68, 0xFE, 0x88, 0x24, 0xCC, 0xE5, 0xB3, 0xAD, 0x51, 0xFE, 0x8E, 0x2B, 0xB2, 0xC4, 0x02, 0x2C, 0x61, 0xB0, 0x02, 0xC1, 0xDF, 0x48, 0x52, 0xE4, 0x91, + 0x0F, 0x38, 0x61, 0x37, 0x87, 0xCA, 0x12, 0x37, 0x10, 0x38, 0xB6, 0x36, 0x4D, 0x92, 0x0E, 0x07, 0xB4, 0xB4, 0x17, 0x40, 0x12, 0x53, 0x45, 0x1D, 0xDC, 0x25, 0x62, 0x4B, 0x5D, 0x03, 0x8B, 0x2D, + 0xFE, 0x29, 0xB8, 0x49, 0x4E, 0xC9, 0x60, 0xF8, 0x78, 0x03, 0xCA, 0xA2, 0x56, 0xA9, 0x5C, 0x98, 0x68, 0xAF, 0x81, 0x97, 0x47, 0xE4, 0xBF, 0x26, 0xFA, 0xAB, 0xA6, 0xDD, 0xBA, 0xED, 0x93, 0xA7, + 0x81, 0x5C, 0x79, 0x5A, 0xD5, 0xEB, 0x7F, 0xB4, 0x59, 0x2D, 0xF6, 0x78, 0xAC, 0x13, 0x75, 0x38, 0x8C, 0xC7, 0xED, 0x3A, 0x62, 0x30, 0xCB, 0xE8, 0x0A, 0xBB, 0xB1, 0x13, 0xC8, 0x0B, 0x70, 0xC7, + 0x89, 0xCF, 0x0C, 0x66, 0xB9, 0x43, 0xE6, 0x7C, 0xE8, 0x14, 0xF1, 0x2D, 0x3D, 0x83, 0xF3, 0xB9, 0x0A, 0x43, 0x20, 0xFE, 0xB7, 0xFB, 0x81, 0xDC, 0x93, 0xB0, 0x5D, 0x7F, 0xE2, 0xD3, 0x65, 0x84, + 0x39, 0x92, 0x14, 0xD3, 0xD7, 0xC7, 0x1A, 0xEF, 0x32, 0x2A, 0x5D, 0x04, 0xB5, 0x47, 0x07, 0x03, 0xB3, 0x66, 0x0B, 0xF8, 0x6B, 0x0B, 0x17, 0xBA, 0x9F, 0xF2, 0x3E, 0x45, 0xF7, 0xBE, 0xFE, 0xC3, + 0x75, 0x87, 0x86, 0xD2, 0x11, 0x1C, 0x81, 0xBA, 0x4D, 0x81, 0xB8, 0x3F, 0xEE, 0xA3, 0x5A, 0x06, 0x68, 0xE5, 0xEB, 0x36, 0x94, 0x96, 0x3B, 0xB4, 0xDB, 0x3A, 0xCC, 0xE4, 0xFC, 0xBA, 0x6F, 0x3F, + 0x6F, 0xED, 0x96, 0x27, 0x58, 0x0D, 0xD2, 0xD2, 0xDC, 0x10, 0x3E, 0xF7, 0xE5, 0x2B, 0xB9, 0x74, 0x5B, 0xD4, 0x2A, 0x7F, 0xBD, 0xB4, 0x59, 0xB5, 0xC8, 0xAA, 0xEB, 0xA6, 0x76, 0x86, 0xEB, 0x89, + 0x9E, 0x31, 0x77, 0xFA, 0xF0, 0x89, 0x7C, 0x61, 0xB0, 0x08, 0xAC, 0xE3, 0x30, 0x4C, 0x41, 0xB4, 0xC7, 0x9E, 0x2E, 0xF9, 0xC8, 0x65, 0xE9, 0x95, 0x8D, 0x87, 0x16, 0xBD, 0xDB, 0x69, 0x15, 0x4F, + 0xB3, 0x31, 0x87, 0xD9, 0x27, 0xB5, 0x29, 0x6C, 0x15, 0x89, 0xFB, 0x1A, 0xE3, 0xD5, 0x53, 0xF1, 0x16, 0xFF, 0x6C, 0xAE, 0x56, 0x91, 0x0C, 0xE6, 0x71, 0x7C, 0x44, 0x6B, 0x99, 0x47, 0xAB, 0x2A, + 0x98, 0x1A, 0x8F, 0x59, 0x99, 0xC1, 0xC6, 0xE5, 0x17, 0xEB, 0x3F, 0xE5, 0x84, 0xF5, 0xD1, 0x00, 0x59, 0x91, 0x0E, 0x22, 0xF4, 0x0F, 0xBD, 0xDB, 0x70, 0x9C, 0x9F, 0x68, 0x6F, 0x51, 0xAB, 0xF7, + 0xD7, 0x20, 0x6A, 0x8B, 0xAB, 0x4A, 0x34, 0x6B, 0x51, 0x52, 0x3C, 0x36, 0x2D, 0x74, 0x92, 0x38, 0xD7, 0xEF, 0x66, 0x71, 0xA8, 0x9C, 0xD8, 0x6A, 0x85, 0x40, 0x60, 0x4F, 0x13, 0x4D, 0x76, 0x02, + 0x67, 0xE9, 0x1E, 0xB9, 0x2F, 0xC0, 0xFC, 0x27, 0x5C, 0xAB, 0x69, 0xC7, 0x76, 0xEF, 0x81, 0xDB, 0xAD, 0x35, 0x02, 0x7E, 0x53, 0x07, 0xF1, 0xD3, 0x4E, 0xBF, 0x5D, 0x6E, 0x4D, 0xF4, 0x24, 0xD7, + 0x09, 0x66, 0x6A, 0x1E, 0x64, 0x9C, 0x04, 0x4C, 0x49, 0x30, 0x09, 0x8B, 0x2E, 0x6E, 0x37, 0x82, 0xA9, 0x39, 0x76, 0xB5, 0x50, 0x73, 0xC5, 0x04, 0x56, 0x3C, 0x7E, 0x05, 0x2B, 0x68, 0x16, 0xC0, + 0x7F, 0x0F, 0xD5, 0x4A, 0x75, 0x9D, 0x2B, 0xC1, 0x89, 0xFA, 0xC3, 0xFF, 0x54, 0x54, 0x9F, 0xC4, 0xDE, 0x19, 0x2E, 0xFB, 0x58, 0xA9, 0xE3, 0x01, 0x86, 0x3A, 0x77, 0x38, 0x09, 0x67, 0x73, 0x59, + 0x10, 0xF6, 0x3D, 0x35, 0xEF, 0x5F, 0xDB, 0xD8, 0x75, 0x1D, 0xE4, 0xBC, 0x6B, 0xF2, 0xE3, 0x09, 0x56, 0x28, 0xDC, 0x7F, 0x67, 0xC1, 0xF5, 0x57, 0x1D, 0x17, 0xAA, 0x34, 0x25, 0x93, 0xB2, 0xC7, + 0xF9, 0x53, 0xC3, 0xF0, 0xF2, 0x2D, 0xA1, 0x86, 0x21, 0x22, 0x03, 0x1B, 0xBE, 0xAF, 0x0D, 0x00, 0xA0, 0x29, 0xC0, 0x43, 0x30, 0x4E, 0x3E, 0x26, 0x09, 0xC4, 0xFE, 0xD8, 0xA7, 0x40, 0x4F, 0xA1, + 0x0E, 0x2E, 0xC8, 0x46, 0xA7, 0x0E, 0xB0, 0xE3, 0x7C, 0x5B, 0xE6, 0x1E, 0x69, 0x8C, 0xF2, 0x29, 0x6E, 0xC1, 0xFB, 0xE6, 0xFE, 0xD7, 0x5F, 0x6F, 0xE3, 0x11, 0x3C, 0x23, 0xB2, 0x9A, 0xFB, 0x5A, + 0x6D, 0x7E, 0x3A, 0x9E, 0x46, 0xE2, 0xD8, 0x9D, 0x8C, 0x06, 0x45, 0x0C, 0xEA, 0x11, 0x49, 0x2C, 0x1A, 0x97, 0xF7, 0xD6, 0xBE, 0x8F, 0xF6, 0xC0, 0x14, 0x93, 0x00, 0x43, 0x02, 0x2B, 0x26, 0x4F, + 0xD3, 0x25, 0x93, 0x95, 0x2B, 0xC6, 0x06, 0xF7, 0x79, 0x59, 0x86, 0x31, 0xE4, 0x8E, 0xED, 0x86, 0xEC, 0x2A, 0x01, 0x3D, 0x8E, 0xB8, 0x66, 0xF3, 0x11, 0xA4, 0x00 }, + .sig_len = 3366, + .sig = { 0x0D, 0xB4, 0x4B, 0x68, 0x43, 0xD0, 0x4E, 0x00, 0x93, 0x18, 0xE8, 0xAF, 0x4F, 0x82, 0xF1, 0xBE, 0x78, 0x49, 0xC3, 0x99, 0x9E, 0xD9, 0xE6, 0x2B, 0x20, 0x0A, 0xF9, 0xB5, 0x3E, 0xFE, 0xFA, 0x73, + 0x02, 0x53, 0xBE, 0xA9, 0xC6, 0xFF, 0x33, 0x07, 0x97, 0xC2, 0x20, 0xFE, 0x12, 0x4D, 0x4F, 0xCC, 0x54, 0x22, 0x20, 0xAF, 0xDF, 0x4F, 0xF6, 0x7F, 0x77, 0xC4, 0x0E, 0x70, 0xF6, 0xF4, 0x52, 0xFD, + 0xBB, 0x06, 0x90, 0xE1, 0x2A, 0xBF, 0x7C, 0x95, 0xFA, 0x6D, 0xF6, 0x36, 0x02, 0xAD, 0x46, 0xCE, 0x27, 0x4A, 0x7F, 0x70, 0x41, 0x42, 0x6B, 0xD1, 0xDA, 0x1C, 0xBD, 0x07, 0x54, 0x5B, 0x89, 0x9B, + 0x9D, 0x85, 0xB5, 0x75, 0x76, 0x43, 0xC1, 0x47, 0xF8, 0x3F, 0x97, 0x5E, 0x88, 0xB9, 0x20, 0x31, 0x62, 0x3D, 0x70, 0x90, 0x7E, 0x8E, 0xF2, 0x82, 0x7D, 0xF9, 0xDB, 0x42, 0x0F, 0x25, 0xBD, 0x1B, + 0x91, 0x15, 0xBE, 0x55, 0xD8, 0xA7, 0x3A, 0x84, 0x94, 0xB6, 0xB2, 0x95, 0x64, 0x19, 0x45, 0x0A, 0xCA, 0x02, 0x49, 0xAD, 0x26, 0xFC, 0x47, 0xAD, 0x54, 0x0E, 0xFB, 0xB8, 0xE0, 0x5C, 0x62, 0x66, + 0x80, 0xB7, 0x1C, 0xE2, 0xEF, 0x4A, 0x1E, 0x8B, 0x5C, 0x4C, 0x6A, 0x2F, 0xD1, 0x0A, 0xA7, 0x93, 0xCE, 0x72, 0xE8, 0x7B, 0x90, 0x63, 0x80, 0x28, 0xCF, 0xDD, 0x5F, 0x1F, 0x16, 0xD4, 0xB4, 0x4B, + 0xD6, 0x3C, 0xBE, 0x17, 0x8B, 0xBC, 0x0F, 0x6C, 0x93, 0x87, 0xFB, 0x63, 0x05, 0xBE, 0x94, 0xBA, 0x41, 0x8B, 0x11, 0x84, 0x32, 0xEF, 0x91, 0xD6, 0x27, 0x65, 0x48, 0xC0, 0x3A, 0x49, 0x37, 0xCA, + 0x8C, 0xAB, 0xE2, 0xF9, 0xC5, 0x8D, 0xB2, 0x7A, 0x57, 0x91, 0x1E, 0x97, 0x0A, 0x38, 0xFE, 0x67, 0xBE, 0xE4, 0x8A, 0xA8, 0x0E, 0x9F, 0xAE, 0x63, 0x61, 0x2E, 0xFC, 0xCF, 0x3F, 0xBF, 0x26, 0xFE, + 0x59, 0x4F, 0x51, 0x83, 0x4E, 0xA5, 0xE9, 0xF9, 0xDD, 0x6D, 0x00, 0x38, 0x73, 0x02, 0x0E, 0x9D, 0xDD, 0x51, 0x06, 0x42, 0x35, 0xC4, 0x1B, 0xB1, 0x3B, 0xAF, 0x3C, 0x93, 0x39, 0x46, 0x91, 0x95, + 0x36, 0x3C, 0xD9, 0x7E, 0xB5, 0x3E, 0x91, 0x18, 0x57, 0x7A, 0x63, 0xA1, 0x79, 0x65, 0x1C, 0xDA, 0x4B, 0x4E, 0x45, 0xC9, 0x67, 0x8F, 0x14, 0xBA, 0xA4, 0x7A, 0x9D, 0xE3, 0x85, 0x37, 0xF7, 0x69, + 0x5F, 0x8B, 0xA1, 0x73, 0xC1, 0x04, 0xCD, 0xA9, 0x70, 0xFD, 0xE3, 0x57, 0xAF, 0xD3, 0xAC, 0x5F, 0x48, 0x1B, 0xF4, 0xD0, 0x8B, 0x64, 0x5B, 0x66, 0x3F, 0xCE, 0x91, 0x7C, 0x6D, 0x70, 0xAE, 0xBC, + 0x59, 0xF5, 0xCA, 0x6E, 0x99, 0xD9, 0xEF, 0x05, 0x3B, 0x5F, 0x58, 0xF3, 0xCF, 0xE0, 0xE6, 0x7F, 0xF9, 0xE9, 0xC2, 0x59, 0x51, 0x2C, 0xA9, 0x68, 0x13, 0xBB, 0x7C, 0xAE, 0x77, 0x57, 0x27, 0xCC, + 0xB0, 0x40, 0xC7, 0x62, 0x8E, 0x62, 0x53, 0x7C, 0xD3, 0x48, 0x60, 0xC1, 0x8E, 0x08, 0x70, 0xC0, 0xAC, 0x72, 0x36, 0x23, 0xC9, 0x05, 0xDD, 0xDD, 0xC7, 0x66, 0x0F, 0x71, 0xD6, 0xAD, 0x1E, 0x4B, + 0xA7, 0x1F, 0x9E, 0x3C, 0x96, 0x4E, 0x05, 0xCB, 0x83, 0xA9, 0x21, 0x7E, 0xE8, 0x63, 0x63, 0xA4, 0x31, 0x1A, 0x0A, 0x8F, 0x32, 0xC1, 0x2D, 0x29, 0x14, 0xDD, 0x36, 0x22, 0x98, 0xCB, 0x81, 0x48, + 0xAC, 0x05, 0xC5, 0x20, 0x34, 0x46, 0x68, 0x8C, 0x0D, 0x0F, 0xCC, 0x3E, 0xA9, 0x48, 0x94, 0x0D, 0x7D, 0x88, 0xE8, 0x15, 0xE9, 0x29, 0x23, 0xFC, 0xE8, 0xFE, 0x7B, 0x94, 0x0A, 0x3E, 0x84, 0xF3, + 0x79, 0xE0, 0xF3, 0x39, 0xAD, 0x03, 0x17, 0x73, 0x11, 0x96, 0x42, 0x6A, 0x78, 0x73, 0xEB, 0xF8, 0xE9, 0x9B, 0xBA, 0x9C, 0x90, 0xD9, 0x1A, 0x23, 0x36, 0x1B, 0xDB, 0x62, 0xB1, 0x56, 0xD5, 0xD5, + 0x81, 0xC7, 0xBE, 0x81, 0xC4, 0x23, 0x12, 0x8B, 0x49, 0xAC, 0x44, 0xD0, 0xB4, 0x52, 0x5E, 0x2D, 0xEF, 0xCB, 0xF6, 0x15, 0x06, 0x9F, 0x82, 0xD0, 0x7D, 0xA8, 0xBE, 0x56, 0x5C, 0x45, 0x06, 0x00, + 0x13, 0x1C, 0x76, 0x76, 0x6A, 0x5D, 0x1D, 0xF2, 0x47, 0x9D, 0x48, 0xBC, 0x5D, 0x3C, 0xC8, 0x58, 0x29, 0xF3, 0xDD, 0xF2, 0xC5, 0xCC, 0x0C, 0x05, 0xD5, 0xD9, 0xED, 0x33, 0x49, 0x9F, 0x1D, 0x86, + 0xEF, 0x3C, 0xCD, 0x1B, 0x2B, 0x3F, 0x81, 0xEA, 0x96, 0x5A, 0xBA, 0xD4, 0x5F, 0x6D, 0x25, 0xC0, 0x1B, 0xB5, 0x2A, 0xE4, 0x28, 0x32, 0x27, 0xA1, 0x44, 0xCA, 0x42, 0x09, 0xEF, 0xDE, 0xD6, 0x8D, + 0x8A, 0x7F, 0x09, 0xF9, 0xCD, 0xF2, 0x11, 0x57, 0x13, 0x3C, 0x6A, 0xCF, 0xF2, 0xC0, 0xC2, 0x84, 0xE0, 0x1C, 0x93, 0x22, 0xE5, 0x9D, 0x86, 0x1F, 0x97, 0xA9, 0x5B, 0xE4, 0x11, 0xD7, 0x06, 0x36, + 0xDD, 0x48, 0xA3, 0xDA, 0x10, 0x46, 0x81, 0x5E, 0x51, 0x01, 0x0B, 0x30, 0x3D, 0xA1, 0xEF, 0xB5, 0x3B, 0xDB, 0x82, 0xB9, 0x28, 0x88, 0x6C, 0x21, 0x7B, 0xDC, 0x26, 0x5A, 0x18, 0x28, 0x06, 0x27, + 0x88, 0xC1, 0xD8, 0xB7, 0x26, 0x35, 0xD1, 0x04, 0xAE, 0x9F, 0xE2, 0x18, 0x68, 0x1A, 0x10, 0xB9, 0x06, 0x80, 0x36, 0xBC, 0xB7, 0xFC, 0x02, 0xC2, 0x11, 0x70, 0x65, 0x79, 0x12, 0x94, 0xB1, 0xD5, + 0x16, 0x2C, 0x5C, 0x37, 0x36, 0xCB, 0x19, 0xB7, 0xAB, 0x4E, 0x92, 0xD8, 0x05, 0x50, 0xB2, 0x23, 0x41, 0x45, 0x0A, 0x1D, 0x90, 0x10, 0xE6, 0xD7, 0xE4, 0x07, 0x0F, 0x56, 0x37, 0x92, 0xC3, 0x20, + 0xE7, 0xAF, 0x12, 0xF1, 0x1F, 0x54, 0x5E, 0x04, 0x8B, 0xB5, 0x42, 0x72, 0x74, 0x3C, 0x06, 0x0C, 0x81, 0x35, 0x5B, 0xFB, 0x80, 0x26, 0x1E, 0x05, 0xE8, 0x55, 0xE8, 0x90, 0x41, 0x9D, 0x39, 0x09, + 0x8A, 0x04, 0xAD, 0x29, 0x8C, 0x0F, 0xF9, 0x7E, 0x0F, 0xB8, 0x0F, 0xF8, 0x03, 0x8C, 0x7B, 0x36, 0x27, 0x40, 0xC9, 0x5A, 0x48, 0xB2, 0x97, 0xBD, 0x84, 0x2C, 0xB2, 0x7A, 0x89, 0x0E, 0xAA, 0x7E, + 0x83, 0x4B, 0xF4, 0xAC, 0x9D, 0x85, 0x72, 0x12, 0x36, 0x66, 0xF1, 0x49, 0x4B, 0xD0, 0x99, 0x8D, 0x94, 0xA1, 0x95, 0x44, 0xDD, 0x94, 0xF0, 0xF5, 0x19, 0xB3, 0xC2, 0x6E, 0x43, 0x97, 0x28, 0xB3, + 0x8B, 0xDF, 0xE2, 0x70, 0xBE, 0x33, 0x1F, 0xCC, 0x77, 0xCB, 0x4D, 0x96, 0x36, 0xD3, 0xBC, 0xE1, 0x53, 0x12, 0x83, 0x59, 0x10, 0x75, 0x08, 0x8E, 0xAB, 0x12, 0xFB, 0x43, 0xB7, 0xB3, 0x1B, 0xB3, + 0x94, 0xFA, 0xD2, 0x7F, 0x98, 0xDF, 0x2B, 0x0E, 0x49, 0x64, 0x4E, 0xD4, 0xD3, 0xC8, 0xDE, 0xB1, 0x52, 0x8E, 0x64, 0x8A, 0x8B, 0x7F, 0x8D, 0x0B, 0x77, 0x42, 0x79, 0xB7, 0x93, 0x48, 0x49, 0xE9, + 0xA5, 0x29, 0x65, 0x67, 0x5E, 0x90, 0x1C, 0x06, 0x3F, 0x42, 0x86, 0xAD, 0x4B, 0x55, 0x73, 0xC2, 0x50, 0xC3, 0x6A, 0xC2, 0xE7, 0x1F, 0x38, 0x51, 0x21, 0xF5, 0xE5, 0x44, 0x9D, 0x09, 0x30, 0xF1, + 0xFB, 0xD6, 0x20, 0x6D, 0x9C, 0x75, 0x42, 0xA2, 0x1D, 0x69, 0x98, 0x5D, 0x41, 0xD3, 0x7F, 0x8B, 0xFE, 0x71, 0xC9, 0x05, 0xD9, 0x30, 0xF8, 0x4B, 0xFD, 0xB2, 0xA6, 0xA2, 0xBD, 0x27, 0x9B, 0x22, + 0xD9, 0x66, 0x88, 0x28, 0x62, 0x15, 0xD4, 0x0F, 0xC8, 0x5A, 0x26, 0x20, 0xA8, 0x2D, 0x9E, 0x7C, 0x5E, 0xD0, 0x10, 0x45, 0x43, 0xA7, 0x7F, 0x15, 0x13, 0x48, 0x9A, 0x09, 0x08, 0x93, 0xEC, 0xAA, + 0x35, 0xC4, 0xF9, 0x89, 0x60, 0xF6, 0x1E, 0xA7, 0xFD, 0x43, 0xAA, 0x0F, 0x00, 0x2C, 0xD7, 0x97, 0x5E, 0xF2, 0x43, 0xBB, 0x43, 0xB4, 0x82, 0xA0, 0xC0, 0x52, 0x44, 0xB6, 0x2F, 0x5C, 0x5B, 0x96, + 0x3D, 0xD0, 0x07, 0xD0, 0x51, 0xBF, 0xC3, 0x51, 0x99, 0x50, 0xDE, 0x33, 0x7B, 0xCB, 0xAA, 0x6F, 0x26, 0x84, 0x3B, 0x68, 0x27, 0xD8, 0x3B, 0x17, 0xA8, 0xE4, 0x34, 0x53, 0x61, 0x1E, 0xE6, 0x1E, + 0x17, 0x89, 0x55, 0x76, 0x8B, 0x34, 0x14, 0xFF, 0xA2, 0xC3, 0xF4, 0x1F, 0x00, 0x8C, 0x9F, 0xE7, 0x18, 0x80, 0xAF, 0x4A, 0x3E, 0x27, 0xA6, 0x3C, 0xD5, 0xD6, 0xE9, 0x56, 0x25, 0xB4, 0xFC, 0x0E, + 0x60, 0xF5, 0x9C, 0x8D, 0xEC, 0x16, 0xE9, 0x74, 0xB9, 0xEC, 0x5F, 0x8A, 0x34, 0x58, 0xB1, 0x31, 0xAB, 0xE7, 0xBC, 0xC4, 0x5A, 0xCC, 0x68, 0x9D, 0xC8, 0xCC, 0xE1, 0x4C, 0x56, 0x62, 0xF3, 0xA3, + 0x89, 0x43, 0x29, 0x80, 0xB2, 0x2A, 0xBC, 0x19, 0x1E, 0x9C, 0x87, 0x13, 0x85, 0x81, 0x16, 0x20, 0xE0, 0xD5, 0x17, 0x7F, 0xFA, 0x44, 0x83, 0x84, 0x04, 0x27, 0x7A, 0xC7, 0x7C, 0x81, 0x00, 0x06, + 0xDC, 0xC1, 0x8C, 0x71, 0x05, 0x2D, 0xE3, 0xE0, 0x93, 0xD3, 0xF6, 0x9D, 0x82, 0x0A, 0x70, 0x85, 0x75, 0xA6, 0xC9, 0xB2, 0x31, 0x25, 0x31, 0x10, 0x53, 0xAA, 0x2D, 0x37, 0x8D, 0x2E, 0x20, 0x18, + 0xAE, 0xF1, 0xA6, 0x15, 0x7F, 0x8C, 0x53, 0x01, 0xD1, 0x12, 0x1F, 0x4A, 0x9D, 0xDC, 0x87, 0x52, 0x69, 0xAA, 0x49, 0x41, 0x83, 0x41, 0x69, 0xB7, 0x7F, 0xB7, 0xE3, 0xA7, 0x60, 0x29, 0xA7, 0xBB, + 0xE5, 0x3F, 0xF2, 0x8A, 0x7D, 0xC4, 0x1D, 0x9A, 0xEA, 0x7B, 0x2A, 0xC8, 0x88, 0x79, 0xFD, 0x0D, 0x7F, 0x8C, 0xFE, 0x12, 0xF8, 0xBC, 0x75, 0xC5, 0xE5, 0x24, 0x33, 0xC4, 0xC9, 0xBA, 0x77, 0x3F, + 0xDC, 0xD7, 0x65, 0xC9, 0x25, 0x71, 0x49, 0xB1, 0xF2, 0x2C, 0x4C, 0x4A, 0x46, 0xC1, 0xFC, 0xFE, 0xC1, 0xCE, 0xAF, 0x96, 0xE2, 0xE8, 0x50, 0x7F, 0x1B, 0x84, 0x6A, 0x11, 0x62, 0x67, 0xEF, 0x79, + 0xC4, 0xAC, 0x0C, 0xF3, 0x15, 0x45, 0x00, 0x2F, 0xE0, 0x5B, 0xC1, 0x79, 0x51, 0xEA, 0xC6, 0xA6, 0xC8, 0x69, 0x55, 0xB3, 0xC1, 0x20, 0x60, 0xD4, 0x69, 0x9F, 0xE3, 0xD0, 0x57, 0xB0, 0x1E, 0x93, + 0x7E, 0x39, 0xC2, 0x40, 0xE6, 0x80, 0x56, 0xBA, 0xC0, 0x25, 0x82, 0x9B, 0xA7, 0xF8, 0xC3, 0x14, 0x07, 0x36, 0xD6, 0xD0, 0x23, 0x18, 0xE7, 0xB8, 0x91, 0x7C, 0xD5, 0xBB, 0xD4, 0xA1, 0x53, 0x54, + 0x02, 0xEF, 0x37, 0xE7, 0xCF, 0x0F, 0x22, 0x08, 0x56, 0x82, 0x6A, 0x4D, 0x28, 0xDC, 0xE3, 0x7D, 0x17, 0x98, 0xAC, 0xB0, 0xC0, 0xCB, 0x86, 0x80, 0x69, 0x7D, 0xB9, 0x4C, 0xE2, 0x69, 0x75, 0x94, + 0x25, 0x46, 0xA3, 0x6A, 0xD2, 0x5F, 0xDD, 0xF4, 0x26, 0x45, 0x00, 0x87, 0x0E, 0x35, 0xC6, 0x79, 0x3A, 0xF0, 0xEC, 0xE2, 0xDA, 0xC9, 0xFA, 0xBE, 0x54, 0x94, 0x4B, 0x15, 0x44, 0x1C, 0x52, 0xC8, + 0x6C, 0xE3, 0x14, 0x47, 0x9B, 0x38, 0xD3, 0x8A, 0xCF, 0xC7, 0xE1, 0xFA, 0x17, 0x0D, 0x48, 0xF4, 0x4E, 0xDE, 0xB6, 0xDE, 0x44, 0xA8, 0x07, 0x55, 0x1D, 0xDD, 0x49, 0xAD, 0x57, 0x05, 0x46, 0x2F, + 0xF5, 0xC0, 0x7B, 0xC6, 0x73, 0xBB, 0xFF, 0x51, 0xBD, 0x1F, 0x25, 0xC2, 0x60, 0x77, 0x93, 0xAB, 0x9B, 0x40, 0x2D, 0x7F, 0x34, 0xC4, 0xF9, 0xF7, 0x93, 0xCB, 0x68, 0x73, 0x2B, 0x31, 0x90, 0x1C, + 0xDE, 0x90, 0x32, 0x63, 0xED, 0x30, 0xDF, 0xAF, 0xB1, 0x07, 0x52, 0x39, 0x4E, 0x40, 0xA4, 0xA2, 0x70, 0x04, 0x32, 0x07, 0xC0, 0xB4, 0x8E, 0x57, 0xEC, 0x50, 0x8C, 0x6C, 0xD6, 0x86, 0x06, 0x9F, + 0x01, 0xDC, 0x56, 0x7B, 0x78, 0xE1, 0xFA, 0xEC, 0x19, 0x9E, 0x2A, 0x34, 0x6C, 0x79, 0xA6, 0xA0, 0x9D, 0xEA, 0xF7, 0xD0, 0x37, 0xC0, 0x8B, 0x96, 0x46, 0x4D, 0x3E, 0x18, 0xAF, 0xD8, 0x87, 0x3A, + 0x0E, 0x64, 0x8F, 0x36, 0xA4, 0xB3, 0x42, 0x19, 0x4C, 0x40, 0x3D, 0xA2, 0xB8, 0x5D, 0xD7, 0x60, 0xB3, 0x44, 0x71, 0xD9, 0x98, 0x83, 0x16, 0xED, 0xCA, 0xB4, 0x22, 0xDF, 0xAB, 0x61, 0xCF, 0x0A, + 0x59, 0x88, 0x4C, 0x0B, 0x42, 0xAC, 0x60, 0x32, 0x84, 0x68, 0x97, 0xB7, 0x99, 0x81, 0xDA, 0x9D, 0xBA, 0xA5, 0xF5, 0x6B, 0x68, 0x05, 0xC6, 0x8D, 0xC4, 0x01, 0x4E, 0xDC, 0xAB, 0xEC, 0x91, 0x17, + 0x3F, 0xD7, 0xDC, 0xAE, 0x91, 0x72, 0x6A, 0x87, 0x0D, 0xE5, 0xD3, 0xC8, 0xF4, 0x6F, 0x2B, 0x04, 0x63, 0xAA, 0x16, 0xDF, 0xFF, 0x34, 0xB6, 0xA7, 0xD2, 0xB7, 0x00, 0xD1, 0x99, 0xB5, 0xC9, 0xAA, + 0xA3, 0xFE, 0x92, 0xA5, 0x6A, 0x7B, 0x30, 0x9B, 0xF8, 0xC0, 0x37, 0x44, 0xF6, 0xCE, 0x4C, 0xEE, 0x31, 0x3A, 0x90, 0x05, 0xA4, 0xAD, 0x3D, 0xC3, 0x9B, 0x62, 0x79, 0x49, 0x10, 0x2B, 0x16, 0xB1, + 0xA2, 0x0B, 0x83, 0xFB, 0x0B, 0x54, 0x9B, 0xE2, 0x00, 0x2A, 0xCC, 0x24, 0x12, 0x90, 0x3E, 0xC8, 0x09, 0xCD, 0x45, 0xAD, 0xE8, 0x3B, 0xF7, 0xC3, 0x48, 0x6E, 0x77, 0xC0, 0x38, 0x1A, 0xAC, 0xDA, + 0xC0, 0xAD, 0x9F, 0x95, 0x51, 0x9F, 0x1B, 0xB2, 0x89, 0x60, 0x57, 0x49, 0x4E, 0xA2, 0x40, 0xCF, 0xDB, 0xC6, 0x5F, 0xD5, 0xA7, 0xAC, 0x7B, 0x25, 0xB3, 0x7C, 0x71, 0xDB, 0x89, 0x69, 0xCF, 0x9E, + 0xBC, 0xDB, 0xBE, 0x61, 0x2D, 0x9C, 0xCA, 0x0F, 0x30, 0x72, 0x83, 0xB3, 0xAF, 0x49, 0x56, 0x71, 0xF8, 0x96, 0x4E, 0xF2, 0x25, 0xBC, 0x48, 0xAF, 0xCE, 0x7A, 0x38, 0x19, 0x1A, 0x42, 0x89, 0x81, + 0xCC, 0x9E, 0x18, 0x71, 0x37, 0xDB, 0x26, 0xE5, 0xF7, 0x2F, 0x5D, 0x42, 0xD9, 0x01, 0x9F, 0x64, 0xEB, 0x25, 0x3C, 0xAA, 0xA2, 0x57, 0x1B, 0x52, 0x9A, 0x3E, 0x01, 0xEF, 0xF5, 0x9F, 0x84, 0x1F, + 0x5A, 0x2B, 0x52, 0xB6, 0x47, 0x28, 0xB3, 0x25, 0xD2, 0x29, 0x3C, 0x74, 0xDA, 0x57, 0x44, 0xD4, 0xCB, 0x74, 0x3B, 0xE8, 0xEE, 0x10, 0xBC, 0x45, 0x5D, 0x09, 0x11, 0x67, 0x3A, 0x75, 0x77, 0xDE, + 0x4B, 0xF8, 0xF1, 0x35, 0xA2, 0x54, 0x4C, 0xED, 0x54, 0x11, 0x84, 0xC3, 0xE0, 0xF3, 0xB5, 0x0F, 0xAD, 0x8B, 0x4B, 0x35, 0xD5, 0x56, 0x3C, 0xDF, 0x14, 0x54, 0x69, 0x43, 0xDE, 0x10, 0x27, 0xA8, + 0xAF, 0xE0, 0x6E, 0xF9, 0xA9, 0xB8, 0x7E, 0x5D, 0xEB, 0x05, 0xED, 0x8C, 0xC9, 0x85, 0x98, 0xBC, 0x29, 0x60, 0x79, 0x02, 0xB8, 0x53, 0x1C, 0xBD, 0xED, 0x7A, 0x1E, 0x1D, 0x46, 0x33, 0xBD, 0x72, + 0xD3, 0x44, 0x53, 0xC2, 0x08, 0xE6, 0x05, 0xE6, 0x7C, 0x01, 0xB6, 0xA7, 0x1D, 0x98, 0x79, 0xCD, 0x83, 0x87, 0x03, 0xC2, 0x17, 0x74, 0x31, 0x58, 0xFF, 0x5F, 0x3E, 0x6A, 0xA2, 0x6D, 0xFD, 0x33, + 0x7C, 0x8F, 0xC5, 0x8C, 0xBB, 0xB3, 0xFE, 0x18, 0xB7, 0x0B, 0xFA, 0x1B, 0x6D, 0x71, 0x81, 0xBB, 0x8B, 0xD0, 0xAD, 0x15, 0x95, 0x44, 0x66, 0x59, 0x6D, 0x9D, 0x90, 0x8C, 0x08, 0x88, 0xB4, 0xA1, + 0xB9, 0x7F, 0x18, 0x56, 0x58, 0xC9, 0x6C, 0x64, 0x71, 0xAA, 0x28, 0x4C, 0xCE, 0x53, 0xB0, 0x8F, 0xBE, 0xBB, 0x65, 0xF5, 0xD4, 0xB3, 0x66, 0xEC, 0x5D, 0x4F, 0x72, 0x8C, 0xE2, 0x6F, 0xD8, 0xD8, + 0x21, 0xDF, 0x4F, 0x6C, 0xEB, 0x53, 0x58, 0x85, 0x1D, 0x04, 0xC4, 0x23, 0x97, 0x4E, 0x8A, 0x91, 0xA4, 0x3F, 0xB2, 0xFF, 0xCF, 0xBA, 0xF9, 0xF4, 0x7D, 0x6B, 0xE9, 0xF5, 0x7B, 0xAC, 0xF4, 0xBB, + 0x82, 0x17, 0x5F, 0x56, 0x07, 0x62, 0x61, 0x4A, 0x7F, 0x45, 0xF5, 0x55, 0x9A, 0x1E, 0xA6, 0x2D, 0x44, 0x46, 0x48, 0xC6, 0x24, 0x44, 0xF2, 0x9B, 0x84, 0x65, 0x10, 0x87, 0x0D, 0xED, 0x51, 0x71, + 0x63, 0x10, 0x9C, 0xDE, 0x6A, 0x3D, 0xC6, 0x93, 0xE9, 0x7A, 0x55, 0x8C, 0x43, 0x22, 0xDD, 0x2D, 0x6C, 0x44, 0x32, 0x34, 0x6B, 0xFE, 0xA1, 0x73, 0x44, 0x28, 0xCA, 0x12, 0x26, 0xFF, 0xBB, 0x96, + 0xA3, 0xDC, 0xCC, 0x87, 0xB1, 0xB9, 0x3D, 0x7A, 0x53, 0x1B, 0x4E, 0xCF, 0x7E, 0x00, 0xC2, 0xF4, 0xB1, 0x31, 0xC2, 0xFB, 0x82, 0x2F, 0x2B, 0xBC, 0x58, 0x5E, 0x04, 0xCC, 0x3F, 0x39, 0x1D, 0x5A, + 0x37, 0x24, 0x86, 0x8E, 0x1C, 0xE7, 0x8F, 0x2B, 0x16, 0xF4, 0xD7, 0xDF, 0x1E, 0x84, 0x4E, 0x89, 0xF9, 0xF9, 0xD4, 0x72, 0xDA, 0x7F, 0xF8, 0xA6, 0x1B, 0x8F, 0x7E, 0xD8, 0xF6, 0xA6, 0xB7, 0x73, + 0x94, 0x52, 0x89, 0xF8, 0x1D, 0xAE, 0x0F, 0x92, 0x9E, 0xCC, 0x07, 0x99, 0x9C, 0xF0, 0x46, 0x9E, 0x33, 0xAE, 0xC1, 0xF4, 0x65, 0xDE, 0x06, 0xCB, 0xB0, 0x9A, 0x8D, 0xC6, 0x47, 0xE9, 0x05, 0xEB, + 0x4C, 0x91, 0x11, 0xF7, 0xE2, 0x0B, 0x35, 0x57, 0xF7, 0x8B, 0x51, 0x98, 0xA6, 0xCE, 0x59, 0x81, 0x85, 0x5D, 0xCA, 0x7F, 0x28, 0x48, 0xBA, 0x49, 0x42, 0xFB, 0x09, 0x93, 0x4A, 0x25, 0x4C, 0x93, + 0x03, 0x82, 0x5A, 0x72, 0xE0, 0xA5, 0x88, 0x3F, 0x1D, 0x9C, 0x12, 0xB6, 0x71, 0x11, 0x53, 0xA2, 0x56, 0x11, 0xC3, 0x43, 0x6A, 0xDA, 0x1B, 0xAD, 0x46, 0x10, 0xC0, 0xBB, 0x49, 0xCA, 0x1F, 0x68, + 0x19, 0xF8, 0x6C, 0xBC, 0x28, 0x41, 0xC5, 0x37, 0x53, 0xCC, 0x5B, 0xC7, 0x33, 0x1E, 0xF1, 0x16, 0x24, 0x0F, 0x8C, 0xEA, 0xE8, 0xA1, 0x46, 0x59, 0x84, 0x8A, 0x32, 0x60, 0x6F, 0x30, 0x08, 0x85, + 0xA2, 0x12, 0x4E, 0x5C, 0x07, 0xD4, 0xFB, 0x83, 0x6F, 0x00, 0xA6, 0x36, 0x94, 0x99, 0x73, 0xF4, 0x94, 0x5F, 0x87, 0x75, 0xAE, 0x4C, 0x58, 0x45, 0x67, 0x38, 0xA1, 0x4B, 0x62, 0x81, 0xAA, 0xC7, + 0x3B, 0xFF, 0x82, 0x27, 0x05, 0xF9, 0xBA, 0xCF, 0xFA, 0xE6, 0x0D, 0xA1, 0x68, 0xAB, 0x93, 0xCA, 0x60, 0xFE, 0xE9, 0x8F, 0x12, 0xCA, 0x27, 0xE1, 0x1E, 0x72, 0x0A, 0x0D, 0x15, 0x70, 0x07, 0x48, + 0x26, 0xA0, 0x1F, 0x3E, 0x6C, 0xA5, 0x97, 0xB5, 0xC3, 0xD5, 0x88, 0xA9, 0x11, 0xE2, 0x37, 0x47, 0xAB, 0x10, 0x95, 0x56, 0xB5, 0x97, 0x24, 0xF6, 0x96, 0x07, 0x2A, 0xD3, 0x91, 0x8A, 0x75, 0x18, + 0xC7, 0x3D, 0x04, 0xA7, 0x99, 0x62, 0x50, 0x37, 0x02, 0xEB, 0x0F, 0x29, 0xFD, 0xD6, 0x39, 0x49, 0xC0, 0x16, 0xE9, 0x2E, 0x52, 0x10, 0x61, 0x62, 0x86, 0x4C, 0x47, 0x7A, 0xA1, 0x05, 0x6B, 0x29, + 0x57, 0x6C, 0xBA, 0xE1, 0xC2, 0x5B, 0xB3, 0x0D, 0x00, 0xB3, 0x11, 0xED, 0x07, 0x09, 0xA5, 0x12, 0x25, 0x62, 0xFB, 0xA3, 0xF5, 0x0D, 0xC5, 0x8D, 0xCF, 0xB9, 0xA9, 0x6F, 0x4B, 0x52, 0x58, 0x21, + 0xB1, 0x16, 0xC7, 0xF9, 0x83, 0x2C, 0x7C, 0xF0, 0xF4, 0x21, 0x28, 0xAD, 0xF4, 0x08, 0xDC, 0x8C, 0x1F, 0xFE, 0x0A, 0x3D, 0x40, 0x8D, 0x63, 0x44, 0xC0, 0xAB, 0xA5, 0x22, 0x3E, 0x39, 0xBE, 0x98, + 0xEE, 0xF7, 0xF5, 0xC9, 0x40, 0x36, 0x82, 0xCE, 0x72, 0x5F, 0x3F, 0x03, 0x25, 0xA2, 0x53, 0xAB, 0xB4, 0x41, 0x22, 0xFF, 0x20, 0x10, 0x7F, 0xCB, 0x4B, 0xC3, 0x3A, 0xC4, 0x64, 0xE8, 0x18, 0x33, + 0xC8, 0x0D, 0x6E, 0xD4, 0x25, 0xAB, 0xD3, 0x7C, 0xE7, 0xAC, 0xD4, 0xD9, 0x1F, 0x50, 0x69, 0xEC, 0x23, 0xF1, 0xB5, 0xA8, 0xA1, 0x2D, 0x19, 0x99, 0xB2, 0x9D, 0x03, 0x14, 0x04, 0xDF, 0xB3, 0xF2, + 0x9D, 0xF6, 0xFC, 0xEF, 0x9E, 0x08, 0x85, 0x35, 0xE2, 0x0A, 0xE0, 0xA3, 0x53, 0x6D, 0x4E, 0x12, 0x01, 0x2F, 0x42, 0x5B, 0xBB, 0xDB, 0x38, 0xC9, 0x39, 0xAF, 0x1E, 0x67, 0x81, 0x19, 0x5D, 0x0E, + 0x40, 0x52, 0x87, 0x8A, 0x32, 0xF9, 0x9B, 0xD7, 0xDE, 0xC4, 0xEB, 0x2F, 0x31, 0x31, 0xA2, 0x5C, 0x37, 0x75, 0xEA, 0x17, 0x02, 0x70, 0xBA, 0x9F, 0x78, 0x4A, 0x5E, 0xA1, 0xC6, 0x2E, 0x5C, 0xF9, + 0xE0, 0xBE, 0x29, 0xF1, 0x40, 0x1E, 0x73, 0x19, 0x48, 0x52, 0x44, 0xA2, 0xDF, 0x49, 0x76, 0xA9, 0x63, 0xFC, 0x46, 0x83, 0x42, 0x6F, 0x88, 0xE4, 0x14, 0x9B, 0xF6, 0xC5, 0x30, 0xAD, 0xD8, 0x86, + 0x36, 0x86, 0x91, 0x26, 0x44, 0x26, 0x48, 0xB3, 0xEC, 0x97, 0x34, 0xEF, 0xF0, 0x7A, 0x62, 0xD8, 0xDA, 0x22, 0x8E, 0x29, 0xA5, 0x39, 0x10, 0xD2, 0xDA, 0x65, 0xE8, 0x4B, 0xB4, 0x5C, 0x97, 0x23, + 0x6E, 0x2A, 0x2E, 0x28, 0xBA, 0xC5, 0x76, 0xE0, 0xC9, 0xA6, 0x6F, 0xD7, 0x08, 0x0A, 0xF5, 0x32, 0x90, 0xE8, 0xC4, 0x74, 0xA8, 0xCA, 0x85, 0x14, 0x2B, 0xCE, 0x5C, 0x45, 0x08, 0xE3, 0x4E, 0x92, + 0xEF, 0x0C, 0x23, 0xCC, 0xB6, 0x62, 0x3E, 0x0C, 0xA9, 0xE0, 0xF3, 0xC2, 0xAF, 0xD6, 0x6E, 0x95, 0x76, 0x36, 0x2E, 0x2A, 0x44, 0xDA, 0x14, 0x01, 0xAA, 0x37, 0x41, 0xD9, 0xDD, 0x62, 0x68, 0x6F, + 0xEF, 0xF3, 0x8C, 0x39, 0x8C, 0x67, 0xE3, 0x20, 0xDC, 0xEE, 0xD6, 0xF1, 0x51, 0xD2, 0x4E, 0x4E, 0x94, 0x08, 0x9E, 0xE3, 0x28, 0x9F, 0x3F, 0xAC, 0x37, 0x07, 0x85, 0x5B, 0xFE, 0x67, 0xB7, 0x54, + 0x0B, 0x19, 0x02, 0x83, 0x85, 0x4B, 0xA1, 0xBF, 0x67, 0x25, 0x76, 0xA1, 0xF7, 0x07, 0x32, 0xAE, 0x05, 0x35, 0xEB, 0xAC, 0x10, 0xE3, 0xC2, 0xC2, 0x64, 0x30, 0x0F, 0xDB, 0x63, 0x86, 0x8E, 0x85, + 0x7A, 0xE8, 0xC4, 0x07, 0x08, 0x2B, 0x8B, 0xB6, 0x67, 0x3A, 0x5C, 0xB3, 0x88, 0x07, 0x23, 0x5C, 0x64, 0x88, 0x0F, 0xC6, 0xE5, 0xD5, 0x35, 0x80, 0xDF, 0x29, 0xAD, 0x33, 0xA0, 0x36, 0x3A, 0x14, + 0xF2, 0x85, 0xA6, 0x43, 0xE3, 0x7E, 0xDB, 0x63, 0xC9, 0x93, 0x0D, 0xA4, 0xC6, 0xBA, 0x88, 0x3E, 0x06, 0x76, 0x70, 0x37, 0xFC, 0x84, 0x68, 0xD9, 0xE5, 0xEA, 0x26, 0xC8, 0xA6, 0x8B, 0x58, 0x0D, + 0x80, 0x6D, 0xC8, 0x90, 0xB1, 0x82, 0xA4, 0x92, 0x22, 0xD4, 0x8E, 0xEF, 0x8D, 0xC6, 0x31, 0x61, 0x4A, 0xFC, 0x00, 0x91, 0xF4, 0xA2, 0x00, 0xD1, 0xEF, 0xCB, 0xFB, 0xA2, 0x7F, 0x8D, 0x92, 0x2A, + 0x8A, 0x6B, 0xEA, 0x1A, 0xD9, 0x7C, 0xA6, 0x24, 0xFD, 0x75, 0xA4, 0xF0, 0x7E, 0x7A, 0xC5, 0xC4, 0x69, 0x7B, 0xDA, 0xD3, 0x41, 0x75, 0xBA, 0x37, 0x8D, 0xB1, 0xF7, 0x89, 0x1D, 0x15, 0x94, 0xA7, + 0xAB, 0x6A, 0x6A, 0x3E, 0x1C, 0x4B, 0x93, 0x45, 0x0B, 0x57, 0xE0, 0x43, 0x6A, 0x8C, 0x31, 0x9E, 0x6C, 0xFF, 0xB5, 0x37, 0x83, 0xF9, 0xB7, 0x72, 0x8D, 0x09, 0xE2, 0xC5, 0xF6, 0xCA, 0xC2, 0xA1, + 0xAC, 0xAF, 0xE3, 0xDE, 0xA1, 0xB6, 0x58, 0x9F, 0xA1, 0xB4, 0xC4, 0x4C, 0xCD, 0x16, 0xB3, 0x5A, 0x1E, 0xDF, 0xFC, 0x68, 0x92, 0x45, 0xE2, 0xE1, 0x3D, 0x43, 0xDD, 0x33, 0xC6, 0xCD, 0x6E, 0x96, + 0xB1, 0x79, 0xD1, 0x42, 0x87, 0x2D, 0xED, 0x9E, 0x60, 0x3F, 0xC4, 0xE9, 0xE9, 0x09, 0x21, 0xFB, 0xA1, 0x29, 0x8B, 0x1F, 0xB8, 0x72, 0x0A, 0x59, 0x6D, 0x78, 0x74, 0x94, 0xC4, 0x92, 0xB8, 0xDA, + 0x51, 0xB1, 0xD2, 0x99, 0x45, 0x2A, 0x47, 0x4B, 0x09, 0x48, 0x05, 0x88, 0x09, 0x03, 0xBF, 0x00, 0x3C, 0x51, 0x49, 0x53, 0x09, 0xD3, 0xD4, 0xEE, 0xC1, 0xC5, 0x49, 0xA0, 0xF9, 0x80, 0xDD, 0xE3, + 0x28, 0xDD, 0x6E, 0xBB, 0xD2, 0x7E, 0xC9, 0x93, 0xA1, 0x87, 0x4F, 0xDA, 0xD0, 0xC0, 0x5A, 0x07, 0x7E, 0x58, 0x42, 0x82, 0x59, 0x1D, 0x13, 0x7D, 0xC5, 0xB2, 0x2B, 0x24, 0x44, 0x0E, 0x57, 0x06, + 0x96, 0xC5, 0x4E, 0xB7, 0x36, 0x22, 0x9F, 0xFD, 0xC5, 0x11, 0x18, 0x1E, 0xCB, 0x96, 0xE1, 0xC4, 0xEF, 0x06, 0x95, 0x46, 0xD2, 0x99, 0x76, 0x39, 0xAF, 0x99, 0x1E, 0xD3, 0x50, 0x79, 0x09, 0x2A, + 0x68, 0x31, 0x5D, 0xDA, 0x09, 0x71, 0xF5, 0x57, 0x97, 0x64, 0x5A, 0x2B, 0x5C, 0x7A, 0xC3, 0x4C, 0x71, 0xEE, 0x66, 0x95, 0xC7, 0xDB, 0x0F, 0x96, 0x53, 0x4A, 0x40, 0x8F, 0xDC, 0x9F, 0xD5, 0xA8, + 0xB4, 0x87, 0x0F, 0xD0, 0x18, 0x41, 0xD3, 0xDA, 0x28, 0x8A, 0x3E, 0x39, 0x35, 0x7B, 0xA8, 0x94, 0x06, 0xF9, 0x1F, 0x02, 0x81, 0x9A, 0xAD, 0x0A, 0xFE, 0xF4, 0xE0, 0xC5, 0xE0, 0x42, 0xD2, 0x75, + 0x1E, 0x8D, 0xCA, 0x5C, 0xB1, 0xCE, 0x07, 0x81, 0x77, 0x31, 0xF2, 0x28, 0x38, 0x9C, 0xF3, 0xDC, 0x91, 0x7C, 0xB6, 0x13, 0xB6, 0xCE, 0xA1, 0xB8, 0xA9, 0x66, 0xB4, 0x1F, 0x42, 0xD8, 0xFB, 0x38, + 0x32, 0x3C, 0x4B, 0x53, 0x55, 0x5E, 0x65, 0x71, 0x72, 0x74, 0x7A, 0xB5, 0xBE, 0xC1, 0xE0, 0x1C, 0x33, 0x37, 0x45, 0x5B, 0x6A, 0x90, 0xA4, 0xC1, 0xCC, 0xE9, 0xEA, 0xF7, 0x09, 0x10, 0x26, 0x31, + 0x55, 0x57, 0x5E, 0x63, 0x64, 0xB2, 0xD1, 0xD8, 0xE6, 0xE8, 0xF7, 0x29, 0x33, 0x37, 0x3E, 0x40, 0x65, 0x82, 0x9C, 0xC3, 0xD5, 0xF7, 0xFD, 0x32, 0x3E, 0x45, 0x46, 0x5E, 0x75, 0x80, 0x82, 0x9D, + 0xA1, 0xAA, 0xBA, 0xCD, 0xFA, 0x06, 0x1F, 0x2A, 0x33, 0x3F, 0x56, 0x5F, 0x6B, 0x76, 0xAB, 0xBA, 0xE7, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1C, 0x2B, 0x37, 0x45, 0x52, 0xC1, 0x78, + 0xA6, 0x02, 0x01, 0x05, 0x20, 0x01, 0x00, 0x98, 0x01, 0x90, 0x20, 0xA2, 0x19, 0x10, 0x08, 0x32, 0x44, 0x00, 0x42, 0x40, 0x42, 0x06, 0x2C, 0x01, 0x30, 0xA4, 0x11, 0x48, 0x10, 0x30, 0xD1, 0x6C, + 0x94, 0x55, 0x2B, 0xE6, 0x37, 0x0B }, + }, + { + .name = "Dilithium 6-5 KAT 2", + .version = 0, + .rho_len = 32, + .rho = { 0xDF, 0x48, 0x53, 0xF4, 0x82, 0xCC, 0x1D, 0x0B, 0x3A, 0x2D, 0x71, 0xE9, 0xEA, 0xCA, 0x06, 0x4E, 0x57, 0xC5, 0xD1, 0x00, 0xDF, 0x79, 0xBD, 0x00, 0x4B, 0xA8, 0x1B, 0x43, 0xEA, 0xCE, 0xC4, 0x01 }, + .seed_len = 32, + .seed = { 0xE1, 0x09, 0x9C, 0x4D, 0x2C, 0x9B, 0x22, 0xE1, 0xAB, 0x0A, 0x55, 0x62, 0x49, 0xDC, 0xA3, 0x84, 0x57, 0x1B, 0x61, 0xDE, 0x2F, 0xC8, 0x48, 0xF2, 0xFE, 0x20, 0x28, 0x25, 0x71, 0x35, 0xC8, 0xD4 }, + .tr_len = 48, + .tr = { 0xB7, 0x83, 0x77, 0xA1, 0x95, 0x7C, 0xF1, 0x58, 0x32, 0xE9, 0x6F, 0x0F, 0x32, 0x62, 0xBB, 0xF2, 0x04, 0xA8, 0xF4, 0x0D, 0xC3, 0xDD, 0x84, 0xD6, 0x5C, 0xAD, 0xA7, 0x40, 0x80, 0x37, 0x81, 0xF6, + 0x47, 0x35, 0x95, 0x1F, 0xDA, 0x90, 0x60, 0x78, 0xDA, 0xB3, 0x39, 0x5D, 0x33, 0xE4, 0xCE, 0x4A }, + .s1_len = 480, + .s1 = { 0xC8, 0x5A, 0xD7, 0x06, 0x07, 0xC2, 0x00, 0xB5, 0x85, 0x65, 0x60, 0x60, 0x9D, 0x67, 0x08, 0x19, 0xCA, 0x54, 0x5E, 0x37, 0x86, 0x5C, 0x52, 0x5B, 0xB4, 0xAC, 0xAC, 0x66, 0x9C, 0xA8, 0x28, 0x33, + 0x08, 0x75, 0x06, 0x54, 0xCA, 0x54, 0x10, 0x9A, 0x0C, 0x7B, 0x31, 0x06, 0x1A, 0xCB, 0xE2, 0xC0, 0x9C, 0x13, 0x18, 0x74, 0x88, 0x7A, 0x83, 0x0B, 0x19, 0x18, 0x15, 0x99, 0x9E, 0x25, 0x0F, 0x95, + 0x6B, 0x51, 0xCB, 0x40, 0x80, 0x5E, 0x10, 0x78, 0x2E, 0x22, 0x75, 0x9B, 0x03, 0x10, 0xC5, 0x60, 0x6C, 0x29, 0x2A, 0x50, 0xAB, 0x43, 0x0C, 0x44, 0xB7, 0x0E, 0x05, 0xCC, 0x04, 0x2E, 0x09, 0x4F, + 0xD1, 0x5A, 0x22, 0xF5, 0xEA, 0xC0, 0x02, 0x0C, 0x87, 0xAE, 0xDD, 0x78, 0x4A, 0xEA, 0x1A, 0x36, 0xDC, 0xBA, 0x4E, 0x32, 0x45, 0xA5, 0xC5, 0x20, 0x5E, 0xCB, 0x4C, 0x46, 0x35, 0xA3, 0x95, 0x55, + 0x52, 0xDD, 0x40, 0x68, 0x43, 0xB2, 0x31, 0x28, 0x16, 0x3A, 0x20, 0x23, 0xAE, 0x09, 0x09, 0x43, 0x02, 0x3C, 0xA5, 0x0D, 0xD3, 0xAA, 0x1D, 0xEB, 0x72, 0x4E, 0x99, 0x01, 0x98, 0x23, 0xB6, 0x5D, + 0xB8, 0x16, 0x88, 0xEC, 0x45, 0x45, 0x50, 0x0D, 0xE3, 0xC2, 0xBA, 0x14, 0xE1, 0x8D, 0xB4, 0x29, 0x4E, 0x02, 0x8B, 0xC5, 0x62, 0xA2, 0x01, 0x51, 0x32, 0x50, 0x1E, 0x07, 0x05, 0x80, 0xB2, 0x68, + 0x0D, 0x6A, 0x17, 0x59, 0xB0, 0x34, 0x90, 0xBA, 0x38, 0x43, 0xB9, 0x01, 0x6C, 0x1C, 0x59, 0x52, 0x4A, 0xA1, 0x52, 0x39, 0xBA, 0x93, 0x2A, 0xC4, 0x1D, 0x6D, 0xC5, 0x80, 0x53, 0x23, 0x8E, 0x50, + 0x2D, 0x9A, 0x12, 0xCC, 0x76, 0x56, 0x8D, 0x63, 0xB4, 0xC5, 0x40, 0x21, 0x4A, 0x84, 0x95, 0x6C, 0xA6, 0x5D, 0x66, 0xC1, 0x64, 0x0F, 0x65, 0xE2, 0x71, 0xAE, 0xA7, 0x26, 0x1D, 0xAB, 0x20, 0x1E, + 0x1B, 0x33, 0xA6, 0xE6, 0x2C, 0xA8, 0xB3, 0x91, 0x6D, 0x37, 0x18, 0x65, 0x4B, 0x56, 0x94, 0x98, 0x3A, 0x35, 0x6A, 0x86, 0x65, 0xC7, 0x32, 0x73, 0x33, 0x8C, 0xEB, 0xC2, 0x0E, 0x44, 0x21, 0xCD, + 0xA6, 0x28, 0x26, 0xCB, 0x60, 0xB7, 0x2A, 0x49, 0x0C, 0x02, 0xB5, 0x28, 0x8B, 0xC4, 0xD1, 0xE5, 0x28, 0x96, 0xF0, 0x6A, 0x0F, 0xE1, 0x84, 0x66, 0x8D, 0x6C, 0x2A, 0x1A, 0x60, 0x67, 0x2C, 0xD4, + 0xB8, 0xF2, 0xE6, 0xB4, 0xF2, 0xDA, 0x2E, 0x35, 0x20, 0x93, 0x49, 0x9A, 0x72, 0x48, 0xA3, 0x29, 0x94, 0x98, 0x5A, 0x93, 0x4C, 0x0B, 0x81, 0x58, 0x21, 0x04, 0x4A, 0x43, 0x2E, 0x5D, 0xD4, 0x62, + 0x2B, 0x15, 0x4A, 0xE2, 0xD6, 0x43, 0x80, 0x82, 0x64, 0x30, 0x3B, 0x6B, 0x14, 0x91, 0x06, 0x5C, 0x0E, 0x1A, 0x83, 0x08, 0x64, 0x12, 0x7A, 0x5C, 0xAC, 0x62, 0x33, 0x34, 0x74, 0x33, 0xA0, 0xC0, + 0xF6, 0x42, 0xD6, 0x81, 0x50, 0x6D, 0x50, 0x0B, 0x97, 0x4C, 0x0D, 0x37, 0x35, 0x15, 0x0B, 0x54, 0x0B, 0xA8, 0xC8, 0x62, 0x68, 0x9E, 0x20, 0x16, 0x91, 0x1B, 0xAE, 0x92, 0x66, 0xCA, 0x8A, 0x23, + 0x93, 0x16, 0xB1, 0xD6, 0x95, 0x28, 0xA9, 0x06, 0x00, 0x05, 0xA1, 0x20, 0x2E, 0xA5, 0xD3, 0x14, 0x31, 0xD8, 0xB8, 0x00, 0x8D, 0x72, 0x0E, 0xDD, 0xB4, 0x01, 0xA8, 0x39, 0xA0, 0x6A, 0xB2, 0xAC, + 0x85, 0xB9, 0x15, 0x94, 0x24, 0x1B, 0x37, 0xB5, 0x56, 0x68, 0x69, 0x88, 0x42, 0x42, 0xDD, 0xA6, 0x61, 0xD0, 0xD6, 0x91, 0x33, 0xC6, 0x0D, 0x22, 0xA8, 0xB9, 0x2C, 0xE8, 0x10, 0x82, 0xC9, 0x6D }, + .s2_len = 576, + .s2 = { 0x28, 0x16, 0x55, 0x5A, 0x48, 0x31, 0x63, 0x39, 0x2B, 0xB3, 0x47, 0x29, 0xE5, 0x86, 0xAA, 0x4D, 0x53, 0x62, 0x4A, 0x98, 0x25, 0x72, 0x55, 0x6F, 0x99, 0x90, 0xB2, 0x36, 0x3B, 0x15, 0x0D, 0x86, + 0x72, 0xEA, 0x86, 0xA8, 0x44, 0x0B, 0x80, 0x93, 0x80, 0x70, 0x0C, 0x81, 0xBA, 0x6D, 0xC4, 0x08, 0x5C, 0xC4, 0x91, 0x70, 0xC0, 0xB6, 0x16, 0x8C, 0x84, 0xC3, 0x46, 0x32, 0x9E, 0xEB, 0x18, 0x5A, + 0xDD, 0x61, 0xE8, 0x5C, 0x88, 0xF6, 0x58, 0x27, 0x6B, 0xA6, 0x05, 0xCB, 0xC0, 0x52, 0x5A, 0x38, 0x0E, 0x88, 0x19, 0x19, 0x1A, 0xD7, 0x1A, 0xD6, 0x5C, 0x35, 0x0C, 0xBD, 0x26, 0xAD, 0x5C, 0xAD, + 0xA2, 0x0C, 0x2B, 0x06, 0xE0, 0x20, 0xDB, 0x80, 0x55, 0x29, 0x0A, 0xDB, 0x6D, 0xC6, 0x65, 0x82, 0x01, 0x91, 0x95, 0xA9, 0x26, 0x6B, 0x05, 0xB7, 0x50, 0x57, 0xCA, 0xE8, 0x92, 0xAD, 0xB1, 0x2A, + 0xA4, 0x5A, 0x23, 0x1B, 0x20, 0x62, 0xA8, 0x83, 0xD3, 0x26, 0x2D, 0x98, 0x10, 0x0B, 0x2D, 0x2D, 0x25, 0xE7, 0xA5, 0xC5, 0x5C, 0xB3, 0xA3, 0x95, 0x35, 0xAE, 0x33, 0xCE, 0x73, 0xD0, 0xD6, 0x21, + 0x01, 0xB4, 0xAB, 0x03, 0x79, 0x24, 0x6A, 0x4B, 0x64, 0x66, 0x08, 0x72, 0x2B, 0x95, 0x30, 0xA0, 0x18, 0xEA, 0x36, 0x14, 0x04, 0xA1, 0x7A, 0x9B, 0x00, 0x27, 0xB0, 0xB2, 0x2D, 0x01, 0xC3, 0xD0, + 0xED, 0x3A, 0x43, 0x53, 0x2B, 0x60, 0xC3, 0xA4, 0x8E, 0x06, 0xE7, 0x56, 0x6B, 0x09, 0x01, 0x1A, 0xDA, 0x82, 0xA2, 0x68, 0x70, 0x2E, 0x61, 0xCB, 0xB2, 0xD2, 0x51, 0xD5, 0x6C, 0x94, 0x2B, 0x3C, + 0x40, 0x34, 0x82, 0x59, 0x5B, 0x4C, 0x77, 0x8D, 0x34, 0xB6, 0x29, 0x2C, 0x5A, 0x32, 0x81, 0xC8, 0x25, 0x31, 0x2B, 0x2C, 0x1B, 0x46, 0x54, 0xA5, 0x6A, 0x6B, 0xAD, 0xD9, 0x6D, 0xCA, 0x24, 0x4B, + 0x55, 0x34, 0x0C, 0xB5, 0xDA, 0x83, 0x58, 0x39, 0x81, 0x32, 0x68, 0x8B, 0x1C, 0x62, 0xF2, 0x32, 0x0A, 0xB0, 0x66, 0x98, 0x18, 0xAC, 0x55, 0x06, 0xE1, 0x25, 0x4D, 0x3A, 0x95, 0x35, 0x81, 0x78, + 0x75, 0xE5, 0x2A, 0x1A, 0x54, 0x28, 0x72, 0x60, 0x78, 0x96, 0x98, 0x75, 0x14, 0x95, 0x65, 0x96, 0x29, 0x68, 0x81, 0x66, 0xBA, 0xB4, 0xD9, 0x69, 0x6D, 0x29, 0xA8, 0x5D, 0x97, 0xA8, 0x91, 0xDB, + 0x30, 0xE4, 0x82, 0x79, 0xC9, 0x60, 0x91, 0x48, 0x58, 0x25, 0xCA, 0x84, 0x54, 0x75, 0x50, 0x59, 0x6B, 0x61, 0xAC, 0xED, 0x46, 0x67, 0x2A, 0xCC, 0x9A, 0x1C, 0x9B, 0xDA, 0x5B, 0x58, 0x21, 0xF0, + 0x60, 0xC1, 0x82, 0xD0, 0x8C, 0x22, 0xA1, 0x05, 0x5B, 0x9C, 0x81, 0xEA, 0x04, 0xB8, 0x0D, 0x25, 0x4B, 0x36, 0x69, 0x98, 0x01, 0x50, 0xCA, 0xEA, 0x02, 0x98, 0x62, 0x34, 0x4F, 0x75, 0xBD, 0x72, + 0x14, 0x64, 0x07, 0xE6, 0xD4, 0x20, 0x89, 0xCA, 0x34, 0x6D, 0x5B, 0x33, 0x74, 0x02, 0xC8, 0x24, 0x58, 0x18, 0xAA, 0x0D, 0x78, 0x69, 0xEA, 0x9A, 0xA5, 0x2B, 0x63, 0x31, 0x93, 0x16, 0x03, 0x40, + 0xC6, 0xCC, 0xA4, 0x20, 0x54, 0x88, 0x52, 0x2C, 0x35, 0x8A, 0x52, 0x00, 0x80, 0x10, 0x62, 0x28, 0x1B, 0x49, 0xC3, 0x6C, 0x82, 0x4E, 0x36, 0xD3, 0x72, 0x46, 0x52, 0x44, 0x65, 0x29, 0x89, 0x13, + 0x19, 0x85, 0x63, 0x3A, 0x8E, 0x89, 0xD2, 0xA6, 0x4C, 0xA3, 0xD0, 0x23, 0x37, 0x72, 0x90, 0xB4, 0xC0, 0x56, 0xAD, 0x59, 0x5A, 0x85, 0x94, 0x5B, 0x1B, 0xC3, 0xCA, 0xC0, 0x50, 0x0D, 0xA8, 0x25, + 0x04, 0xEC, 0x00, 0x95, 0x04, 0x03, 0x02, 0x04, 0x81, 0x44, 0x85, 0x15, 0xA2, 0xDB, 0xD6, 0x10, 0x05, 0xA5, 0xAC, 0x64, 0x15, 0x46, 0xD0, 0x10, 0x1E, 0x43, 0x36, 0x25, 0x86, 0x98, 0x84, 0xA7, + 0x79, 0xAE, 0x62, 0x8A, 0x68, 0xA6, 0x75, 0x88, 0x3B, 0xB0, 0x4C, 0xA0, 0x09, 0x50, 0x8D, 0x68, 0xD8, 0x46, 0xC4, 0x04, 0x40, 0x41, 0x40, 0x4A, 0x74, 0x74, 0x56, 0x8B, 0x66, 0x6B, 0x50, 0x96, + 0x2D, 0x91, 0x72, 0xAD, 0xBA, 0x43, 0xD4, 0x20, 0x25, 0x20, 0x31, 0x0A, 0x27, 0x44, 0xB4, 0xD0, 0xB2, 0x54, 0x96, 0x15, 0x1D, 0x4D, 0xB6, 0x06, 0x31, 0x95, 0x2A, 0x05, 0x57, 0x25, 0x18, 0x6F }, + .t0_len = 2688, + .t0 = { 0x8F, 0xC7, 0xF7, 0xB9, 0x1E, 0x48, 0x4A, 0x3B, 0xD2, 0x6D, 0x29, 0x6E, 0xE5, 0x24, 0xA4, 0xEF, 0x3B, 0x79, 0x23, 0xCA, 0x0E, 0x05, 0x32, 0x23, 0x65, 0x7E, 0x00, 0x59, 0x75, 0xB0, 0xEA, 0x7C, + 0x53, 0x69, 0xCE, 0xC4, 0x5F, 0xB0, 0xEF, 0x38, 0x69, 0x1C, 0x07, 0xB7, 0x3D, 0x6D, 0xEF, 0xFF, 0x7F, 0x64, 0x62, 0x75, 0xDA, 0xB3, 0xFB, 0x1A, 0x19, 0xED, 0x08, 0xBD, 0x99, 0x38, 0xB2, 0xDC, + 0x99, 0x66, 0xE0, 0xA5, 0x55, 0x9F, 0x33, 0x02, 0xFF, 0x31, 0x44, 0x9F, 0x05, 0x9A, 0xE0, 0x97, 0xF0, 0xE8, 0x0E, 0xE2, 0xEA, 0x27, 0xA1, 0xE4, 0xE7, 0xC4, 0x23, 0x03, 0xBC, 0x4C, 0xFC, 0xC5, + 0xF8, 0xF5, 0x02, 0xE4, 0x97, 0xED, 0xED, 0x05, 0x93, 0x12, 0xEF, 0x78, 0x51, 0x4A, 0xD0, 0xFA, 0x14, 0xF9, 0xBB, 0xE5, 0x0D, 0x1D, 0x2F, 0x94, 0xC3, 0xA8, 0xAC, 0xF6, 0x63, 0xD1, 0x75, 0x2D, + 0x3D, 0x2E, 0xDA, 0x1D, 0xE6, 0x33, 0xB8, 0x72, 0x73, 0xE6, 0x29, 0x53, 0xCC, 0x57, 0x55, 0xFF, 0xB3, 0x77, 0x2F, 0x84, 0x01, 0x20, 0x38, 0x64, 0x6C, 0x4B, 0xE1, 0x58, 0x52, 0x18, 0xC1, 0x89, + 0x12, 0xBB, 0x45, 0xBF, 0x83, 0x7D, 0x43, 0x94, 0xA8, 0x80, 0x42, 0xBA, 0xAA, 0x16, 0x3F, 0x29, 0x4A, 0xF6, 0x9A, 0x2B, 0x79, 0xEF, 0xCE, 0xB9, 0x4F, 0xC3, 0x6B, 0xF7, 0x79, 0xDE, 0x53, 0x8A, + 0x3C, 0xC6, 0xBA, 0xB7, 0x23, 0x95, 0xA0, 0x5C, 0xB7, 0x8D, 0xF4, 0x0B, 0x6A, 0xC7, 0x2C, 0x63, 0x8E, 0x1C, 0x31, 0x05, 0x2A, 0xDB, 0xF8, 0xB5, 0x4B, 0x76, 0xFA, 0x4D, 0x66, 0x01, 0xFE, 0x6B, + 0xAB, 0x3B, 0x32, 0xD3, 0xD7, 0x01, 0xBE, 0xA0, 0xAC, 0x9A, 0x38, 0xFD, 0x7A, 0x38, 0x58, 0x00, 0x46, 0x1E, 0xC2, 0xE3, 0x7D, 0xD5, 0x7F, 0x2D, 0x7E, 0xBE, 0xA8, 0x0A, 0x74, 0xF1, 0xCD, 0x3E, + 0x52, 0x55, 0xC8, 0x88, 0xEA, 0xCB, 0xFE, 0xE0, 0x88, 0x0A, 0x72, 0xE9, 0x05, 0x8E, 0xBA, 0x84, 0xA7, 0xA2, 0x66, 0x47, 0x39, 0x4D, 0x8D, 0x2A, 0xC4, 0xFA, 0xE6, 0x79, 0x15, 0xDD, 0xC1, 0xBC, + 0xEC, 0xAE, 0x5B, 0x05, 0x85, 0x07, 0x75, 0x25, 0xBE, 0xB2, 0xBC, 0x4A, 0x3F, 0xDE, 0x9E, 0xD1, 0xEE, 0x2B, 0xAE, 0xFB, 0x92, 0x75, 0xA4, 0xCB, 0x65, 0x41, 0xA1, 0xEE, 0x65, 0xBD, 0xA5, 0x6F, + 0xEF, 0x14, 0x6D, 0xD8, 0x8F, 0x08, 0x6A, 0xE1, 0xF2, 0xA6, 0xFA, 0xA5, 0xA5, 0xF4, 0xE0, 0x21, 0x07, 0x15, 0x9A, 0x3C, 0xBD, 0x13, 0x45, 0x3B, 0x1E, 0xF8, 0x6C, 0x18, 0x18, 0xDE, 0xF4, 0x6D, + 0x51, 0xFB, 0x27, 0xC0, 0xF4, 0x7A, 0x61, 0x64, 0xCB, 0xC8, 0x84, 0x97, 0x3D, 0xB1, 0xDC, 0xF5, 0xA8, 0xCB, 0x70, 0x65, 0xB3, 0x46, 0xDA, 0xFC, 0xF8, 0x05, 0x9C, 0x47, 0x96, 0x20, 0x95, 0x6A, + 0xA0, 0x7D, 0x72, 0x02, 0x71, 0x34, 0xCE, 0xF0, 0x92, 0x56, 0x07, 0xC9, 0xB4, 0xB9, 0xEB, 0x6C, 0x84, 0x29, 0x62, 0xF1, 0x08, 0xDD, 0x38, 0x8B, 0x46, 0x4C, 0x04, 0xD6, 0x0E, 0x0E, 0xC5, 0x65, + 0x40, 0xFD, 0xEE, 0x23, 0x16, 0x65, 0x2C, 0x66, 0xBD, 0x0C, 0x17, 0x2E, 0xEF, 0x13, 0xBC, 0x69, 0xFC, 0xA0, 0xE0, 0xF6, 0xFE, 0x5F, 0x52, 0xBF, 0xDF, 0x00, 0xC3, 0xF2, 0xD7, 0x67, 0xE9, 0x4C, + 0x1E, 0x8B, 0x90, 0x79, 0x1B, 0x7C, 0x59, 0x85, 0x0B, 0x6F, 0x5D, 0x90, 0x1A, 0xC4, 0x9D, 0x82, 0x59, 0x04, 0xF0, 0xD0, 0x2A, 0xFD, 0x39, 0x2A, 0x99, 0x20, 0xBA, 0x0B, 0x1A, 0x46, 0x73, 0x62, + 0x86, 0xAF, 0x99, 0xB3, 0x4A, 0x7C, 0x0A, 0x89, 0xEE, 0x30, 0xD1, 0x9A, 0x0C, 0x5D, 0x12, 0x77, 0x4A, 0xFC, 0xE0, 0xAE, 0x68, 0xC1, 0x9F, 0x90, 0x60, 0x38, 0x72, 0x76, 0x78, 0x62, 0xCF, 0x63, + 0x9F, 0xB0, 0xBC, 0x46, 0x52, 0x6F, 0x39, 0x08, 0x53, 0x25, 0x86, 0x3C, 0x69, 0xCA, 0x57, 0x0A, 0xD3, 0xAC, 0x01, 0x0D, 0x81, 0x28, 0x7B, 0x5A, 0x08, 0x88, 0xF7, 0x06, 0xDD, 0x7C, 0x6B, 0xF2, + 0x07, 0x3E, 0x4D, 0x94, 0x1E, 0x70, 0x88, 0xB1, 0x62, 0x64, 0x95, 0xD3, 0x06, 0x2E, 0x97, 0x58, 0xC7, 0x75, 0x6B, 0xFB, 0x54, 0xD4, 0xB5, 0x3C, 0x9C, 0xDE, 0xBE, 0xD4, 0x79, 0xF5, 0x8A, 0x5C, + 0x61, 0x69, 0x27, 0xB7, 0xAE, 0x79, 0x99, 0xF5, 0xB6, 0x1B, 0x9F, 0x4A, 0x9B, 0xBB, 0x88, 0xEC, 0x96, 0xB8, 0xB6, 0x50, 0x14, 0x3C, 0x07, 0x24, 0x57, 0x04, 0xA4, 0xF5, 0xBE, 0x3D, 0x7B, 0x70, + 0x12, 0xFA, 0x24, 0xAE, 0x8E, 0xDD, 0x78, 0x37, 0x97, 0x1A, 0xAD, 0xBB, 0x56, 0xAF, 0x8B, 0xC7, 0xB2, 0x82, 0xAD, 0xCA, 0x99, 0x35, 0x08, 0x9F, 0x67, 0xFD, 0xD9, 0x1B, 0x98, 0xB6, 0x1F, 0xFC, + 0xC9, 0x2A, 0xB2, 0x5F, 0xDE, 0x15, 0x55, 0x2E, 0xB1, 0xC1, 0x5F, 0xE1, 0x26, 0x36, 0x6D, 0x6C, 0x24, 0x60, 0xC7, 0xE7, 0x47, 0x05, 0x45, 0x07, 0x74, 0xDA, 0x52, 0xC9, 0x49, 0x91, 0xD6, 0x0F, + 0xEB, 0x61, 0x64, 0xCE, 0xA7, 0xEB, 0x12, 0x39, 0x6E, 0xCF, 0x64, 0xD3, 0x15, 0x95, 0x23, 0x13, 0x4A, 0xBE, 0x3F, 0x22, 0xD5, 0x4F, 0xE1, 0x4D, 0xFC, 0x64, 0x4E, 0x00, 0xB9, 0x45, 0x97, 0x50, + 0x39, 0xCD, 0x80, 0xDC, 0x77, 0xA2, 0x69, 0x4A, 0xAB, 0xED, 0xC3, 0xF3, 0xD9, 0x9F, 0x7D, 0x46, 0x4C, 0x29, 0xC6, 0xA5, 0xD1, 0x6C, 0xB5, 0xFE, 0xCD, 0xB6, 0x1B, 0x00, 0x53, 0xEE, 0x56, 0xAE, + 0x01, 0x6C, 0x7E, 0x16, 0x15, 0x7C, 0x91, 0xAD, 0xA3, 0xBE, 0xD6, 0xC2, 0xC4, 0xEC, 0xFD, 0x11, 0x33, 0x3D, 0x12, 0xE7, 0x41, 0x45, 0x80, 0xAC, 0xA6, 0xE6, 0x44, 0x06, 0x0B, 0xC6, 0xFA, 0xCA, + 0x0E, 0xCB, 0x29, 0xBD, 0xFE, 0x45, 0xCB, 0x21, 0xAB, 0xED, 0xD9, 0x80, 0xC4, 0x93, 0x44, 0xD1, 0xEF, 0xE2, 0xB5, 0x2B, 0x3F, 0xCE, 0x7D, 0xDC, 0x91, 0xBF, 0xE4, 0x4D, 0x40, 0x09, 0xE3, 0xD7, + 0xFF, 0xE7, 0x02, 0xA8, 0x1E, 0xF8, 0x7D, 0xBC, 0x6C, 0xA7, 0x4C, 0x11, 0x31, 0xAD, 0x14, 0x15, 0xB4, 0x09, 0xA2, 0x65, 0xA6, 0xDD, 0x43, 0xBC, 0x3B, 0x44, 0x1B, 0x48, 0x30, 0x89, 0xFE, 0xEE, + 0x81, 0xF0, 0x55, 0xA5, 0xA0, 0xB5, 0xCA, 0x54, 0xF1, 0x33, 0xFF, 0x04, 0x0E, 0x38, 0xC1, 0xC0, 0x71, 0x20, 0x3F, 0x56, 0x2B, 0xEA, 0x8D, 0x67, 0x0D, 0x11, 0x67, 0x85, 0x4F, 0xCB, 0xD7, 0x7E, + 0x9E, 0x42, 0xD3, 0xE7, 0x4F, 0xED, 0xBA, 0x64, 0x05, 0xA9, 0xA5, 0x6A, 0x4A, 0x3D, 0x9B, 0xE9, 0xE9, 0x2A, 0x71, 0x2B, 0xE7, 0x1C, 0x2C, 0xE4, 0xCE, 0x46, 0xB2, 0x2B, 0x01, 0xAB, 0xA3, 0x5B, + 0x1C, 0xF2, 0x63, 0x7F, 0xEA, 0xE7, 0xE0, 0x00, 0x1A, 0x80, 0xC6, 0x9B, 0x6D, 0x85, 0x73, 0x24, 0xF0, 0x43, 0x50, 0x12, 0x0B, 0xB6, 0xC7, 0xEE, 0x6C, 0x61, 0xD9, 0xB6, 0x06, 0x93, 0xA5, 0x18, + 0x5D, 0x6A, 0xA0, 0xD6, 0x14, 0xEC, 0xD7, 0x53, 0xBE, 0xE3, 0xCB, 0x9D, 0x6A, 0x1D, 0x11, 0xC1, 0xF5, 0x59, 0xA6, 0x12, 0x00, 0x9E, 0x90, 0x58, 0xB3, 0xF5, 0x3D, 0xD4, 0xF5, 0x91, 0x58, 0x16, + 0x58, 0xF0, 0x55, 0x9B, 0xC8, 0x0F, 0xA5, 0x44, 0x72, 0xD0, 0x44, 0xC2, 0xA3, 0x74, 0x27, 0x3E, 0x4F, 0xDD, 0x88, 0xEA, 0x41, 0x32, 0xBE, 0xD3, 0x2C, 0x45, 0x14, 0xF8, 0xEE, 0x2A, 0x9D, 0xF2, + 0x95, 0x46, 0xE4, 0x17, 0x60, 0x8E, 0xEA, 0xF1, 0xF0, 0x86, 0x7A, 0x52, 0x06, 0x6B, 0x0C, 0x82, 0xAC, 0xED, 0x08, 0x67, 0x4B, 0x98, 0xEC, 0x77, 0x22, 0x5C, 0x35, 0xDB, 0x38, 0xCB, 0x76, 0x2A, + 0x04, 0xF3, 0xAA, 0x73, 0xFE, 0xBA, 0xA2, 0x03, 0xCF, 0xA3, 0x78, 0xEB, 0x77, 0x00, 0x58, 0xF6, 0xC9, 0x52, 0x56, 0x61, 0x0C, 0x4B, 0xA3, 0xF3, 0xB5, 0xF9, 0x49, 0x1F, 0x64, 0x76, 0x44, 0x3A, + 0x0E, 0x44, 0x6E, 0xBF, 0x90, 0xEB, 0xF8, 0xDE, 0x87, 0x77, 0x65, 0x6D, 0xD6, 0x0B, 0x00, 0xDA, 0x62, 0x85, 0x57, 0x12, 0xD3, 0xDA, 0x18, 0xA2, 0x4C, 0x55, 0xEB, 0x7F, 0x43, 0xC4, 0x12, 0xCD, + 0x86, 0xD3, 0x44, 0xDA, 0xB3, 0x10, 0x5B, 0x15, 0x57, 0x10, 0x91, 0x6D, 0xEB, 0x20, 0x16, 0x54, 0xE0, 0x2E, 0x1F, 0x61, 0x0D, 0xD2, 0x8E, 0xF7, 0xEF, 0x31, 0x62, 0xF4, 0x83, 0x33, 0x81, 0xBC, + 0xB0, 0x59, 0x33, 0x19, 0x8F, 0x1D, 0xE1, 0x95, 0xE0, 0xB8, 0xD7, 0xD1, 0x31, 0xB5, 0xA0, 0x24, 0xBC, 0xB5, 0xD0, 0xF7, 0x8B, 0xF8, 0xB1, 0xAA, 0xD2, 0x4A, 0xC7, 0x69, 0x25, 0xA8, 0x1F, 0x6E, + 0xDE, 0x65, 0xC2, 0xA7, 0x26, 0x4C, 0xBF, 0xAF, 0x3B, 0x6F, 0x3D, 0x89, 0x64, 0x17, 0x5E, 0x21, 0x02, 0xD9, 0x58, 0x8E, 0xC9, 0x64, 0xD0, 0x7B, 0xEF, 0x4A, 0x45, 0x2F, 0x04, 0xA2, 0x21, 0xEC, + 0x42, 0xEB, 0xF9, 0x50, 0x4B, 0x4D, 0x77, 0x47, 0x56, 0x1E, 0xD8, 0xED, 0x6F, 0xF4, 0x1B, 0xE7, 0x5F, 0x9D, 0x95, 0x1A, 0xDF, 0x69, 0x67, 0x26, 0xFC, 0x17, 0x1D, 0x6D, 0x51, 0x39, 0xF8, 0xCA, + 0xCE, 0x3A, 0x7F, 0xFF, 0xF6, 0x99, 0xE3, 0x55, 0x68, 0x62, 0xAB, 0x5E, 0x8A, 0x7B, 0x22, 0x34, 0xDC, 0x10, 0xD7, 0x2E, 0x45, 0x1B, 0x92, 0xEF, 0x47, 0x89, 0x98, 0x52, 0xA9, 0xEF, 0xF5, 0xF5, + 0x7C, 0x38, 0x24, 0xCA, 0xED, 0x4B, 0xCF, 0x9C, 0x97, 0xCA, 0x99, 0xBD, 0xE9, 0x79, 0xAA, 0x1A, 0x07, 0xFE, 0x18, 0x0E, 0x26, 0x0E, 0x97, 0xFC, 0xC3, 0xDA, 0x0D, 0x95, 0xD9, 0xB9, 0xD1, 0x6D, + 0xF3, 0x15, 0x4F, 0xB1, 0xB8, 0xA2, 0x6C, 0x3D, 0xA9, 0x4F, 0x6E, 0x93, 0xD9, 0x23, 0x8F, 0xE7, 0xB7, 0xF6, 0xFB, 0x8D, 0xB7, 0x18, 0x7E, 0x3F, 0xA6, 0xE9, 0xD5, 0x91, 0x75, 0x1D, 0x3E, 0xD6, + 0xC7, 0x56, 0xE8, 0x01, 0xCA, 0x5D, 0x90, 0x7F, 0x59, 0x0B, 0x13, 0x17, 0x12, 0xCF, 0x87, 0xF9, 0xD8, 0xE6, 0x44, 0x1C, 0x22, 0x43, 0x61, 0x03, 0xE4, 0x93, 0x2F, 0x74, 0x88, 0x33, 0x18, 0xC6, + 0xB0, 0x36, 0x1D, 0xB7, 0x78, 0x26, 0x56, 0x4C, 0xCE, 0x92, 0x01, 0x6E, 0x94, 0xC2, 0x5E, 0x10, 0x0F, 0x75, 0xD5, 0xB2, 0x27, 0xE0, 0xE5, 0xE4, 0x3F, 0xEF, 0x2F, 0x78, 0xF8, 0xA6, 0x6C, 0x3A, + 0xDF, 0xED, 0xEA, 0x92, 0x80, 0x25, 0x0E, 0x55, 0x62, 0x4E, 0xF9, 0x60, 0x5D, 0x0C, 0x32, 0xBF, 0x98, 0xC6, 0xBA, 0x8F, 0xB3, 0xA0, 0xA8, 0xF9, 0x38, 0xE9, 0x4E, 0xF2, 0x71, 0x4B, 0x2F, 0x9C, + 0x0F, 0xF5, 0x12, 0x7F, 0x64, 0x50, 0x2B, 0xC8, 0xF2, 0x19, 0x90, 0x2D, 0xCB, 0x8F, 0x2A, 0x86, 0x00, 0xC6, 0x58, 0x94, 0x64, 0x9D, 0x0A, 0xAD, 0x29, 0x2F, 0xB1, 0xD0, 0x0C, 0x02, 0x1C, 0x67, + 0x9F, 0x84, 0xE4, 0x8F, 0x48, 0x8F, 0xA5, 0x48, 0x6E, 0x6E, 0x73, 0xF9, 0xCC, 0x01, 0x26, 0x72, 0xF3, 0x89, 0x93, 0xCA, 0x31, 0x99, 0x82, 0xCA, 0x06, 0x34, 0x6A, 0xBE, 0x91, 0x18, 0x6C, 0x7F, + 0x5C, 0x38, 0x5A, 0x62, 0x5C, 0xFF, 0x7F, 0x28, 0x2F, 0xE6, 0x03, 0x09, 0xB1, 0xE3, 0x13, 0x39, 0x6B, 0x5A, 0x39, 0xBF, 0x04, 0x8D, 0x5A, 0xBA, 0x1B, 0x47, 0xE9, 0x95, 0x4B, 0x51, 0xBB, 0xE6, + 0x30, 0x02, 0xA6, 0x6D, 0xA8, 0x0C, 0x71, 0x5F, 0xDB, 0x6A, 0x80, 0x9F, 0x33, 0xFB, 0x10, 0x27, 0x9F, 0x97, 0xDD, 0x31, 0xD0, 0x0C, 0x78, 0xE2, 0x46, 0x8A, 0xB3, 0x96, 0x27, 0x1E, 0x0B, 0xB1, + 0x9B, 0xEA, 0x40, 0x79, 0xD9, 0x74, 0xC4, 0x11, 0x34, 0xDB, 0xC8, 0x29, 0xDB, 0xFD, 0xAF, 0x81, 0xE0, 0x27, 0x66, 0x9C, 0x23, 0xE0, 0xAC, 0xAF, 0xB7, 0x07, 0x06, 0x07, 0x72, 0x63, 0x5E, 0xE2, + 0x0F, 0x83, 0x73, 0xB6, 0xB5, 0xC2, 0xD6, 0xED, 0xEF, 0x8F, 0xD6, 0xFB, 0xC1, 0x94, 0x3E, 0xF7, 0x1A, 0x12, 0xEF, 0x26, 0x0A, 0xF5, 0x81, 0x13, 0x62, 0x06, 0x06, 0xB0, 0x68, 0x4E, 0xC8, 0x81, + 0x90, 0xE7, 0xF1, 0xCD, 0x33, 0x5E, 0x6A, 0x7E, 0x75, 0x98, 0x4C, 0xD8, 0xF4, 0x7C, 0xD0, 0xCF, 0x8A, 0x2A, 0x51, 0x85, 0xCE, 0x7D, 0x06, 0xA4, 0xB4, 0x64, 0x1C, 0x15, 0x37, 0x04, 0x92, 0xB2, + 0x0C, 0x3C, 0x37, 0xE9, 0xB3, 0x01, 0x6B, 0x72, 0xDA, 0x51, 0x14, 0x38, 0xFE, 0xA7, 0x90, 0x79, 0x63, 0x8F, 0x28, 0x96, 0x15, 0xD4, 0xAA, 0x8F, 0xB8, 0x00, 0x6C, 0x3A, 0x9D, 0x70, 0x81, 0x12, + 0x0F, 0x92, 0xBC, 0xC4, 0xB8, 0xE3, 0x24, 0x6E, 0xBD, 0xA9, 0x9C, 0x0F, 0x46, 0xA4, 0x25, 0xDD, 0xC6, 0x8B, 0x98, 0x68, 0xCA, 0x07, 0xF0, 0x0A, 0x29, 0xB3, 0xB1, 0xF0, 0x47, 0x0F, 0x3F, 0x35, + 0x31, 0x2B, 0xDB, 0xD1, 0x5B, 0x68, 0xA7, 0x87, 0x89, 0x29, 0xF3, 0x13, 0x64, 0xC6, 0x55, 0x62, 0x51, 0x80, 0x20, 0x4D, 0x50, 0x85, 0x97, 0xA1, 0xE8, 0xA8, 0x2E, 0xAE, 0x4C, 0x99, 0xB4, 0x6B, + 0x91, 0xB8, 0x91, 0xD7, 0xC6, 0xC3, 0x1E, 0x28, 0x94, 0x27, 0xD8, 0x2F, 0xD3, 0xFD, 0xC8, 0xB4, 0x23, 0x2C, 0x79, 0x05, 0x0A, 0x2E, 0x7C, 0x42, 0xE0, 0x63, 0xDD, 0xB5, 0x5B, 0xC6, 0x84, 0xF3, + 0x1E, 0xCF, 0x70, 0x3D, 0x32, 0x94, 0x59, 0x3D, 0xC3, 0x05, 0x0D, 0x37, 0x30, 0xB3, 0xC1, 0x31, 0xDA, 0x4F, 0xFD, 0xC6, 0x8E, 0x3E, 0x93, 0xE9, 0xAA, 0x73, 0xF8, 0xA6, 0x83, 0x8F, 0xEE, 0xB5, + 0xCF, 0x2D, 0x35, 0xFF, 0xDE, 0x67, 0xE4, 0x7A, 0xA7, 0xC2, 0xB8, 0x29, 0x49, 0xDC, 0xA0, 0x0A, 0x85, 0x7D, 0x9B, 0x00, 0xB9, 0xD8, 0x1B, 0xB1, 0x6C, 0x7F, 0xF7, 0xE9, 0xAA, 0x60, 0x96, 0x52, + 0xAB, 0x6C, 0x85, 0x69, 0x5F, 0x0E, 0x97, 0xEC, 0x7A, 0x2F, 0x2A, 0xA6, 0x84, 0x12, 0xCE, 0x00, 0xD9, 0xCC, 0x10, 0x66, 0x8D, 0x6F, 0xDB, 0x68, 0x64, 0x3D, 0xA4, 0xA2, 0xBE, 0xF7, 0xA4, 0x14, + 0xCB, 0x81, 0x48, 0x63, 0x15, 0xEE, 0x7E, 0xD6, 0x93, 0x64, 0xB2, 0xFB, 0x1D, 0x76, 0x7E, 0x94, 0xB4, 0x29, 0x76, 0x19, 0x5F, 0x3A, 0x6B, 0x69, 0xC3, 0x65, 0xFF, 0x7E, 0x73, 0x52, 0x20, 0xE2, + 0x1D, 0x77, 0xF7, 0x62, 0x59, 0xF7, 0xD6, 0xB0, 0x16, 0xF8, 0x27, 0x17, 0xCF, 0x25, 0x05, 0x54, 0x0F, 0x0F, 0x98, 0xBC, 0xB5, 0x08, 0x61, 0xA7, 0x03, 0x5E, 0xD5, 0xFD, 0x5F, 0x6A, 0x13, 0x8A, + 0x76, 0x55, 0xB9, 0xAE, 0x92, 0x08, 0x3E, 0x49, 0x13, 0xB0, 0x2F, 0x9D, 0x55, 0x5B, 0xD8, 0x06, 0x6A, 0x39, 0x3F, 0x74, 0x03, 0x46, 0xFA, 0x39, 0x85, 0x28, 0x7D, 0x39, 0x46, 0x2D, 0x5E, 0xF9, + 0x7C, 0x1A, 0x1A, 0xF4, 0x7B, 0x90, 0x1C, 0xCE, 0x78, 0xC1, 0x89, 0x06, 0x4C, 0x8D, 0xC6, 0x7C, 0xEF, 0x32, 0xE0, 0x8A, 0x1C, 0x2B, 0x26, 0x9D, 0x86, 0xAD, 0x0F, 0xE4, 0x67, 0x89, 0xA6, 0x42, + 0x5B, 0xF7, 0x62, 0xBF, 0x77, 0xE2, 0x4E, 0xC6, 0xC0, 0xA2, 0x9F, 0x3D, 0xAD, 0x42, 0xB2, 0x5F, 0x6A, 0x87, 0x2D, 0x5A, 0x34, 0x24, 0x8D, 0x9F, 0x17, 0xD2, 0x3B, 0xB0, 0x6C, 0xF0, 0xE6, 0x15, + 0x86, 0xBB, 0x51, 0x25, 0xFF, 0x42, 0xF9, 0xC1, 0x62, 0x22, 0xC6, 0x0D, 0x09, 0xB4, 0x00, 0x18, 0x10, 0x0D, 0xAD, 0xA6, 0xED, 0x17, 0xE6, 0x44, 0x07, 0xE4, 0xA5, 0x7E, 0x42, 0x1F, 0xDB, 0x62, + 0xBE, 0x50, 0x3A, 0xF9, 0x51, 0xBC, 0x33, 0x11, 0x4D, 0xA6, 0x9B, 0x32, 0x60, 0xD0, 0x5C, 0x3D, 0x52, 0xA0, 0xA8, 0xA1, 0x99, 0x17, 0x89, 0x70, 0x98, 0x31, 0x1D, 0x2F, 0x54, 0x83, 0x6E, 0x3C, + 0x07, 0xEF, 0xED, 0xD2, 0x0F, 0x44, 0xD6, 0xF8, 0x80, 0x42, 0x95, 0xAD, 0xC7, 0x42, 0x21, 0x6F, 0xED, 0x26, 0xA2, 0x63, 0x7F, 0xF4, 0xAD, 0x0C, 0x0B, 0x8A, 0x14, 0xFF, 0xF1, 0x79, 0xDE, 0x97, + 0x38, 0x7E, 0x4E, 0x84, 0x70, 0xFA, 0x05, 0x48, 0x4F, 0x7E, 0x4B, 0xFD, 0xB0, 0x3F, 0xC5, 0x69, 0xF7, 0x8F, 0xF1, 0xFB, 0xCD, 0x01, 0xEA, 0x27, 0x01, 0x5A, 0x8A, 0xBD, 0xAF, 0xDD, 0xC4, 0x2E, + 0x29, 0x67, 0xFC, 0xC2, 0xB0, 0xEE, 0x80, 0xAC, 0x49, 0xE3, 0xD8, 0x4C, 0x4A, 0xBF, 0xA6, 0x56, 0x7F, 0x95, 0xB9, 0x25, 0x27, 0x10, 0x71, 0x20, 0x85, 0xE3, 0x95, 0x4F, 0x08, 0xBF, 0xB0, 0x29, + 0x2B, 0x22, 0x6F, 0xC6, 0x4F, 0xD8, 0xAE, 0x20, 0x55, 0xF1, 0x92, 0xA1, 0xD3, 0x7C, 0x3D, 0x86, 0x37, 0x4E, 0x23, 0x3E, 0xE4, 0xE6, 0x95, 0xF3, 0xFF, 0x33, 0x06, 0xAE, 0x12, 0xB5, 0x86, 0x41, + 0x15, 0x24, 0x3F, 0xE6, 0x0C, 0x64, 0xA2, 0xA5, 0x58, 0x96, 0xD6, 0x77, 0x57, 0x34, 0xB6, 0x6A, 0x63, 0x10, 0x56, 0x93, 0x4A, 0x1C, 0xBC, 0xB1, 0x46, 0x7B, 0x10, 0xF4, 0xA4, 0x07, 0x7C, 0x92, + 0xF4, 0x76, 0x4B, 0x72, 0xC1, 0x3B, 0x02, 0xAC, 0x8C, 0x72, 0x43, 0xDD, 0xA4, 0x15, 0x38, 0xD0, 0x12, 0x67, 0x2B, 0x68, 0x9D, 0x4F, 0x10, 0xF7, 0x6A, 0x14, 0xCD, 0x35, 0xF0, 0xEC, 0x2E, 0xFC, + 0xC7, 0x44, 0x0E, 0x8E, 0xF1, 0x8C, 0xB5, 0xAB, 0x8B, 0x43, 0xAF, 0x3C, 0x86, 0x3D, 0x9A, 0x11, 0x67, 0xCF, 0x8E, 0xB2, 0xCA, 0x26, 0xC3, 0x4E, 0x83, 0xF2, 0x7C, 0xC4, 0x20, 0x39, 0x93, 0x1B, + 0xCF, 0x29, 0xF8, 0xA8, 0xA3, 0xA5, 0x2F, 0xD0, 0x3B, 0x97, 0x0C, 0xA8, 0x33, 0x77, 0xE1, 0x9F, 0xE7, 0xC3, 0x97, 0x5B, 0x06, 0x17, 0xF5, 0x25, 0xD0, 0xA1, 0xFE, 0xBA, 0x90, 0xFD, 0x2F, 0xBD, + 0x90, 0x7A, 0x81, 0x12, 0x63, 0x65, 0x5D, 0x12, 0x40, 0xD9, 0x2B, 0x38, 0x47, 0xCF, 0x22, 0x58, 0x50, 0x21, 0xCF, 0x03, 0xDE, 0x6E, 0x8A, 0x7A, 0x55, 0xB6, 0x0D, 0xE0, 0xC5, 0xBE, 0x9B, 0x65, + 0xBF, 0xCA, 0xCC, 0xB8, 0x7E, 0x64, 0xD3, 0x85, 0x50, 0x0A, 0x04, 0xD5, 0x4D, 0x98, 0x89, 0x2E, 0x9F, 0x31, 0xB8, 0x9B, 0x8A, 0x63, 0xDB, 0xAC, 0x8F, 0x43, 0x41, 0xB6, 0xD4, 0x34, 0x84, 0x86, + 0x2C, 0x0C, 0x67, 0xA0, 0xD8, 0x64, 0x12, 0x37, 0x48, 0x08, 0x55, 0x51, 0x02, 0xD3, 0xDC, 0x67, 0xCF, 0xB9, 0xF4, 0x74, 0x09, 0x48, 0x75, 0x8E, 0xB0, 0xB9, 0xF3, 0x4C, 0xC4, 0x02, 0xDC, 0x64, + 0x83, 0xF6, 0xE8, 0xD1, 0x6B, 0xBB, 0x0C, 0x5D, 0x9E, 0xEC, 0xD5, 0x79, 0xA3, 0x41, 0x62, 0xDF, 0x1A, 0x45, 0x94, 0xD7, 0xC1, 0x62, 0xF8, 0x25, 0xD9, 0xAC, 0xB5, 0xEE, 0x22, 0x26, 0x95, 0x7B, + 0x88, 0x83, 0x1C, 0x32, 0x54, 0x26, 0x4C, 0x6C, 0x66, 0x8C, 0xB3, 0xB7, 0x14, 0xA0, 0x3E, 0x5D, 0xC3, 0x7A, 0x53, 0x3F, 0x49, 0xA0, 0xE9, 0x10, 0x14, 0x8A, 0xDA, 0x56, 0xB0, 0x24, 0x86, 0x89, + 0x5D, 0xBF, 0x2C, 0x86, 0x87, 0x31, 0xDB, 0x9E, 0x9A, 0xA6, 0x75, 0x36, 0xE6, 0xD2, 0xD8, 0xE2, 0x43, 0x8A, 0xB3, 0x97, 0xFD, 0x18, 0x41, 0x15, 0x5E, 0xE8, 0x14, 0x1C, 0xE1, 0xF7, 0x8A, 0x8A, + 0xE5, 0x06, 0x59, 0xDC, 0x8C, 0x3B, 0x27, 0x34, 0x64, 0x0A, 0xC4, 0xAA, 0xDE, 0xA6, 0x52, 0x09, 0xFB, 0xAE, 0xE7, 0xBF, 0xFC, 0xC0, 0xB4, 0xF1, 0x83, 0xE0, 0xF9, 0xB0, 0x33, 0x5F, 0x45, 0x83, + 0x07, 0x43, 0x75, 0x17, 0x76, 0x42, 0x30, 0xB8, 0x6B, 0x20, 0xD6, 0x24, 0x92, 0xE1, 0x0F, 0xAB, 0xCB, 0xDB, 0x1E, 0x87, 0x8E, 0xC0, 0xC6, 0xC3, 0xD7, 0x98, 0x76, 0x67, 0x34, 0xCE, 0x11, 0xD9, + 0xC7, 0x6E, 0xA0, 0x63, 0xE9, 0x7B, 0x93, 0xE9, 0xC4, 0x26, 0x90, 0x24, 0xD3, 0x86, 0x5C, 0x33, 0xEF, 0x87, 0x9F, 0x96, 0xC2, 0xD9, 0x08, 0xEB, 0xA9, 0x10, 0x37, 0x05, 0x29, 0xE0, 0x19, 0xCA, + 0xD3, 0x71, 0xA6, 0x53, 0x38, 0x05, 0x2A, 0x07, 0xD2, 0x2B, 0x75, 0xA1, 0x4D, 0xDE, 0x39, 0xF2, 0x25, 0xA0, 0x74, 0xDC, 0xB0, 0x67, 0xEE, 0x5C, 0x5D, 0x21, 0x69, 0x29, 0x55, 0xF3, 0xC5, 0xAA, + 0x61, 0xE1, 0x49, 0x72, 0x30, 0x31, 0x8C, 0x2A, 0xC4, 0x1B, 0x86, 0x17, 0x23, 0x72, 0x6D, 0x42, 0xC9, 0xB2, 0xD6, 0x12, 0x29, 0x60, 0x1A, 0x9D, 0x27, 0x45, 0x79, 0x77, 0xE4, 0xCF, 0x65, 0x46 }, + .t1_len = 1728, + .t1 = { 0xF9, 0x5F, 0x3F, 0xEE, 0x32, 0x04, 0xCC, 0xF1, 0x5D, 0xE5, 0x3E, 0x61, 0x29, 0xEC, 0xDA, 0xB5, 0xB5, 0x8C, 0xF5, 0xF9, 0xE7, 0xBD, 0x39, 0x77, 0x16, 0xE9, 0xD6, 0x4A, 0x2A, 0x19, 0x8D, 0xA4, + 0xF6, 0xE6, 0xC4, 0x2F, 0x9E, 0xF9, 0x45, 0x45, 0x2E, 0x9E, 0xF6, 0x6A, 0x45, 0xD8, 0x07, 0x7B, 0x57, 0x17, 0x71, 0xAA, 0x9E, 0xEC, 0xA7, 0x48, 0x50, 0x15, 0x17, 0xD5, 0x68, 0xF1, 0xA1, 0x3A, + 0x3C, 0x2A, 0xD9, 0x49, 0x27, 0x23, 0x20, 0xCA, 0x7E, 0xAA, 0x54, 0x4C, 0x82, 0x66, 0xAE, 0xC8, 0x8A, 0xA8, 0x54, 0x89, 0x52, 0x89, 0x6C, 0x19, 0xAC, 0xF8, 0xC8, 0x92, 0x5A, 0x86, 0xAC, 0xD2, + 0x02, 0x6F, 0xFE, 0xD2, 0x96, 0xA8, 0xF4, 0x44, 0x39, 0x89, 0xC2, 0x81, 0x96, 0xE6, 0x32, 0x23, 0x91, 0xCD, 0xEB, 0x44, 0x83, 0x11, 0x6D, 0x07, 0xBB, 0x4E, 0x4B, 0xBD, 0xAA, 0xAD, 0x05, 0xA6, + 0x04, 0x66, 0xAE, 0x1D, 0x96, 0x53, 0xEA, 0x23, 0x04, 0x4D, 0xEE, 0xF9, 0xC3, 0x45, 0xE3, 0x2D, 0xD6, 0xF6, 0xDA, 0x3E, 0xF7, 0x16, 0xD6, 0x7C, 0x20, 0xB8, 0xFA, 0x9C, 0xBA, 0x6C, 0xF7, 0xD4, + 0xFC, 0x3D, 0x7E, 0x6E, 0x76, 0xA5, 0x0D, 0x6A, 0xAB, 0x80, 0x81, 0x9F, 0x36, 0xFD, 0x48, 0xA3, 0xBA, 0xFD, 0xC8, 0x14, 0x6C, 0x85, 0x5C, 0x92, 0x06, 0xB8, 0xE8, 0xC2, 0x40, 0x52, 0x98, 0x43, + 0xC8, 0x37, 0xEE, 0x49, 0x79, 0x1C, 0xEA, 0x36, 0xEF, 0xA6, 0xA1, 0x1B, 0x45, 0x02, 0x06, 0x09, 0xD9, 0x6F, 0x02, 0x8E, 0x32, 0x21, 0xCE, 0x58, 0x55, 0x57, 0xF4, 0xDB, 0xAD, 0x58, 0x10, 0xC5, + 0xB2, 0x5E, 0xFA, 0x56, 0xE2, 0x4B, 0x0B, 0x95, 0xFE, 0xC7, 0x07, 0x06, 0xD9, 0xE0, 0xE2, 0xCC, 0x7C, 0xA9, 0x72, 0x41, 0xE5, 0xD8, 0x6D, 0x87, 0xBE, 0x9A, 0xD8, 0x67, 0xF9, 0xB3, 0x15, 0xC1, + 0x44, 0xF7, 0xE1, 0x3B, 0xBA, 0x7B, 0xAB, 0x04, 0x8A, 0x8A, 0x3B, 0xE4, 0x60, 0x56, 0x65, 0xD9, 0xDF, 0x4A, 0x1F, 0xA8, 0xC4, 0x14, 0x40, 0x76, 0x18, 0x40, 0xA7, 0xC5, 0xEB, 0x5A, 0xF8, 0x1C, + 0x70, 0x09, 0x5F, 0x08, 0xA1, 0xEB, 0x15, 0x44, 0x8E, 0x62, 0xC8, 0xCD, 0xF9, 0x73, 0xE4, 0xE9, 0x31, 0x7E, 0x00, 0xE4, 0x58, 0x92, 0xFA, 0xB2, 0xA2, 0xF8, 0xC4, 0x82, 0x74, 0xEB, 0xBD, 0xA6, + 0x4A, 0xD0, 0x89, 0x3D, 0x75, 0xDB, 0x79, 0x27, 0x58, 0xA5, 0x61, 0x89, 0x05, 0x36, 0xD3, 0x9E, 0x80, 0x43, 0x00, 0x12, 0xEF, 0x67, 0x54, 0x31, 0xF9, 0xC0, 0xC1, 0x63, 0xFF, 0x21, 0xBE, 0x80, + 0xF2, 0x73, 0xAB, 0x24, 0x2A, 0x13, 0x6E, 0x80, 0x3F, 0x44, 0x93, 0xC5, 0xDC, 0x56, 0x08, 0x77, 0xAB, 0x53, 0x8A, 0xA7, 0x22, 0x43, 0x82, 0x05, 0x40, 0xC9, 0x3B, 0x89, 0xE6, 0x6B, 0xB9, 0x6B, + 0xE8, 0xD7, 0x04, 0x33, 0xD3, 0x94, 0x20, 0x90, 0x8D, 0x82, 0x98, 0x30, 0xFD, 0x32, 0xDA, 0xB8, 0x84, 0x50, 0xE4, 0xBF, 0xAE, 0x20, 0x89, 0x35, 0x05, 0x08, 0x26, 0xF1, 0x43, 0x3E, 0x72, 0xAA, + 0xD2, 0x7E, 0xC6, 0x5F, 0x75, 0xEF, 0xBA, 0xB2, 0x64, 0x51, 0x80, 0x84, 0x7B, 0x72, 0xDD, 0x64, 0x11, 0x58, 0xDE, 0x07, 0xDE, 0x17, 0x26, 0xD6, 0x8F, 0xF6, 0x1A, 0xD4, 0x66, 0x20, 0x65, 0x74, + 0x89, 0x0A, 0x72, 0x78, 0x89, 0x61, 0xEA, 0x67, 0xD0, 0xC4, 0xAE, 0xDA, 0x41, 0x0E, 0x81, 0x0E, 0x67, 0xC7, 0x57, 0xFD, 0x23, 0x36, 0xFF, 0x8B, 0xB7, 0x2A, 0x76, 0x37, 0x03, 0xF9, 0x6B, 0x6A, + 0x58, 0x81, 0x60, 0x2D, 0x88, 0xBD, 0x06, 0x71, 0xD7, 0x8D, 0x44, 0xAF, 0x0A, 0xB8, 0x9C, 0x1F, 0x5D, 0xCC, 0x18, 0xD5, 0x27, 0x24, 0x8A, 0x83, 0x31, 0x5C, 0xD3, 0x36, 0x8A, 0x16, 0x80, 0x83, + 0x4C, 0xE0, 0x6F, 0x47, 0x22, 0x78, 0xC5, 0x5A, 0x33, 0x29, 0xF3, 0xA1, 0xFC, 0xC2, 0x98, 0x45, 0x51, 0x7A, 0x0E, 0xD2, 0x69, 0x2F, 0x54, 0x56, 0xCC, 0x60, 0x25, 0x5A, 0x66, 0xD3, 0x4C, 0x2D, + 0x24, 0x29, 0xFB, 0x7F, 0x78, 0xDB, 0x1B, 0xCC, 0xF1, 0xD2, 0x74, 0x09, 0xD7, 0x5F, 0xDF, 0xFF, 0xF3, 0x79, 0xE7, 0xC9, 0xC3, 0xAA, 0x52, 0xD9, 0xAA, 0xB3, 0xE6, 0x7E, 0xBE, 0xD8, 0x6F, 0x03, + 0xEE, 0xB4, 0x8D, 0x1B, 0xEC, 0x27, 0x1F, 0x12, 0x5C, 0x0E, 0x6A, 0xE6, 0x6D, 0x2A, 0xEC, 0x53, 0x59, 0x5B, 0x05, 0xB1, 0x93, 0x02, 0xD2, 0x28, 0x62, 0xE1, 0x49, 0x49, 0x02, 0x5B, 0x58, 0xA7, + 0x56, 0x6C, 0x2A, 0x15, 0xD2, 0xFB, 0x0B, 0xC6, 0x21, 0x31, 0x3A, 0x37, 0x08, 0x61, 0x01, 0x22, 0xDD, 0x28, 0xF6, 0x5C, 0xF1, 0x4F, 0xB1, 0x70, 0xD1, 0x13, 0xF5, 0xBF, 0x35, 0x75, 0xF6, 0xFE, + 0xBA, 0x1A, 0x00, 0xBB, 0x72, 0xB7, 0xCF, 0xB2, 0xDB, 0x8E, 0x45, 0x59, 0x28, 0xC3, 0x3A, 0xEC, 0xA5, 0x8F, 0x56, 0x9C, 0x57, 0xAF, 0xD4, 0xC8, 0x6A, 0x32, 0x32, 0xA7, 0x70, 0x8D, 0xFC, 0x19, + 0x7C, 0x8A, 0x40, 0x6B, 0xAC, 0x4F, 0xF0, 0x3B, 0x67, 0xA5, 0x17, 0x6C, 0x3D, 0xFA, 0x38, 0x9F, 0x3D, 0x08, 0x85, 0x31, 0x68, 0x2A, 0xDC, 0xDD, 0x95, 0x6C, 0xBB, 0x4D, 0x54, 0xAB, 0x77, 0x71, + 0xCE, 0x49, 0xAA, 0x1B, 0x39, 0x19, 0x0A, 0x3C, 0xD9, 0x82, 0x9E, 0x71, 0x2A, 0xD7, 0x61, 0xBC, 0x42, 0xAB, 0xA9, 0x03, 0x34, 0x39, 0xBC, 0x43, 0x45, 0xD3, 0xAF, 0xD4, 0xFE, 0x07, 0x8A, 0x3D, + 0x4A, 0xDA, 0x80, 0xEB, 0xCA, 0xCE, 0x4E, 0x92, 0x48, 0x25, 0x1D, 0x1F, 0xA4, 0x2F, 0x35, 0x61, 0xD3, 0x2E, 0x81, 0x36, 0x50, 0xA0, 0x3C, 0x44, 0x56, 0x90, 0xE4, 0x31, 0xF2, 0x3B, 0x7F, 0x90, + 0x44, 0xC4, 0xEE, 0x24, 0x4B, 0xAC, 0x25, 0xDD, 0x8C, 0x73, 0x49, 0xB4, 0x1A, 0x3E, 0xDC, 0x08, 0xC2, 0x00, 0x6E, 0x2A, 0xF8, 0xA9, 0x0E, 0x60, 0x67, 0xCB, 0x0D, 0xDC, 0x7A, 0x39, 0xDD, 0xE0, + 0x68, 0x2A, 0xE0, 0x79, 0x37, 0x31, 0xFD, 0x6F, 0x5F, 0x61, 0xBA, 0x91, 0xAE, 0xDF, 0x96, 0x30, 0xC6, 0x8C, 0x55, 0x58, 0xBB, 0xD4, 0xA2, 0x8C, 0x8F, 0xF3, 0x13, 0x93, 0xC4, 0x56, 0x46, 0xB6, + 0x96, 0x11, 0xF2, 0x0C, 0xF8, 0x12, 0x0F, 0xC2, 0xDB, 0xAC, 0x8D, 0x7D, 0xAA, 0xFE, 0x6B, 0xCF, 0xEC, 0x22, 0x5C, 0x41, 0xD5, 0x38, 0xA7, 0x25, 0x57, 0x47, 0xA5, 0x8D, 0xAF, 0x93, 0xB4, 0xEB, + 0x64, 0xCF, 0x72, 0x88, 0xFF, 0xE3, 0x49, 0x7D, 0xDB, 0x7B, 0x1F, 0xE2, 0x97, 0x89, 0x5B, 0x95, 0xBC, 0xF1, 0xC4, 0xD1, 0xE5, 0x7D, 0x1B, 0xD7, 0xA0, 0x3B, 0x20, 0xC7, 0x17, 0x0E, 0xAB, 0xB5, + 0x61, 0xF9, 0xFE, 0x1B, 0x6E, 0x75, 0x8F, 0x4C, 0x3A, 0xD2, 0xF6, 0x2C, 0x69, 0x90, 0xCF, 0x68, 0x56, 0xB0, 0x01, 0x8F, 0x68, 0xD0, 0x60, 0x87, 0xF1, 0xFA, 0xB1, 0x6A, 0x95, 0x80, 0xBB, 0x7B, + 0xC6, 0x15, 0xE5, 0x70, 0x27, 0xE9, 0x10, 0xC4, 0x16, 0xB0, 0x5D, 0xBB, 0x46, 0x68, 0xAC, 0xFC, 0xCE, 0x56, 0x9B, 0xCD, 0xD2, 0xBC, 0xE3, 0x00, 0xCF, 0x35, 0x75, 0x57, 0xE3, 0x7C, 0xBE, 0x2C, + 0xE8, 0x6D, 0xA1, 0x0A, 0x6A, 0x30, 0x97, 0xC6, 0x51, 0x6F, 0x0F, 0xA1, 0x01, 0x65, 0xB4, 0x0F, 0xD6, 0x03, 0x12, 0x4A, 0x6E, 0x01, 0xEB, 0x06, 0x17, 0x01, 0x2D, 0x6A, 0xC1, 0xA4, 0xC9, 0x0E, + 0xE8, 0xE3, 0x4C, 0x56, 0x7F, 0x1A, 0xC3, 0xCB, 0x7A, 0x98, 0xCC, 0xF1, 0xF5, 0x4F, 0x3C, 0x32, 0xCB, 0x7D, 0x24, 0xB0, 0x2E, 0x56, 0xFE, 0xBD, 0x15, 0x86, 0x63, 0x81, 0xE9, 0xF8, 0xE7, 0x68, + 0xCC, 0x6F, 0x75, 0xEB, 0x17, 0x57, 0x9F, 0x3D, 0xD8, 0x24, 0xE5, 0x54, 0xEF, 0xD4, 0xFF, 0x88, 0x8F, 0x6D, 0x3E, 0xED, 0xDD, 0xC9, 0x32, 0xFF, 0x89, 0xED, 0x78, 0x2A, 0x5D, 0xC9, 0xE2, 0xAB, + 0x7D, 0xEF, 0x35, 0x6A, 0x96, 0x49, 0xC4, 0x2B, 0x46, 0x4D, 0x79, 0x39, 0x78, 0x45, 0xE8, 0x95, 0x74, 0x6B, 0x78, 0x55, 0x15, 0x13, 0x20, 0xD8, 0x9D, 0xE7, 0x26, 0x75, 0xF7, 0x23, 0xBB, 0xDB, + 0xF4, 0xFD, 0x61, 0x39, 0x93, 0x7A, 0x38, 0x3C, 0xE1, 0x78, 0x60, 0xFE, 0xD9, 0xE2, 0x87, 0x20, 0x1B, 0x05, 0xA7, 0xB4, 0xAC, 0x59, 0x29, 0x8B, 0x00, 0x93, 0xA9, 0x80, 0xE4, 0x9F, 0x6E, 0x36, + 0x11, 0x13, 0xEE, 0xB3, 0xD5, 0x5A, 0x34, 0x9F, 0xBC, 0x12, 0xFA, 0xC0, 0x2D, 0x7B, 0xE4, 0xE2, 0x69, 0x02, 0x32, 0x73, 0x18, 0xD0, 0xBE, 0x03, 0xC5, 0xEF, 0xC1, 0xC7, 0xC3, 0x43, 0x53, 0xC3, + 0xF4, 0x3D, 0x24, 0x65, 0xFD, 0xAD, 0xD2, 0x9B, 0xAC, 0xD0, 0x0F, 0x3F, 0xA0, 0x27, 0x2B, 0x4F, 0x0F, 0xE1, 0x4C, 0xFC, 0x09, 0x0D, 0x4D, 0x7D, 0xE4, 0x27, 0xF7, 0xA4, 0x0A, 0xCC, 0xF8, 0x46, + 0x3B, 0x39, 0x87, 0xEE, 0x6F, 0x89, 0x22, 0x94, 0x48, 0x09, 0x1F, 0xF6, 0x9E, 0x98, 0xB8, 0x53, 0xFC, 0xF6, 0x82, 0xC2, 0x5A, 0x20, 0xDB, 0xA3, 0x1E, 0x59, 0x19, 0x2B, 0x3C, 0x2E, 0xF6, 0xC8, + 0xB5, 0x3A, 0x9F, 0x33, 0x7E, 0xB7, 0xF0, 0x09, 0x50, 0x94, 0x2F, 0x6E, 0x48, 0xD0, 0x4C, 0xA8, 0x53, 0x31, 0x4A, 0x40, 0x43, 0xE1, 0x6C, 0x32, 0x9E, 0xF4, 0xF1, 0xCE, 0xD5, 0x28, 0xBB, 0xF9, + 0xE6, 0x6F, 0x69, 0x42, 0xD6, 0x37, 0x20, 0x48, 0x0D, 0x2D, 0x96, 0xE2, 0x8D, 0xDA, 0xF2, 0x75, 0x64, 0x2F, 0x87, 0x62, 0xB1, 0xF0, 0xBF, 0x83, 0x43, 0x7E, 0x3B, 0xE1, 0x66, 0x40, 0x29, 0x6E, + 0xD9, 0x9B, 0xC5, 0x45, 0xF2, 0x2A, 0x12, 0x07, 0xCC, 0x93, 0xA5, 0x9C, 0x65, 0x06, 0xA8, 0xCF, 0x09, 0xC2, 0x75, 0xB0, 0x5C, 0xD0, 0xD0, 0x70, 0xD1, 0x02, 0xCE, 0x90, 0x0D, 0xE7, 0x09, 0xD9, + 0x7D, 0xC4, 0x38, 0x4D, 0xF1, 0x37, 0x38, 0x7D, 0x71, 0x1B, 0x34, 0x3B, 0xE9, 0x34, 0x33, 0xB7, 0xD9, 0x01, 0xC8, 0x1C, 0xE4, 0xDD, 0x33, 0x50, 0x34, 0x01, 0x18, 0xE9, 0x31, 0x73, 0x63, 0x16, + 0xD4, 0x02, 0x58, 0x34, 0x65, 0xA2, 0xED, 0x73, 0x3E, 0x41, 0x9C, 0x85, 0x26, 0xD3, 0x83, 0xA3, 0x0A, 0xB2, 0x6F, 0xF3, 0xA6, 0x44, 0x2F, 0x74, 0xBF, 0xF7, 0x92, 0xFC, 0x12, 0xBE, 0xA0, 0xD4, + 0x41, 0xAC, 0xB3, 0xA5, 0xE4, 0x6D, 0x0D, 0xD5, 0x80, 0xDB, 0x1C, 0xC4, 0x4A, 0x68, 0x19, 0x91, 0x86, 0xE3, 0x3B, 0xA5, 0xCD, 0x3B, 0xF6, 0x28, 0xDE, 0x88, 0x9D, 0x1E, 0x1B, 0x80, 0xF7, 0xDB, + 0xFE, 0x28, 0x9B, 0x11, 0xF6, 0x69, 0x1B, 0xB9, 0x5A, 0x3D, 0x17, 0xD5, 0x09, 0xAE, 0x61, 0x3E, 0x81, 0x35, 0xC8, 0x5F, 0x08, 0x08, 0xAB, 0x58, 0xD3, 0x01, 0x89, 0xF5, 0x6D, 0x69, 0x93, 0x2A, + 0x17, 0xD8, 0x74, 0xF5, 0x34, 0x96, 0xE7, 0x33, 0x66, 0x4F, 0x60, 0xE7, 0xED, 0xEE, 0x32, 0x41, 0xC4, 0x10, 0x2B, 0x10, 0xF0, 0x53, 0xBB, 0xD6, 0xCF, 0x92, 0xC4, 0xD7, 0x90, 0xE9, 0x04, 0x97, + 0xDF, 0xF2, 0x22, 0x5E, 0x57, 0x8A, 0x02, 0x31, 0xD7, 0x89, 0xBF, 0x8F, 0x38, 0x15, 0x19, 0x04, 0xB1, 0xCB, 0x12, 0xE1, 0x40, 0x91, 0xAF, 0x26, 0x71, 0xF5, 0x5E, 0x99, 0x8E, 0xF1, 0x83, 0x0E, + 0x69, 0x39, 0x5D, 0x4B, 0x12, 0xEF, 0xA3, 0x3F, 0x30, 0x91, 0xD9, 0xEE, 0x09, 0xE6, 0xD1, 0x2E, 0x0B, 0x8B, 0x36, 0xEE, 0xCF, 0xEA, 0xE6, 0x27, 0x5C, 0x16, 0x00, 0x3A, 0x08, 0xE2, 0xB5, 0x00, + 0x19, 0xAD, 0x1A, 0x57, 0xBD, 0x13, 0x13, 0x70, 0xA7, 0x4D, 0xAA, 0x06, 0x88, 0x85, 0x69, 0x00, 0xF9, 0x04, 0x6E, 0x31, 0xFB, 0xCD, 0x72, 0xFF, 0xF6, 0x2A, 0x66, 0xFD, 0x13, 0x2E, 0x26, 0x70, + 0xF2, 0xF8, 0xFB, 0x69, 0x91, 0x26, 0x9F, 0x69, 0xE7, 0x5C, 0x9A, 0x18, 0x40, 0x99, 0x1D, 0x43, 0x3B, 0xF9, 0x02, 0xAE, 0xD6, 0x87, 0x3F, 0x56, 0x11, 0xF8, 0xCA, 0x2E, 0x02, 0x99, 0x8E, 0x15, + 0x66, 0xF4, 0x50, 0x3E, 0xB1, 0xCB, 0x12, 0x60, 0x51, 0x2C, 0xE1, 0xF0, 0x85, 0x9C, 0xED, 0xCD, 0xFC, 0x56, 0x15, 0x65, 0xD3, 0x2B, 0xF7, 0xDC, 0xE1, 0xCB, 0x30, 0xF9, 0x07, 0x54, 0x73, 0xC6, + 0x22, 0x1E, 0x28, 0xD0, 0x85, 0x75, 0xB0, 0x42, 0x8F, 0x66, 0x63, 0x9F, 0x76, 0x06, 0xB0, 0x78, 0x25, 0x05, 0x5A, 0xBA, 0xE8, 0x17, 0xCD, 0x67, 0xAF, 0x4E, 0xD7, 0x59, 0x57, 0x3D, 0xF0, 0x51, + 0x02, 0x88, 0x79, 0xA1, 0x73, 0x0E, 0x89, 0x87, 0x55, 0x69, 0xD7, 0xFA, 0x12, 0x0F, 0x81, 0x80, 0xB9, 0x04, 0x95, 0x82, 0x93, 0x42, 0x8A, 0xF8, 0x9B, 0x9C, 0x96, 0x15, 0x2C, 0x40, 0x87, 0x81, + 0x2F, 0xDE, 0x74, 0x4F, 0x42, 0x41, 0x70, 0x5C, 0x85, 0x8A, 0x71, 0xB0, 0x0E, 0x66, 0xDA, 0xD4, 0x0F, 0xCF, 0x62, 0xB2, 0x23, 0x70, 0xFF, 0x6B, 0xAE, 0xA8, 0xF5, 0x18, 0x70, 0x78, 0x17, 0x75 }, + .msg_len = 2442, + .msg = { 0xAC, 0xB4, 0x14, 0xEB, 0x55, 0xAE, 0x5E, 0x49, 0x10, 0x7B, 0xD0, 0xAC, 0x59, 0x75, 0x54, 0x4F, 0x83, 0x10, 0x4F, 0x72, 0x64, 0x49, 0x5A, 0xE0, 0xBF, 0x0A, 0x6D, 0x95, 0x94, 0xC4, 0x22, 0xC1, + 0x6B, 0x99, 0x46, 0x9E, 0xCC, 0xDF, 0xE8, 0xB8, 0x00, 0x08, 0x75, 0xB4, 0x69, 0x30, 0x98, 0x91, 0xEA, 0x42, 0x58, 0x6A, 0x61, 0x5D, 0x14, 0x6D, 0xE6, 0x4F, 0xE5, 0x92, 0x77, 0xA6, 0x16, 0x31, + 0xB2, 0xC7, 0xF7, 0x37, 0x9C, 0xD5, 0x2F, 0xAB, 0x38, 0x71, 0xBA, 0xDE, 0x12, 0x0E, 0xE9, 0x55, 0x8D, 0x14, 0x79, 0xA9, 0x19, 0x25, 0x63, 0x45, 0x78, 0xCF, 0x14, 0xD3, 0x5D, 0xF3, 0xB5, 0x67, + 0x2F, 0x8B, 0x5F, 0x9F, 0x95, 0x6F, 0xA9, 0xF7, 0x48, 0x9D, 0x6E, 0x37, 0xE2, 0x07, 0xFE, 0x55, 0x60, 0x17, 0x73, 0x6F, 0x6B, 0x14, 0x7A, 0x8C, 0xF6, 0x64, 0xD0, 0xE0, 0x52, 0x1D, 0x94, 0x73, + 0x7E, 0x18, 0x18, 0x8A, 0x1B, 0x7C, 0x30, 0x29, 0x6C, 0xCC, 0x90, 0x67, 0xE7, 0xB5, 0x5D, 0x6E, 0x0F, 0x2F, 0xBD, 0x87, 0x5F, 0x42, 0xFE, 0xFE, 0xCA, 0xC4, 0x95, 0x10, 0xE3, 0x24, 0x96, 0x8B, + 0x07, 0x37, 0x2D, 0xEB, 0x10, 0xA3, 0x1C, 0x58, 0x54, 0x57, 0xE0, 0xC4, 0x88, 0x79, 0xCE, 0x44, 0xBC, 0x78, 0x89, 0x8E, 0xCE, 0xFA, 0xC7, 0xBC, 0xEE, 0x90, 0xD0, 0xF8, 0x92, 0x5D, 0xF2, 0xB5, + 0x2D, 0x5A, 0xC8, 0x16, 0x92, 0xE0, 0x16, 0x0F, 0x8F, 0xD5, 0x80, 0x86, 0x45, 0x49, 0x84, 0x28, 0x26, 0x0F, 0x59, 0x2E, 0x29, 0xBB, 0x90, 0xFC, 0xB0, 0x7D, 0x04, 0x24, 0xEC, 0x79, 0xFB, 0x08, + 0x18, 0x40, 0xCB, 0x82, 0x7C, 0xAA, 0x4A, 0x9D, 0x56, 0x21, 0x83, 0xD1, 0x0E, 0xE4, 0x1D, 0x28, 0x1E, 0x26, 0xCE, 0x3E, 0xC0, 0x06, 0x9C, 0x83, 0xE1, 0xE4, 0x46, 0xEF, 0x82, 0xE2, 0xE3, 0x0D, + 0xEB, 0xE3, 0xF4, 0x09, 0xE0, 0xA9, 0xE6, 0xD1, 0x55, 0x0E, 0x22, 0x4D, 0xB1, 0x5D, 0xBD, 0xDA, 0x44, 0x34, 0x1E, 0x4E, 0xD6, 0xF8, 0xB8, 0x98, 0x47, 0x16, 0xCA, 0x87, 0x23, 0x31, 0x97, 0x52, + 0x85, 0x47, 0xD0, 0x90, 0x05, 0x86, 0x07, 0xCA, 0x14, 0x14, 0x24, 0xA1, 0x31, 0x45, 0xF1, 0xE8, 0x96, 0x55, 0x52, 0x88, 0xC5, 0xE2, 0x87, 0x7A, 0xB3, 0xB5, 0x1C, 0x7F, 0x92, 0x48, 0xD2, 0xD5, + 0x6A, 0x85, 0x21, 0x97, 0x5B, 0xC4, 0xEA, 0xE3, 0xD0, 0x09, 0x98, 0x8C, 0xBD, 0x73, 0xC6, 0x69, 0x31, 0xBA, 0xDA, 0x07, 0x25, 0xFB, 0x8A, 0x34, 0x48, 0xD4, 0x3E, 0x0C, 0x73, 0x64, 0xE9, 0x49, + 0x4F, 0xC4, 0xE2, 0x95, 0xA7, 0x00, 0xE7, 0x99, 0x72, 0xE1, 0xFF, 0xD6, 0x26, 0xD1, 0xCB, 0xE0, 0x19, 0x99, 0x17, 0x85, 0x16, 0x38, 0xB1, 0x92, 0xEF, 0x9F, 0x5C, 0x03, 0x22, 0x3F, 0x2B, 0xBD, + 0x67, 0xEB, 0x59, 0xA5, 0xE8, 0xBA, 0xEC, 0x3D, 0xB4, 0x06, 0x16, 0x93, 0x82, 0x74, 0x20, 0x1D, 0xEA, 0x1A, 0xE6, 0x40, 0xF6, 0xEE, 0x7E, 0x04, 0x7C, 0xC4, 0xC1, 0x3F, 0x80, 0xDC, 0x65, 0xE3, + 0xFC, 0xB5, 0xC6, 0x23, 0x86, 0x01, 0x5F, 0x4E, 0xF1, 0xBF, 0xEC, 0x56, 0x1E, 0x12, 0x1F, 0x9B, 0xFA, 0x9B, 0x20, 0x75, 0xBC, 0x1C, 0x47, 0x30, 0x50, 0x3F, 0xDD, 0x5D, 0xEB, 0xCE, 0x8A, 0x53, + 0x5E, 0xCA, 0x01, 0xB9, 0xD5, 0xB0, 0x21, 0xC2, 0x90, 0x85, 0x4B, 0x5F, 0x3D, 0x49, 0xEF, 0xFB, 0x26, 0x3D, 0xDA, 0x34, 0xC4, 0xE9, 0x6A, 0xEA, 0xE9, 0xE7, 0x1A, 0x68, 0x6C, 0x00, 0x9B, 0x20, + 0x59, 0x94, 0xB4, 0x6C, 0xFD, 0xF1, 0xF7, 0x67, 0x27, 0xCA, 0x67, 0xD4, 0x15, 0xB9, 0xD2, 0x1D, 0x54, 0x31, 0x2C, 0xDC, 0x6A, 0x8E, 0xD0, 0xAE, 0xAB, 0x96, 0xB5, 0x80, 0xD0, 0xB4, 0x19, 0xE2, + 0x05, 0x8E, 0x5D, 0x84, 0x3C, 0x17, 0xC9, 0x6D, 0x15, 0x65, 0x49, 0x96, 0x2F, 0x81, 0xC2, 0x66, 0x23, 0x3E, 0xD2, 0xB7, 0x95, 0xFA, 0xC4, 0x0B, 0x19, 0x92, 0xB6, 0x26, 0x45, 0x7F, 0x21, 0x1F, + 0x08, 0x10, 0x6A, 0xD8, 0x6F, 0x57, 0x02, 0xB9, 0xDE, 0xB9, 0x32, 0x3A, 0x09, 0x70, 0xAD, 0x86, 0x12, 0x5E, 0xCA, 0x83, 0x6E, 0x0A, 0x3D, 0x6C, 0xCB, 0xC3, 0x80, 0xD4, 0x74, 0x04, 0x9B, 0xD9, + 0x6E, 0xA2, 0x46, 0xB8, 0xBD, 0x95, 0x42, 0x79, 0x3A, 0x66, 0xE1, 0x5B, 0x31, 0x9A, 0xEC, 0xE6, 0xBE, 0xE1, 0x7A, 0xDB, 0xBA, 0x7D, 0xB3, 0x37, 0xD2, 0x5F, 0x8F, 0x64, 0x27, 0x74, 0x03, 0x0A, + 0x2F, 0xF9, 0x69, 0xCB, 0x56, 0x71, 0xF5, 0x99, 0x01, 0xCB, 0x10, 0x9E, 0x66, 0x1E, 0x55, 0xFD, 0x5E, 0x75, 0xEB, 0x2A, 0x96, 0xDC, 0x37, 0xFE, 0xC7, 0x6A, 0x82, 0xEB, 0x89, 0xD0, 0x20, 0xB4, + 0x91, 0x62, 0x71, 0xCF, 0xB0, 0xCB, 0x33, 0x42, 0x49, 0x4F, 0xDB, 0x62, 0xEA, 0x0D, 0x25, 0x3F, 0xB8, 0xFF, 0x2E, 0x91, 0x35, 0x7B, 0x33, 0xD9, 0x6D, 0x41, 0x53, 0x0B, 0x8B, 0x5E, 0x95, 0x50, + 0xFE, 0x9B, 0x3F, 0x9F, 0x34, 0xFD, 0x5A, 0x2A, 0x1A, 0x6A, 0x8B, 0xEB, 0x93, 0xCC, 0xC3, 0x22, 0x62, 0x2F, 0x3B, 0x5E, 0x84, 0x87, 0xDE, 0x19, 0xAF, 0x57, 0xCB, 0xD1, 0x48, 0x1A, 0xCE, 0x02, + 0x77, 0x9A, 0xD9, 0x28, 0xB1, 0x7A, 0x9B, 0x05, 0xCB, 0xEB, 0x72, 0x2C, 0x78, 0x3B, 0x08, 0x8B, 0x59, 0x12, 0xC2, 0xD6, 0x7C, 0xE5, 0x07, 0x3F, 0x18, 0x01, 0xC2, 0x31, 0x70, 0xDE, 0xB1, 0xEB, + 0x6D, 0xDF, 0xFC, 0x4C, 0x33, 0xDD, 0x25, 0xF9, 0x4F, 0x4F, 0xBE, 0x59, 0xD7, 0x04, 0xE4, 0x78, 0xFB, 0x49, 0xDD, 0x21, 0x42, 0x80, 0x1C, 0x37, 0xED, 0x8F, 0x53, 0x9E, 0xC1, 0x78, 0x2E, 0xBD, + 0x2F, 0x32, 0x53, 0xBB, 0xE1, 0x9C, 0x5A, 0x04, 0x8B, 0x9E, 0xF4, 0x18, 0x24, 0xA8, 0x11, 0x11, 0x9F, 0x3A, 0x6A, 0xD2, 0xA0, 0xD4, 0xB7, 0x73, 0x38, 0xE0, 0x01, 0x35, 0x8C, 0x61, 0xA9, 0x79, + 0x45, 0x72, 0xB0, 0xC4, 0x6E, 0xB1, 0xE0, 0xE5, 0x75, 0xD4, 0xDA, 0x14, 0x1A, 0x41, 0x58, 0x29, 0xBA, 0x87, 0x12, 0xB7, 0x91, 0xB6, 0x25, 0xB1, 0xB0, 0xEA, 0x84, 0x0E, 0xE7, 0x45, 0xD9, 0xFF, + 0xE1, 0xE9, 0x9E, 0xFD, 0x78, 0x2B, 0xA2, 0x58, 0x59, 0x35, 0x1F, 0x44, 0x36, 0x54, 0x99, 0x51, 0x02, 0xCB, 0xEF, 0xAD, 0x7E, 0x59, 0xD0, 0x3C, 0x9A, 0x50, 0x2E, 0xD7, 0xB7, 0x71, 0x44, 0xD0, + 0x56, 0x6E, 0x4B, 0xFA, 0xC0, 0x86, 0xA7, 0xDE, 0xA3, 0x56, 0xCB, 0x9E, 0x5A, 0xC0, 0x2D, 0xBF, 0x7E, 0x81, 0xD6, 0xCE, 0xED, 0x4A, 0x33, 0xDA, 0x8D, 0x80, 0x1D, 0x61, 0xBA, 0xB5, 0xC0, 0x1F, + 0x25, 0x9E, 0xE3, 0xA9, 0x9F, 0xF7, 0xF6, 0xD7, 0xBF, 0x8F, 0x21, 0x60, 0xC4, 0xBC, 0x3F, 0x89, 0x07, 0x36, 0x07, 0x4B, 0x00, 0x0C, 0x4C, 0x58, 0xFA, 0x46, 0x15, 0x88, 0x0F, 0x93, 0xFA, 0xD4, + 0x3D, 0x56, 0x57, 0xC7, 0x60, 0x45, 0xD7, 0xC4, 0x14, 0xE6, 0xB8, 0x5F, 0x63, 0xAA, 0xC9, 0x1F, 0x04, 0xA6, 0x16, 0x18, 0x4E, 0x04, 0xFF, 0x9A, 0xAD, 0x51, 0x3B, 0xA7, 0x67, 0x21, 0x5F, 0xB0, + 0x33, 0x1A, 0x36, 0x9D, 0x36, 0xC0, 0xAE, 0x9B, 0x1E, 0xC1, 0x26, 0x8F, 0x1D, 0x0B, 0x43, 0xC4, 0x2B, 0x78, 0x6D, 0xB2, 0x3D, 0xD6, 0x64, 0x65, 0xB3, 0xAF, 0x17, 0xFF, 0xC6, 0x8C, 0x67, 0x96, + 0x4C, 0x2F, 0xC9, 0xE4, 0x1E, 0xAB, 0xC4, 0x5D, 0xB6, 0x8C, 0xD2, 0xC3, 0xD9, 0x5B, 0x8B, 0xEC, 0x78, 0x7D, 0x99, 0x4B, 0xB8, 0xE9, 0xCF, 0x1D, 0xD7, 0xD4, 0xC5, 0x63, 0xFC, 0xA5, 0xD8, 0x0B, + 0x3F, 0x1F, 0xE8, 0xE3, 0xC7, 0xBF, 0xB7, 0xD1, 0x71, 0xF5, 0xB9, 0x02, 0x3B, 0xFB, 0xCC, 0x0C, 0xF4, 0x37, 0x1B, 0x63, 0xC8, 0x56, 0xED, 0xBD, 0xA1, 0x54, 0xB4, 0x31, 0x3C, 0x47, 0x98, 0x3F, + 0x40, 0x27, 0xF9, 0xE6, 0x1E, 0x86, 0xDA, 0x1E, 0x8C, 0xD7, 0x87, 0xE3, 0xE6, 0xB5, 0x0E, 0x1D, 0xFC, 0x92, 0x01, 0xB9, 0xAB, 0x92, 0x05, 0x9F, 0x8B, 0x6D, 0x1B, 0xF7, 0x85, 0x6C, 0xD5, 0x5C, + 0x5B, 0x1D, 0x6C, 0x4E, 0x6E, 0xBF, 0x81, 0x8D, 0x48, 0x1C, 0x56, 0xF6, 0x6C, 0x79, 0x44, 0x4F, 0x5A, 0x65, 0x44, 0xA6, 0x4A, 0x7D, 0x78, 0xEA, 0xD3, 0x3E, 0xB8, 0x05, 0xA6, 0xAC, 0x43, 0x10, + 0xCD, 0x46, 0xA2, 0x33, 0x1E, 0x70, 0x7B, 0x9B, 0x09, 0x50, 0xCA, 0x12, 0x09, 0x24, 0x02, 0xD6, 0x8C, 0x1C, 0xC5, 0xC3, 0xF2, 0x69, 0xDF, 0xDB, 0x13, 0xAB, 0x34, 0xB9, 0x7E, 0xAB, 0x50, 0xB0, + 0x74, 0x5B, 0xE7, 0x2B, 0xB0, 0xFD, 0x2D, 0x73, 0xBE, 0xA5, 0xDD, 0x37, 0x80, 0x23, 0x93, 0xB6, 0x35, 0xE4, 0x2A, 0x0D, 0xEF, 0x85, 0x44, 0xA9, 0x6E, 0x7F, 0x40, 0xA8, 0xD9, 0xD0, 0x6B, 0x64, + 0xE3, 0x8D, 0xC4, 0x06, 0xBD, 0x59, 0xAC, 0x5C, 0x4E, 0x21, 0x85, 0x91, 0xD2, 0x0B, 0x8D, 0xBA, 0x21, 0x25, 0x97, 0x80, 0x96, 0x51, 0x7E, 0xC5, 0xC0, 0x3F, 0x9B, 0xC6, 0xF9, 0x6C, 0xB2, 0x55, + 0xE2, 0x16, 0xEF, 0x82, 0xD7, 0xC7, 0xC8, 0x73, 0x02, 0x9F, 0x9E, 0x1D, 0x98, 0xEB, 0xC0, 0xD8, 0xE1, 0x31, 0x2B, 0x84, 0xB8, 0xD0, 0x2E, 0x8D, 0x68, 0x0A, 0xA5, 0x6A, 0x50, 0x6C, 0x86, 0x68, + 0xB5, 0xB9, 0xC5, 0x6D, 0x04, 0xCF, 0x68, 0xE3, 0x7C, 0x7C, 0xB1, 0xB9, 0x37, 0x7C, 0x86, 0x72, 0x40, 0xCD, 0x42, 0xFC, 0x7F, 0xBD, 0xE0, 0xAC, 0x44, 0xE3, 0xDC, 0xCF, 0xD3, 0xF8, 0x77, 0xC9, + 0x92, 0x3A, 0xE9, 0xCE, 0xCE, 0x0C, 0xBD, 0xAB, 0x00, 0xCA, 0x53, 0x0F, 0x43, 0x4A, 0x33, 0xF1, 0xC9, 0x39, 0xFB, 0x88, 0xAD, 0xEF, 0x4D, 0x12, 0xAC, 0xBD, 0x8B, 0x2B, 0x5A, 0x13, 0x9A, 0x3F, + 0xB7, 0x76, 0xD8, 0x22, 0x3A, 0x98, 0x46, 0x46, 0x5C, 0x03, 0x72, 0xB8, 0xC3, 0x23, 0x3F, 0xB5, 0x28, 0x0E, 0x93, 0x6B, 0xBE, 0x9F, 0xD4, 0x90, 0x58, 0x96, 0x14, 0x63, 0xA4, 0x41, 0x9D, 0x93, + 0x9F, 0x4F, 0x1F, 0xEA, 0x70, 0x5E, 0xB6, 0x31, 0x14, 0xF0, 0xA3, 0x53, 0x36, 0x38, 0xDC, 0x4D, 0x3E, 0xFD, 0x62, 0x01, 0x47, 0x77, 0x0A, 0xD8, 0x77, 0xE2, 0x35, 0x42, 0x99, 0xCE, 0xC6, 0xE5, + 0xC1, 0x89, 0x24, 0xE7, 0x8D, 0xD6, 0x61, 0x69, 0x7A, 0xDF, 0x89, 0xA7, 0x7C, 0x73, 0x65, 0x52, 0x2D, 0x3E, 0x8F, 0xC0, 0x85, 0x51, 0x87, 0x13, 0x9F, 0x7E, 0x43, 0xE9, 0xA0, 0x62, 0x9E, 0xE3, + 0x21, 0xB2, 0xCB, 0xD9, 0xF0, 0x07, 0xB0, 0x5C, 0x22, 0xEF, 0xF5, 0x6F, 0xE4, 0x80, 0x45, 0x68, 0x6B, 0x36, 0xC5, 0xBA, 0xC2, 0x26, 0x7F, 0x37, 0xA2, 0xE3, 0xD4, 0xE0, 0x3E, 0x19, 0xB1, 0xE4, + 0x22, 0xAC, 0xEA, 0x31, 0xC2, 0xE9, 0xF3, 0xE7, 0x54, 0x19, 0x76, 0xD4, 0xE2, 0xFA, 0x03, 0x11, 0x9D, 0xF9, 0xC4, 0xCC, 0x2D, 0x54, 0x18, 0xF0, 0xFC, 0x7A, 0x46, 0x7C, 0xD9, 0x8E, 0x29, 0x06, + 0x95, 0xB9, 0x53, 0x0B, 0x91, 0xD5, 0xDF, 0x8C, 0x62, 0x6C, 0x72, 0x36, 0xA5, 0xC0, 0xFB, 0xA7, 0x35, 0x78, 0xB9, 0xA4, 0x74, 0x91, 0xCA, 0x0A, 0xD2, 0x6A, 0x14, 0x4B, 0x0F, 0x23, 0xEC, 0x23, + 0xD2, 0xC5, 0xB2, 0xDA, 0xA0, 0x3B, 0xF4, 0x01, 0x30, 0xF1, 0x4B, 0x9A, 0x42, 0x7C, 0xDF, 0xF1, 0xF2, 0x32, 0xC9, 0xCF, 0x02, 0x42, 0x62, 0x28, 0xC5, 0x70, 0xCF, 0x1F, 0xA7, 0xC0, 0x0A, 0x77, + 0x3B, 0xC0, 0xD7, 0x08, 0x58, 0x58, 0x85, 0x42, 0xBB, 0xF8, 0xF5, 0x81, 0x54, 0x08, 0x70, 0x89, 0x7B, 0xFA, 0xC8, 0x38, 0x7C, 0xBB, 0xA3, 0x41, 0x6A, 0x84, 0x6C, 0xF9, 0xF4, 0xF5, 0xD3, 0xF9, + 0xDC, 0xED, 0xD0, 0x80, 0xCC, 0x0D, 0xE9, 0xF7, 0x1B, 0x93, 0x82, 0x8B, 0x83, 0x54, 0x30, 0x89, 0x8E, 0x82, 0x89, 0x6C, 0xD3, 0xF3, 0x0F, 0xE2, 0xAF, 0x83, 0x49, 0xDB, 0x29, 0x4F, 0xB2, 0xA8, + 0xFF, 0xC0, 0x84, 0x86, 0x92, 0xA0, 0xB9, 0xE8, 0xA6, 0x6E, 0xBB, 0xFC, 0x0F, 0x89, 0x6F, 0x8D, 0x03, 0xE3, 0xC6, 0xA0, 0xC2, 0x7E, 0x0F, 0x21, 0x77, 0xB8, 0x5A, 0x2F, 0x6F, 0xE3, 0x1E, 0x8A, + 0xAF, 0x14, 0xEA, 0x5C, 0x1F, 0xDC, 0x54, 0xE8, 0x0C, 0xDE, 0x47, 0xAE, 0x27, 0xA1, 0x61, 0x26, 0x46, 0x80, 0x10, 0x70, 0x23, 0xCF, 0xFA, 0x96, 0x1E, 0x91, 0x3C, 0x4E, 0x6A, 0xF9, 0x6C, 0x0B, + 0xE3, 0x7A, 0xD8, 0x59, 0xC3, 0x34, 0xCD, 0xB8, 0xBB, 0xEE, 0xCB, 0x54, 0x43, 0x66, 0x27, 0x39, 0xD0, 0x27, 0xEF, 0x1B, 0x95, 0x35, 0xA5, 0xA4, 0x6E, 0x21, 0x69, 0x93, 0x3E, 0x41, 0x94, 0x54, + 0x02, 0x56, 0x23, 0xFD, 0x67, 0x79, 0xF5, 0x4C, 0x62, 0x2E, 0xF8, 0x1A, 0xB9, 0x28, 0x9B, 0x50, 0x75, 0x8E, 0xA3, 0x4F, 0x86, 0x8E, 0xC8, 0x5A, 0xEE, 0x58, 0x9B, 0x08, 0x96, 0x2B, 0x85, 0xCF, + 0x53, 0x7B, 0xC7, 0x33, 0xF6, 0x2A, 0xAF, 0xA9, 0x5F, 0xD8, 0x1A, 0x60, 0xD5, 0xC2, 0xE3, 0x8D, 0x6E, 0xA0, 0xDF, 0x7D, 0x13, 0x90, 0xBC, 0x50, 0x50, 0xE2, 0x46, 0x3E, 0x3E, 0x2E, 0x3A, 0x76, + 0x9D, 0xE2, 0xA9, 0x4A, 0xBD, 0xED, 0xFA, 0x0E, 0xD6, 0x7C, 0xC0, 0xFF, 0xAF, 0xC5, 0xA0, 0x5A, 0x3B, 0x0F, 0xD3, 0x7B, 0xBE, 0x69, 0x67, 0xBE, 0xD8, 0xDE, 0xBF, 0x02, 0xA4, 0x2C, 0xDC, 0x80, + 0xBD, 0xC6, 0x21, 0x58, 0xE1, 0x84, 0xFD, 0xB6, 0x67, 0x2F, 0x79, 0x47, 0x50, 0x5E, 0x2C, 0x0A, 0x6C, 0x77, 0x62, 0xB1, 0x14, 0x5C, 0x4B, 0xAF, 0x30, 0xE3, 0xD3, 0x24, 0x34, 0xD2, 0x27, 0x07, + 0x04, 0x4D, 0xC9, 0x9D, 0x2C, 0xF2, 0xD3, 0x8F, 0x15, 0xC4, 0x3A, 0xBC, 0x86, 0x32, 0x38, 0x2B, 0xBB, 0xC9, 0xE0, 0xF1, 0x06, 0x56, 0x59, 0x06, 0xF7, 0xD4, 0x94, 0x8D, 0x30, 0xFB, 0x19, 0xED, + 0xCC, 0x37, 0x48, 0x10, 0x03, 0x97, 0xF7, 0x1E, 0x15, 0x48, 0xE5, 0x8A, 0x5A, 0x01, 0x87, 0x6D, 0x0A, 0x12, 0xDC, 0xC8, 0x00, 0x00, 0x22, 0x42, 0x21, 0xC4, 0xAB, 0xD9, 0x8A, 0x50, 0x22, 0x50, + 0x6D, 0x24, 0xBF, 0x4D, 0x9B, 0x91, 0x08, 0x99, 0x1A, 0xD3, 0x42, 0x1D, 0x4A, 0xB9, 0xCC, 0x39, 0x3D, 0xCB, 0x8D, 0x74, 0x4F, 0x97, 0x82, 0x2F, 0x95, 0xCB, 0xB2, 0x64, 0x0E, 0x73, 0xE4, 0x01, + 0xF0, 0x44, 0xFE, 0x20, 0x25, 0x3A, 0xCB, 0x8B, 0x32, 0xA7, 0x5F, 0xED, 0xA6, 0x40, 0xE1, 0x90, 0x45, 0x4B, 0xAB, 0x69, 0x5A, 0x23, 0xB1, 0x4A, 0xE3, 0xEF, 0x60, 0xB0, 0x04, 0x91, 0xAB, 0x22, + 0xF6, 0x22, 0xDA, 0xA8, 0x9B, 0x6B, 0x2E, 0x6D, 0x18, 0xE7, 0x35, 0x67, 0x2F, 0xE0, 0xEB, 0x2D, 0xE2, 0x69, 0xE4, 0xE3, 0x86, 0xC9, 0x26, 0xE2, 0x3B, 0x86, 0x5E, 0x1B, 0xA2, 0x2D, 0xDA, 0x68, + 0x82, 0x93, 0xDE, 0x14, 0x41, 0x02, 0xF7, 0x03, 0x0F, 0xDE, 0x6D, 0xF6, 0x53, 0xE4, 0x10, 0x6C, 0x08, 0xC2, 0x46, 0x7A, 0xD7, 0xC5, 0x4D, 0x1D, 0xF0, 0xDC, 0x59, 0x81, 0x00, 0x48, 0x76, 0xC6, + 0xBA, 0xA8, 0x72, 0x0F, 0x70, 0x94, 0x27, 0x00, 0xA1, 0x54, 0xA3, 0x76, 0xC8, 0xD4, 0x5D, 0xAE, 0x1B, 0xE7, 0x49, 0x10, 0x14, 0x8E, 0xE3, 0xF2, 0x73, 0x3E, 0x59, 0x1E, 0x19, 0x65, 0xFE, 0x76, + 0x3B, 0x58, 0xC8, 0xB2, 0x8A, 0xF2, 0x5E, 0x9B, 0x3C, 0x63, 0x3A, 0xBD, 0x83, 0xF1, 0xC0, 0xA4, 0xF6, 0x8D, 0xA2, 0xE0, 0xB8, 0x50, 0x83, 0xBF, 0x97, 0xD4, 0xE9, 0x19, 0x34, 0x0C, 0x04, 0x37, + 0xA6, 0x04, 0x41, 0x6C, 0x4F, 0x62, 0x9B, 0x33, 0x03, 0x9B, 0xBF, 0x2A, 0x1F, 0x56, 0x15, 0x48, 0x32, 0x17, 0x80, 0x41, 0x1D, 0x2E, 0x8A, 0xC0, 0xED, 0xAE, 0x76, 0xFC, 0x3A, 0x19, 0xF3, 0xC8, + 0x4C, 0x3B, 0xE9, 0x02, 0xA1, 0xE8, 0x4F, 0xDF, 0x69, 0xB1, 0x1A, 0x12, 0xDC, 0x8B, 0x78, 0xEF, 0x25, 0x7B, 0x5F, 0xBB, 0x5D, 0x92, 0x3F, 0xFD, 0x54, 0x84, 0x51, 0xA5, 0x2C, 0x6A, 0x3A, 0xF3, + 0x1C, 0x70, 0x26, 0x6A, 0xE8, 0xA9, 0x57, 0xB2, 0xBD, 0x72, 0xA5, 0x1A, 0x03, 0x4A, 0x29, 0x21, 0xB8, 0xE1, 0x93, 0x21, 0x10, 0x8A, 0xC3, 0x03, 0xB0, 0xD2, 0xE2, 0x69, 0xD0, 0x32, 0xC3, 0xDB, + 0x13, 0xF2, 0x1D, 0x55, 0x8C, 0x82, 0xBA, 0x41, 0x58, 0x96, 0x2F, 0x22, 0x10, 0xE1, 0xC5, 0xFD, 0xD9, 0x6C, 0x98, 0xD6, 0x63, 0x9A, 0xA8, 0x44, 0xF3, 0x4E, 0x40, 0xC1, 0xB9, 0xC9, 0x09, 0xCC, + 0x6A, 0xF1, 0xE9, 0x7A, 0x8D, 0xC8, 0x3B, 0x78, 0xC7, 0x2B, 0x30, 0xB7, 0xAE, 0x40, 0x0F, 0x44, 0xCA, 0x60, 0xAF, 0x37, 0x77, 0x0B, 0x3D, 0x91, 0x47, 0xF7, 0xD6, 0xF5, 0xA3, 0x27, 0xF3, 0x4D, + 0xF7, 0xCB, 0x88, 0x91, 0xE7, 0x1D, 0x41, 0xD7, 0x23, 0xCB, 0x18, 0xE0, 0xDD, 0x32, 0x4E, 0x5C, 0xD2, 0x2A, 0xE0, 0xD9, 0xF2, 0xB1, 0xD2, 0xBF, 0xCE, 0xD0, 0x28, 0x8B, 0x7A, 0xA7, 0x3A, 0xF4, + 0xFE, 0x0A, 0x81, 0x81, 0xBA, 0x1A, 0xA7, 0xEA, 0xE9, 0x66, 0xD0, 0xA2, 0x40, 0xE1, 0x0F, 0xE5, 0x73, 0x5D, 0x98, 0x32, 0x6A, 0x10, 0x6D, 0x16, 0xDC, 0x49, 0xF3, 0xFD, 0xB1, 0x9D, 0x3A, 0x84, + 0x49, 0xC5, 0x6A, 0x74, 0x15, 0x36, 0x55, 0x60, 0x0E, 0x4C, 0x9E, 0x38, 0xD3, 0x02, 0xC6, 0xD4, 0x08, 0x00, 0x17, 0xD9, 0x3C, 0x62, 0x83, 0x88, 0xDF, 0x94, 0x86, 0x03, 0x29, 0xBA, 0xA2, 0x89, + 0xEF, 0xA4, 0x58, 0x7F, 0x07, 0x9C, 0x6F, 0x03, 0xFA, 0x03, 0xC5, 0x45, 0x40, 0xA0, 0xAB, 0x4B, 0x06, 0x7E, 0xE4, 0x6A, 0x5A, 0x34, 0x6F, 0x2F, 0xBB, 0xFF, 0x65, 0x70, 0xED, 0x01, 0x66, 0xA5, + 0x5C, 0x25, 0x8E, 0xAB, 0xD6, 0x2A, 0xD9, 0x0F, 0x06, 0x0F, 0xAD, 0xE8, 0x4E, 0x8F, 0xAC, 0x79, 0x9F, 0x79, 0x28, 0x28, 0x5F, 0x58, 0x55, 0x7A, 0x72, 0xE0, 0x55, 0xB5, 0x35, 0xD0, 0x0B, 0xD9, + 0xA4, 0x88, 0x0D, 0x10, 0xC0, 0x5C, 0x07, 0xCF, 0xE7, 0xA6, 0xFE, 0xAD, 0xFC, 0xDE, 0xD8, 0x80, 0x52, 0x18, 0x03, 0xE3, 0x39, 0xF6, 0xEA, 0xE3, 0xFF, 0x28, 0xA0, 0xA4, 0x71, 0xA0, 0x03, 0x35, + 0x8F, 0x95, 0x23, 0x20, 0xF4, 0x1A, 0x0A, 0xEF, 0x9D, 0x28 }, + .sig_len = 3366, + .sig = { 0xE3, 0x56, 0xC5, 0x7E, 0x58, 0x56, 0x1F, 0xB9, 0x28, 0x54, 0x04, 0x00, 0xEA, 0x85, 0x91, 0x25, 0x01, 0xC3, 0x07, 0xA3, 0x5E, 0x51, 0x97, 0xD0, 0x48, 0xB4, 0xBB, 0xCB, 0x4D, 0x64, 0xC4, 0x76, + 0x2F, 0x3D, 0xD8, 0x93, 0x5D, 0x3F, 0xE0, 0x36, 0x42, 0x76, 0x76, 0x8E, 0xEF, 0x98, 0xE2, 0x50, 0x4F, 0xA5, 0x80, 0xE1, 0x74, 0x63, 0x84, 0xD4, 0x31, 0x51, 0x9A, 0x1B, 0xCE, 0x85, 0xEA, 0x99, + 0x45, 0xA8, 0x53, 0xC7, 0xFB, 0x8A, 0x8E, 0xC0, 0x87, 0x78, 0xF4, 0x0D, 0xD2, 0xE7, 0x56, 0x66, 0x9F, 0x57, 0x56, 0x28, 0xF9, 0x9F, 0x6E, 0xC0, 0x6B, 0x21, 0xDA, 0xB2, 0x09, 0x3B, 0xD3, 0x78, + 0xEA, 0x1A, 0x6A, 0xA6, 0xBA, 0xB8, 0x90, 0x31, 0x8C, 0xAD, 0xD4, 0xC3, 0xE6, 0xEE, 0xEE, 0xF6, 0x36, 0xC5, 0xB3, 0x8E, 0x9A, 0xF2, 0x96, 0x38, 0x8C, 0x31, 0x33, 0x79, 0x6D, 0x6E, 0x34, 0x59, + 0x26, 0xA0, 0x76, 0x1C, 0x45, 0x98, 0x1F, 0xD7, 0x7A, 0x83, 0x4D, 0xC2, 0x99, 0x60, 0xB0, 0xF7, 0xD6, 0x23, 0xD2, 0xB6, 0xDB, 0xB0, 0xCE, 0x1A, 0xC7, 0x75, 0xDE, 0xD5, 0x74, 0x6E, 0xC9, 0xE4, + 0xAE, 0x29, 0x97, 0xFF, 0xCA, 0xFD, 0xF4, 0xFF, 0xA6, 0x5C, 0x0E, 0xC4, 0xE9, 0x67, 0xFE, 0x73, 0x60, 0x1F, 0x32, 0xDC, 0x56, 0x0E, 0x9F, 0x89, 0x1C, 0xE4, 0xCC, 0xE5, 0xB1, 0x86, 0xD4, 0x36, + 0x81, 0x2B, 0x3F, 0xB5, 0xFA, 0x93, 0xDF, 0x58, 0xCA, 0xB7, 0xD9, 0x66, 0x1A, 0x8A, 0x92, 0x68, 0x03, 0x98, 0x53, 0x45, 0xCA, 0x34, 0x02, 0x69, 0x08, 0x4C, 0xD7, 0xDE, 0xCA, 0x8D, 0x33, 0x6B, + 0x42, 0xA6, 0x88, 0xF4, 0x0B, 0x85, 0x7C, 0xAE, 0x9A, 0x37, 0xC8, 0xD4, 0x04, 0x94, 0x5C, 0xA9, 0x24, 0x83, 0xAA, 0xFC, 0x07, 0xA5, 0xDA, 0xB0, 0x69, 0x8E, 0x4D, 0x19, 0x80, 0x91, 0xC3, 0x4C, + 0xF7, 0xDD, 0x59, 0x4B, 0xC2, 0xAA, 0x63, 0xE5, 0xA4, 0x48, 0xAA, 0xC4, 0xE9, 0xB8, 0xC2, 0xA1, 0xDB, 0xB3, 0x71, 0x7E, 0xFD, 0x7D, 0xB0, 0xDF, 0x44, 0x09, 0xF5, 0xF0, 0x10, 0xC0, 0xB3, 0xE3, + 0x7F, 0xE9, 0xBC, 0x6C, 0xE0, 0x76, 0x03, 0xA8, 0x6B, 0xB2, 0x73, 0x92, 0x9F, 0x30, 0x05, 0xCA, 0x18, 0xB6, 0xE7, 0xD4, 0x8D, 0x34, 0x4B, 0xF6, 0x81, 0x2A, 0x6D, 0x34, 0x47, 0xBD, 0x3E, 0xF1, + 0xD1, 0x3F, 0x56, 0xBA, 0x47, 0x3B, 0x84, 0xD1, 0xDB, 0xB1, 0xAA, 0x48, 0x9E, 0x84, 0xC3, 0x57, 0x79, 0x07, 0xA0, 0x4D, 0x5D, 0xEE, 0x13, 0x4B, 0xFF, 0x8B, 0x18, 0x2C, 0xBE, 0x11, 0x10, 0x37, + 0x0C, 0x08, 0xD7, 0x3D, 0x5B, 0x2C, 0x7D, 0x63, 0xA4, 0x1E, 0x32, 0x45, 0x6A, 0x1B, 0xFD, 0x51, 0xE7, 0xC6, 0xD7, 0x91, 0x73, 0xD8, 0x39, 0x0F, 0x8B, 0x44, 0x85, 0xF1, 0xF2, 0x2F, 0x82, 0x36, + 0x65, 0x5A, 0xA4, 0x96, 0xC6, 0x4A, 0xDB, 0xA4, 0xA7, 0xB3, 0xB3, 0x34, 0xC6, 0x23, 0x7E, 0x1C, 0xAF, 0x2E, 0xEC, 0xBF, 0xE7, 0x86, 0x41, 0x71, 0x4C, 0xBF, 0x4C, 0x0E, 0xB8, 0xC9, 0x5F, 0x8D, + 0xDE, 0x86, 0x5D, 0xC5, 0x2A, 0x42, 0x0A, 0x1E, 0x64, 0x04, 0x9B, 0x06, 0x9A, 0xDB, 0x19, 0xDF, 0xAB, 0x56, 0x6D, 0x5B, 0xE8, 0x0D, 0x38, 0xDC, 0xF8, 0x49, 0xAE, 0x83, 0xBB, 0xAC, 0x02, 0x9D, + 0x65, 0xBB, 0x53, 0xAE, 0x15, 0x5E, 0x4F, 0x38, 0x05, 0x41, 0x69, 0x8C, 0xD3, 0x0F, 0xDB, 0x90, 0x3F, 0x89, 0xFB, 0xF1, 0x55, 0xE1, 0xD2, 0xE3, 0x7C, 0xC3, 0xF0, 0x87, 0xCA, 0xC6, 0xFD, 0x24, + 0x7A, 0xBE, 0xEF, 0xE0, 0xD6, 0x2A, 0xA2, 0xC1, 0xC3, 0xAA, 0x30, 0xAF, 0x56, 0x87, 0x59, 0xDB, 0x20, 0xD4, 0x91, 0xE1, 0x61, 0x13, 0xC9, 0xDB, 0xA2, 0x49, 0x59, 0x72, 0x70, 0x0E, 0xA9, 0x94, + 0xB2, 0x14, 0x69, 0xFD, 0xCA, 0xC0, 0x17, 0x8B, 0x27, 0xAD, 0x88, 0xAD, 0xA6, 0xDF, 0x9B, 0x34, 0xD9, 0x7E, 0xC3, 0xE5, 0xA5, 0xDE, 0x23, 0xE8, 0x2F, 0x47, 0xF5, 0x49, 0x6A, 0x62, 0x23, 0x2C, + 0x93, 0x55, 0xAA, 0x6C, 0x93, 0x5E, 0xA1, 0x88, 0x68, 0x9B, 0xBF, 0x09, 0xBB, 0x94, 0xDE, 0x69, 0x64, 0x30, 0xBA, 0xBB, 0xB5, 0xE8, 0x2B, 0xF4, 0x4B, 0x63, 0x0E, 0x3F, 0xFA, 0xD7, 0x76, 0xC0, + 0x50, 0x77, 0x37, 0x3B, 0x4B, 0x03, 0x78, 0x61, 0xCD, 0x51, 0x51, 0xC9, 0xF6, 0xAA, 0xDD, 0xEE, 0xBD, 0x1A, 0x06, 0x65, 0x38, 0xE3, 0x6E, 0xD2, 0xF7, 0x90, 0x1C, 0xF3, 0xB6, 0xB8, 0x4A, 0x21, + 0x4F, 0x1E, 0x28, 0x43, 0xF4, 0xE9, 0x09, 0x9B, 0x11, 0x3E, 0x90, 0x6E, 0x3B, 0xA0, 0x1A, 0xA7, 0xA3, 0x19, 0x33, 0xA3, 0x6D, 0x08, 0xA1, 0x01, 0x04, 0x2C, 0x40, 0xCF, 0x26, 0x8B, 0xE5, 0x8E, + 0xE7, 0x11, 0x28, 0xAF, 0x92, 0x18, 0x66, 0xAE, 0xA9, 0xD0, 0x2D, 0x6C, 0x48, 0xAA, 0xCC, 0x75, 0x18, 0xA9, 0x44, 0x4C, 0x57, 0x36, 0x9D, 0x24, 0x37, 0x85, 0x7C, 0x18, 0x3D, 0xBB, 0x61, 0xB9, + 0x5D, 0x83, 0x92, 0xF3, 0x7B, 0x4D, 0xF6, 0x2C, 0xCA, 0x19, 0x1A, 0xD8, 0x01, 0x95, 0xEA, 0x30, 0xEC, 0x7D, 0xE7, 0x1E, 0x9A, 0xC5, 0x30, 0x6A, 0xD7, 0x01, 0x5F, 0xAA, 0xA5, 0xB3, 0x5D, 0xA1, + 0xFD, 0xF2, 0xF8, 0x4B, 0xC3, 0xDF, 0x79, 0xB7, 0x9A, 0x5F, 0x85, 0x3B, 0x12, 0xE0, 0x4A, 0x64, 0x89, 0xB5, 0x02, 0x94, 0x62, 0xE2, 0x08, 0xB1, 0x58, 0x0C, 0x2D, 0x8E, 0xB7, 0x6D, 0x99, 0x73, + 0xD4, 0x8B, 0x60, 0xD6, 0x49, 0x60, 0xC2, 0xD5, 0x6E, 0xCA, 0xBF, 0xFE, 0xF3, 0x6B, 0x2B, 0xC8, 0xA7, 0xF5, 0xFA, 0x1E, 0xB9, 0x4A, 0xE3, 0xC4, 0x91, 0x42, 0x20, 0x41, 0xBE, 0x74, 0x2E, 0x69, + 0x74, 0x32, 0x55, 0xB8, 0xE8, 0xF0, 0x30, 0xA7, 0x84, 0xCC, 0xD4, 0x8E, 0x6D, 0x1B, 0xB0, 0x81, 0x8B, 0x7D, 0xE7, 0xCE, 0x51, 0x9D, 0x53, 0x91, 0xA5, 0xE1, 0x07, 0x96, 0x12, 0x4B, 0xE3, 0xD5, + 0xDE, 0x83, 0xD6, 0xBE, 0x88, 0x7C, 0x19, 0x94, 0x56, 0x82, 0x61, 0xD4, 0xD8, 0x34, 0xA8, 0xAF, 0x85, 0xB2, 0xB6, 0x94, 0x15, 0x77, 0xF8, 0x6A, 0x36, 0x7E, 0x53, 0x0A, 0x27, 0x94, 0xDF, 0xEF, + 0x14, 0xC3, 0x20, 0x8C, 0xC7, 0xC6, 0xD7, 0x06, 0x4E, 0x3B, 0xC7, 0x82, 0x66, 0x41, 0xB8, 0xB4, 0xAA, 0xC4, 0x5E, 0xE2, 0x81, 0x80, 0xF9, 0x97, 0x79, 0xC3, 0x6B, 0x31, 0x40, 0xB8, 0xB4, 0x24, + 0x11, 0x18, 0x1C, 0x26, 0xA5, 0xC2, 0x29, 0xFD, 0xEB, 0x68, 0xC1, 0x3E, 0xFB, 0x87, 0x03, 0x9C, 0x01, 0x0E, 0xA8, 0xDC, 0xE2, 0xF0, 0xD9, 0x9E, 0xE5, 0xF9, 0x49, 0xDA, 0xCB, 0x4D, 0x1A, 0x8D, + 0x98, 0x3A, 0xE3, 0x07, 0x87, 0x3F, 0xB7, 0x21, 0x4A, 0x94, 0x6E, 0x12, 0x75, 0x0E, 0x88, 0xE8, 0x7C, 0xB0, 0xD6, 0x04, 0x27, 0x9B, 0x45, 0xF3, 0x39, 0x57, 0x3C, 0x3D, 0xE4, 0x15, 0x96, 0x20, + 0xDA, 0x63, 0x3D, 0x07, 0xBB, 0xAE, 0xE7, 0x87, 0x45, 0xC2, 0x42, 0x4B, 0xCA, 0x1A, 0x62, 0x4F, 0x8E, 0x1B, 0xA0, 0xC7, 0x3E, 0x92, 0x84, 0x32, 0xDB, 0x99, 0x22, 0xDA, 0xC4, 0x03, 0x70, 0x5C, + 0x8A, 0x2A, 0x19, 0x7F, 0x26, 0x87, 0x27, 0x9C, 0x83, 0x56, 0x88, 0x0C, 0xC2, 0x9F, 0xE5, 0xB2, 0x7B, 0xA8, 0x82, 0xF4, 0xBE, 0x58, 0x21, 0x4A, 0x55, 0xF3, 0x7A, 0x82, 0xDB, 0x0D, 0x47, 0xB7, + 0xFF, 0xFD, 0x84, 0xD0, 0x5C, 0x89, 0x43, 0xB9, 0x21, 0x26, 0xDA, 0x61, 0x3F, 0x24, 0xB6, 0x89, 0x44, 0x78, 0x74, 0xD1, 0x5C, 0x16, 0x06, 0xCA, 0x5B, 0xE7, 0x2D, 0x10, 0x52, 0x65, 0xA1, 0x7D, + 0x0B, 0x53, 0xF3, 0x54, 0x5C, 0xD9, 0x24, 0xA4, 0xEA, 0x3C, 0xFA, 0xCD, 0xDD, 0x4A, 0x06, 0xCE, 0xE7, 0x38, 0x7B, 0x92, 0x6E, 0x42, 0xCB, 0xB6, 0x34, 0xEC, 0x96, 0xB3, 0x97, 0x55, 0x6D, 0x06, + 0x30, 0xCD, 0x7C, 0x3F, 0xA8, 0xB4, 0xA5, 0xAF, 0xC6, 0x7B, 0x8B, 0x23, 0x3C, 0xD4, 0xD6, 0x77, 0x1D, 0x7E, 0x73, 0x2A, 0x40, 0xD4, 0xBB, 0x1A, 0x5B, 0xB0, 0xF3, 0x55, 0x38, 0x6E, 0x71, 0x80, + 0x5F, 0x1D, 0xD3, 0xD0, 0x44, 0xC4, 0x3C, 0xE2, 0xCE, 0x33, 0x4B, 0x6C, 0x81, 0xE8, 0x4A, 0xD8, 0x5B, 0xE8, 0x25, 0xB0, 0x5C, 0x56, 0x36, 0xC0, 0x49, 0xBA, 0x7F, 0x62, 0x2D, 0xFD, 0x0A, 0x98, + 0x29, 0x40, 0x03, 0xAB, 0x87, 0xB1, 0x4F, 0x8E, 0x30, 0x1C, 0xDF, 0xA5, 0x83, 0xDD, 0x2A, 0x89, 0x16, 0x32, 0x0A, 0x58, 0x0C, 0xB2, 0x7A, 0xC4, 0x02, 0x53, 0xAA, 0x28, 0x64, 0x50, 0xEA, 0x19, + 0x45, 0x3D, 0x34, 0x89, 0xE2, 0x84, 0x18, 0x17, 0xC7, 0x8F, 0x90, 0xA8, 0x54, 0x74, 0xDE, 0x21, 0x39, 0x5E, 0xC4, 0x41, 0x58, 0x30, 0x60, 0x68, 0x5F, 0xA9, 0xEC, 0x74, 0x37, 0x08, 0xE2, 0x75, + 0xC6, 0x82, 0x67, 0xC6, 0xD6, 0x8C, 0xF3, 0xCA, 0x03, 0x47, 0x63, 0x82, 0x06, 0x6D, 0xFA, 0xDF, 0x48, 0x2E, 0xD9, 0x57, 0xE5, 0x34, 0x75, 0x24, 0x26, 0xAA, 0x78, 0x85, 0xD1, 0x36, 0x12, 0xE3, + 0x48, 0x7E, 0xD1, 0x5C, 0xBB, 0xC4, 0x54, 0x07, 0x98, 0x79, 0x7C, 0xC3, 0x33, 0x05, 0xE3, 0x08, 0x71, 0xDC, 0xAC, 0x0C, 0x8E, 0x83, 0x8C, 0x3F, 0x0F, 0xF0, 0x25, 0x59, 0x40, 0xC8, 0xC6, 0xBF, + 0xE9, 0x27, 0x93, 0xE5, 0xBA, 0x8B, 0x61, 0x54, 0xAE, 0xCD, 0x07, 0x1F, 0x45, 0xCE, 0x0B, 0x63, 0x71, 0x8C, 0x52, 0xAC, 0x0F, 0xD0, 0xDC, 0x74, 0x9F, 0x4A, 0xD2, 0x63, 0x4F, 0xFF, 0x15, 0xE2, + 0xB8, 0x0D, 0xA0, 0x94, 0xDE, 0x03, 0xC7, 0xBF, 0x1E, 0xA6, 0xD7, 0xC8, 0x01, 0x77, 0x5A, 0x1F, 0x9A, 0xD7, 0x88, 0x8A, 0xC0, 0x91, 0x13, 0xD8, 0xE6, 0xD9, 0x40, 0x95, 0xA3, 0x92, 0x3C, 0x48, + 0xE7, 0x4B, 0x3C, 0x84, 0x88, 0xDC, 0x64, 0xDA, 0x8D, 0xDC, 0x21, 0x1B, 0x76, 0x0E, 0xEC, 0x33, 0x8D, 0x65, 0x89, 0x74, 0x65, 0x18, 0x6D, 0xE3, 0x1C, 0x5D, 0xAC, 0x92, 0x52, 0x3F, 0xF7, 0x7A, + 0xC1, 0x1B, 0xFE, 0xC3, 0xDA, 0xBD, 0x40, 0x6D, 0x33, 0x5B, 0x24, 0x47, 0x85, 0x6B, 0x37, 0xD2, 0x18, 0xF2, 0xDC, 0x59, 0x10, 0x33, 0xBF, 0x2F, 0x5B, 0x73, 0x8F, 0xE7, 0xE8, 0xDC, 0x5F, 0x7A, + 0x50, 0x64, 0x7C, 0xA0, 0x8B, 0xC4, 0x53, 0xAB, 0x21, 0x41, 0xB4, 0x02, 0x8F, 0x37, 0x6B, 0x03, 0xE9, 0xC9, 0x51, 0x36, 0xA5, 0x70, 0x5F, 0xAC, 0xB6, 0x25, 0xDD, 0x0B, 0x73, 0xC9, 0xE8, 0xA5, + 0x37, 0x1E, 0x00, 0x4B, 0x70, 0x9D, 0x66, 0x55, 0x48, 0x10, 0x73, 0x61, 0xAA, 0x67, 0x9E, 0x3D, 0x96, 0x47, 0xBD, 0x08, 0x35, 0x41, 0xE6, 0x15, 0x8A, 0x75, 0xC5, 0xFB, 0x8E, 0xE7, 0x4C, 0x84, + 0xE0, 0x30, 0xAE, 0x57, 0xC9, 0x3D, 0x03, 0x82, 0xF0, 0xA3, 0xD2, 0x53, 0x3F, 0x75, 0x0B, 0xC0, 0xC5, 0xD1, 0xF3, 0x51, 0x27, 0x05, 0x8F, 0x5A, 0x38, 0xF8, 0xC1, 0x82, 0x7A, 0x2E, 0x96, 0x92, + 0xEF, 0x65, 0x65, 0x2F, 0xD9, 0x31, 0x5A, 0x41, 0x0B, 0x5E, 0x46, 0x27, 0xFA, 0x08, 0x87, 0x39, 0xA9, 0xA4, 0x81, 0x43, 0xA1, 0xB7, 0x45, 0xF1, 0x8B, 0x98, 0xE9, 0xDC, 0x4C, 0x95, 0x48, 0x22, + 0xB9, 0xC1, 0xBE, 0x35, 0x28, 0xA9, 0xE5, 0x8C, 0x19, 0x92, 0x40, 0xCF, 0x16, 0x68, 0xBF, 0x5A, 0xFC, 0xAD, 0x02, 0x0F, 0x51, 0xD0, 0x8A, 0x31, 0xB6, 0x80, 0xDF, 0x75, 0x72, 0x18, 0x3B, 0x28, + 0xA4, 0x13, 0x2D, 0x5A, 0x0F, 0x7A, 0x7D, 0xBE, 0x6A, 0xCE, 0x9B, 0xD8, 0x50, 0xC9, 0x4B, 0x13, 0x5C, 0x0C, 0x94, 0x61, 0xA0, 0xCC, 0x23, 0xE3, 0xD8, 0x82, 0xD6, 0x16, 0x71, 0x7F, 0x04, 0x6B, + 0x7A, 0x75, 0x85, 0x5C, 0x23, 0x2B, 0x36, 0x58, 0x00, 0x86, 0x4A, 0x4C, 0xF6, 0x92, 0xD8, 0xA5, 0xE0, 0x61, 0x80, 0x22, 0x83, 0x0B, 0xAE, 0x71, 0xA3, 0x38, 0x94, 0x7F, 0xFE, 0xCA, 0xC0, 0xCA, + 0x85, 0xE2, 0x89, 0x43, 0x33, 0xDC, 0xA6, 0x21, 0x81, 0x83, 0x82, 0x0A, 0x06, 0x86, 0x81, 0xA7, 0x11, 0xAC, 0x3A, 0x08, 0x08, 0xDB, 0xA9, 0x09, 0x38, 0x20, 0x15, 0xE6, 0x8C, 0x03, 0xBA, 0xFC, + 0x34, 0x07, 0xE2, 0x3E, 0x4C, 0xE8, 0x8F, 0x0F, 0x90, 0xFF, 0x59, 0x2F, 0x0F, 0xCC, 0x90, 0xDB, 0x58, 0x31, 0x8E, 0xE9, 0xB4, 0x4B, 0xD6, 0x32, 0x10, 0xD3, 0x2F, 0xFB, 0x68, 0x4B, 0xA6, 0x4C, + 0x4B, 0xB0, 0x19, 0x8C, 0x54, 0x27, 0x1C, 0x5A, 0xA3, 0x6E, 0xF1, 0x09, 0x53, 0x51, 0x1C, 0x90, 0x32, 0xDD, 0x6F, 0x12, 0x8B, 0x48, 0x90, 0xB6, 0xA3, 0x0E, 0x89, 0x3A, 0x3C, 0xE1, 0xA9, 0xD2, + 0xE8, 0x12, 0x0B, 0x44, 0x10, 0x9B, 0x1E, 0x61, 0xCF, 0x5C, 0xD0, 0x49, 0x3B, 0x31, 0xC2, 0x60, 0x2C, 0xD3, 0xFC, 0x95, 0x19, 0x6C, 0x91, 0xD0, 0xF4, 0x63, 0x60, 0x05, 0xC2, 0x59, 0xC3, 0x5B, + 0xDB, 0x2D, 0x6B, 0x64, 0x58, 0xD4, 0xCF, 0x3A, 0x0B, 0x99, 0xB5, 0x51, 0x9B, 0xF4, 0x14, 0xA3, 0x53, 0x11, 0xAC, 0x71, 0x7C, 0xC6, 0x3F, 0x92, 0xB4, 0x69, 0xB3, 0x72, 0x28, 0xFA, 0xEE, 0x3D, + 0x41, 0x3B, 0xCB, 0x4A, 0x2B, 0x1A, 0x97, 0x7D, 0x5B, 0x1C, 0x4B, 0x22, 0x4C, 0xB4, 0xAE, 0x3D, 0xF1, 0x33, 0x62, 0x9F, 0xA9, 0x3B, 0xA9, 0xBC, 0x23, 0x85, 0x2D, 0x4D, 0x4B, 0xE7, 0x17, 0x87, + 0x68, 0x30, 0x32, 0xA3, 0x4E, 0x1A, 0x9E, 0xD5, 0xF8, 0xD3, 0x97, 0x77, 0xFF, 0xCB, 0x71, 0xE7, 0x97, 0x77, 0x46, 0x88, 0xF3, 0x23, 0x00, 0x9D, 0x74, 0xB8, 0x76, 0x77, 0x79, 0xE3, 0x5E, 0xBB, + 0x51, 0x14, 0xB0, 0x48, 0x58, 0x89, 0x6B, 0x93, 0xA5, 0x86, 0x3E, 0xC5, 0xB1, 0x98, 0x41, 0x5E, 0xA0, 0xCD, 0x63, 0x6B, 0x18, 0xE3, 0xDF, 0x2C, 0x09, 0x48, 0xF7, 0x26, 0x3C, 0x33, 0x9C, 0xA3, + 0x36, 0x95, 0x15, 0xC2, 0x9C, 0x34, 0x4B, 0xC4, 0xF6, 0x7B, 0xB3, 0x2D, 0x9B, 0x92, 0xAD, 0x91, 0x44, 0x30, 0x28, 0x0E, 0x23, 0xF5, 0x4C, 0xCC, 0xE8, 0xCC, 0xE9, 0x6B, 0xF2, 0x06, 0x1F, 0x0C, + 0xA4, 0xD7, 0x7A, 0x18, 0xF5, 0xBB, 0xEF, 0xF2, 0xF3, 0x67, 0x31, 0xD7, 0x53, 0xFF, 0xD4, 0x2B, 0x6B, 0x13, 0x5E, 0x59, 0xAE, 0x6A, 0x0D, 0x59, 0xB9, 0xA0, 0x6A, 0xFB, 0xF5, 0x0D, 0xEE, 0x98, + 0x7C, 0x64, 0xD6, 0xB4, 0xE3, 0xA8, 0xB5, 0x77, 0xF0, 0x84, 0xC3, 0x89, 0x88, 0x45, 0xCD, 0x8B, 0xAE, 0x9D, 0x0F, 0x12, 0x3A, 0x71, 0x98, 0xB8, 0xA7, 0xF1, 0x12, 0x1C, 0x96, 0xE1, 0x02, 0xAB, + 0x66, 0x8E, 0x46, 0xF0, 0xD3, 0x54, 0x73, 0xE3, 0x5D, 0xD4, 0x2D, 0xA7, 0xAC, 0xA5, 0x0B, 0x3A, 0x57, 0x01, 0x66, 0xAE, 0xFE, 0xDB, 0x88, 0x82, 0x47, 0x70, 0x25, 0x9F, 0xCD, 0x93, 0xD9, 0xB1, + 0x88, 0xF5, 0x28, 0xD0, 0x18, 0x9A, 0xAB, 0x2D, 0x2C, 0x14, 0x84, 0x04, 0x63, 0xE1, 0x48, 0xBE, 0x4E, 0x28, 0xE5, 0xF1, 0x39, 0x28, 0x5B, 0xA9, 0x41, 0xF8, 0xAF, 0xC3, 0x3F, 0x51, 0xDF, 0x2B, + 0xBE, 0xB9, 0x5B, 0xA2, 0x56, 0x0D, 0xD0, 0x80, 0x0E, 0xC7, 0x5A, 0x8C, 0x82, 0xA0, 0xFC, 0x4D, 0x5E, 0x61, 0xA4, 0x84, 0x3A, 0xE4, 0xE8, 0xBD, 0xEF, 0x02, 0x83, 0xE4, 0xE6, 0x1B, 0x5D, 0x11, + 0x2D, 0x68, 0xCB, 0xE3, 0xEA, 0x13, 0x5B, 0xC9, 0x78, 0x73, 0xDE, 0xC4, 0xE6, 0x09, 0x88, 0xC3, 0xB3, 0x64, 0x05, 0x57, 0xAF, 0x18, 0xE8, 0x7A, 0xA4, 0xA2, 0xE8, 0x24, 0xE1, 0x21, 0x53, 0x93, + 0x6B, 0x32, 0x2E, 0xB1, 0x38, 0xC9, 0x37, 0x41, 0x3F, 0x81, 0xAC, 0xA1, 0xDF, 0xFD, 0x2E, 0x3A, 0xC5, 0xBE, 0xB9, 0x6E, 0x3D, 0x03, 0x89, 0xA0, 0xAF, 0x18, 0xFC, 0xBD, 0x24, 0x0E, 0x58, 0xB8, + 0xFE, 0x36, 0xF7, 0x92, 0x74, 0x9A, 0xE6, 0x83, 0x07, 0xA7, 0xC6, 0xF7, 0xE9, 0x73, 0x58, 0x71, 0xF0, 0x0C, 0x8C, 0x97, 0x79, 0x0D, 0x47, 0x38, 0x95, 0x6F, 0xA2, 0xCF, 0x35, 0xD5, 0x99, 0x45, + 0x1C, 0x6A, 0xF0, 0x2E, 0x8A, 0x4F, 0x6B, 0x3A, 0x94, 0x37, 0x9C, 0x27, 0x39, 0x53, 0x2B, 0xE2, 0x0C, 0x55, 0x15, 0xB8, 0xD3, 0x28, 0x80, 0x25, 0x9F, 0x4C, 0x7F, 0xC3, 0xB6, 0x62, 0xBA, 0xE6, + 0xB5, 0x39, 0xEB, 0x09, 0x76, 0x21, 0xA4, 0xBC, 0x06, 0x5A, 0x46, 0x6E, 0xDA, 0x90, 0xED, 0xCE, 0x89, 0xE9, 0x85, 0x44, 0x79, 0x07, 0xF7, 0x75, 0x2D, 0x13, 0xA5, 0x9C, 0x0C, 0x03, 0x6A, 0xE3, + 0xA6, 0x00, 0x2F, 0xDD, 0x1E, 0x60, 0x20, 0x0C, 0xA2, 0x7D, 0x8F, 0x0C, 0x2D, 0xF8, 0x06, 0x32, 0x71, 0xC4, 0xAC, 0x8F, 0x71, 0x34, 0xC4, 0x85, 0xB7, 0x99, 0xC4, 0x6B, 0xAE, 0x40, 0x0B, 0x2C, + 0x54, 0xCD, 0x0C, 0xB6, 0xFD, 0x3F, 0x79, 0x15, 0x59, 0xC1, 0x7E, 0xF2, 0x2D, 0x0F, 0x86, 0xCA, 0xAA, 0xAC, 0xFA, 0xBF, 0x9F, 0x33, 0xEC, 0xCC, 0x79, 0xE7, 0x8D, 0xEC, 0xF4, 0x30, 0x48, 0x7D, + 0xA0, 0x4A, 0x6B, 0x68, 0x93, 0x4C, 0xC5, 0x67, 0x7F, 0xFE, 0x07, 0x8B, 0x6F, 0x7D, 0x0B, 0xB9, 0xBB, 0xF2, 0x18, 0x23, 0x76, 0x17, 0x07, 0x22, 0x86, 0x91, 0x0B, 0xA3, 0x18, 0xFF, 0x6B, 0xD0, + 0x98, 0xEB, 0xE9, 0xF4, 0xA9, 0xEA, 0x92, 0x1B, 0xE2, 0x66, 0x4A, 0x75, 0x0F, 0xB1, 0x41, 0x28, 0x47, 0xA8, 0xD5, 0x0D, 0xD3, 0xC2, 0xE7, 0x09, 0x9B, 0x46, 0x13, 0xE2, 0x0B, 0x6E, 0x1F, 0xCC, + 0x61, 0x4B, 0x18, 0x13, 0x9D, 0xDF, 0x6F, 0xFB, 0xF7, 0xD7, 0x47, 0x5A, 0xCF, 0xA9, 0xA0, 0x88, 0x39, 0xE7, 0xE7, 0xA4, 0x70, 0xE2, 0xEF, 0x6A, 0x92, 0x58, 0xF9, 0xE3, 0x3A, 0x9A, 0x8E, 0xAA, + 0xF2, 0xDA, 0x93, 0xBE, 0x79, 0xA1, 0xBB, 0x6C, 0xAA, 0xB7, 0x27, 0xA4, 0xC0, 0xC8, 0x40, 0x68, 0x8C, 0x31, 0x6F, 0x2A, 0x11, 0x96, 0xB9, 0x0A, 0xBA, 0x58, 0x47, 0xF0, 0x45, 0x64, 0x0B, 0x72, + 0xDB, 0x15, 0xEA, 0x56, 0xE7, 0xF1, 0xA6, 0x23, 0x40, 0xFD, 0xB1, 0x41, 0xC1, 0x84, 0xF4, 0x2E, 0x4C, 0xE8, 0xEE, 0x50, 0x18, 0x3F, 0xDB, 0x06, 0x88, 0xEF, 0x5B, 0xCA, 0xD4, 0x9B, 0x0F, 0xF2, + 0xEB, 0xDC, 0x98, 0xC1, 0xE0, 0xCE, 0xFD, 0x5F, 0x9B, 0x6B, 0xE0, 0xBF, 0x92, 0x45, 0xF9, 0x7C, 0x83, 0xB7, 0xF4, 0xF8, 0xB9, 0xC3, 0x6E, 0x58, 0xAA, 0x79, 0xE9, 0x0B, 0x23, 0x71, 0x71, 0xCF, + 0x46, 0xCF, 0x6A, 0x85, 0x25, 0x05, 0x25, 0x97, 0xFB, 0xA6, 0x04, 0x8E, 0x58, 0x85, 0x3B, 0xCF, 0xD3, 0x2C, 0x87, 0xA1, 0xA2, 0xEB, 0x5C, 0xD0, 0x15, 0xCE, 0x21, 0xF3, 0xD8, 0xFA, 0xB7, 0x30, + 0xE4, 0x7E, 0x64, 0x4E, 0x34, 0x7E, 0x2B, 0xA0, 0x13, 0x26, 0x1D, 0xCB, 0x5E, 0x89, 0xAC, 0x6A, 0xEF, 0x40, 0xE9, 0xAB, 0xD1, 0xE3, 0xEF, 0x20, 0x47, 0x93, 0xC0, 0x4C, 0xDE, 0x00, 0x9A, 0x42, + 0xFC, 0x2B, 0xF2, 0x2C, 0x4B, 0xB3, 0x14, 0xD7, 0x45, 0x3B, 0x80, 0xE2, 0xEC, 0x9E, 0xB9, 0x2D, 0x8E, 0xA3, 0x8E, 0xCF, 0xD5, 0x3B, 0xCB, 0xD3, 0xA9, 0x11, 0x5D, 0x67, 0xDC, 0x07, 0x90, 0x8F, + 0x96, 0x0C, 0x85, 0xDB, 0xD5, 0x89, 0x0B, 0xBA, 0x3F, 0x19, 0xB6, 0xF2, 0xFD, 0xFC, 0x8A, 0x02, 0x4D, 0xAB, 0x98, 0x22, 0x96, 0x72, 0x0D, 0x46, 0x38, 0x9B, 0xE8, 0x18, 0x5C, 0x1C, 0xA9, 0x41, + 0x50, 0x52, 0xE4, 0xD2, 0x10, 0xCD, 0xE3, 0x5E, 0xA4, 0x68, 0xC5, 0x28, 0x16, 0x2B, 0xE1, 0xC7, 0x65, 0xD0, 0xAC, 0x90, 0x36, 0xF6, 0x7E, 0xA0, 0x0D, 0xEA, 0x17, 0xFE, 0x8E, 0x44, 0xCC, 0x5F, + 0x3C, 0xED, 0xB8, 0x9F, 0xE9, 0xC6, 0xBB, 0x0E, 0x3E, 0x1A, 0x9F, 0x9E, 0x45, 0x3E, 0x68, 0x07, 0x88, 0xFA, 0xCB, 0xDE, 0xF9, 0x1D, 0x4B, 0x56, 0x1B, 0xCE, 0x52, 0x5C, 0x8C, 0x45, 0x2A, 0x24, + 0x43, 0x17, 0xEC, 0xAA, 0xEC, 0xE1, 0x23, 0x9E, 0x02, 0x45, 0xBE, 0xC0, 0xD3, 0xA3, 0x0E, 0x59, 0x08, 0x35, 0x76, 0x35, 0x68, 0xA5, 0x1C, 0x87, 0x0E, 0x08, 0xD9, 0x2F, 0x98, 0x54, 0x9A, 0x18, + 0x39, 0xB2, 0xC6, 0x49, 0x1D, 0xA8, 0x8A, 0x6A, 0xD2, 0x0D, 0x55, 0x39, 0x67, 0xE9, 0xB7, 0xF7, 0xAC, 0xAA, 0x0D, 0x4A, 0x9B, 0xE4, 0xE2, 0xCD, 0x4C, 0x7F, 0x3F, 0xFE, 0xE9, 0xF7, 0xBB, 0x6A, + 0x91, 0x7E, 0x91, 0xC6, 0x3C, 0xA1, 0x76, 0x38, 0x93, 0xCE, 0x74, 0xD8, 0x36, 0x07, 0xAD, 0x47, 0x6C, 0xC5, 0x32, 0x53, 0x53, 0xFC, 0x6E, 0x9D, 0xBB, 0xC8, 0xF5, 0xEE, 0x7E, 0x11, 0xA1, 0x33, + 0xE9, 0x38, 0xE2, 0x16, 0xFE, 0x27, 0x1A, 0xF3, 0xF6, 0x1D, 0x21, 0xDE, 0x2B, 0x82, 0x17, 0x67, 0x2F, 0xFA, 0x31, 0x05, 0x8F, 0x0B, 0x38, 0xD1, 0xE3, 0xC3, 0x59, 0xBB, 0x30, 0x55, 0xC3, 0xF0, + 0x1A, 0x8F, 0xDB, 0xBA, 0x86, 0xC3, 0x35, 0x76, 0x45, 0xE0, 0x8D, 0x50, 0x58, 0xD9, 0x41, 0xB4, 0xF6, 0x1F, 0xF0, 0x69, 0x3B, 0x83, 0x14, 0xFC, 0x10, 0xDF, 0xB5, 0xEF, 0x75, 0x29, 0xFC, 0x74, + 0xBF, 0xEE, 0x90, 0x27, 0x37, 0x17, 0x88, 0x82, 0xDD, 0x39, 0xAF, 0x06, 0x16, 0x63, 0xFE, 0xFA, 0xE8, 0x0F, 0x9E, 0x0E, 0x91, 0x6D, 0x34, 0x6C, 0x46, 0x80, 0x85, 0x54, 0xD6, 0x65, 0x9B, 0xB9, + 0x19, 0x82, 0xA4, 0x32, 0x4C, 0x19, 0xEF, 0xE3, 0x33, 0x92, 0x1D, 0xE9, 0x40, 0x6A, 0x1A, 0x92, 0xAE, 0x9F, 0x04, 0xBE, 0x98, 0x2B, 0xD0, 0x7C, 0x28, 0x1E, 0xF2, 0x9B, 0x88, 0x5C, 0xE9, 0x0E, + 0xCD, 0xC2, 0x71, 0xF0, 0x7B, 0xAB, 0x2B, 0xEA, 0x94, 0xFB, 0x9A, 0x66, 0x5C, 0x05, 0x23, 0x04, 0xAC, 0x18, 0x13, 0x24, 0x52, 0x16, 0xFD, 0x90, 0xE5, 0xA7, 0x89, 0x81, 0xB0, 0xB3, 0xB0, 0x36, + 0xEA, 0x9B, 0x84, 0xB6, 0x46, 0xFA, 0x08, 0xD8, 0xB4, 0x4C, 0x15, 0x65, 0x43, 0xA0, 0x4D, 0x4F, 0x77, 0x11, 0x96, 0x7E, 0xF1, 0x5B, 0xFC, 0x17, 0x9E, 0x97, 0x87, 0xDE, 0x9D, 0xA9, 0x60, 0x70, + 0x1B, 0x7F, 0x37, 0x65, 0x92, 0xD9, 0xBA, 0x20, 0xD3, 0xBE, 0xD1, 0xDC, 0x34, 0x14, 0x71, 0x63, 0x30, 0x98, 0x06, 0x2F, 0x4E, 0x37, 0xA1, 0xF9, 0xA5, 0xE1, 0x7D, 0x2F, 0x3B, 0xE3, 0x2E, 0x48, + 0x51, 0xFF, 0x5D, 0x2E, 0x41, 0x16, 0x3B, 0x95, 0xF2, 0x5E, 0x6E, 0x7F, 0xD2, 0x2C, 0x60, 0x9D, 0x23, 0xA8, 0x18, 0x25, 0x4D, 0x44, 0x00, 0x0A, 0x9C, 0xBC, 0x24, 0x10, 0x9F, 0xA2, 0xA5, 0x39, + 0x1D, 0x77, 0x16, 0xAF, 0x82, 0x28, 0x3B, 0xE4, 0x74, 0x9E, 0x92, 0x6D, 0x66, 0x1E, 0x58, 0x04, 0xF8, 0x3C, 0x06, 0x1F, 0x81, 0x06, 0x0E, 0xF6, 0xB4, 0xE8, 0xB4, 0x3F, 0xF6, 0x44, 0x99, 0x72, + 0x86, 0x7D, 0x75, 0x26, 0x66, 0x35, 0xDA, 0xE6, 0x76, 0xE0, 0xDB, 0x22, 0x15, 0x15, 0x01, 0xFE, 0xC8, 0xD1, 0xE2, 0x83, 0x73, 0xB8, 0x1A, 0x37, 0xAF, 0x98, 0xF1, 0xF8, 0x85, 0x81, 0xBE, 0x04, + 0x29, 0x10, 0x48, 0x81, 0x33, 0x1A, 0x9A, 0x3E, 0x4A, 0xC8, 0x75, 0x12, 0x63, 0x5E, 0xEB, 0x1A, 0x0B, 0x76, 0x7E, 0x8B, 0xAC, 0x39, 0x80, 0x66, 0x3C, 0xD1, 0x79, 0xF0, 0x86, 0x84, 0x7A, 0xA7, + 0xE7, 0xDC, 0x9F, 0x21, 0x5F, 0x91, 0xFF, 0x42, 0x83, 0xE6, 0x63, 0x91, 0x8D, 0x54, 0xAA, 0x43, 0x0E, 0xA5, 0x22, 0x14, 0x69, 0xD3, 0x71, 0xE7, 0xDF, 0x46, 0x05, 0x21, 0x4C, 0x9F, 0x22, 0x75, + 0xD3, 0xD7, 0xA5, 0x10, 0x8B, 0x22, 0x2E, 0x76, 0x0F, 0x3E, 0xDE, 0xDE, 0xB7, 0xC0, 0x5E, 0x6C, 0x18, 0xF9, 0xA6, 0x19, 0x3A, 0x66, 0x83, 0x94, 0xAE, 0x63, 0x22, 0x63, 0xB0, 0x5A, 0xD2, 0x5E, + 0x67, 0x45, 0x23, 0x5A, 0xC5, 0x35, 0x24, 0x93, 0x6F, 0x1D, 0x57, 0x52, 0xBC, 0x5B, 0xB7, 0xB2, 0x8E, 0xBA, 0xC5, 0xA3, 0x38, 0x20, 0x48, 0x01, 0x85, 0x10, 0xA4, 0x4F, 0x08, 0x0B, 0xFF, 0xC4, + 0x24, 0x35, 0x43, 0x54, 0x5D, 0x81, 0xC1, 0xD6, 0xD9, 0xED, 0xEE, 0xF3, 0x13, 0x2A, 0x53, 0x56, 0x5A, 0x73, 0x82, 0x8C, 0x96, 0xBA, 0xBB, 0xCA, 0xD1, 0xD6, 0xDE, 0xE8, 0x0F, 0x22, 0x55, 0x74, + 0x84, 0x92, 0xAF, 0xC3, 0xDB, 0x01, 0x2C, 0x2D, 0x51, 0x52, 0x5F, 0x66, 0x69, 0x71, 0x84, 0xAA, 0xAD, 0xB7, 0xDA, 0xE4, 0xE7, 0xEC, 0x00, 0x1A, 0x24, 0x2B, 0x3B, 0x89, 0xA5, 0xB5, 0xB6, 0xD1, + 0xEB, 0x01, 0x0D, 0x3F, 0xA0, 0xB1, 0xB7, 0xC8, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x1C, 0x25, 0x36, 0x41, 0x49, 0x12, 0x14, + 0x01, 0x24, 0x04, 0x20, 0x00, 0x75, 0x90, 0x22, 0xCB, 0xA2, 0x43, 0x00, 0x02, 0x02, 0x02, 0x06, 0x93, 0x00, 0x60, 0x50, 0x12, 0x2C, 0x20, 0x90, 0x81, 0x81, 0x84, 0x01, 0x01, 0x05, 0xC0, 0x37, + 0xA5, 0x26, 0x63, 0x08, 0xD2, 0x06 }, + }, + { + .name = "Dilithium 6-5 KAT 3", + .version = 0, + .rho_len = 32, + .rho = { 0x69, 0x04, 0x82, 0xBF, 0xF6, 0xC1, 0xD0, 0xBA, 0x6C, 0x07, 0x1D, 0xD3, 0x95, 0xAD, 0xF6, 0x9E, 0x55, 0xE1, 0xBF, 0xC4, 0xE0, 0x99, 0x2A, 0x86, 0x50, 0xFF, 0xB5, 0xE6, 0x0A, 0x02, 0xB1, 0x72 }, + .seed_len = 32, + .seed = { 0xCC, 0x1F, 0x50, 0xE1, 0xD7, 0xCD, 0x3B, 0x19, 0xA7, 0xF1, 0xDC, 0x62, 0xA1, 0x7F, 0x23, 0xD3, 0x65, 0x46, 0x53, 0xB4, 0x76, 0x68, 0x52, 0xCA, 0x41, 0x37, 0x4E, 0x2E, 0xD8, 0x37, 0x3A, 0x96 }, + .tr_len = 48, + .tr = { 0x29, 0x10, 0x67, 0xB6, 0x4B, 0x15, 0xBB, 0x06, 0xD9, 0x16, 0x70, 0xAB, 0x0A, 0xCB, 0xDD, 0x01, 0x01, 0x30, 0x13, 0x75, 0xDB, 0xE0, 0x88, 0xC5, 0xFE, 0x9B, 0xD5, 0x52, 0xB1, 0x13, 0xF7, 0x7C, + 0x23, 0x0B, 0x12, 0xD9, 0x6D, 0xDF, 0x19, 0xD8, 0x0B, 0xD5, 0x9A, 0xAB, 0x9D, 0x79, 0xB5, 0x74 }, + .s1_len = 480, + .s1 = { 0x42, 0xC0, 0x74, 0x75, 0xE3, 0x94, 0x12, 0xBB, 0xD8, 0x5D, 0x93, 0xC2, 0x90, 0x43, 0x59, 0x91, 0x97, 0x49, 0x5E, 0x05, 0x44, 0xAE, 0x12, 0x44, 0x43, 0x32, 0xD9, 0xAD, 0x3B, 0x0B, 0x1C, 0x25, + 0xD9, 0x25, 0x67, 0x86, 0x4E, 0x51, 0x12, 0x2D, 0x0A, 0x4B, 0x26, 0x48, 0x0C, 0xE2, 0x90, 0xBA, 0xA4, 0x14, 0x81, 0x80, 0x68, 0x4E, 0x64, 0xC5, 0x48, 0xB6, 0x09, 0x64, 0x85, 0x10, 0x4C, 0x11, + 0x06, 0x71, 0x55, 0x5D, 0x4E, 0x99, 0x4D, 0x05, 0xF3, 0x18, 0x6C, 0x5B, 0x34, 0x98, 0xCD, 0xD8, 0x21, 0x8A, 0x21, 0xD5, 0x6E, 0x5C, 0x9B, 0x5E, 0x5C, 0xCC, 0x6D, 0xC6, 0x96, 0x91, 0x1A, 0x59, + 0x29, 0xC0, 0x2E, 0x0B, 0x41, 0x36, 0xC6, 0xA2, 0x00, 0x80, 0xD5, 0x84, 0x32, 0x39, 0x97, 0xA2, 0xC6, 0xA6, 0xB6, 0x48, 0xC6, 0x69, 0x4C, 0x35, 0xA6, 0x98, 0xB5, 0xAA, 0x85, 0x44, 0xC9, 0x90, + 0xC2, 0x76, 0x9B, 0xA6, 0xCC, 0x58, 0x72, 0xC3, 0xC2, 0x81, 0x64, 0x55, 0x90, 0x11, 0xEB, 0xD2, 0x72, 0xD1, 0xC8, 0x86, 0xA1, 0x10, 0x5A, 0x1A, 0xAD, 0xD6, 0x66, 0x98, 0x02, 0x32, 0x50, 0xC0, + 0x22, 0x88, 0x82, 0x01, 0xD1, 0x75, 0xBB, 0xCE, 0x34, 0xB2, 0x4C, 0x89, 0xA1, 0x4D, 0x68, 0x43, 0xB7, 0x1E, 0xDA, 0x65, 0x28, 0xBA, 0x2E, 0x56, 0x9C, 0xC1, 0x09, 0x30, 0x98, 0x50, 0x5A, 0x70, + 0x82, 0xAA, 0x26, 0x06, 0x62, 0x81, 0x8E, 0x44, 0x08, 0x66, 0xDA, 0xDA, 0xAC, 0xA5, 0x95, 0x8E, 0x13, 0x01, 0xD3, 0x8C, 0x9A, 0x85, 0x25, 0x87, 0x16, 0x9A, 0x2E, 0x86, 0x83, 0x58, 0x41, 0xB1, + 0xA2, 0xEC, 0x46, 0x64, 0x34, 0x58, 0x99, 0x05, 0x69, 0xA7, 0xE1, 0x06, 0x88, 0x90, 0xDC, 0x21, 0x5D, 0x38, 0x30, 0x24, 0x6D, 0xD3, 0x74, 0xE8, 0x4A, 0x49, 0x41, 0xB1, 0x65, 0x92, 0x46, 0x4D, + 0x89, 0x60, 0x33, 0x27, 0x12, 0xA5, 0x2A, 0xC5, 0xC1, 0x22, 0xD8, 0x45, 0xEB, 0xCC, 0x41, 0x46, 0x4E, 0x10, 0xE4, 0x36, 0x40, 0xA9, 0x31, 0x89, 0xD0, 0x96, 0xC6, 0x20, 0x04, 0x48, 0x82, 0x55, + 0x82, 0xCB, 0xB2, 0x83, 0x38, 0x6D, 0x59, 0xEC, 0x82, 0x6E, 0x47, 0xD0, 0xAB, 0x5D, 0x42, 0xDC, 0xE4, 0xB1, 0x29, 0x67, 0x31, 0x9C, 0x06, 0xBB, 0xF2, 0x20, 0x6C, 0x1B, 0x96, 0xAD, 0x55, 0xC2, + 0xB1, 0x4B, 0x13, 0x3A, 0x99, 0x0C, 0x7B, 0xEE, 0x2A, 0x88, 0x63, 0x41, 0x69, 0x50, 0x03, 0x17, 0x12, 0x93, 0x40, 0xE9, 0x38, 0xCA, 0xF6, 0xD4, 0xCE, 0x55, 0x1B, 0x21, 0x93, 0xC2, 0xB0, 0x4C, + 0x64, 0x5A, 0x29, 0x81, 0x36, 0x2E, 0x99, 0xD0, 0x03, 0xE9, 0x2D, 0x8D, 0x00, 0xDA, 0x08, 0x00, 0xA8, 0x8D, 0xE2, 0xAD, 0x69, 0xE8, 0x8D, 0x28, 0x29, 0xAA, 0x5C, 0xC8, 0x1A, 0x73, 0x36, 0x12, + 0x19, 0x25, 0xC3, 0x43, 0xB7, 0xCE, 0x85, 0x87, 0xC8, 0x2A, 0x62, 0x28, 0x9D, 0x18, 0x4F, 0x6B, 0x57, 0x87, 0xA2, 0x68, 0x36, 0x24, 0x08, 0x4D, 0x1A, 0xA5, 0x02, 0x8C, 0xD1, 0x5A, 0x02, 0xBB, + 0x82, 0x94, 0x61, 0x28, 0x68, 0x17, 0x16, 0x66, 0xC8, 0x90, 0x82, 0x26, 0x00, 0x09, 0xB6, 0x79, 0x42, 0xB6, 0x8C, 0xAC, 0x53, 0xD7, 0x21, 0x26, 0x6C, 0x08, 0xD9, 0x2C, 0xA3, 0xB3, 0xC9, 0x9E, + 0x21, 0xC4, 0x68, 0x89, 0x91, 0x53, 0x4D, 0xB5, 0xC3, 0xCC, 0xC5, 0x1E, 0x25, 0x80, 0x65, 0xEB, 0x65, 0x05, 0x22, 0xCE, 0x55, 0xE0, 0x25, 0x8E, 0x29, 0x73, 0x34, 0x3C, 0x8A, 0xF1, 0xBC, 0x4A }, + .s2_len = 576, + .s2 = { 0x72, 0x47, 0x19, 0x00, 0x5B, 0x84, 0x62, 0x22, 0xB5, 0x50, 0x39, 0xB6, 0xF5, 0x48, 0x12, 0x45, 0x08, 0xCA, 0xA6, 0x63, 0x34, 0x06, 0xC0, 0xD8, 0x63, 0x69, 0x83, 0xEB, 0xB6, 0x20, 0x5A, 0xC1, + 0x10, 0xB3, 0xB0, 0x38, 0x31, 0xB7, 0x65, 0xC1, 0x88, 0x22, 0x91, 0x0D, 0xB2, 0xB4, 0x06, 0xA7, 0x04, 0xC8, 0xAE, 0x1E, 0x10, 0xC2, 0x68, 0x48, 0xA7, 0x03, 0x17, 0xC0, 0xD0, 0x50, 0x4F, 0x36, + 0x8C, 0x95, 0x03, 0xAB, 0x6E, 0x06, 0x36, 0x6F, 0x69, 0xC0, 0x90, 0xAB, 0x02, 0xCA, 0xD5, 0x96, 0xB8, 0x92, 0x00, 0x6F, 0x16, 0x09, 0x73, 0x46, 0x20, 0xB0, 0xDD, 0x60, 0x6F, 0x16, 0x08, 0x20, + 0x0D, 0x46, 0x56, 0x72, 0xC7, 0x92, 0x8B, 0x26, 0x4A, 0xB2, 0x3D, 0x98, 0x02, 0xBA, 0x28, 0x71, 0xC8, 0x70, 0x96, 0xE2, 0xD9, 0x2B, 0x23, 0xC7, 0x43, 0x2B, 0x16, 0xE3, 0x52, 0x37, 0x9C, 0x40, + 0x98, 0x05, 0xE8, 0x62, 0xC4, 0xC4, 0x54, 0x80, 0x53, 0x54, 0x99, 0x01, 0x80, 0x06, 0xB2, 0x56, 0xA8, 0xD8, 0x8A, 0x9B, 0x1D, 0x30, 0x32, 0x43, 0x83, 0x5E, 0x06, 0x57, 0xDA, 0xB4, 0x50, 0xF0, + 0x04, 0x36, 0x31, 0x61, 0x21, 0x69, 0x56, 0xC5, 0x01, 0x04, 0x71, 0x25, 0xCD, 0x24, 0x44, 0x06, 0x15, 0x45, 0xA9, 0x10, 0x06, 0x00, 0x2D, 0x9B, 0xB9, 0x35, 0x14, 0x21, 0x95, 0xC3, 0x8C, 0x58, + 0xA8, 0x62, 0x56, 0xD2, 0x48, 0x43, 0x71, 0xAC, 0x66, 0xF3, 0xD6, 0xB5, 0x0C, 0x04, 0x6D, 0x58, 0x26, 0xAE, 0x35, 0x4C, 0xD7, 0xD9, 0x42, 0x43, 0x10, 0xAA, 0x84, 0x00, 0x29, 0x91, 0xB0, 0x2B, + 0x10, 0xB1, 0x13, 0x91, 0x0E, 0x80, 0x21, 0x26, 0x64, 0xC6, 0x90, 0x44, 0xA4, 0x23, 0xB9, 0xA1, 0x71, 0xB7, 0x16, 0x30, 0x68, 0xCC, 0xE1, 0xA0, 0x8A, 0xA9, 0x82, 0x2A, 0xDA, 0x68, 0x25, 0x2A, + 0x30, 0x0C, 0xE8, 0xBC, 0x92, 0xA4, 0x2D, 0x72, 0x19, 0x07, 0xA4, 0x29, 0x1A, 0x79, 0xEE, 0xCC, 0x45, 0xAC, 0x29, 0x1B, 0xC4, 0x2C, 0x47, 0x33, 0x27, 0x04, 0x05, 0xBD, 0x42, 0x34, 0x51, 0x18, + 0x5A, 0x64, 0x00, 0x43, 0x60, 0x0E, 0x33, 0xE9, 0xB2, 0xA1, 0x0D, 0xD4, 0x90, 0x1A, 0x92, 0xC6, 0xE6, 0xC0, 0x4C, 0x41, 0x52, 0x0D, 0xE1, 0x80, 0x4D, 0xC9, 0x46, 0xA8, 0x61, 0x17, 0xCB, 0x06, + 0x65, 0x00, 0x95, 0x2E, 0xB3, 0x11, 0x67, 0xAE, 0x96, 0x64, 0x4A, 0x66, 0x0E, 0x88, 0x0A, 0x9A, 0x95, 0x38, 0x0E, 0x85, 0x44, 0x63, 0x63, 0x3C, 0x2D, 0x22, 0x07, 0x98, 0x80, 0x2D, 0xA3, 0x6C, + 0xA6, 0xAE, 0x58, 0x9A, 0x78, 0xA9, 0x88, 0x20, 0x49, 0x6C, 0x37, 0x56, 0x90, 0x56, 0x30, 0x22, 0x6B, 0xE5, 0x0A, 0x5B, 0xD2, 0x40, 0xC1, 0xE6, 0x00, 0x11, 0x4E, 0x05, 0x2A, 0x5A, 0x07, 0x4D, + 0x4B, 0x07, 0xA6, 0xD9, 0x16, 0x1B, 0x18, 0x87, 0xC1, 0x0D, 0xCA, 0xA5, 0xAB, 0x0B, 0x57, 0xA2, 0xB9, 0xC6, 0x6C, 0x42, 0x6B, 0x62, 0x85, 0xCD, 0x4B, 0x09, 0x76, 0x6E, 0xAD, 0x46, 0x9E, 0xCA, + 0xA0, 0x14, 0x5D, 0xC6, 0x53, 0x12, 0x4F, 0x1A, 0xD4, 0x26, 0x92, 0x88, 0xA0, 0xD2, 0xCA, 0x3A, 0x5A, 0x03, 0x6E, 0x0E, 0x5A, 0x2A, 0xA0, 0x28, 0xB0, 0xA4, 0xEA, 0xC5, 0x9D, 0x28, 0x30, 0x8A, + 0x17, 0x00, 0x4D, 0xBC, 0x9A, 0xA5, 0x80, 0x9A, 0x75, 0x26, 0x54, 0x5B, 0x01, 0xA5, 0x96, 0xE7, 0xB9, 0xA4, 0x5A, 0x19, 0x85, 0x4A, 0xAE, 0x4D, 0x33, 0xAF, 0x42, 0xCD, 0x41, 0xAD, 0x28, 0x86, + 0xA6, 0xAC, 0x68, 0x65, 0x26, 0xB4, 0x5B, 0x69, 0xBA, 0x29, 0xCB, 0x8A, 0x90, 0xCB, 0x3A, 0xAE, 0x83, 0xB2, 0x92, 0x19, 0x22, 0x64, 0x8C, 0x15, 0xB2, 0xEC, 0x2A, 0x49, 0xB7, 0x66, 0xA6, 0x48, + 0x11, 0x26, 0x3D, 0xB9, 0x46, 0x90, 0x29, 0x53, 0xD4, 0xA9, 0x75, 0x5D, 0x32, 0x42, 0xA7, 0xDA, 0xAD, 0x4C, 0x71, 0x89, 0xA4, 0x98, 0x73, 0x25, 0x4E, 0x72, 0xC8, 0xD6, 0xF4, 0x36, 0x8A, 0xA0, + 0x2B, 0x29, 0x1B, 0xC8, 0x3A, 0xC8, 0xAC, 0x45, 0x26, 0x5C, 0x4E, 0xA9, 0x92, 0xC6, 0x96, 0xB6, 0xB5, 0xDA, 0xBA, 0x8E, 0x00, 0x43, 0xD6, 0x53, 0xE3, 0x31, 0x6B, 0x25, 0xB6, 0x09, 0xE6, 0x64 }, + .t0_len = 2688, + .t0 = { 0x2B, 0xEB, 0x6D, 0xC0, 0xF5, 0x40, 0x20, 0x91, 0xC3, 0xCB, 0x14, 0xA3, 0x48, 0xBE, 0x8E, 0xA6, 0xD5, 0x30, 0xCF, 0x26, 0x81, 0xED, 0x36, 0x60, 0x03, 0xBE, 0xE2, 0x57, 0x88, 0x6B, 0x93, 0x72, + 0x82, 0x89, 0x4C, 0x11, 0x16, 0x62, 0xED, 0x2A, 0x66, 0x52, 0x0C, 0x9E, 0x24, 0xCF, 0xC9, 0x5D, 0x00, 0x54, 0x7C, 0x7A, 0x7F, 0x31, 0x34, 0x24, 0x2C, 0x35, 0xA3, 0xE4, 0xDA, 0x82, 0x88, 0x79, + 0x4B, 0xD1, 0xCB, 0x43, 0x56, 0x85, 0x5D, 0xD5, 0xAE, 0x2A, 0xD7, 0xA7, 0x86, 0xC7, 0x16, 0x6D, 0xE0, 0xA4, 0xCC, 0x5B, 0x82, 0x84, 0xB1, 0x27, 0x14, 0xA8, 0x12, 0x7D, 0xBF, 0x3C, 0x6D, 0x1B, + 0xE7, 0x6E, 0xE0, 0x92, 0x57, 0x7B, 0x5C, 0x8D, 0xD4, 0x3F, 0xE9, 0x7D, 0xE3, 0xA1, 0xC8, 0x79, 0x92, 0xEF, 0xCD, 0xA3, 0x9C, 0xD2, 0xA8, 0xF1, 0xB0, 0xAC, 0x5E, 0xF1, 0x21, 0x0F, 0x43, 0x30, + 0x33, 0xFB, 0x9D, 0x34, 0x63, 0x80, 0x81, 0x05, 0xB3, 0xA9, 0xA3, 0x06, 0x3C, 0x9A, 0x22, 0xD2, 0xBA, 0x7F, 0xC6, 0x7B, 0x4C, 0x24, 0xEA, 0xA2, 0x05, 0x01, 0x08, 0xD1, 0xDA, 0xDC, 0x06, 0xA7, + 0x5D, 0xFE, 0xDD, 0x1C, 0x72, 0xEF, 0xA8, 0x3B, 0xDB, 0x98, 0x63, 0xF9, 0x74, 0xC1, 0xFD, 0x77, 0x86, 0xFA, 0x07, 0x48, 0x5F, 0x2A, 0xD0, 0x9B, 0xB8, 0x72, 0x77, 0xBB, 0x45, 0xC6, 0x52, 0x04, + 0xB1, 0xF5, 0x7B, 0xD1, 0xF3, 0xF9, 0x0E, 0xE6, 0x1D, 0xEC, 0x75, 0x49, 0x79, 0xDA, 0xCC, 0xE1, 0x3A, 0xCA, 0xC5, 0x57, 0xFA, 0x2A, 0x98, 0x79, 0x04, 0x03, 0xFA, 0x4E, 0xA5, 0xF5, 0xE2, 0x00, + 0x4A, 0x7F, 0x51, 0x3D, 0x76, 0x14, 0x35, 0x66, 0x1A, 0xD2, 0x4E, 0x9F, 0x45, 0x74, 0xC9, 0x5A, 0x84, 0x98, 0xCB, 0x93, 0x55, 0x96, 0x14, 0x47, 0xBF, 0x76, 0xD7, 0xDD, 0xD3, 0x5C, 0x9D, 0x4C, + 0x47, 0x28, 0xF4, 0x33, 0x91, 0x98, 0x5E, 0x91, 0xAC, 0x13, 0x8A, 0xC2, 0x9B, 0xB1, 0x85, 0x10, 0xE0, 0xFB, 0x4B, 0x15, 0x9E, 0xCF, 0x08, 0xED, 0xD7, 0x6E, 0xA2, 0x4F, 0x15, 0xD2, 0x58, 0xED, + 0xD0, 0x4D, 0x28, 0x65, 0xF2, 0xEB, 0x79, 0xA3, 0xB3, 0xCB, 0x75, 0x1E, 0x46, 0x68, 0x58, 0xED, 0xBA, 0xA3, 0xBE, 0x52, 0x4B, 0x5F, 0x55, 0x21, 0x51, 0xFE, 0xAB, 0xCE, 0x22, 0x06, 0xCB, 0xE3, + 0x11, 0x7A, 0xD3, 0x4F, 0xF4, 0xB3, 0x76, 0x5B, 0x1C, 0xCC, 0x01, 0xE0, 0xCE, 0xC7, 0xB3, 0xF7, 0x63, 0xBE, 0xCF, 0x0C, 0x33, 0xDC, 0x9A, 0x9C, 0xD0, 0x89, 0x7B, 0x91, 0x6C, 0xFE, 0x37, 0xF5, + 0x12, 0xB5, 0xA4, 0xA1, 0x78, 0x2C, 0xF4, 0xF3, 0x3C, 0x9C, 0xD2, 0x22, 0xDC, 0x29, 0x27, 0x00, 0x80, 0x67, 0xD2, 0x52, 0x01, 0xC3, 0x59, 0x8F, 0x67, 0xDC, 0x8D, 0x14, 0x09, 0x0C, 0x27, 0xB4, + 0xE3, 0x0E, 0x09, 0xA9, 0x45, 0x79, 0xC0, 0xDF, 0x5C, 0x70, 0xB1, 0xFF, 0xB0, 0xDB, 0xCB, 0xB3, 0x55, 0xE9, 0x49, 0x72, 0x9B, 0xB6, 0xC2, 0xFC, 0xA8, 0x47, 0xDB, 0x59, 0x59, 0x9E, 0xA3, 0x9B, + 0x18, 0xF5, 0x9E, 0xAE, 0x64, 0x96, 0x87, 0x4C, 0x3A, 0x07, 0x8A, 0x2E, 0x78, 0x5C, 0x6A, 0x41, 0x3F, 0x9C, 0x7D, 0xC6, 0xEF, 0x9A, 0xB6, 0x0C, 0x44, 0xFE, 0x79, 0xB7, 0x7F, 0x56, 0x5F, 0xC2, + 0xA4, 0x51, 0xE1, 0x71, 0x84, 0x31, 0x5F, 0x68, 0x98, 0x04, 0x5C, 0x86, 0x95, 0x8D, 0x44, 0x69, 0x1E, 0xB8, 0x2E, 0x8F, 0x2A, 0x50, 0xAC, 0xD3, 0xB7, 0x61, 0xE2, 0x75, 0x27, 0x78, 0x2A, 0x64, + 0x87, 0xFB, 0xA0, 0xBD, 0x19, 0x57, 0x27, 0x89, 0x5D, 0xB3, 0x21, 0x08, 0x8E, 0x16, 0x0E, 0x79, 0x14, 0xDB, 0x17, 0xC6, 0x77, 0x41, 0x1D, 0x37, 0x4F, 0x37, 0x90, 0x5F, 0xD4, 0x70, 0x0E, 0x65, + 0xF9, 0x6E, 0x94, 0x74, 0xA7, 0xC5, 0x6D, 0x58, 0x70, 0xFE, 0x05, 0x32, 0x05, 0xD1, 0xAB, 0x91, 0x99, 0xAC, 0xD1, 0xD3, 0x01, 0x17, 0x26, 0xF6, 0xAD, 0xB8, 0x47, 0x7C, 0x35, 0x8B, 0x25, 0x06, + 0x0C, 0x3E, 0x95, 0x0C, 0x29, 0xF3, 0xE4, 0x6E, 0x29, 0xBC, 0x04, 0x30, 0x69, 0x65, 0x19, 0xF2, 0xF7, 0x4A, 0x21, 0xA1, 0x89, 0x3C, 0xE8, 0x49, 0x15, 0xF4, 0x8F, 0x0B, 0x51, 0x5D, 0x1D, 0x5D, + 0x4F, 0xCE, 0x88, 0x35, 0xE8, 0x24, 0x69, 0x6F, 0x68, 0x3D, 0x74, 0xFF, 0x82, 0xAF, 0x45, 0x21, 0x84, 0xDE, 0xD8, 0x10, 0xBB, 0x75, 0xBD, 0xF1, 0xDC, 0x97, 0x16, 0x7E, 0x8C, 0xCE, 0xE5, 0xCA, + 0x99, 0xC9, 0x55, 0x7B, 0xAA, 0x91, 0x18, 0x84, 0xF1, 0xC9, 0x7F, 0x05, 0xD3, 0xFE, 0xC4, 0xF8, 0x69, 0x79, 0xCC, 0xE1, 0xA6, 0x28, 0x4E, 0xAA, 0xFA, 0x6B, 0x14, 0x97, 0x08, 0xC9, 0x11, 0x57, + 0x85, 0x36, 0x0F, 0xA8, 0x89, 0x6A, 0x4B, 0xE6, 0x2B, 0x43, 0xA8, 0x38, 0x15, 0xC1, 0xC5, 0x01, 0xC9, 0x5B, 0xC4, 0x27, 0xAB, 0x9D, 0xFF, 0xD7, 0x58, 0xA8, 0x20, 0x21, 0x15, 0x61, 0x29, 0x26, + 0x89, 0x19, 0xBA, 0x4E, 0x11, 0xDC, 0x12, 0x21, 0x7F, 0xA1, 0x5E, 0x0F, 0x6F, 0xC4, 0x24, 0x4C, 0xB9, 0xCB, 0x00, 0x34, 0x9B, 0xA0, 0x16, 0x22, 0xCA, 0x92, 0x6B, 0x87, 0x33, 0x57, 0x37, 0xFF, + 0x8E, 0xAE, 0xE2, 0x66, 0x34, 0x5D, 0x1F, 0xAA, 0x88, 0x27, 0xF0, 0x6B, 0x9D, 0x45, 0xED, 0x66, 0xED, 0xED, 0xB9, 0x41, 0x35, 0x8F, 0xEB, 0x72, 0x27, 0xAA, 0xB2, 0xE4, 0x9E, 0x83, 0x48, 0x08, + 0x6E, 0x7B, 0x42, 0x77, 0x05, 0xE1, 0xE0, 0x74, 0xA5, 0xEB, 0x99, 0x49, 0x20, 0x5A, 0x69, 0xD0, 0x2D, 0x26, 0xA2, 0x54, 0xAC, 0x44, 0x9F, 0xE4, 0x6A, 0xCF, 0x58, 0x58, 0x99, 0xEB, 0x92, 0xBB, + 0xF3, 0x0D, 0xE8, 0xD6, 0xBA, 0xC0, 0x14, 0xB8, 0x67, 0xE6, 0x9B, 0xF7, 0x50, 0x98, 0xB9, 0x87, 0x52, 0x29, 0x39, 0x25, 0x4D, 0x7C, 0x46, 0xA0, 0x7E, 0x06, 0x53, 0x12, 0x20, 0xCA, 0xF3, 0x0A, + 0x4E, 0x4F, 0x33, 0xDC, 0x91, 0xB4, 0x02, 0x49, 0xE5, 0xA7, 0xA4, 0x0F, 0x8C, 0x42, 0xA6, 0x2A, 0x14, 0x3D, 0x8D, 0x29, 0xC8, 0x4D, 0x96, 0x8F, 0x8D, 0x98, 0xBD, 0xAE, 0x37, 0xA8, 0x6E, 0xFD, + 0x74, 0x54, 0xE9, 0x62, 0x6A, 0x8D, 0x9D, 0xA7, 0x13, 0x48, 0x36, 0x86, 0x73, 0x1C, 0x00, 0x55, 0x8B, 0x37, 0xCA, 0x30, 0x35, 0xF6, 0xE3, 0x9B, 0xAA, 0x44, 0x1E, 0xEF, 0xB1, 0xE0, 0xAE, 0x98, + 0x9D, 0x84, 0xF8, 0x8F, 0x55, 0x61, 0x9B, 0xBA, 0xC3, 0x43, 0x50, 0x67, 0xBB, 0x56, 0xEE, 0x5E, 0xEB, 0xDE, 0x3C, 0x3E, 0xFF, 0x10, 0x9E, 0x0C, 0x4E, 0x24, 0x1F, 0xC4, 0xE6, 0xF4, 0x2D, 0x01, + 0x3C, 0xEF, 0xFB, 0x09, 0x1D, 0x19, 0x76, 0x4C, 0x7B, 0x74, 0xDF, 0xE7, 0xC9, 0xF0, 0x99, 0xB9, 0xF7, 0x99, 0x19, 0xAF, 0xE0, 0x19, 0x4D, 0x44, 0xD1, 0x54, 0x7B, 0x91, 0x8F, 0x31, 0x9F, 0x6D, + 0x7F, 0x55, 0x44, 0xAA, 0x44, 0x65, 0x8C, 0xCB, 0xFF, 0xEE, 0x80, 0xC0, 0x89, 0xA1, 0x4F, 0x8E, 0xC8, 0x07, 0x9C, 0xED, 0xA4, 0xFB, 0x11, 0x8A, 0x66, 0x30, 0xB7, 0xED, 0xA5, 0x40, 0xBF, 0x90, + 0x1E, 0x47, 0xBD, 0x62, 0xE3, 0x83, 0x49, 0x75, 0x63, 0x2E, 0xB0, 0x3B, 0x78, 0x9B, 0xC0, 0xEF, 0x45, 0x71, 0xC3, 0x3E, 0xD4, 0x10, 0xA1, 0xC0, 0x87, 0xCB, 0xEA, 0xE1, 0xEC, 0xE6, 0x69, 0x8F, + 0xC7, 0x5B, 0x10, 0xF5, 0x8D, 0x87, 0xE9, 0x14, 0x12, 0x21, 0x3A, 0x57, 0xE9, 0xD3, 0xFA, 0xE9, 0x87, 0x8C, 0x87, 0x38, 0x2F, 0x3A, 0x12, 0x72, 0x8C, 0x67, 0x31, 0xBF, 0xC4, 0x42, 0xD7, 0x9D, + 0x27, 0x13, 0xAA, 0x9A, 0x72, 0x77, 0x71, 0x28, 0xF5, 0x19, 0x3B, 0x5F, 0xBE, 0xD8, 0x89, 0xCA, 0x23, 0x78, 0x66, 0x06, 0x7B, 0x33, 0x44, 0xBC, 0x30, 0x48, 0x37, 0xE3, 0xB0, 0xF8, 0x4D, 0x53, + 0x48, 0x74, 0xD2, 0x21, 0x26, 0x49, 0xFF, 0xB2, 0x1A, 0x9F, 0x55, 0x94, 0x05, 0xF6, 0x45, 0xA0, 0x1F, 0xC5, 0x90, 0x91, 0xCC, 0x3F, 0x12, 0xF8, 0x07, 0x16, 0xB6, 0xD6, 0x36, 0x23, 0xEE, 0x1D, + 0x94, 0xCC, 0x0F, 0xE0, 0xFB, 0xCC, 0x2F, 0xA4, 0xE5, 0xD6, 0xF6, 0xE4, 0x51, 0xC1, 0x8E, 0x9D, 0x69, 0x81, 0xE0, 0xA4, 0xD8, 0x12, 0x9F, 0x4C, 0x7F, 0x46, 0xC5, 0x05, 0xC1, 0xD8, 0x4A, 0x49, + 0xF7, 0x00, 0x28, 0x18, 0x35, 0xA9, 0xF1, 0x07, 0xF7, 0x1A, 0x38, 0x58, 0xAF, 0x7B, 0xEF, 0x93, 0x6E, 0x0C, 0x21, 0x6E, 0x36, 0xEE, 0x72, 0x76, 0x9E, 0x9D, 0xB1, 0x15, 0x49, 0x22, 0x2D, 0xBB, + 0x24, 0xC2, 0xF3, 0x8B, 0x9A, 0xF8, 0x33, 0x65, 0x9A, 0x4C, 0x2C, 0xEE, 0xA8, 0x5C, 0x84, 0x14, 0x0A, 0x28, 0x6D, 0x39, 0xCC, 0x4E, 0x27, 0x6E, 0xD2, 0xBA, 0x1E, 0x26, 0x55, 0xF1, 0x7B, 0xFB, + 0xEF, 0xF0, 0x3F, 0x5B, 0xAA, 0xF0, 0xAC, 0xA3, 0x14, 0x8D, 0xAB, 0xF6, 0x88, 0x0F, 0xA6, 0x74, 0xAF, 0xCB, 0xDA, 0xFC, 0x82, 0x05, 0x4D, 0x41, 0x12, 0x05, 0x2B, 0x62, 0xE0, 0x1B, 0xC7, 0xF9, + 0x97, 0x06, 0xB7, 0x01, 0xC1, 0x65, 0x9C, 0x28, 0x6B, 0x9B, 0x7A, 0x4F, 0xF3, 0x7B, 0x22, 0x4E, 0x3D, 0xDA, 0x47, 0x9B, 0x52, 0x5D, 0xA8, 0xA1, 0xE1, 0x7E, 0x3E, 0xE8, 0xDD, 0xCD, 0x71, 0xB1, + 0xA4, 0x09, 0xF3, 0xE9, 0xB2, 0xF5, 0xCD, 0xFB, 0xBE, 0xC9, 0x1C, 0xDB, 0x74, 0x76, 0x5A, 0x81, 0x47, 0xCF, 0x4A, 0xE7, 0xA5, 0xB6, 0x43, 0xFC, 0x34, 0xB2, 0x59, 0x1F, 0x1F, 0x09, 0xBC, 0xD5, + 0xB5, 0x65, 0x9E, 0x12, 0x7D, 0x43, 0xE3, 0xF5, 0x48, 0xE0, 0xF5, 0x9C, 0xE4, 0x2B, 0x39, 0x41, 0x41, 0xCF, 0xF7, 0x12, 0xD7, 0x92, 0x33, 0x82, 0x19, 0x40, 0xA8, 0xD5, 0x1D, 0x7D, 0x1F, 0xCF, + 0x0D, 0x4D, 0xD7, 0xD5, 0xB8, 0x35, 0x73, 0xFB, 0x73, 0x51, 0x02, 0xB7, 0x2D, 0x86, 0x75, 0xFF, 0x3C, 0x7F, 0xA8, 0xE7, 0x08, 0x7B, 0x99, 0xAB, 0x00, 0x61, 0xCB, 0x7F, 0xA5, 0x4D, 0x67, 0xBC, + 0x54, 0x4A, 0x34, 0x9E, 0xE2, 0x36, 0x8A, 0x2F, 0x97, 0x3D, 0xB4, 0x3C, 0xFA, 0xF8, 0x68, 0xFE, 0x3B, 0x0D, 0x54, 0x50, 0x97, 0x21, 0xF2, 0x5A, 0x53, 0x2B, 0x16, 0xFD, 0x4A, 0x12, 0xA2, 0x8E, + 0xE5, 0x66, 0x3E, 0x22, 0x93, 0x02, 0xDE, 0x88, 0x7A, 0x7C, 0xF4, 0xF3, 0xBF, 0x18, 0x7D, 0xC6, 0x78, 0x6E, 0x9F, 0x80, 0x94, 0x80, 0x63, 0xAC, 0x38, 0x90, 0x20, 0xCE, 0xC3, 0xC0, 0xD1, 0x1A, + 0xAF, 0x7F, 0xC3, 0x40, 0x89, 0x38, 0xB3, 0xC8, 0xB4, 0xA4, 0xA4, 0x9E, 0x93, 0xB8, 0x3D, 0x67, 0x10, 0x90, 0xD0, 0xE0, 0x02, 0x11, 0x70, 0x62, 0x18, 0x6B, 0xF7, 0xE8, 0xEE, 0x4A, 0xA4, 0x1B, + 0x54, 0xDD, 0xA0, 0x9A, 0x56, 0x0E, 0x9C, 0x6A, 0xF2, 0x1B, 0x20, 0xA2, 0x37, 0x30, 0xD4, 0x9D, 0x0C, 0x31, 0xB1, 0x51, 0x05, 0x9E, 0x15, 0x71, 0xC7, 0x6C, 0x25, 0x72, 0x03, 0x43, 0x93, 0xCC, + 0xDC, 0x5E, 0x11, 0x92, 0x0B, 0x6B, 0x78, 0xF7, 0xB4, 0xEB, 0x05, 0x64, 0x7B, 0x82, 0xED, 0xAD, 0x25, 0xD2, 0xD6, 0xD0, 0x9A, 0x4E, 0xA7, 0x83, 0x2D, 0xF1, 0x15, 0xC7, 0x27, 0x48, 0x9D, 0x2B, + 0x29, 0xE9, 0xB7, 0xDB, 0x85, 0x58, 0xE8, 0x54, 0x44, 0xDE, 0xEE, 0x60, 0x93, 0x40, 0x0F, 0x18, 0xA8, 0xC7, 0x80, 0x41, 0xE1, 0x02, 0x05, 0x50, 0xB1, 0x51, 0xC5, 0x78, 0xF8, 0x5F, 0xDA, 0x90, + 0x17, 0x1A, 0x04, 0x29, 0xE7, 0x70, 0x89, 0xBB, 0x04, 0xB8, 0x15, 0xAC, 0x6F, 0x5F, 0xAB, 0x93, 0x64, 0xED, 0xF7, 0x99, 0x40, 0x88, 0xA1, 0x53, 0x67, 0x07, 0xED, 0x65, 0x55, 0x24, 0x77, 0xC5, + 0xBA, 0x3F, 0x41, 0xD4, 0x84, 0xB5, 0xEB, 0xDC, 0x75, 0xD4, 0x83, 0xD0, 0xCA, 0x11, 0xA1, 0x1A, 0xB8, 0x2C, 0xE2, 0x5B, 0x22, 0xED, 0xBB, 0x6D, 0xE4, 0xA3, 0x64, 0x4C, 0xE6, 0x66, 0x94, 0x93, + 0x9C, 0x2A, 0xCD, 0x54, 0x75, 0x8A, 0x57, 0xFA, 0x1F, 0xBA, 0x6E, 0x48, 0x09, 0xE0, 0x27, 0xEF, 0x25, 0x8B, 0x30, 0xE2, 0x14, 0xD9, 0x0D, 0x6A, 0xA1, 0x81, 0xA5, 0x90, 0xE2, 0x41, 0xD2, 0x30, + 0xDF, 0xD2, 0x56, 0x26, 0x71, 0x50, 0x5E, 0x91, 0x8A, 0xB4, 0x6E, 0x94, 0x8B, 0xCD, 0x7D, 0x0A, 0xD2, 0x22, 0x69, 0xA8, 0x63, 0x29, 0x74, 0x4D, 0x5E, 0x4D, 0xF6, 0x27, 0x49, 0x78, 0x23, 0x75, + 0xF3, 0x87, 0x42, 0xE9, 0xB2, 0x92, 0xBB, 0x52, 0x74, 0x50, 0x18, 0x57, 0x1B, 0xC1, 0x5F, 0x57, 0x2C, 0x53, 0x4A, 0x90, 0x05, 0x56, 0xD8, 0x8C, 0x12, 0x8B, 0xAA, 0x9D, 0x07, 0x31, 0x00, 0xFE, + 0xF6, 0xC4, 0x34, 0xFE, 0x2A, 0x90, 0x5C, 0x3C, 0x98, 0xA2, 0x3E, 0x1B, 0xEA, 0x74, 0x64, 0x0C, 0xC7, 0x84, 0x95, 0x74, 0xDE, 0x5F, 0x88, 0xD8, 0x0D, 0xCD, 0xD0, 0xEA, 0x49, 0xD6, 0x83, 0x7A, + 0x78, 0x28, 0xEB, 0x56, 0x0E, 0x78, 0x61, 0x89, 0x7C, 0xD3, 0xBC, 0x37, 0xC7, 0xB5, 0x0C, 0xFA, 0x3A, 0xAD, 0x07, 0xC9, 0x25, 0xBC, 0xEC, 0x7F, 0x8E, 0xD6, 0x58, 0x92, 0xDA, 0x07, 0xE3, 0x3A, + 0x9E, 0xD0, 0x05, 0x85, 0x8E, 0xEE, 0x92, 0x26, 0x53, 0xAA, 0x1F, 0x23, 0x9A, 0xD5, 0xB7, 0x74, 0x48, 0x9C, 0xE1, 0xFB, 0xA7, 0xE6, 0xB4, 0x18, 0x42, 0xA5, 0x6B, 0x53, 0xA9, 0x23, 0x05, 0x1C, + 0x90, 0x8D, 0x52, 0x3F, 0xA5, 0x73, 0xDA, 0xBC, 0xA8, 0xF0, 0xB7, 0x8C, 0xB3, 0x72, 0x3E, 0x78, 0x38, 0xE0, 0x80, 0xA6, 0x1A, 0x1F, 0x0A, 0x32, 0x03, 0x5F, 0x68, 0xE1, 0x5A, 0x0B, 0x5D, 0x07, + 0x45, 0x3F, 0x3A, 0xE2, 0xC9, 0xF7, 0x51, 0x86, 0xA1, 0xAE, 0x7F, 0x5A, 0x84, 0x20, 0x6F, 0xFF, 0x9F, 0x7A, 0xD1, 0xD3, 0x2B, 0x69, 0xAE, 0xCE, 0x16, 0x9C, 0x82, 0x40, 0xB9, 0xF5, 0x8F, 0xE6, + 0xF2, 0xFB, 0xAC, 0x22, 0xC7, 0x61, 0x9E, 0x93, 0x8D, 0x38, 0x9B, 0x08, 0x7A, 0x9F, 0x84, 0x6F, 0x0A, 0x1E, 0x17, 0x26, 0x68, 0x50, 0x64, 0x76, 0x28, 0xEE, 0xDC, 0x5D, 0xAD, 0xF8, 0x38, 0xEF, + 0x38, 0xD5, 0xB6, 0x27, 0xD1, 0xFE, 0x92, 0x9F, 0x28, 0x76, 0xC9, 0xB5, 0x17, 0x51, 0x1C, 0xC6, 0xD9, 0xB8, 0xAA, 0x53, 0x86, 0xB8, 0xA7, 0x78, 0xAD, 0x2A, 0x47, 0xBF, 0x34, 0x98, 0xC8, 0xD2, + 0x87, 0x54, 0x0E, 0xD0, 0x50, 0xFB, 0xDA, 0xE6, 0x68, 0x9F, 0xF1, 0x4A, 0x5A, 0x89, 0x9C, 0x02, 0x1E, 0x6E, 0x43, 0x34, 0x0C, 0x67, 0x4F, 0x97, 0xF5, 0x7E, 0xE6, 0x64, 0x6D, 0x83, 0xB1, 0xCF, + 0xC0, 0x56, 0x94, 0x56, 0xCB, 0xE8, 0xA9, 0xE1, 0x18, 0x52, 0x6F, 0x2C, 0x7D, 0xDD, 0x31, 0x92, 0x47, 0xF0, 0x95, 0xE1, 0xA2, 0x4E, 0xAE, 0x4B, 0xE2, 0x03, 0x7C, 0xD8, 0x5D, 0xFD, 0xEB, 0x13, + 0xDD, 0xC2, 0x6D, 0x14, 0x8F, 0x98, 0x38, 0x3A, 0x10, 0x04, 0x3B, 0xA5, 0xB8, 0x6F, 0xA5, 0x76, 0x46, 0xA3, 0x70, 0x83, 0xD6, 0x51, 0xE1, 0x0C, 0xFB, 0x2A, 0x64, 0x97, 0x10, 0xDE, 0x3B, 0xAD, + 0xDF, 0xF2, 0x85, 0x49, 0xD2, 0xFA, 0xD7, 0x57, 0x51, 0x3D, 0x62, 0x91, 0x84, 0x1E, 0x68, 0x6E, 0x41, 0xAF, 0xB8, 0xD6, 0x0F, 0xEF, 0xA9, 0x68, 0x0C, 0x69, 0x9F, 0xBF, 0xDA, 0xCB, 0x69, 0x44, + 0x95, 0x7B, 0x95, 0x7A, 0x67, 0x7E, 0x27, 0x90, 0xCF, 0x4B, 0x9D, 0x04, 0x6F, 0x41, 0x9E, 0x34, 0x18, 0x2F, 0x14, 0x0C, 0x2F, 0xE1, 0x2A, 0xBA, 0x1C, 0x2D, 0xB9, 0x4C, 0x7B, 0x99, 0x7F, 0xC2, + 0x8F, 0xB2, 0xEF, 0xD9, 0x44, 0xE8, 0xF6, 0x7F, 0xE0, 0xFC, 0x69, 0x0A, 0x07, 0x9A, 0xC8, 0x7F, 0x22, 0x11, 0x2E, 0xD1, 0x87, 0xEE, 0x9C, 0x07, 0x4F, 0x8D, 0xCB, 0x4A, 0x66, 0x9C, 0x1F, 0x59, + 0x4C, 0x30, 0x03, 0x47, 0xF9, 0x06, 0xC3, 0x73, 0x56, 0x71, 0x2D, 0x87, 0x84, 0x64, 0xC5, 0x37, 0x6C, 0xB8, 0x42, 0x7B, 0xB9, 0x32, 0xBF, 0xBE, 0x14, 0x75, 0x78, 0x37, 0x7A, 0x8D, 0xC0, 0xD3, + 0x6C, 0x62, 0x42, 0x5C, 0xEC, 0xF1, 0x58, 0x8D, 0xFF, 0x0B, 0x1E, 0x8D, 0xD3, 0x8B, 0x7E, 0x72, 0x2D, 0xC2, 0x9D, 0xE3, 0xB8, 0x0E, 0xD1, 0xB1, 0xA7, 0xCA, 0x8A, 0x40, 0x0E, 0x0F, 0xAE, 0x28, + 0xD6, 0x84, 0xB2, 0xB5, 0x42, 0xA5, 0x63, 0x99, 0xAA, 0x59, 0xCB, 0x08, 0x18, 0x15, 0x4B, 0x77, 0x36, 0x4C, 0xDE, 0xAD, 0xA6, 0x78, 0x41, 0xCD, 0x70, 0xA1, 0xF1, 0x24, 0xD6, 0xD0, 0x5F, 0x8B, + 0xC3, 0x94, 0x00, 0xD5, 0x14, 0x00, 0xB6, 0x4D, 0x9E, 0xCD, 0x94, 0x9B, 0xEF, 0xBC, 0x7D, 0xB8, 0x21, 0x30, 0xAF, 0x3A, 0x91, 0x2D, 0x79, 0x3E, 0x75, 0x7F, 0x1F, 0x05, 0x72, 0x46, 0xB3, 0x2E, + 0xCC, 0x8F, 0x74, 0xDB, 0x4F, 0x5F, 0xA2, 0x94, 0xD6, 0x0F, 0x94, 0xCB, 0x47, 0x3B, 0x55, 0xA7, 0xDD, 0xCE, 0x7B, 0xFC, 0xA7, 0x91, 0x1B, 0x24, 0xF8, 0x4D, 0xF7, 0xEC, 0xAA, 0xF7, 0xA0, 0xA1, + 0x6D, 0x5F, 0xCF, 0x91, 0x80, 0x83, 0xF7, 0x35, 0x1A, 0x0E, 0x9E, 0xB3, 0x08, 0x59, 0x5A, 0x4A, 0x53, 0x24, 0x0D, 0x82, 0xBF, 0x5C, 0x95, 0xFD, 0x20, 0x9E, 0xA5, 0xAD, 0xCE, 0x53, 0x36, 0xCA, + 0x6A, 0x54, 0xBC, 0xF6, 0xD4, 0x62, 0xF8, 0x9C, 0x00, 0x7C, 0x4E, 0x60, 0x33, 0x1A, 0xF1, 0xC3, 0x44, 0xCE, 0xB8, 0xC1, 0x96, 0xAE, 0x56, 0x91, 0xA9, 0xE0, 0x82, 0x57, 0x15, 0x0E, 0xF2, 0xB7, + 0xE9, 0x47, 0x39, 0x77, 0x43, 0x99, 0x0D, 0x84, 0xF7, 0xFB, 0x9C, 0x23, 0x89, 0x0A, 0x05, 0xA5, 0xAD, 0xFA, 0x93, 0x57, 0x42, 0x03, 0xB2, 0xF0, 0x32, 0xD6, 0xB2, 0x2A, 0x2F, 0x3F, 0x2D, 0x26, + 0x97, 0x82, 0x39, 0xCC, 0x30, 0xA7, 0xB6, 0xEE, 0x06, 0x44, 0x87, 0x27, 0xDA, 0x6D, 0x92, 0x17, 0xA9, 0x2B, 0x34, 0xA2, 0x92, 0x39, 0xCE, 0xB9, 0xA1, 0xA0, 0x59, 0xBD, 0xFC, 0x62, 0x4F, 0xD8, + 0x8E, 0x85, 0x66, 0xCD, 0xA6, 0xAA, 0x26, 0x4A, 0x95, 0xE2, 0x23, 0xDE, 0x5B, 0x1F, 0xA6, 0x0A, 0x28, 0x62, 0x31, 0xAB, 0xC5, 0xED, 0xEF, 0x6D, 0x01, 0x58, 0xDD, 0x62, 0xFA, 0x0D, 0x81, 0x0B, + 0xAB, 0xD4, 0xF9, 0xD4, 0xAA, 0x5D, 0xC1, 0xE8, 0xB2, 0xB4, 0x04, 0xE4, 0xDD, 0xAA, 0x53, 0x2C, 0x11, 0x93, 0xA0, 0x5B, 0x38, 0xD7, 0x19, 0x55, 0x12, 0x50, 0x65, 0xC7, 0xE5, 0x15, 0x86, 0xE9, + 0x67, 0x7F, 0x3A, 0x19, 0xA8, 0xBA, 0x71, 0x3C, 0xE6, 0x6C, 0x58, 0x6B, 0xA6, 0x90, 0xC8, 0xEC, 0xB3, 0x8E, 0x3E, 0x8B, 0xC6, 0xF1, 0x36, 0x67, 0xF5, 0x68, 0x30, 0xC5, 0xB5, 0x2A, 0x9B, 0x28, + 0xD8, 0x15, 0x5D, 0xF3, 0xDD, 0x19, 0x61, 0x94, 0xE8, 0x50, 0x9B, 0x33, 0x87, 0xE2, 0x01, 0x4E, 0xE0, 0x37, 0x1F, 0x29, 0xA6, 0x5D, 0xD9, 0x93, 0xB1, 0x4C, 0x14, 0x31, 0x39, 0x16, 0x11, 0x1C, + 0x99, 0xC9, 0xEA, 0x87, 0xA6, 0xAC, 0xF1, 0xE9, 0xD8, 0x8F, 0xD7, 0x73, 0xA9, 0x2B, 0x5E, 0x95, 0xB2, 0x5E, 0x4A, 0x35, 0xA3, 0x31, 0xE3, 0xA0, 0xA7, 0xAC, 0xC6, 0x4A, 0xAF, 0x9C, 0x58, 0x03, + 0xEE, 0x05, 0xE7, 0x43, 0xA7, 0x9C, 0x30, 0xBE, 0x3D, 0x8F, 0xA1, 0xEF, 0x78, 0xF9, 0x56, 0xD5, 0x23, 0xCF, 0xF7, 0xFC, 0x8F, 0xB0, 0x8C, 0xFF, 0x7A, 0xC0, 0xBD, 0xEA, 0xF6, 0x07, 0xEF, 0x5C, + 0x76, 0x05, 0x9F, 0x0C, 0x5A, 0xCB, 0x94, 0x54, 0x33, 0x16, 0x19, 0x29, 0x59, 0xF3, 0x24, 0xC6, 0xB3, 0xF1, 0xB5, 0xA2, 0x48, 0xD1, 0xC5, 0xAD, 0x2B, 0xF9, 0xF2, 0x64, 0x6B, 0x03, 0xF3, 0xF9, + 0x66, 0x4B, 0xFE, 0xB7, 0x9B, 0x23, 0x5E, 0x7F, 0xB7, 0x7A, 0xEF, 0x34, 0x55, 0x73, 0x6D, 0x25, 0x48, 0x98, 0xEB, 0xBB, 0x9F, 0xAF, 0x11, 0x70, 0x3B, 0x87, 0x7E, 0xE3, 0x58, 0x99, 0xF4, 0xC0, + 0x57, 0x60, 0x2D, 0x66, 0xD4, 0xF1, 0x59, 0x1F, 0x71, 0x93, 0xF0, 0xE5, 0x2B, 0xFB, 0x95, 0x29, 0xA5, 0x93, 0x34, 0xC0, 0x17, 0x48, 0x3B, 0xCC, 0x64, 0xE0, 0x4D, 0x8F, 0xC1, 0x24, 0xA6, 0x7F }, + .t1_len = 1728, + .t1 = { 0x9D, 0xE4, 0x51, 0x4C, 0xDF, 0x3B, 0xC3, 0x9C, 0x78, 0xFA, 0xE6, 0x6C, 0x17, 0xDC, 0xB3, 0x1B, 0x5A, 0x7F, 0x6B, 0xAA, 0x31, 0x96, 0x55, 0xFA, 0x73, 0xB8, 0x54, 0x47, 0xA2, 0x55, 0x5E, 0xD0, + 0xB9, 0x55, 0x96, 0xDC, 0x8A, 0x69, 0x33, 0xDF, 0x68, 0x4E, 0xE1, 0x2B, 0xB0, 0x8A, 0xA0, 0xAD, 0xE0, 0x6F, 0xF0, 0xFD, 0x20, 0x2B, 0x4A, 0xD8, 0x94, 0x9E, 0x54, 0xD2, 0x3B, 0xCE, 0x47, 0x21, + 0xD6, 0x37, 0xC6, 0x53, 0x5E, 0x86, 0x12, 0xD1, 0x9D, 0x2A, 0x96, 0x12, 0x76, 0x59, 0xD4, 0xE8, 0xC3, 0xF0, 0x36, 0xA0, 0x8E, 0xA5, 0xEC, 0xCA, 0x8F, 0xD0, 0x6F, 0x30, 0x61, 0xBF, 0x7A, 0x83, + 0xEF, 0xC5, 0xF6, 0x3B, 0x34, 0xDF, 0xE2, 0xA9, 0x0D, 0x5F, 0x86, 0x68, 0xF8, 0xDC, 0x30, 0xC6, 0x1A, 0xB4, 0x38, 0x61, 0x0D, 0xA7, 0x15, 0x60, 0x38, 0xD2, 0xF3, 0x8B, 0xFC, 0xDF, 0xFF, 0x11, + 0x28, 0x7A, 0xFA, 0x81, 0x84, 0x6C, 0x05, 0xCC, 0x33, 0x80, 0x6C, 0x2C, 0xEC, 0x39, 0x90, 0x8A, 0xC0, 0x3C, 0x4A, 0x94, 0x4D, 0x35, 0xA6, 0x7F, 0x4B, 0xB4, 0xA9, 0x63, 0x78, 0x38, 0x54, 0xD5, + 0x99, 0x9C, 0xA7, 0x26, 0x28, 0xA1, 0xEB, 0xB9, 0xA7, 0x88, 0x96, 0x6C, 0x62, 0xA1, 0xC1, 0xE5, 0x10, 0x1E, 0x4F, 0x1B, 0xC3, 0xAA, 0xE1, 0xA4, 0xDF, 0xDC, 0x95, 0xB3, 0x4D, 0x87, 0xEC, 0xE0, + 0x57, 0x3A, 0xA6, 0x06, 0x8B, 0x2D, 0xD7, 0x4A, 0x72, 0x52, 0x81, 0xED, 0x17, 0x99, 0x72, 0x5D, 0x33, 0x1A, 0x24, 0x85, 0x2C, 0xB1, 0xB7, 0x89, 0x36, 0xC3, 0x9A, 0x75, 0x39, 0xDA, 0x9D, 0x8E, + 0x4C, 0x1A, 0x54, 0x1A, 0x38, 0xF2, 0x5E, 0x17, 0x41, 0xD9, 0x76, 0xBC, 0x87, 0xA5, 0x58, 0x3B, 0x59, 0x9C, 0x43, 0xC4, 0x68, 0x3C, 0xFE, 0x0D, 0xC7, 0x95, 0x3A, 0x9F, 0x67, 0xD6, 0x1B, 0xD8, + 0x7F, 0xD7, 0x65, 0x53, 0xC9, 0xD3, 0xBC, 0x43, 0x30, 0x52, 0xFF, 0x02, 0xE4, 0x2A, 0x5C, 0xAA, 0xDD, 0x99, 0x65, 0xF8, 0xDF, 0x7B, 0x16, 0xDD, 0xF2, 0x91, 0x70, 0x5D, 0x12, 0x18, 0x99, 0x9F, + 0xFE, 0xEB, 0x27, 0xB5, 0xF5, 0xC5, 0x76, 0x04, 0xE3, 0x92, 0x35, 0x57, 0x08, 0x18, 0x78, 0x7E, 0x2A, 0x26, 0x03, 0x7E, 0x88, 0x25, 0x9C, 0xFC, 0x74, 0x8A, 0x47, 0x55, 0xCC, 0xA3, 0xC8, 0x8A, + 0xD0, 0xC8, 0x39, 0x71, 0x1F, 0x2D, 0x04, 0xF4, 0xAB, 0x38, 0x04, 0x37, 0x38, 0xD1, 0xC0, 0xF7, 0x00, 0xB1, 0xDD, 0x93, 0x6F, 0x1D, 0x71, 0x73, 0x21, 0x08, 0xBA, 0xE7, 0xEF, 0x77, 0x02, 0xCA, + 0xC2, 0xB6, 0x2D, 0x79, 0xAA, 0x0E, 0xFB, 0x30, 0xF8, 0x4E, 0x20, 0x73, 0xF8, 0xA1, 0xE8, 0x28, 0x6D, 0xBB, 0xC3, 0xA3, 0x8C, 0xFF, 0x7A, 0x18, 0xC0, 0x02, 0x49, 0x87, 0xEF, 0xA1, 0x2B, 0x7E, + 0x87, 0xA6, 0x78, 0x67, 0x10, 0x86, 0x18, 0xE7, 0x4D, 0x92, 0x99, 0x6A, 0x3B, 0x19, 0x0E, 0x11, 0x50, 0x07, 0x4A, 0x01, 0x25, 0x5C, 0x5E, 0x9F, 0xED, 0x0F, 0xA9, 0xCD, 0x80, 0x84, 0x2D, 0x30, + 0x64, 0x85, 0x5F, 0x34, 0xDA, 0x7B, 0xA9, 0xC6, 0xD7, 0x16, 0x25, 0x1A, 0x3F, 0xD9, 0xDC, 0x2F, 0x73, 0xBB, 0x25, 0xC1, 0xD7, 0x4C, 0x59, 0xFE, 0x72, 0xEF, 0xB8, 0x33, 0x9A, 0x60, 0xCF, 0xC5, + 0xD5, 0x6A, 0x61, 0x5E, 0x38, 0x77, 0x0D, 0x28, 0x8B, 0x81, 0x15, 0x9E, 0x18, 0xD8, 0x1F, 0xFC, 0x80, 0xC2, 0xFE, 0xAD, 0x02, 0x06, 0x5A, 0xF4, 0x40, 0x66, 0xD5, 0xB4, 0x7B, 0xD5, 0x13, 0x25, + 0xE6, 0xA5, 0x6D, 0xA9, 0x96, 0x26, 0x8A, 0xB5, 0xF4, 0xA0, 0x25, 0x6E, 0xC6, 0xA1, 0xD0, 0x94, 0x9F, 0xC4, 0xFA, 0x93, 0xFB, 0x03, 0x6A, 0xF1, 0x62, 0x6E, 0xA1, 0xFF, 0x65, 0xE8, 0xEC, 0x0D, + 0x80, 0x6F, 0xF2, 0xDE, 0x11, 0xD8, 0x29, 0xD5, 0x82, 0x91, 0xB5, 0xF0, 0x94, 0x41, 0x11, 0x0E, 0x77, 0xB3, 0x61, 0x83, 0x30, 0xAF, 0xAB, 0xB2, 0xD7, 0xE8, 0xBD, 0xFF, 0x2F, 0xE7, 0x94, 0xA6, + 0x9F, 0x77, 0x2D, 0x4F, 0xBA, 0x9E, 0xDD, 0x68, 0xF9, 0x97, 0x77, 0x73, 0x09, 0x5B, 0xC8, 0xF5, 0x25, 0x6E, 0xF5, 0x0B, 0x92, 0x32, 0x63, 0xE2, 0x4C, 0x9F, 0x9C, 0xF2, 0x2B, 0xA1, 0x12, 0xA9, + 0xD0, 0x05, 0x85, 0xCE, 0x48, 0xFD, 0xD9, 0x0E, 0x70, 0xCA, 0xA9, 0x60, 0x27, 0x22, 0x6A, 0x14, 0x69, 0x02, 0xD3, 0xED, 0xCC, 0xA3, 0x3D, 0x5D, 0x4A, 0x1F, 0x89, 0x4B, 0x25, 0x9B, 0x56, 0x67, + 0x5A, 0x2A, 0x90, 0xE8, 0xC4, 0xB0, 0xD7, 0xC9, 0xC1, 0xD1, 0x9F, 0x08, 0xE0, 0x05, 0x9F, 0x8F, 0x50, 0x12, 0x4A, 0x54, 0xCD, 0x32, 0x9F, 0x81, 0xF1, 0xCB, 0xC6, 0x21, 0xEB, 0x08, 0x58, 0x98, + 0xE7, 0x87, 0x45, 0x79, 0xB2, 0x18, 0xAA, 0xAF, 0x37, 0x1D, 0xCE, 0xB1, 0x5D, 0xC6, 0x38, 0x7B, 0xF7, 0x59, 0x8A, 0xE1, 0xF4, 0x04, 0xCE, 0xCE, 0x6A, 0xDB, 0x8F, 0x0E, 0x2E, 0x06, 0x75, 0x9D, + 0xD5, 0x6E, 0x0E, 0x17, 0xF2, 0x6F, 0x66, 0x95, 0x09, 0xCE, 0x6E, 0xA2, 0xD5, 0x80, 0x9C, 0x83, 0xCD, 0xCF, 0xD3, 0xFB, 0x3D, 0x01, 0xA8, 0xA9, 0xD1, 0x19, 0x15, 0x47, 0x83, 0xC9, 0x3A, 0x70, + 0xA2, 0xD5, 0x7B, 0x3F, 0x60, 0xC7, 0xE7, 0xBB, 0x6E, 0x5B, 0x64, 0xDA, 0x5F, 0x04, 0x03, 0x42, 0xEE, 0xE3, 0x07, 0x74, 0x56, 0x36, 0x62, 0x1C, 0xF6, 0xA5, 0xCA, 0xF5, 0x59, 0x3C, 0x06, 0xD4, + 0xF7, 0x18, 0xA3, 0x93, 0x49, 0x80, 0xAB, 0xB1, 0x5F, 0x39, 0x55, 0x62, 0xAF, 0x41, 0x3A, 0xD4, 0x77, 0xC8, 0x85, 0xBC, 0xEE, 0x24, 0xFE, 0xA1, 0xEB, 0x6C, 0x6D, 0x48, 0xB0, 0x7F, 0xB2, 0xCB, + 0x95, 0xD7, 0x63, 0xD4, 0x96, 0xD3, 0x23, 0x7D, 0x41, 0xA8, 0x6F, 0x00, 0x99, 0x1A, 0x88, 0xDF, 0xB9, 0xF6, 0x97, 0xD5, 0xD9, 0xD1, 0x6C, 0xC1, 0xAA, 0xB8, 0xF1, 0xF9, 0x73, 0x04, 0x86, 0xE8, + 0xDA, 0x73, 0xDF, 0x72, 0x53, 0xBA, 0xF3, 0xC3, 0x44, 0xC1, 0x63, 0xC6, 0x0E, 0x16, 0x5A, 0x05, 0xEA, 0x20, 0xE4, 0xD5, 0xF4, 0x11, 0xA2, 0x18, 0x5D, 0x76, 0x87, 0x37, 0xA6, 0x8E, 0x95, 0xDF, + 0x9E, 0x20, 0x77, 0x4E, 0x20, 0xFF, 0x5B, 0x0E, 0xE0, 0x80, 0x67, 0x33, 0xD7, 0xED, 0x20, 0x89, 0x65, 0xEA, 0xF7, 0x76, 0x9A, 0x53, 0xEF, 0x64, 0x24, 0xC9, 0x89, 0x6B, 0x16, 0x43, 0x48, 0xAD, + 0x25, 0x44, 0x66, 0xFA, 0x93, 0xCA, 0x37, 0xCE, 0x74, 0x91, 0xBE, 0x47, 0x25, 0x42, 0xA3, 0x87, 0x06, 0x10, 0x80, 0x92, 0x86, 0x94, 0xCF, 0x89, 0x8A, 0xAD, 0x20, 0x25, 0xB8, 0x79, 0x94, 0x92, + 0xE9, 0x79, 0xE4, 0xA7, 0xC8, 0x8A, 0x4A, 0x38, 0x87, 0xB9, 0xAD, 0x05, 0xCE, 0x0A, 0xA5, 0x19, 0xEB, 0x1C, 0x36, 0x29, 0x9F, 0xD7, 0x6F, 0x4F, 0xFE, 0x9E, 0x1A, 0x51, 0x16, 0x2A, 0xC3, 0x0D, + 0xFB, 0xF8, 0xB4, 0xEB, 0x40, 0xDE, 0x4C, 0x23, 0x62, 0x9A, 0x51, 0x00, 0x5D, 0x75, 0x13, 0xCC, 0x32, 0x60, 0xC8, 0xEE, 0x82, 0x34, 0x4B, 0x23, 0x97, 0x03, 0x38, 0x63, 0xE0, 0xEC, 0x0A, 0xF7, + 0x21, 0xE2, 0x04, 0x96, 0xB5, 0xBA, 0x99, 0x42, 0x9E, 0x23, 0xE8, 0x4F, 0x82, 0x19, 0xD0, 0x2F, 0xF6, 0x7A, 0x28, 0xAE, 0x50, 0xDE, 0xD0, 0x92, 0x1D, 0x01, 0x41, 0x97, 0xAD, 0xC2, 0xF6, 0xCF, + 0x80, 0xA0, 0x3D, 0x88, 0xED, 0x7D, 0x7B, 0x36, 0x1A, 0x4A, 0x77, 0xD9, 0x27, 0xE0, 0xCC, 0x3B, 0x89, 0xDF, 0x65, 0x1B, 0x74, 0xF1, 0x1E, 0x7B, 0xA0, 0x25, 0x74, 0x7F, 0x71, 0x07, 0xF4, 0xC9, + 0xD8, 0xCA, 0x39, 0x41, 0xFE, 0x06, 0x8B, 0x3E, 0xC3, 0x34, 0x68, 0xBF, 0x1E, 0xF0, 0xE2, 0x9A, 0xC5, 0xC7, 0x6F, 0x35, 0x54, 0x6D, 0x23, 0x15, 0x93, 0x87, 0x10, 0x89, 0xE3, 0x2A, 0x08, 0x35, + 0xFE, 0x92, 0x1A, 0x54, 0xF8, 0xD6, 0x41, 0xDF, 0x03, 0x04, 0x0E, 0x30, 0x67, 0x82, 0xF0, 0x94, 0xDB, 0xF3, 0x6A, 0x74, 0x09, 0xFA, 0x60, 0xE1, 0x09, 0x48, 0x00, 0x5D, 0xD9, 0x6A, 0x5C, 0x2D, + 0x2D, 0x77, 0xD6, 0x26, 0x95, 0x87, 0xCB, 0xBE, 0xAF, 0x45, 0xEF, 0xF0, 0x4A, 0x42, 0xAA, 0x16, 0xD0, 0xDD, 0x4B, 0x57, 0xC7, 0xFF, 0x04, 0xF2, 0x4B, 0x2C, 0xE9, 0x31, 0xBC, 0x6E, 0x66, 0x28, + 0x6C, 0xAF, 0xAE, 0xE0, 0x6A, 0xCC, 0xCE, 0x46, 0x15, 0x1E, 0xF8, 0xEF, 0xF0, 0x8D, 0x20, 0x29, 0xB3, 0x65, 0xF7, 0xEC, 0x31, 0x62, 0x06, 0x65, 0xE6, 0x4D, 0xB3, 0x84, 0x43, 0x43, 0x57, 0xFA, + 0x92, 0x16, 0x96, 0x96, 0x9A, 0x10, 0xB1, 0xF4, 0xCF, 0x51, 0xE7, 0xC4, 0xE7, 0x45, 0xDD, 0x61, 0xA2, 0xFC, 0x84, 0xFF, 0x23, 0x59, 0x88, 0x86, 0x2E, 0x2D, 0x08, 0x5E, 0xEB, 0x66, 0x37, 0x36, + 0x39, 0x7E, 0x4F, 0x53, 0x2C, 0xEB, 0xCE, 0x1E, 0xEC, 0x8B, 0x5E, 0xD4, 0x70, 0x78, 0xC2, 0x5A, 0xF0, 0xE5, 0x2E, 0xAB, 0x5C, 0x3F, 0x8B, 0x17, 0x85, 0x9F, 0x7C, 0x72, 0x74, 0xFB, 0xB1, 0xDA, + 0x60, 0xCD, 0x19, 0x0C, 0x68, 0x3B, 0x40, 0x61, 0x20, 0xD7, 0xE1, 0x1F, 0x5A, 0x63, 0x96, 0x87, 0xAC, 0xC2, 0x46, 0x90, 0xC8, 0xBA, 0x84, 0x6A, 0xA0, 0x67, 0x46, 0x28, 0x8B, 0x5A, 0x26, 0x30, + 0x23, 0x88, 0xFC, 0x70, 0x9B, 0xB2, 0x74, 0x94, 0xB8, 0x93, 0x33, 0x25, 0x8B, 0x4B, 0xE6, 0x10, 0x61, 0xF3, 0xE8, 0x2E, 0x8C, 0xE4, 0x31, 0x90, 0xDC, 0x39, 0x47, 0x0F, 0xBE, 0x47, 0xB7, 0x28, + 0x6E, 0x6E, 0x2F, 0x8E, 0x32, 0xC4, 0x05, 0x7C, 0x2E, 0xBD, 0x48, 0x91, 0xD5, 0x10, 0xC6, 0xEA, 0x69, 0x6D, 0x8C, 0x58, 0x63, 0xC3, 0x98, 0x84, 0x4B, 0xDF, 0x73, 0x5C, 0xF8, 0x53, 0xA0, 0x9A, + 0xD6, 0x34, 0xF4, 0x3F, 0x52, 0x5E, 0x35, 0x4D, 0x22, 0x8C, 0xC0, 0x9F, 0x60, 0x4B, 0xFC, 0xF8, 0xF2, 0xED, 0xA5, 0x1B, 0x6F, 0x3F, 0x26, 0xC4, 0xB0, 0xBD, 0x7F, 0xEC, 0x60, 0xB1, 0xD9, 0x9D, + 0xDB, 0x5F, 0xAD, 0x87, 0x8C, 0x23, 0xB7, 0x65, 0x90, 0x8D, 0x27, 0xD7, 0xB5, 0x14, 0xBF, 0xA6, 0x91, 0x3A, 0xBD, 0x8C, 0x7B, 0x40, 0xF5, 0xE1, 0x7B, 0xA7, 0x8E, 0x94, 0x00, 0xAA, 0x41, 0xA8, + 0x1D, 0x42, 0x42, 0x37, 0x59, 0x80, 0xE7, 0xB0, 0x29, 0x11, 0x65, 0xBA, 0xF2, 0x13, 0xA6, 0x7D, 0xC3, 0x14, 0xBF, 0x0D, 0x8D, 0x14, 0x87, 0x3B, 0xB7, 0xC7, 0xA0, 0x41, 0xCF, 0xFA, 0xD5, 0x80, + 0x06, 0x65, 0xBF, 0x28, 0xC4, 0x62, 0xFB, 0x2D, 0x53, 0x54, 0xE0, 0x1B, 0x3C, 0x4A, 0xD1, 0x1E, 0x0B, 0x81, 0xA6, 0x75, 0x43, 0xAF, 0x70, 0xAA, 0x9F, 0x97, 0xCD, 0xD7, 0x07, 0xC6, 0xC1, 0xD2, + 0x1C, 0x6D, 0x4F, 0xDD, 0x18, 0xB6, 0xAE, 0x83, 0xE3, 0x89, 0x52, 0x5E, 0xEF, 0x3D, 0x82, 0xD1, 0x01, 0x43, 0x01, 0x4E, 0xF9, 0x7A, 0x75, 0xAE, 0x30, 0xC3, 0x99, 0xC9, 0xFF, 0xF1, 0xF9, 0x59, + 0x25, 0x9C, 0xED, 0x34, 0x35, 0xDA, 0xEC, 0xA6, 0xDB, 0x98, 0x6A, 0x09, 0xBF, 0x9A, 0xF8, 0xF1, 0x66, 0x2A, 0x03, 0x8A, 0xB5, 0x14, 0x23, 0xB6, 0x66, 0x75, 0x22, 0xAB, 0x72, 0xA2, 0x5D, 0x14, + 0x89, 0xE0, 0x6E, 0x77, 0xCD, 0x08, 0xAE, 0x8B, 0xBE, 0x13, 0xEF, 0xC1, 0x1C, 0x2C, 0x48, 0xF8, 0x9A, 0x73, 0x3B, 0x57, 0xA1, 0x69, 0xE3, 0x76, 0x80, 0xD8, 0x50, 0x31, 0x4F, 0x8E, 0xF0, 0x8F, + 0x43, 0x8C, 0xD2, 0xF3, 0x55, 0x4D, 0x15, 0xBC, 0x35, 0x72, 0x2B, 0xF6, 0xED, 0x5C, 0x41, 0x14, 0x01, 0xB3, 0x1B, 0x10, 0x18, 0x53, 0xF7, 0x0A, 0x1A, 0x5A, 0xBF, 0x02, 0x8D, 0x1F, 0x87, 0x9F, + 0xB8, 0x1C, 0xA2, 0x7F, 0xD7, 0x70, 0x29, 0x9D, 0x7E, 0x00, 0x77, 0x82, 0xC2, 0xCB, 0x65, 0xAF, 0xE9, 0x0E, 0x85, 0x73, 0xAA, 0xF8, 0x95, 0xE1, 0xF4, 0xA0, 0x3B, 0xC0, 0xE2, 0x55, 0x39, 0xC7, + 0x48, 0xB2, 0x5B, 0xC0, 0x86, 0x56, 0x3B, 0x1A, 0xED, 0x6D, 0x7C, 0xE1, 0xD3, 0xF0, 0x84, 0x78, 0xC9, 0xFD, 0xBE, 0x43, 0x1B, 0x33, 0xB0, 0x9A, 0x92, 0xFB, 0xA7, 0x2F, 0x09, 0x64, 0xA2, 0x92, + 0x5F, 0x41, 0xFF, 0xFC, 0xD8, 0xBA, 0x32, 0x59, 0x43, 0x59, 0x53, 0x98, 0xB2, 0xD9, 0x39, 0xC8, 0xA4, 0xC9, 0x0B, 0x1D, 0x58, 0x4C, 0x66, 0x9F, 0x0F, 0xFA, 0xCD, 0x43, 0x41, 0xE0, 0x35, 0x58, + 0x70, 0x07, 0x15, 0xC6, 0x1C, 0x3C, 0x64, 0x0D, 0x42, 0x5B, 0x67, 0xEB, 0x0D, 0xAA, 0xBF, 0x5E, 0xD3, 0x09, 0x20, 0x5F, 0xB0, 0x9A, 0x0C, 0x6B, 0x3D, 0xDD, 0xBB, 0x5F, 0x28, 0x8E, 0x57, 0x3B, + 0x46, 0x1A, 0x58, 0xF5, 0xEF, 0x5D, 0x43, 0x50, 0x13, 0x63, 0xD8, 0xB1, 0xA7, 0x79, 0xDC, 0x5E, 0x27, 0xDE, 0xAC, 0xDF, 0xCD, 0xCD, 0x0A, 0x9C, 0x20, 0x24, 0xAE, 0x48, 0x1C, 0xD9, 0x81, 0xD5 }, + .msg_len = 3300, + .msg = { 0xD2, 0x1A, 0x6B, 0xB3, 0xA2, 0x35, 0x68, 0x05, 0xE6, 0x78, 0x67, 0x3C, 0x45, 0xFB, 0x05, 0x5F, 0xC5, 0x26, 0x6E, 0x3F, 0x69, 0x2A, 0xF9, 0x93, 0x5A, 0xEA, 0x30, 0x7F, 0x14, 0xA5, 0xC4, 0x1B, + 0x97, 0x99, 0x66, 0xA5, 0xDF, 0xE4, 0x2E, 0xBF, 0xED, 0x14, 0x87, 0xE4, 0x82, 0x2B, 0x74, 0xAB, 0x5A, 0xF2, 0x89, 0x95, 0xE0, 0x85, 0xEC, 0x80, 0x07, 0xEC, 0xA4, 0x97, 0x7C, 0x63, 0xEE, 0x52, + 0x99, 0xFE, 0xC6, 0x3D, 0xCC, 0xBC, 0x42, 0xEE, 0xAC, 0xAB, 0x48, 0x8E, 0x57, 0x42, 0x49, 0xE9, 0xD8, 0x56, 0x14, 0x67, 0x50, 0xAD, 0x97, 0xC8, 0xA4, 0x43, 0x48, 0x5E, 0xC1, 0xC5, 0x82, 0x0B, + 0xEB, 0x09, 0x64, 0x64, 0x00, 0x10, 0xF6, 0x40, 0x71, 0x40, 0x79, 0x1E, 0x74, 0x68, 0x4D, 0xBB, 0x91, 0x05, 0x2E, 0x2D, 0x8B, 0xEF, 0x7B, 0xDC, 0xD7, 0x8B, 0x2E, 0xC0, 0x3C, 0x97, 0xA5, 0x32, + 0x95, 0xD6, 0x83, 0xBD, 0xBE, 0x32, 0xA7, 0x0D, 0xC1, 0x9A, 0x2F, 0x75, 0xB8, 0x61, 0x3A, 0xEA, 0x96, 0x16, 0xAE, 0x0E, 0x28, 0x01, 0x79, 0x49, 0x28, 0x20, 0xF7, 0x3F, 0xB7, 0xFA, 0x41, 0x21, + 0xE6, 0x73, 0xFB, 0x5C, 0x32, 0x8F, 0x41, 0xB6, 0x7F, 0xF8, 0xFF, 0xA7, 0xAE, 0xE6, 0x56, 0x4A, 0xDA, 0xBA, 0x04, 0x6D, 0x6E, 0x1D, 0x6A, 0xA1, 0x3F, 0xB2, 0x49, 0x65, 0x39, 0x0F, 0x82, 0x92, + 0x46, 0xDF, 0xA8, 0x76, 0x38, 0x51, 0x40, 0x50, 0x75, 0xF7, 0x6C, 0xF9, 0x4C, 0x66, 0xFF, 0xC3, 0x30, 0x82, 0x14, 0xDF, 0x09, 0x60, 0xC6, 0x49, 0xAA, 0xED, 0xC2, 0x29, 0x26, 0xCE, 0x93, 0x57, + 0xD3, 0x87, 0x5F, 0x8B, 0x71, 0xD6, 0x8D, 0x75, 0x99, 0x9A, 0xA3, 0x66, 0x3C, 0x30, 0xA9, 0xED, 0xF0, 0x72, 0x28, 0xBF, 0x7D, 0xFF, 0x49, 0xEC, 0x1E, 0x6C, 0x7A, 0x33, 0xD2, 0x05, 0x35, 0x97, + 0x00, 0x3B, 0x82, 0x39, 0x2E, 0x82, 0x6E, 0xBD, 0x70, 0x1B, 0x4C, 0x98, 0x1A, 0xAA, 0xC9, 0x95, 0x1C, 0x79, 0xE0, 0x8F, 0x59, 0x2C, 0x2C, 0x06, 0x37, 0xC8, 0xE5, 0xA7, 0xF9, 0xDC, 0xDA, 0x59, + 0x9E, 0x85, 0x9C, 0x31, 0x7D, 0x48, 0x88, 0xB4, 0x09, 0x89, 0x92, 0xE0, 0xE2, 0xD9, 0x79, 0xE4, 0x1C, 0x70, 0x36, 0x86, 0xD5, 0x77, 0xE5, 0xBA, 0x60, 0x01, 0xEC, 0x4F, 0x58, 0x71, 0x40, 0x71, + 0x12, 0x93, 0xD6, 0x64, 0x96, 0x36, 0x32, 0xF8, 0x7E, 0xA0, 0x46, 0x1E, 0x0E, 0x0C, 0x5E, 0x9D, 0x8D, 0x29, 0x2F, 0xB4, 0x09, 0xF9, 0xF9, 0xAB, 0x17, 0x2E, 0xE1, 0x7F, 0xC8, 0xAF, 0xAB, 0xAD, + 0x06, 0xE4, 0x2B, 0x43, 0x7C, 0xE2, 0x29, 0x24, 0xEB, 0x5D, 0xBD, 0x3A, 0x80, 0xA0, 0x69, 0x62, 0xF3, 0xB3, 0x79, 0x46, 0x25, 0x9F, 0x9C, 0x75, 0xA2, 0x33, 0xCB, 0x2B, 0x4A, 0xBD, 0xC5, 0xCD, + 0x1B, 0x64, 0x8F, 0xAE, 0xB1, 0xBE, 0x86, 0x30, 0xDB, 0x40, 0xD1, 0x51, 0xB8, 0xFB, 0xA6, 0x93, 0xDF, 0x2C, 0x5B, 0xDC, 0xAA, 0x14, 0xDC, 0x47, 0x83, 0xF4, 0x50, 0xB6, 0xBC, 0x40, 0x75, 0x15, + 0xCE, 0xEB, 0xC5, 0xC9, 0xA4, 0x7B, 0xD1, 0xA1, 0x41, 0x38, 0x4F, 0x0B, 0x59, 0x6C, 0xAB, 0x11, 0x35, 0xC0, 0x75, 0x65, 0x1C, 0xBA, 0x98, 0x9C, 0x19, 0x0F, 0x31, 0x71, 0xDC, 0x1D, 0x72, 0x33, + 0x0E, 0xDA, 0xA0, 0x16, 0x56, 0x81, 0x3C, 0x4B, 0x78, 0x11, 0x71, 0x50, 0x60, 0xB0, 0x23, 0xFC, 0x42, 0x67, 0x45, 0xC3, 0x01, 0xB2, 0xA9, 0x1E, 0x0D, 0x08, 0xED, 0x3B, 0xDE, 0xD4, 0x38, 0xC4, + 0xCE, 0x67, 0x99, 0xC3, 0x5F, 0x39, 0x81, 0xC8, 0x82, 0xA0, 0xBD, 0xE4, 0xA2, 0xFE, 0xEB, 0x1A, 0x52, 0xCA, 0xFA, 0x47, 0xB0, 0xC4, 0x85, 0x58, 0xFC, 0x43, 0xF9, 0x8F, 0xE0, 0x8F, 0x03, 0xA7, + 0x11, 0x28, 0x36, 0x2B, 0xB6, 0xFB, 0x9D, 0xA6, 0xA2, 0x22, 0x49, 0xF4, 0xD4, 0x35, 0x2A, 0xE7, 0xD3, 0xDA, 0xE8, 0x5D, 0xE4, 0x97, 0xE2, 0x41, 0x1E, 0xAD, 0xCF, 0xE5, 0xBF, 0x1A, 0x3C, 0x07, + 0x5C, 0x45, 0x81, 0x1E, 0x00, 0x97, 0xEC, 0xEA, 0x25, 0x5F, 0xE1, 0x5B, 0xD8, 0x32, 0x1F, 0xE8, 0xB5, 0x46, 0xA8, 0xCA, 0xCF, 0xB8, 0x99, 0xEE, 0xCF, 0x54, 0x19, 0xDB, 0x36, 0x3C, 0x75, 0x67, + 0xC2, 0xFE, 0x73, 0x60, 0xB3, 0x6D, 0xE1, 0x46, 0x74, 0xF5, 0x00, 0xA3, 0x1D, 0x3E, 0xEC, 0x71, 0x45, 0x1A, 0x7C, 0x0D, 0x55, 0x76, 0xA8, 0x93, 0x9C, 0x0F, 0x6D, 0x4D, 0x9F, 0x2F, 0x03, 0xF3, + 0xC5, 0x16, 0xCE, 0x25, 0xCE, 0x73, 0xAB, 0xB3, 0x5C, 0x73, 0xAA, 0x94, 0xF6, 0xAE, 0xFA, 0xE6, 0xAD, 0x87, 0x05, 0x2D, 0x6B, 0x19, 0x5F, 0xA4, 0x35, 0x86, 0x81, 0x7F, 0x5B, 0xB9, 0x74, 0xAA, + 0xE7, 0xF1, 0xB8, 0x60, 0x89, 0x22, 0x41, 0x1A, 0xA5, 0xB0, 0xD7, 0xD5, 0x74, 0x01, 0x6C, 0xBD, 0x3D, 0xED, 0x13, 0x39, 0x56, 0x23, 0x47, 0x0A, 0x10, 0x8F, 0xA0, 0xE1, 0xD3, 0xF9, 0xFA, 0xA7, + 0xE1, 0xE5, 0x03, 0x18, 0x43, 0xF2, 0xA2, 0x3D, 0xBC, 0xE8, 0xB1, 0x96, 0x31, 0x52, 0x90, 0xDE, 0xA5, 0x79, 0x5E, 0x41, 0x15, 0xD5, 0x3D, 0xC5, 0x70, 0xA4, 0x44, 0x06, 0x4C, 0xFA, 0x3C, 0x94, + 0x57, 0xDB, 0xF3, 0xEE, 0x32, 0x3B, 0x19, 0x66, 0xEC, 0xD2, 0x27, 0x0C, 0x32, 0x91, 0x0F, 0x8F, 0x43, 0x05, 0x22, 0x47, 0x12, 0x58, 0xA1, 0xF1, 0x95, 0x5A, 0x6E, 0x1D, 0xD8, 0xC8, 0x4E, 0xD9, + 0xA5, 0x66, 0x49, 0x9B, 0xF8, 0x56, 0x28, 0x61, 0x53, 0x51, 0xAB, 0xE8, 0x4B, 0x40, 0x14, 0x21, 0xDA, 0x2C, 0xFA, 0xF5, 0x75, 0xE2, 0x64, 0x4C, 0x93, 0x04, 0xC0, 0x75, 0xEC, 0xFC, 0x37, 0x40, + 0x66, 0xCE, 0xC7, 0x13, 0xFA, 0x4C, 0x0D, 0x89, 0x04, 0x36, 0x89, 0xFB, 0xC5, 0x9F, 0xF5, 0x4B, 0x8F, 0x97, 0xEE, 0x0A, 0x3B, 0x09, 0x89, 0xBC, 0x5E, 0x4E, 0xF8, 0x3C, 0xC9, 0x83, 0x3E, 0x75, + 0xBC, 0x8B, 0x67, 0xBB, 0x5E, 0xE3, 0xC0, 0x6E, 0xA1, 0x56, 0x61, 0x1C, 0xDA, 0x95, 0xA6, 0x70, 0x24, 0x16, 0x80, 0x75, 0x30, 0xEA, 0x20, 0x6E, 0xD8, 0x98, 0x35, 0xD2, 0x08, 0x05, 0xEA, 0x98, + 0x8B, 0x19, 0x58, 0x56, 0x9C, 0xDF, 0x7F, 0x80, 0x99, 0x96, 0x21, 0x4D, 0xAD, 0xAB, 0x4E, 0x20, 0xBD, 0x44, 0x91, 0x7E, 0x34, 0x10, 0xEC, 0x6B, 0xEA, 0xC9, 0x8F, 0xEA, 0x07, 0xF7, 0x64, 0xE8, + 0x5B, 0x66, 0xAE, 0xD5, 0xE1, 0x7C, 0xF6, 0x75, 0xD2, 0xED, 0x8E, 0x63, 0xDB, 0x72, 0x8F, 0xE7, 0x51, 0x58, 0xCB, 0x31, 0x77, 0x9E, 0x31, 0x37, 0x96, 0x48, 0xB4, 0x3D, 0x68, 0xCC, 0xFF, 0x37, + 0x80, 0x85, 0x4C, 0xF0, 0x35, 0x35, 0xC5, 0x71, 0x22, 0x01, 0x94, 0x56, 0xE7, 0x3C, 0xF0, 0x67, 0x69, 0xBF, 0x1F, 0xBF, 0x55, 0x85, 0x42, 0x24, 0x1C, 0xE6, 0x65, 0xBD, 0x10, 0xF9, 0x21, 0x82, + 0x85, 0x53, 0x58, 0x5E, 0x0C, 0xF6, 0x64, 0xCD, 0xC6, 0x16, 0x0F, 0x9C, 0x47, 0xFA, 0x53, 0x30, 0x59, 0x1B, 0x74, 0x19, 0x4F, 0x47, 0x16, 0x05, 0x6C, 0xA8, 0x39, 0x93, 0xEF, 0xEC, 0x4A, 0x52, + 0xDB, 0x9A, 0x1F, 0xBD, 0x3B, 0x2F, 0x50, 0x4A, 0xC1, 0x96, 0x67, 0x32, 0x51, 0x67, 0x40, 0x73, 0x75, 0xB6, 0xD7, 0xDE, 0x73, 0x9F, 0x07, 0x94, 0x7B, 0x51, 0x1C, 0x8D, 0x47, 0x57, 0x44, 0xE5, + 0xC2, 0x9D, 0x6E, 0x28, 0x6A, 0x37, 0xF1, 0xFF, 0x83, 0x17, 0xBD, 0x01, 0x78, 0xF0, 0xE3, 0x06, 0xA3, 0x8F, 0xA6, 0xE7, 0x5F, 0x4A, 0x80, 0x42, 0x7F, 0xEB, 0x2C, 0x91, 0x23, 0x5D, 0x3E, 0x7F, + 0x20, 0xD8, 0x10, 0x1C, 0xFC, 0x03, 0xBB, 0x73, 0xF4, 0x4E, 0xF5, 0x9A, 0xF3, 0x52, 0x6E, 0x9A, 0xFC, 0x58, 0x00, 0x27, 0xA1, 0xDA, 0xDE, 0x37, 0x65, 0x42, 0x38, 0xB8, 0xEC, 0x7A, 0xF0, 0x10, + 0x52, 0x48, 0xFE, 0x30, 0x78, 0x4A, 0x88, 0xB7, 0x2E, 0x11, 0xFC, 0x1B, 0xD8, 0x07, 0xE4, 0x7A, 0x34, 0x9B, 0xD2, 0x90, 0x75, 0xBE, 0xFB, 0xB2, 0x97, 0x30, 0xEF, 0x8E, 0x85, 0xE3, 0xAB, 0xD5, + 0x10, 0x55, 0x59, 0xBA, 0xCE, 0xE7, 0x4A, 0xA2, 0x7D, 0x90, 0xD3, 0x60, 0xA8, 0xD6, 0x29, 0xDB, 0xEC, 0x95, 0xEB, 0x34, 0xC7, 0xF7, 0xCA, 0x20, 0x09, 0x6F, 0xF7, 0xB5, 0x21, 0xE4, 0x0D, 0x39, + 0x44, 0xA9, 0x75, 0x43, 0x68, 0x96, 0xF3, 0x72, 0xEE, 0xAB, 0x6B, 0x86, 0x15, 0xEB, 0x91, 0x69, 0x79, 0x65, 0xBB, 0xF9, 0x55, 0x77, 0x9D, 0xD3, 0x04, 0x7F, 0x7E, 0x3B, 0xF0, 0x29, 0xE3, 0x50, + 0x9A, 0x57, 0x80, 0x24, 0x74, 0x45, 0xD6, 0x22, 0x3D, 0x08, 0x5A, 0xFB, 0x42, 0x91, 0xD9, 0x76, 0xEF, 0xAD, 0xC4, 0x1E, 0x42, 0xDC, 0x2C, 0x07, 0x28, 0xD1, 0x8F, 0x61, 0x55, 0x65, 0x4A, 0x33, + 0x2F, 0xEC, 0x72, 0xEB, 0x6A, 0xEF, 0x8B, 0x92, 0xC1, 0xD1, 0x77, 0xE3, 0xDC, 0x28, 0xC3, 0x19, 0x71, 0xBC, 0xAF, 0xF7, 0x6D, 0xDE, 0xBF, 0xD9, 0x58, 0x8B, 0xC2, 0x44, 0xB1, 0x16, 0xD4, 0x09, + 0xE5, 0x8D, 0xC5, 0xAD, 0xA1, 0x64, 0x86, 0x63, 0xD6, 0x03, 0xC4, 0x7F, 0xAE, 0xB8, 0x14, 0xAA, 0xA7, 0xEB, 0x9B, 0x62, 0x64, 0x35, 0x6F, 0x92, 0x6C, 0x18, 0xB9, 0x35, 0x7B, 0xF4, 0x26, 0xB8, + 0x9D, 0xDC, 0x8E, 0xB9, 0x17, 0x7E, 0xCE, 0xB5, 0xC6, 0xCD, 0xC6, 0x4D, 0xD8, 0xFE, 0xB7, 0xB3, 0x26, 0xBC, 0x1B, 0xA8, 0x9B, 0xD9, 0x03, 0x52, 0x35, 0xDA, 0x0E, 0x64, 0x4E, 0xF9, 0x59, 0xC5, + 0x8D, 0xD9, 0x7B, 0x88, 0xD5, 0xC7, 0x49, 0xB3, 0x69, 0x31, 0xAC, 0x26, 0x94, 0xC6, 0x71, 0x51, 0xDB, 0x08, 0x94, 0x65, 0x2E, 0x99, 0x25, 0x42, 0x22, 0xD3, 0x7C, 0xEF, 0xE9, 0xE2, 0x7B, 0x3D, + 0xD6, 0x63, 0xA1, 0x52, 0xDB, 0xE2, 0x9A, 0x36, 0x39, 0xAF, 0xE4, 0x2F, 0x45, 0x78, 0x93, 0x70, 0x76, 0x18, 0x05, 0x63, 0xAA, 0xD6, 0xAD, 0x73, 0x92, 0x55, 0xEA, 0x01, 0x2A, 0x17, 0xD2, 0xA5, + 0x66, 0x27, 0xD8, 0x4C, 0x44, 0xFB, 0xAB, 0x26, 0x1D, 0x39, 0x2A, 0x96, 0x6C, 0xFE, 0x19, 0x27, 0x87, 0x99, 0xCF, 0x16, 0x34, 0xD4, 0x23, 0x84, 0x32, 0x3C, 0x49, 0x61, 0x90, 0xD4, 0xB9, 0xFB, + 0x66, 0x26, 0x94, 0xE3, 0x88, 0x7E, 0xA6, 0x6A, 0xB9, 0xE8, 0xB1, 0x95, 0x48, 0x8C, 0x8D, 0xCA, 0x47, 0xC8, 0xBC, 0x04, 0x24, 0x24, 0x77, 0x59, 0x13, 0x7C, 0xFB, 0xF8, 0x6D, 0xED, 0xC3, 0x64, + 0x19, 0x04, 0xCB, 0x6F, 0xAC, 0xBB, 0x30, 0xA9, 0xFA, 0x84, 0xAC, 0xF6, 0x9A, 0x67, 0xB4, 0xAF, 0xDF, 0x4C, 0x2A, 0xA4, 0x20, 0xFC, 0x0D, 0x90, 0xCE, 0xFA, 0x0D, 0xFB, 0xBC, 0xD3, 0x07, 0x2D, + 0x9F, 0x77, 0x2F, 0xD6, 0x05, 0x8E, 0x2B, 0xF0, 0xE2, 0x51, 0xBE, 0x93, 0xB0, 0x0D, 0xC4, 0x37, 0x65, 0xB5, 0x3D, 0xB5, 0x1B, 0x22, 0xF1, 0x2D, 0x3E, 0xD0, 0xCC, 0x56, 0x55, 0xE4, 0xAE, 0xBD, + 0x9D, 0x92, 0x3F, 0x99, 0xA4, 0x3E, 0x44, 0x61, 0xDC, 0xF5, 0x99, 0x20, 0x30, 0xE6, 0x6A, 0x1C, 0xDC, 0x3A, 0x65, 0x55, 0x8D, 0x9B, 0xB3, 0xA3, 0x97, 0x88, 0xD9, 0x23, 0x28, 0x38, 0x7D, 0x14, + 0x48, 0x50, 0xDD, 0x37, 0x06, 0xFD, 0x7A, 0x07, 0x9E, 0x3D, 0x23, 0x98, 0xF5, 0x42, 0xF9, 0x1A, 0x8A, 0xAA, 0xBF, 0x0C, 0x50, 0x68, 0xDB, 0xAF, 0x1F, 0xCC, 0x51, 0x60, 0x39, 0x8A, 0xBE, 0xCF, + 0x74, 0x88, 0x4B, 0xEB, 0x04, 0xF3, 0xA3, 0xEA, 0x38, 0xBB, 0xB8, 0x0D, 0x79, 0x8F, 0x59, 0x81, 0xB3, 0xF2, 0xDB, 0x6C, 0x7B, 0x33, 0xF8, 0x67, 0xB7, 0xDC, 0x06, 0xA4, 0x41, 0x7E, 0x30, 0xF9, + 0x4C, 0xDB, 0x4F, 0x52, 0x3A, 0xEE, 0xA0, 0xBE, 0x12, 0xBD, 0x75, 0xAA, 0xED, 0x57, 0x52, 0x0D, 0xB0, 0xD4, 0xB4, 0xF0, 0x13, 0xBE, 0x3A, 0x1D, 0xC7, 0xAE, 0x5C, 0x58, 0xFD, 0x1D, 0xE9, 0x63, + 0x7F, 0x7D, 0x82, 0xF6, 0x97, 0xB7, 0xE9, 0x2D, 0xA4, 0x27, 0xA7, 0x8F, 0xEE, 0xC6, 0xA5, 0xC0, 0x25, 0x5E, 0xB5, 0x7A, 0x43, 0xDE, 0xA6, 0xCE, 0xBC, 0x88, 0x05, 0xBC, 0x04, 0xE0, 0x4F, 0xE7, + 0x89, 0xE2, 0x22, 0xB1, 0xE2, 0x64, 0x2D, 0x26, 0xED, 0xC1, 0x4F, 0xB3, 0x6E, 0xCC, 0x60, 0x92, 0xB3, 0x06, 0x0E, 0x45, 0xEE, 0xD6, 0xC5, 0xB3, 0x5D, 0xE8, 0x74, 0x1F, 0x72, 0x93, 0x39, 0x30, + 0xEC, 0xBD, 0x73, 0x38, 0xCF, 0x39, 0x47, 0x41, 0x22, 0x35, 0x73, 0x65, 0x70, 0x0C, 0xB5, 0x0C, 0x5E, 0xB1, 0x76, 0xFB, 0x92, 0x81, 0x4F, 0xA7, 0xF4, 0x03, 0x25, 0x70, 0xCC, 0xEE, 0x6B, 0x85, + 0x92, 0x36, 0xAD, 0x5D, 0xA5, 0xF1, 0x73, 0x01, 0x29, 0xED, 0xC7, 0xBE, 0x21, 0x8B, 0xA9, 0x87, 0x46, 0x20, 0xF6, 0xF0, 0xEB, 0xC4, 0x5E, 0x0B, 0xD6, 0x22, 0xF8, 0xFD, 0x1A, 0xE6, 0x97, 0x49, + 0x94, 0xAF, 0x95, 0xC6, 0x51, 0x9E, 0xC1, 0xC4, 0x66, 0x50, 0xC0, 0x73, 0xD1, 0x94, 0xFA, 0x6E, 0xBC, 0x62, 0xF4, 0x05, 0xF6, 0x3A, 0x34, 0x16, 0x78, 0x2A, 0x47, 0x87, 0x2C, 0x7D, 0x77, 0xD6, + 0x48, 0xD0, 0xA1, 0xC8, 0x02, 0xFF, 0xDF, 0xDE, 0x5F, 0xDC, 0x11, 0x2C, 0x94, 0xCF, 0xC6, 0x8F, 0x40, 0x18, 0x89, 0xEF, 0xC5, 0x22, 0xFE, 0x48, 0x8F, 0xDB, 0x53, 0x84, 0xC0, 0xD9, 0x31, 0x47, + 0xAB, 0x65, 0x87, 0x65, 0x9D, 0x93, 0x6F, 0x98, 0xEC, 0xFB, 0xCD, 0xCF, 0xBF, 0x8B, 0x35, 0x2D, 0x60, 0x5F, 0x18, 0xC8, 0x55, 0xE2, 0x55, 0x97, 0x43, 0xED, 0x97, 0x99, 0x1C, 0x5D, 0x50, 0xDF, + 0x44, 0xA7, 0xB9, 0x29, 0x30, 0x38, 0x35, 0x65, 0x4A, 0x39, 0x55, 0xAB, 0xC5, 0xBE, 0xE6, 0x32, 0x74, 0x00, 0xA7, 0xCC, 0xCE, 0x46, 0x0B, 0x31, 0x8D, 0x8B, 0x5E, 0xCE, 0x5B, 0x12, 0xF6, 0x06, + 0xAD, 0xB3, 0xD7, 0xB5, 0xED, 0x59, 0x56, 0x3B, 0x8E, 0x67, 0x5E, 0x78, 0x02, 0x9A, 0xAB, 0xC2, 0x34, 0x44, 0x2C, 0x24, 0x63, 0x25, 0x6F, 0xE0, 0x2B, 0x04, 0xF5, 0x56, 0xDA, 0x35, 0xC4, 0x61, + 0x5D, 0x14, 0xA9, 0xF4, 0xEF, 0xF1, 0x7D, 0xB0, 0xDB, 0x81, 0xDE, 0x4B, 0xDD, 0x89, 0x4F, 0x66, 0x28, 0xA1, 0x20, 0xBE, 0x2D, 0x4C, 0xF3, 0xE1, 0xF4, 0x6D, 0x53, 0x81, 0x78, 0x99, 0x65, 0x70, + 0x35, 0xA7, 0x61, 0x37, 0xE2, 0x3C, 0x0B, 0x0E, 0x8D, 0xDD, 0x29, 0x46, 0x5D, 0x7F, 0x15, 0x62, 0x8F, 0xD4, 0x35, 0xE6, 0xCA, 0xAC, 0xA4, 0x19, 0x4F, 0xDB, 0xF8, 0x5F, 0xDC, 0xC3, 0x1D, 0x5D, + 0xAF, 0xCB, 0x52, 0x56, 0x8B, 0x7C, 0x0C, 0xFB, 0xE7, 0x13, 0xBC, 0x85, 0xFA, 0x42, 0x4B, 0xA3, 0xAB, 0xE1, 0x49, 0xE4, 0x03, 0x5F, 0xC8, 0x68, 0x07, 0xA8, 0xB8, 0x76, 0xD2, 0x16, 0x3B, 0x44, + 0x7C, 0xAD, 0x5E, 0xC0, 0xE6, 0xEF, 0x38, 0xA1, 0xD5, 0x91, 0xAF, 0xB4, 0x62, 0x67, 0xF9, 0xDB, 0xF1, 0x42, 0xCA, 0xB1, 0xCA, 0xC1, 0xF7, 0x3B, 0xEB, 0xA2, 0x12, 0x99, 0x2F, 0xC6, 0xD4, 0x64, + 0x7E, 0xC1, 0x78, 0x48, 0xD1, 0xAD, 0xBB, 0x19, 0x01, 0x27, 0x7A, 0x50, 0x78, 0xDD, 0x72, 0xD9, 0xC9, 0x18, 0x4E, 0x89, 0x3C, 0x08, 0x06, 0xE9, 0xB4, 0xAF, 0xF0, 0xA8, 0x24, 0x67, 0x0D, 0x43, + 0x86, 0x20, 0xF2, 0xA7, 0xE8, 0xD2, 0x96, 0x5B, 0x61, 0x9D, 0x29, 0x1E, 0x58, 0x24, 0xC0, 0x14, 0xFC, 0x88, 0x8A, 0x36, 0xFB, 0xBE, 0x17, 0x35, 0x64, 0x31, 0xF0, 0x03, 0x90, 0x38, 0xF9, 0xB4, + 0x97, 0x90, 0x2A, 0xED, 0x96, 0x9F, 0x9C, 0x48, 0x83, 0x90, 0xB7, 0x08, 0x77, 0x63, 0x63, 0x8E, 0x97, 0x68, 0x01, 0x12, 0x7B, 0xAF, 0x1F, 0x53, 0x80, 0x3C, 0x4D, 0xC9, 0x64, 0x9F, 0x0E, 0xE8, + 0x5D, 0x67, 0xB2, 0x39, 0xE2, 0xBD, 0xAF, 0xB2, 0xBD, 0x75, 0xF1, 0xD1, 0xDA, 0x22, 0xA5, 0x6F, 0xB3, 0xAF, 0x10, 0xA9, 0xDD, 0xE7, 0xAD, 0x30, 0x6C, 0x4A, 0xF8, 0x68, 0x10, 0x29, 0x31, 0x6C, + 0x0E, 0x19, 0x49, 0x22, 0x8E, 0x6B, 0xF5, 0xAD, 0xF9, 0x42, 0xF1, 0xC0, 0xEF, 0x92, 0xB2, 0xBC, 0xBC, 0x0C, 0x70, 0xD4, 0x9E, 0x58, 0x08, 0x85, 0x14, 0x44, 0x24, 0x0A, 0x78, 0xB1, 0x4D, 0x21, + 0xB5, 0x4F, 0x66, 0x27, 0x14, 0x82, 0xF4, 0x9B, 0x85, 0xF5, 0x18, 0x0B, 0x26, 0x80, 0x50, 0x32, 0x73, 0x68, 0x49, 0x6C, 0xFA, 0x8B, 0x54, 0xEC, 0xB9, 0x7E, 0xE6, 0xD2, 0x8E, 0xB7, 0x4A, 0x37, + 0x42, 0xF6, 0x85, 0x83, 0xDA, 0x04, 0x68, 0x09, 0x00, 0x2C, 0x22, 0xF7, 0xB3, 0x1F, 0xBC, 0x05, 0x66, 0x96, 0x9F, 0x9A, 0x15, 0xCD, 0xCA, 0x89, 0x2C, 0x4B, 0xEB, 0x10, 0x1A, 0x2A, 0xC3, 0x52, + 0x6C, 0x76, 0xE9, 0xD3, 0x09, 0x82, 0xC9, 0xB4, 0x89, 0x34, 0x50, 0xFD, 0xEC, 0x40, 0x01, 0xD2, 0x43, 0x18, 0x28, 0xD2, 0x4D, 0x8B, 0x1A, 0x67, 0xDF, 0x80, 0xE2, 0xE1, 0x0E, 0xD2, 0xEA, 0x8D, + 0x72, 0x32, 0x27, 0x05, 0x5C, 0x48, 0x00, 0x66, 0x65, 0xF7, 0xDA, 0x8E, 0x03, 0x2E, 0xFD, 0xC7, 0x0B, 0xC7, 0xEE, 0xB2, 0xB3, 0x69, 0xB5, 0x51, 0xFA, 0xC5, 0x42, 0xAD, 0x6D, 0xF1, 0xA2, 0x31, + 0x07, 0xE2, 0xB3, 0xC0, 0xE3, 0xCC, 0xAC, 0xC2, 0x5F, 0x26, 0x40, 0x4C, 0x08, 0x5C, 0xBF, 0x56, 0xE5, 0x2D, 0x35, 0xD7, 0x94, 0x8D, 0xB9, 0xFD, 0xA6, 0xDF, 0xC2, 0x47, 0x09, 0x99, 0x47, 0x19, + 0xD8, 0xCE, 0xD4, 0x1A, 0x2C, 0xC9, 0xB3, 0xC4, 0xB2, 0xBE, 0xF0, 0x96, 0x7C, 0xB7, 0x18, 0x61, 0xCF, 0x0E, 0x6A, 0xEA, 0x9B, 0xEC, 0x93, 0x95, 0x72, 0x6A, 0xA0, 0xE2, 0xF1, 0xA7, 0x24, 0x7E, + 0xD0, 0xF6, 0x03, 0x8E, 0x3D, 0xF4, 0xBF, 0x56, 0x67, 0x86, 0x07, 0x35, 0x90, 0xDC, 0xF9, 0x7F, 0x8F, 0x0A, 0x99, 0x65, 0x8D, 0x8F, 0x63, 0x0A, 0x2D, 0x13, 0x0C, 0x46, 0xCF, 0x4D, 0x26, 0xC6, + 0x69, 0x36, 0x0D, 0x0F, 0x70, 0xB7, 0x5F, 0x90, 0x4C, 0x9F, 0x92, 0x3A, 0xB2, 0x85, 0xD5, 0xDB, 0x12, 0x9F, 0x6C, 0x25, 0xAD, 0x21, 0xF9, 0xE2, 0x6A, 0xC8, 0x44, 0xD0, 0x7A, 0x8E, 0xED, 0x86, + 0xC4, 0xE2, 0x24, 0xEB, 0xFC, 0x5B, 0x3F, 0x72, 0x0D, 0x6F, 0x94, 0xB0, 0xA0, 0x1B, 0x14, 0x33, 0xC4, 0x6B, 0x40, 0xCF, 0x84, 0xE8, 0x0F, 0x7A, 0x6A, 0xFA, 0x7B, 0xB8, 0xF9, 0xAC, 0xF8, 0x18, + 0xAD, 0x3C, 0xAB, 0x2D, 0xDD, 0x69, 0x04, 0xC0, 0x67, 0xBE, 0xA4, 0xF1, 0xFE, 0x79, 0xB8, 0x3C, 0xB0, 0xAA, 0x8F, 0xC7, 0x5B, 0x6B, 0x09, 0x6B, 0xAD, 0x6F, 0xE9, 0x4A, 0xBF, 0xD4, 0x8F, 0x8E, + 0xFC, 0x0F, 0x2B, 0x9A, 0x02, 0xEB, 0xDA, 0x8F, 0xDB, 0xDB, 0xE1, 0xC7, 0x7F, 0x18, 0x54, 0xED, 0xBA, 0x18, 0xAA, 0xE7, 0xF3, 0x1C, 0xED, 0x9C, 0xD3, 0x4C, 0x1B, 0x35, 0x51, 0x08, 0xDF, 0x18, + 0xA8, 0x95, 0x39, 0x32, 0xF7, 0x55, 0x4A, 0xF0, 0x5B, 0x20, 0x3A, 0x96, 0xA9, 0xBB, 0x93, 0xE0, 0xEF, 0xF5, 0x1D, 0x7F, 0x93, 0xB5, 0x6E, 0x35, 0x15, 0x62, 0xCF, 0x85, 0xA2, 0xD3, 0x5E, 0xAE, + 0x2C, 0x24, 0x27, 0xB8, 0x9A, 0x86, 0x62, 0xA1, 0xC7, 0x23, 0xD4, 0xF1, 0x4E, 0x6E, 0xAF, 0xDB, 0xD6, 0x36, 0xC2, 0xBB, 0x7A, 0xDE, 0x29, 0xC1, 0xA6, 0xBC, 0x8A, 0x46, 0x37, 0x34, 0xC8, 0x08, + 0xBE, 0xC6, 0x8B, 0x1E, 0x9A, 0x31, 0xAF, 0x6E, 0x29, 0xB4, 0x12, 0xF1, 0xCB, 0x8C, 0x90, 0xA9, 0x91, 0x1A, 0xC5, 0xC3, 0xEA, 0x71, 0xE4, 0x61, 0x13, 0xD2, 0xD7, 0xB1, 0xAE, 0x2D, 0x88, 0x02, + 0xB0, 0x6A, 0x77, 0x0F, 0xD0, 0xE9, 0xE4, 0x65, 0x28, 0x95, 0xE4, 0x21, 0x81, 0xAD, 0x09, 0xBB, 0x54, 0x1E, 0x94, 0x93, 0xF2, 0x58, 0x71, 0x1B, 0xB7, 0xBE, 0xDD, 0x3E, 0x7C, 0xA8, 0xB8, 0xCE, + 0x87, 0x56, 0x69, 0xCF, 0x80, 0xA6, 0x88, 0x0E, 0xCA, 0x3F, 0x13, 0x80, 0x0D, 0xE7, 0x01, 0x1E, 0xA6, 0x7F, 0x44, 0x3E, 0x50, 0x5C, 0x4F, 0xB4, 0x55, 0x60, 0x8A, 0xE5, 0x86, 0xF9, 0x22, 0xB3, + 0xC8, 0x3F, 0xD3, 0x3B, 0x30, 0x6B, 0xDE, 0xDB, 0x86, 0x22, 0x3C, 0x33, 0xE3, 0xAA, 0x65, 0xED, 0xC9, 0x3C, 0xBC, 0xF3, 0xA0, 0x3A, 0xDA, 0xF9, 0xF3, 0x28, 0x99, 0x79, 0x51, 0xD5, 0x9A, 0x92, + 0x00, 0xC0, 0xBA, 0x26, 0x18, 0xE3, 0x59, 0x6A, 0xF1, 0x76, 0xB4, 0x31, 0x22, 0xCE, 0xDC, 0x52, 0xB1, 0xE0, 0x06, 0xEA, 0x6D, 0x12, 0xDC, 0x23, 0x6A, 0x6F, 0xCD, 0x7C, 0xC4, 0x68, 0x25, 0xF2, + 0xEF, 0x7E, 0xD7, 0x16, 0x83, 0xA7, 0x31, 0xD7, 0x46, 0xFF, 0xF2, 0xFE, 0x54, 0xE0, 0xB3, 0x92, 0xA8, 0xCB, 0xFA, 0x38, 0x87, 0x31, 0x96, 0xBB, 0x2B, 0x83, 0x5D, 0xCA, 0x7C, 0xB7, 0xC3, 0xED, + 0x9A, 0x00, 0x4C, 0x7A, 0x32, 0x9B, 0x97, 0x34, 0xA1, 0x11, 0x74, 0x4B, 0xDA, 0xCD, 0xB6, 0x69, 0xE6, 0x9E, 0x9D, 0xF1, 0xE5, 0x2F, 0x07, 0xC5, 0x13, 0xE3, 0x75, 0x2A, 0x0C, 0xCD, 0x81, 0xD7, + 0xDD, 0xC4, 0xA6, 0x48, 0x68, 0xB7, 0xBB, 0x2B, 0xBB, 0xD2, 0x09, 0x53, 0x73, 0x48, 0x05, 0x22, 0xBE, 0x10, 0x61, 0x52, 0x48, 0xA1, 0x79, 0xDC, 0xB6, 0x1D, 0xAC, 0x90, 0xF7, 0xFA, 0x5F, 0xA9, + 0xB8, 0x4F, 0x19, 0x0A, 0x9C, 0x62, 0xB5, 0xFF, 0x9C, 0xD4, 0x73, 0xA9, 0x40, 0xF0, 0x3E, 0x71, 0x07, 0x15, 0x7D, 0x7E, 0xB6, 0x0A, 0xF1, 0xE3, 0xE3, 0x84, 0xFF, 0xE8, 0xA6, 0x7D, 0xCB, 0x23, + 0x89, 0xB3, 0xB0, 0xFA, 0xB7, 0xC7, 0x89, 0xCF, 0x10, 0x0C, 0xA9, 0x5C, 0xD6, 0xA8, 0x54, 0x42, 0xCB, 0x9A, 0x2C, 0x24, 0x3F, 0xB9, 0xD4, 0x54, 0xB2, 0x0B, 0xAE, 0x57, 0x62, 0xD7, 0x2B, 0x8F, + 0xE7, 0x9B, 0x4D, 0xF8, 0x11, 0x63, 0xD6, 0x1D, 0xE4, 0x57, 0x8C, 0xF9, 0x76, 0x99, 0x2D, 0x8B, 0x99, 0x89, 0xFC, 0x68, 0x08, 0x9F, 0x81, 0x1F, 0x53, 0xDB, 0x1E, 0x10, 0x92, 0xB6, 0x02, 0x20, + 0x55, 0x28, 0x76, 0xB8, 0x18, 0xBE, 0xA9, 0x81, 0x57, 0x18, 0x98, 0xCD, 0x6A, 0xB7, 0xB5, 0xF1, 0x3C, 0x46, 0xB0, 0xA0, 0x76, 0x52, 0x6E, 0x32, 0x41, 0xD6, 0x50, 0x14, 0xF8, 0x55, 0xEF, 0xD7, + 0xBD, 0xE0, 0x8A, 0xD9, 0x1F, 0x25, 0x9D, 0xCB, 0x64, 0xE9, 0x4E, 0xC3, 0xDA, 0xD9, 0x78, 0x11, 0xEB, 0x02, 0x4E, 0xE1, 0xD3, 0x41, 0x52, 0x1D, 0xC9, 0x2A, 0xE5, 0xE9, 0x3C, 0x73, 0x42, 0x20, + 0x88, 0x97, 0x6F, 0x2D, 0x27, 0xD6, 0x4E, 0x1D, 0x19, 0x3B, 0x95, 0x5E, 0x67, 0x36, 0xAD, 0x2B, 0xCC, 0xF3, 0xC1, 0xA5, 0x3D, 0x59, 0x05, 0x76, 0x43, 0x4A, 0xCB, 0xC0, 0xB6, 0x87, 0xF2, 0x7F, + 0x25, 0x5F, 0xEF, 0x35, 0x4E, 0x68, 0xAC, 0xA4, 0x71, 0x60, 0xEF, 0xA7, 0x12, 0x6F, 0x90, 0x8E, 0x08, 0xE4, 0x54, 0x8C, 0x11, 0x54, 0x6D, 0x9C, 0x41, 0x2D, 0x68, 0x5F, 0xA8, 0x4D, 0x2E, 0xB4, + 0xDC, 0xB2, 0xBD, 0xFC, 0x48, 0xE2, 0xFA, 0x80, 0x23, 0x54, 0x81, 0x98, 0xEB, 0xB0, 0x72, 0xA4, 0x80, 0x44, 0xF4, 0x39, 0x11, 0x43, 0xE3, 0xBE, 0xF4, 0xFF, 0x90, 0x66, 0xA4, 0xB0, 0xD0, 0x3A, + 0xDC, 0x82, 0x68, 0x19, 0xD6, 0x75, 0x88, 0xBA, 0x84, 0xF9, 0x9D, 0xA2, 0x74, 0x24, 0x10, 0x36, 0x52, 0xAC, 0xC0, 0x39, 0xDD, 0xD3, 0xB5, 0x67, 0x85, 0x1C, 0xD7, 0x8E, 0x41, 0x17, 0xA8, 0xB9, + 0x3A, 0xFE, 0x01, 0xFC, 0x8E, 0xEB, 0xDA, 0xA1, 0xAC, 0xB8, 0xBA, 0x9D, 0x09, 0x57, 0x89, 0xE7, 0x6B, 0x9D, 0x5A, 0xB9, 0xEE, 0x17, 0x7A, 0x15, 0xD6, 0x66, 0xEF, 0x17, 0x1F, 0xE1, 0xD4, 0xBD, + 0xCC, 0xFE, 0x2E, 0x58, 0xCE, 0x66, 0x9B, 0x56, 0x1F, 0x63, 0x02, 0x8C, 0x6C, 0xE2, 0x6D, 0xB5, 0xC8, 0x18, 0x2F, 0xE0, 0x48, 0x68, 0x0B, 0x17, 0x5C, 0x7A, 0xB4, 0x07, 0x21, 0x5F, 0xF3, 0xA7, + 0x80, 0x1C, 0x95, 0x0D, 0x50, 0x98, 0x67, 0xAB, 0x1B, 0x0B, 0xEF, 0x89, 0xB3, 0xE3, 0x8A, 0x38, 0x79, 0x15, 0x22, 0x5E, 0xDE, 0x76, 0xF9, 0x1A, 0xAD, 0x15, 0xA8, 0x5D, 0x8C, 0x46, 0xEF, 0xD5, + 0x88, 0xBB, 0x3B, 0xAA, 0xCB, 0xC5, 0x2C, 0x03, 0x62, 0x11, 0x51, 0x24, 0x73, 0x42, 0x0F, 0x3F, 0x06, 0x1F, 0x5F, 0x53, 0xE9, 0x35, 0x3D, 0xE0, 0x78, 0x04, 0x25, 0x74, 0x5A, 0x76, 0x43, 0x9B, + 0x38, 0x11, 0x51, 0x1C, 0x86, 0xCA, 0x50, 0x32, 0x51, 0xF2, 0x41, 0x13, 0x38, 0x4E, 0x1A, 0x24, 0xA9, 0x36, 0x75, 0x36, 0xE7, 0x96, 0xCE, 0x08, 0xB8, 0x96, 0xF5, 0x72, 0x48, 0x9A, 0x23, 0x39, + 0xE8, 0x2A, 0x85, 0x6C }, + .sig_len = 3366, + .sig = { 0x02, 0xDC, 0x2B, 0xA0, 0x51, 0x2A, 0xB4, 0x69, 0x6F, 0xE3, 0x10, 0x24, 0x8A, 0xCC, 0x49, 0x59, 0x7B, 0xB6, 0xA8, 0x71, 0xA3, 0x67, 0x50, 0xB0, 0xF4, 0x9D, 0xFA, 0x78, 0x3C, 0x02, 0xD1, 0x60, + 0x99, 0x5B, 0xB1, 0xF8, 0x5C, 0xBF, 0xD6, 0x1D, 0xC2, 0xBB, 0x5D, 0xEF, 0x05, 0x7A, 0x64, 0xBF, 0x46, 0xC7, 0xFB, 0x58, 0x39, 0x14, 0x30, 0x71, 0x97, 0x63, 0x0C, 0x36, 0xBB, 0x7C, 0x48, 0xB3, + 0x3E, 0x18, 0x6A, 0x65, 0x6B, 0xFD, 0x4E, 0x19, 0xA6, 0x19, 0x96, 0x13, 0x12, 0xD2, 0xCA, 0x25, 0x3F, 0xB7, 0xC7, 0x6A, 0xF3, 0x99, 0x7C, 0x14, 0xE1, 0x60, 0x78, 0x62, 0xA4, 0x33, 0xB7, 0xEB, + 0x10, 0x01, 0xED, 0x04, 0x7A, 0x05, 0xDF, 0xEE, 0x7F, 0x1E, 0xB1, 0x5E, 0x5D, 0xFE, 0xB1, 0xD3, 0x8E, 0x40, 0x6D, 0x8F, 0xF8, 0xB7, 0x2A, 0xA6, 0x62, 0x5C, 0x6D, 0x8D, 0xB9, 0x88, 0x4C, 0x03, + 0x9D, 0x15, 0xA7, 0x30, 0x16, 0x6D, 0x36, 0xB0, 0x53, 0x4B, 0x5A, 0xF1, 0xC0, 0x20, 0xD9, 0x09, 0x17, 0x80, 0xEA, 0x07, 0xE0, 0x97, 0x6C, 0x67, 0xF6, 0xEA, 0xBA, 0x64, 0x0B, 0xCB, 0x4E, 0x38, + 0xAD, 0xC7, 0xD2, 0x98, 0x44, 0x94, 0xBE, 0x19, 0xCA, 0x21, 0xB2, 0x90, 0x90, 0x12, 0x24, 0x95, 0x0F, 0x0D, 0x97, 0xD1, 0x9B, 0xBF, 0x00, 0xD3, 0xD2, 0x1E, 0x31, 0xE7, 0x16, 0xF1, 0xA6, 0x5F, + 0x1F, 0x7C, 0xF0, 0x99, 0x98, 0x4C, 0xBD, 0x02, 0x5C, 0xE3, 0x04, 0x19, 0xE0, 0xEB, 0x86, 0x8F, 0x57, 0xA4, 0xA4, 0xED, 0xD9, 0x02, 0x05, 0xBA, 0x42, 0x1D, 0x54, 0x75, 0x71, 0x8D, 0xA4, 0x12, + 0xC0, 0xD1, 0x6C, 0xC4, 0x5C, 0x1B, 0xF5, 0xC6, 0xFF, 0xA3, 0x8D, 0xF3, 0x75, 0xEE, 0x1F, 0x4C, 0x9E, 0x4B, 0x0E, 0xFB, 0xAD, 0xBE, 0xFC, 0x97, 0x3B, 0xF1, 0x81, 0xED, 0x77, 0x49, 0x99, 0x93, + 0x91, 0x99, 0xAB, 0x30, 0xD8, 0x0B, 0xDD, 0x70, 0xFA, 0xE3, 0x11, 0x2E, 0x22, 0x44, 0xBC, 0x29, 0x1F, 0xCA, 0x47, 0x17, 0x7E, 0xF9, 0xA6, 0xBA, 0xBE, 0x45, 0x1F, 0x17, 0xA3, 0x60, 0xBC, 0x8C, + 0xE6, 0xDF, 0x1C, 0x05, 0x67, 0x3D, 0xF1, 0xC2, 0xF5, 0x4A, 0x52, 0xEA, 0x39, 0x8A, 0x7D, 0xDE, 0x20, 0xC7, 0xFA, 0x76, 0x30, 0x66, 0xFB, 0xDD, 0x74, 0x22, 0x79, 0x61, 0x25, 0x14, 0xDF, 0xE7, + 0x46, 0x8E, 0x9B, 0x1D, 0x27, 0x57, 0x6C, 0x39, 0xA5, 0xFC, 0xA1, 0x21, 0xDF, 0x00, 0x6E, 0xCD, 0xF2, 0x0B, 0x30, 0xF4, 0x9E, 0x17, 0xF6, 0xA7, 0x8C, 0xA2, 0x76, 0x75, 0xA0, 0xE6, 0xC1, 0x4F, + 0x3E, 0x6A, 0xF1, 0x43, 0x3C, 0xBF, 0xEA, 0x4A, 0xC2, 0xEC, 0xF9, 0xFB, 0x91, 0xDD, 0x68, 0xB3, 0x96, 0x40, 0xBB, 0x07, 0xDB, 0xE9, 0xC3, 0xCB, 0x90, 0xF8, 0x67, 0x09, 0xB1, 0x74, 0x25, 0xCE, + 0x4C, 0x10, 0x1F, 0x87, 0xBA, 0x37, 0xB7, 0xE8, 0x1C, 0x91, 0xA9, 0x2A, 0xB4, 0x78, 0xCF, 0x7A, 0xEF, 0x8F, 0x3D, 0xB5, 0x2C, 0x8E, 0x3C, 0xDC, 0x65, 0x95, 0x83, 0x76, 0xBE, 0xFD, 0xE9, 0xEA, + 0x56, 0x38, 0x4B, 0xF0, 0x44, 0xF0, 0x37, 0x32, 0xFA, 0x34, 0x34, 0x98, 0x44, 0xBC, 0x91, 0x13, 0xD4, 0x19, 0xDB, 0xB2, 0x4D, 0xB4, 0x44, 0xE2, 0x53, 0xAF, 0x4E, 0x62, 0xA7, 0x23, 0x38, 0x4C, + 0x3A, 0xE6, 0x85, 0x37, 0xB4, 0x1A, 0x2B, 0x86, 0x19, 0xF8, 0x4B, 0x59, 0x32, 0xC6, 0x02, 0x69, 0xE1, 0x08, 0x77, 0x49, 0x0D, 0x82, 0x52, 0xB5, 0x3A, 0x42, 0x5D, 0x6E, 0x69, 0xAE, 0xC0, 0x4B, + 0xBD, 0x2B, 0xD6, 0x7F, 0x32, 0x2D, 0x71, 0x31, 0x2C, 0x49, 0xC1, 0x6C, 0xAC, 0xC9, 0xE3, 0xCB, 0xE8, 0x67, 0xE2, 0xA4, 0xEC, 0x65, 0xEE, 0x9C, 0xA0, 0x41, 0xD6, 0xDE, 0xAF, 0x5F, 0xA0, 0x90, + 0xAF, 0xE6, 0x37, 0xA6, 0x50, 0xC0, 0x2A, 0x45, 0x72, 0xCD, 0x30, 0xBC, 0xFE, 0x8E, 0x90, 0x6B, 0x43, 0x82, 0xB5, 0xA8, 0x12, 0xD5, 0xBD, 0x6F, 0xCE, 0x64, 0xEE, 0xF6, 0xEC, 0xC1, 0x1D, 0xC8, + 0x39, 0xB7, 0xC4, 0xF0, 0x6C, 0xE5, 0x28, 0x50, 0x95, 0x4A, 0x08, 0x06, 0x0B, 0x49, 0x67, 0x97, 0xAC, 0xFC, 0x87, 0xE7, 0xC4, 0xAE, 0xED, 0x04, 0x46, 0x1E, 0xF1, 0xC4, 0x8E, 0x5C, 0x25, 0x46, + 0x0A, 0x90, 0x0E, 0x19, 0x26, 0x9B, 0xCA, 0x58, 0xF9, 0x72, 0xF9, 0x67, 0x9C, 0x45, 0xB9, 0xA4, 0x37, 0xCD, 0x20, 0x1E, 0xB1, 0xD1, 0x08, 0x91, 0xBA, 0x73, 0x75, 0x60, 0x9A, 0x6A, 0x47, 0x50, + 0x85, 0x98, 0x0D, 0xDF, 0x03, 0x6E, 0x8F, 0xE8, 0x62, 0xCC, 0xA1, 0x7F, 0x7D, 0x4B, 0xC2, 0x8B, 0x3C, 0xE8, 0x09, 0x17, 0x8E, 0xEF, 0x8D, 0x3B, 0x0D, 0x3D, 0x87, 0x48, 0x4E, 0x57, 0x05, 0xE5, + 0x7B, 0xC5, 0x02, 0xD4, 0x69, 0x9D, 0x56, 0xB2, 0xDD, 0x4E, 0x71, 0xEE, 0x11, 0x80, 0x9A, 0x7D, 0x88, 0x4C, 0x74, 0x79, 0xC9, 0x17, 0x85, 0x14, 0xE9, 0x1D, 0xCD, 0xB1, 0x9A, 0xDE, 0xF3, 0x3F, + 0x85, 0xCE, 0x95, 0x8F, 0xFA, 0x0E, 0xCC, 0x3E, 0x6B, 0xB8, 0x24, 0xCC, 0xB7, 0xFA, 0x21, 0x66, 0x02, 0x75, 0x2D, 0x3C, 0xF4, 0xE7, 0x66, 0xEB, 0xF5, 0x8D, 0x51, 0x65, 0x82, 0x80, 0x9B, 0xB3, + 0x6D, 0x95, 0xFB, 0xE1, 0xFA, 0xB5, 0x26, 0x1A, 0xCC, 0x34, 0x10, 0xCC, 0x81, 0x71, 0x34, 0x31, 0x0C, 0xB5, 0x28, 0x35, 0x7D, 0xB8, 0xF2, 0x48, 0x21, 0xD6, 0x75, 0x2F, 0xDE, 0xDF, 0x58, 0x06, + 0xBC, 0xDC, 0xD0, 0xE9, 0x28, 0x53, 0x54, 0x06, 0x8D, 0x08, 0xF0, 0x49, 0x67, 0xC0, 0x2D, 0xCB, 0x77, 0xD7, 0xDF, 0xE2, 0xDE, 0xD6, 0x97, 0xC3, 0x86, 0x66, 0xAF, 0xAD, 0x6D, 0x61, 0xE4, 0xB9, + 0x1C, 0x33, 0x3C, 0x15, 0x4A, 0x9C, 0x95, 0x41, 0x8D, 0x82, 0xAE, 0x50, 0xD9, 0x48, 0xF5, 0xF5, 0xEB, 0xBC, 0x09, 0xBA, 0xC3, 0x94, 0x77, 0xC3, 0xC6, 0xF0, 0x5D, 0x3F, 0x8A, 0xB1, 0x27, 0x30, + 0x96, 0xB5, 0x2C, 0x40, 0x06, 0x57, 0x4E, 0x32, 0x85, 0x3E, 0xD8, 0xF1, 0x9A, 0x9B, 0xF2, 0x10, 0x07, 0x9A, 0xF3, 0x72, 0xD0, 0xE1, 0xCB, 0xE8, 0x45, 0x21, 0x6A, 0x98, 0x2A, 0xC5, 0x75, 0x8B, + 0x58, 0x96, 0xBD, 0x5A, 0xFD, 0x83, 0x0C, 0xA0, 0x9C, 0x55, 0xB9, 0x8C, 0xD7, 0x31, 0x7F, 0xB8, 0x39, 0x51, 0x98, 0xD5, 0x1A, 0xEE, 0x55, 0x43, 0xC7, 0x21, 0x82, 0xB8, 0xA1, 0xEB, 0x8D, 0x72, + 0xE4, 0x12, 0x70, 0xB6, 0x40, 0x41, 0x66, 0x4D, 0xA0, 0x64, 0x31, 0x5A, 0xAC, 0xC4, 0x26, 0xF3, 0x74, 0xA9, 0x4E, 0x8E, 0x22, 0xA2, 0xC4, 0xE0, 0x54, 0x32, 0x98, 0xED, 0x59, 0x60, 0x34, 0xAD, + 0xC8, 0x2D, 0xC7, 0x5E, 0x06, 0xCE, 0xE9, 0xC1, 0x2B, 0x91, 0xE5, 0x2C, 0xDB, 0x60, 0xD6, 0xA6, 0x8F, 0x61, 0x95, 0xBB, 0xB7, 0xA6, 0x0F, 0x10, 0x2D, 0xF2, 0x5E, 0xFA, 0x4C, 0xF0, 0xA1, 0xC0, + 0x23, 0x11, 0xF1, 0xF1, 0x9D, 0x7D, 0x40, 0xE5, 0x95, 0xD5, 0x28, 0xBF, 0x23, 0x51, 0xEC, 0x59, 0x93, 0x46, 0x19, 0x61, 0x61, 0xD3, 0x8C, 0x8E, 0x81, 0xF9, 0xD9, 0x52, 0x3C, 0x77, 0xD0, 0xF2, + 0x55, 0xF2, 0x97, 0xBB, 0x88, 0x90, 0xC2, 0xC5, 0x7B, 0x87, 0x77, 0x43, 0x51, 0x82, 0x1C, 0x8A, 0x90, 0xCC, 0x3A, 0x74, 0xAC, 0xD4, 0x3C, 0x46, 0x5C, 0xBD, 0x5E, 0x5B, 0x94, 0xB6, 0x27, 0xCE, + 0xBC, 0x7C, 0x7F, 0x00, 0x06, 0x36, 0xC6, 0x16, 0x84, 0x77, 0xF2, 0x43, 0xD0, 0xC9, 0xFA, 0x96, 0x14, 0xEA, 0xCC, 0x82, 0x2F, 0x1B, 0x7C, 0x1D, 0x79, 0xE1, 0x60, 0x19, 0x20, 0x02, 0x76, 0xD1, + 0xA9, 0x26, 0x5A, 0x63, 0x7F, 0xD9, 0x64, 0x3F, 0x94, 0xF9, 0x67, 0xF6, 0xF5, 0xA3, 0x59, 0x98, 0x87, 0x13, 0x39, 0xEC, 0x35, 0xB6, 0xCC, 0x9E, 0xC8, 0xCE, 0xA0, 0x25, 0xE5, 0x71, 0x75, 0x2B, + 0x33, 0xF1, 0x71, 0x33, 0xD3, 0x01, 0x18, 0x55, 0x96, 0x1E, 0x2A, 0xC3, 0x94, 0x9C, 0x7F, 0xE1, 0x8C, 0x7F, 0xAC, 0x92, 0x55, 0x13, 0x42, 0xBF, 0x36, 0x05, 0x53, 0x14, 0xDE, 0xA9, 0xF1, 0x27, + 0x40, 0xE9, 0xDE, 0x7C, 0xBE, 0x73, 0x9E, 0x4C, 0x6A, 0x95, 0x1A, 0x15, 0xFD, 0xC7, 0x96, 0x06, 0xDF, 0xCC, 0x7E, 0x33, 0x73, 0x4F, 0x11, 0x9E, 0x43, 0xCB, 0xB4, 0x9B, 0x1F, 0x1B, 0x82, 0x69, + 0x8F, 0x00, 0xA8, 0x40, 0x10, 0xC8, 0xC6, 0x1F, 0x73, 0x0E, 0x90, 0xD3, 0x41, 0xFD, 0xC5, 0x77, 0x90, 0xF3, 0x5A, 0x81, 0x3A, 0x10, 0x53, 0x72, 0x1F, 0xCF, 0xE2, 0x55, 0x85, 0x87, 0xB3, 0x6E, + 0xA9, 0x19, 0x1F, 0x48, 0x6E, 0xE9, 0xCB, 0xB6, 0x45, 0x76, 0xEA, 0x25, 0xC7, 0x3E, 0x58, 0x7A, 0xF2, 0x45, 0x67, 0x40, 0xC3, 0x89, 0xF4, 0x49, 0xE2, 0x2A, 0xDE, 0xC6, 0x94, 0xD5, 0xB4, 0xD2, + 0x43, 0x05, 0x97, 0x36, 0x0C, 0xA2, 0x9F, 0xFA, 0xCD, 0xD4, 0x2A, 0xE5, 0x05, 0xEC, 0xEC, 0x10, 0x5A, 0x65, 0x16, 0x44, 0x85, 0xE2, 0x74, 0xC7, 0xED, 0x70, 0xF1, 0xAE, 0x24, 0x44, 0x42, 0x38, + 0x23, 0xDC, 0x02, 0x90, 0xF7, 0x45, 0x44, 0x7D, 0xBF, 0x30, 0x7F, 0x48, 0x9D, 0xFE, 0xDC, 0x26, 0x73, 0x1D, 0x3B, 0xD2, 0xBE, 0xB6, 0x9F, 0xAD, 0x82, 0x20, 0x9B, 0xB3, 0x1D, 0x4F, 0xBF, 0x2E, + 0x9C, 0x5B, 0x60, 0x80, 0x1A, 0xE8, 0x6C, 0xBE, 0x19, 0xD9, 0x9F, 0xEC, 0x15, 0x07, 0x81, 0x4F, 0x64, 0x38, 0x5F, 0x48, 0x91, 0xC7, 0x5A, 0x90, 0x22, 0x5D, 0xA7, 0x2A, 0x9A, 0xCE, 0xAF, 0xA2, + 0x00, 0xCF, 0xB0, 0x6F, 0x40, 0x9A, 0x14, 0x3F, 0x7C, 0xE7, 0xCD, 0x49, 0x7C, 0x19, 0x41, 0x5F, 0xDD, 0xD5, 0x26, 0xA4, 0xDC, 0xC9, 0x8B, 0xD1, 0x79, 0x70, 0xA7, 0xBD, 0xBB, 0x09, 0xF0, 0x61, + 0x77, 0xCD, 0xE8, 0x76, 0x05, 0x90, 0xBA, 0x6B, 0xFC, 0x82, 0xC3, 0xD1, 0xCE, 0x56, 0xAB, 0x3A, 0x43, 0xFA, 0x3B, 0xC1, 0xF4, 0x5F, 0x55, 0xD9, 0x67, 0x8F, 0x66, 0x03, 0x39, 0xBF, 0xB9, 0x03, + 0xA0, 0x39, 0x88, 0x6F, 0x76, 0x72, 0xF8, 0x3C, 0x4B, 0xE3, 0xAF, 0x0E, 0xEB, 0x49, 0xE0, 0x8E, 0x1F, 0xA4, 0x89, 0x67, 0x41, 0xC9, 0x49, 0xEC, 0xFD, 0xD5, 0xA2, 0x7D, 0x5E, 0x4F, 0xE7, 0x40, + 0x46, 0x18, 0xE0, 0xD6, 0xDE, 0x87, 0xE9, 0x7B, 0x15, 0x49, 0xAF, 0x57, 0xD0, 0xDA, 0x2D, 0x27, 0x66, 0xEA, 0xEE, 0xB7, 0x6D, 0xAB, 0x81, 0x36, 0xA5, 0x4C, 0x90, 0xCC, 0xFD, 0xCD, 0xCB, 0xCA, + 0x09, 0x0E, 0xAD, 0x20, 0x7F, 0xD6, 0xB6, 0xAE, 0xD2, 0x2D, 0x50, 0xB2, 0x1F, 0x83, 0x06, 0x77, 0x97, 0x82, 0x45, 0xBA, 0xF0, 0x01, 0xC3, 0xF1, 0x94, 0xEE, 0x3B, 0xC7, 0x91, 0xC7, 0xFE, 0xB0, + 0xAA, 0xB2, 0x0E, 0x74, 0xC9, 0x76, 0x0B, 0x8D, 0xD1, 0xF8, 0xFA, 0xBD, 0x35, 0x7B, 0x0B, 0x21, 0x9E, 0x27, 0xB5, 0x39, 0xD2, 0xB1, 0x9C, 0xD9, 0x44, 0xCA, 0x2A, 0x52, 0x0F, 0x26, 0x9F, 0x05, + 0x3F, 0x5B, 0x33, 0x35, 0x86, 0x64, 0xE7, 0x34, 0x70, 0xD2, 0x9F, 0xD7, 0x78, 0x6B, 0x67, 0x3B, 0x79, 0x28, 0xFA, 0xE8, 0x6F, 0x0D, 0xFE, 0x96, 0xD8, 0xA0, 0xDE, 0xAC, 0x07, 0xE4, 0x35, 0x8E, + 0xFC, 0xB7, 0x95, 0xA3, 0x8D, 0x24, 0x36, 0x2C, 0xE3, 0xCD, 0x67, 0x81, 0xD1, 0x6F, 0x4E, 0x2C, 0x2C, 0xF1, 0x39, 0x38, 0x50, 0x3D, 0xC0, 0xC5, 0x4E, 0x12, 0xD3, 0xF7, 0x41, 0x44, 0xD5, 0xE1, + 0x01, 0xD3, 0xA4, 0x6E, 0x53, 0x9B, 0x86, 0x34, 0xBF, 0xE9, 0xFB, 0x1E, 0xB0, 0x92, 0x22, 0x7B, 0xDA, 0x57, 0x5E, 0xBD, 0x23, 0xAF, 0xC0, 0xF7, 0x23, 0x67, 0x02, 0xDD, 0x75, 0x73, 0xA0, 0x7A, + 0x4C, 0x35, 0xE5, 0x80, 0x36, 0xED, 0xC0, 0xC6, 0x17, 0x22, 0x22, 0x35, 0x6E, 0x58, 0x34, 0x50, 0xEE, 0x12, 0x78, 0xBF, 0x23, 0xE0, 0xC7, 0xD1, 0xE4, 0xD3, 0x68, 0x3D, 0x3A, 0x80, 0x6B, 0x9F, + 0x21, 0xF2, 0x5C, 0x07, 0x13, 0xB9, 0xAE, 0xDF, 0xE4, 0x13, 0xCA, 0xA4, 0x90, 0xE3, 0x60, 0xB9, 0x4A, 0x9F, 0x2E, 0x23, 0x12, 0xB9, 0x3D, 0x77, 0x7F, 0x0B, 0xD4, 0x08, 0x6B, 0x26, 0xEE, 0x04, + 0x0C, 0x7C, 0x0A, 0xD3, 0x5B, 0xAF, 0x2F, 0x7D, 0x35, 0x4F, 0x21, 0xFD, 0x1B, 0x43, 0x08, 0xB7, 0x04, 0x47, 0xB9, 0x16, 0x35, 0x05, 0x63, 0x04, 0xD9, 0xF3, 0x32, 0x1B, 0xFE, 0x88, 0x22, 0x0B, + 0x0B, 0x8E, 0x2E, 0x63, 0x43, 0x56, 0x91, 0x4C, 0x8F, 0xA2, 0x54, 0x9F, 0xD9, 0x76, 0xD3, 0xB4, 0x42, 0x8F, 0x5E, 0x04, 0x17, 0x83, 0xB3, 0xFC, 0x89, 0x85, 0x20, 0xC8, 0x56, 0x94, 0xCF, 0x17, + 0xD5, 0x48, 0x7D, 0xEE, 0x98, 0x6A, 0xB0, 0x1C, 0x3A, 0xC2, 0x61, 0x09, 0x7C, 0xA2, 0xDC, 0xEF, 0x9B, 0x4A, 0xAE, 0x9B, 0xB2, 0x54, 0x71, 0xDD, 0x79, 0x3A, 0x43, 0xED, 0x1A, 0x13, 0x0B, 0x35, + 0xB0, 0x16, 0x29, 0xA5, 0xA8, 0xA7, 0xDA, 0xC1, 0xA1, 0x1B, 0x0F, 0x16, 0x19, 0xAF, 0x2A, 0xB2, 0x9D, 0xEB, 0x9F, 0xDE, 0x14, 0xA0, 0x03, 0x95, 0x0F, 0x2D, 0x84, 0x10, 0xF9, 0x15, 0x85, 0x6A, + 0x84, 0x6E, 0x76, 0xF9, 0x39, 0x38, 0xBB, 0x4A, 0xFE, 0x27, 0x50, 0xFB, 0x76, 0xF7, 0x65, 0x6C, 0xA3, 0xF2, 0x55, 0x14, 0x5E, 0xDB, 0xE7, 0xD8, 0x74, 0xE8, 0xBD, 0x78, 0xEE, 0xD4, 0xEC, 0x0E, + 0x44, 0x57, 0x55, 0xCA, 0x12, 0xB9, 0x51, 0xC3, 0x05, 0x80, 0x9A, 0xEB, 0x46, 0x4C, 0x9C, 0xE4, 0x33, 0x6F, 0x91, 0x88, 0x9C, 0xBD, 0xB2, 0x06, 0x70, 0x96, 0xA3, 0x63, 0xD0, 0xE6, 0xBF, 0xF0, + 0x77, 0xE4, 0x98, 0x48, 0x1F, 0x12, 0x52, 0x22, 0xB7, 0xF3, 0x40, 0x2C, 0x66, 0x6D, 0xE7, 0x62, 0x5A, 0x71, 0x90, 0x00, 0xCE, 0x6B, 0xF3, 0xAB, 0x07, 0x8B, 0x11, 0x88, 0x02, 0xC6, 0xE3, 0x00, + 0x4C, 0x98, 0xF1, 0x76, 0x39, 0x4A, 0xEA, 0xFC, 0x02, 0x72, 0x28, 0x7D, 0x7E, 0x89, 0xBF, 0x13, 0xF0, 0xE2, 0xD9, 0xDC, 0x13, 0x50, 0x5D, 0xFC, 0x17, 0x28, 0x86, 0xFB, 0xDE, 0x7A, 0x86, 0xCC, + 0x0C, 0xBF, 0x34, 0x3E, 0x33, 0xAF, 0x51, 0xCF, 0xE6, 0x20, 0x31, 0xAE, 0x70, 0x06, 0xAB, 0xB0, 0x08, 0x87, 0xC1, 0x6C, 0x77, 0xDD, 0xB9, 0xE9, 0xA7, 0xBB, 0xDD, 0x45, 0xF6, 0x1D, 0x2E, 0xE6, + 0x9E, 0x91, 0xF0, 0x0B, 0x68, 0xAD, 0xD7, 0xB5, 0xE2, 0x52, 0x13, 0x31, 0x27, 0x5D, 0x30, 0x20, 0xD4, 0x42, 0xC7, 0xFC, 0xB2, 0xCD, 0xF5, 0xFB, 0xE5, 0x71, 0x6F, 0x90, 0x7E, 0x67, 0x30, 0x8D, + 0xAF, 0x5B, 0xC1, 0x5D, 0x8C, 0xDA, 0x9A, 0xEA, 0x8A, 0xA1, 0x74, 0x3E, 0x2F, 0x69, 0x6A, 0x63, 0x5A, 0x3C, 0x38, 0x77, 0x82, 0x65, 0x16, 0x0C, 0xBE, 0x86, 0xCF, 0x68, 0xB3, 0x61, 0x87, 0xCD, + 0x3E, 0xC1, 0xE0, 0x69, 0xD5, 0x89, 0x8D, 0xAE, 0x1A, 0x84, 0x21, 0x71, 0xBF, 0x22, 0xFB, 0x32, 0x6C, 0x7D, 0x86, 0x5D, 0x4A, 0x87, 0x3D, 0xF4, 0xF9, 0xCA, 0xA6, 0xDB, 0x42, 0x9D, 0x2D, 0xF1, + 0x2B, 0x06, 0xD3, 0xF9, 0x3E, 0xA3, 0xDF, 0xBD, 0xFC, 0xA9, 0xEB, 0x08, 0xF7, 0x0F, 0x44, 0x5D, 0xC2, 0xCF, 0xE1, 0x56, 0xBA, 0xFF, 0xB2, 0x20, 0xE7, 0xC2, 0x4D, 0x41, 0xC4, 0x0C, 0xE3, 0x66, + 0x97, 0x07, 0x1B, 0x99, 0xE2, 0x1F, 0xAF, 0x50, 0x99, 0xB2, 0x9A, 0x0F, 0x47, 0x17, 0x9D, 0x64, 0xF1, 0x09, 0xCE, 0x3D, 0x31, 0xF7, 0xDC, 0x3D, 0xAA, 0x45, 0xD6, 0x41, 0x42, 0xC2, 0xF2, 0x47, + 0x40, 0x1D, 0xD1, 0x27, 0xAF, 0x55, 0x99, 0xCA, 0x07, 0xE5, 0xF2, 0x14, 0x90, 0x06, 0x1F, 0x43, 0xCD, 0x31, 0x9A, 0xF2, 0x63, 0x21, 0x9E, 0xF3, 0x08, 0x62, 0xEE, 0xAD, 0x7E, 0xA8, 0x34, 0xBD, + 0x86, 0xAA, 0xC6, 0x69, 0x8C, 0x50, 0x79, 0x19, 0x77, 0x06, 0x8E, 0x34, 0x7D, 0x86, 0xD7, 0xAB, 0x37, 0x02, 0xAB, 0x17, 0x52, 0x1C, 0xF6, 0x83, 0x8F, 0x11, 0x33, 0x46, 0xE0, 0x9F, 0xC1, 0xC2, + 0xB1, 0xF3, 0x02, 0x40, 0x84, 0xCA, 0x48, 0x0B, 0x4C, 0x5B, 0xBB, 0x0C, 0x74, 0x16, 0x5C, 0xD5, 0x84, 0x5B, 0x1A, 0x57, 0x4A, 0x0E, 0xFC, 0xB2, 0x77, 0xD8, 0x63, 0x8D, 0x75, 0x05, 0x24, 0xD6, + 0x75, 0x43, 0x45, 0x64, 0xCF, 0x67, 0x75, 0x41, 0x87, 0x19, 0xE2, 0xD0, 0x14, 0xCA, 0x0A, 0xF9, 0x17, 0x4C, 0x79, 0x53, 0x9D, 0xCE, 0xB9, 0x4C, 0x4E, 0xA0, 0x4D, 0x0E, 0x3E, 0xC5, 0x73, 0xFC, + 0xBF, 0xD0, 0x38, 0x3C, 0x9A, 0x72, 0xD5, 0x4F, 0xF9, 0x7E, 0x8B, 0x42, 0xAD, 0x16, 0xAA, 0x72, 0x23, 0xDA, 0x2A, 0x6D, 0xF1, 0xAD, 0x66, 0xC2, 0x17, 0x13, 0x2E, 0x6F, 0xA8, 0x9A, 0x33, 0xDA, + 0x19, 0x07, 0x43, 0x12, 0x89, 0x6A, 0x13, 0xC9, 0x96, 0xE0, 0x61, 0x7B, 0xF0, 0xF5, 0x3E, 0x5D, 0x0A, 0x86, 0xBA, 0xDB, 0xDC, 0x20, 0xC0, 0xB9, 0x6D, 0x3F, 0xB6, 0x40, 0x86, 0x7B, 0x20, 0xDF, + 0xD1, 0xFC, 0x71, 0x97, 0x99, 0xE9, 0x86, 0x36, 0x0D, 0x57, 0xDE, 0xB4, 0x9F, 0x71, 0x7B, 0x0D, 0x77, 0xD2, 0x5A, 0x08, 0xC3, 0x5A, 0xF7, 0x2E, 0x83, 0x99, 0x44, 0x23, 0x24, 0x78, 0x40, 0x5F, + 0xE4, 0x34, 0x9A, 0x0E, 0x3B, 0x24, 0xB0, 0x46, 0xB4, 0xAB, 0xA2, 0x2B, 0x68, 0xDA, 0x21, 0xF0, 0x4B, 0xDC, 0x9E, 0x33, 0xFE, 0x66, 0xD0, 0x39, 0xB3, 0xAF, 0x69, 0xC3, 0x42, 0xBA, 0xC0, 0x70, + 0x34, 0xA3, 0x9C, 0x31, 0xF9, 0x41, 0x3D, 0x80, 0x37, 0x5C, 0xBE, 0x1F, 0xAC, 0x63, 0xA9, 0x3E, 0xE0, 0x36, 0xA8, 0xA7, 0x47, 0x77, 0xD9, 0xFB, 0x9B, 0x19, 0x7C, 0x33, 0x40, 0xBD, 0xA7, 0xEC, + 0x57, 0xC2, 0xBB, 0x72, 0xCE, 0x04, 0x39, 0x46, 0x20, 0x72, 0x3B, 0xC0, 0xBE, 0x3D, 0xAA, 0xA9, 0xE4, 0xE5, 0xD7, 0xB4, 0x10, 0x30, 0xAD, 0xA4, 0x59, 0x93, 0x7E, 0x14, 0x5E, 0x1E, 0xDA, 0xCE, + 0x14, 0x4D, 0x56, 0x1A, 0xFA, 0x5F, 0x3D, 0x6D, 0x99, 0x97, 0xFC, 0x1E, 0xBC, 0xD8, 0x66, 0x39, 0xA2, 0x0A, 0xDF, 0xE6, 0x15, 0x74, 0x08, 0xF1, 0x9A, 0xB3, 0xBB, 0xB0, 0xE8, 0x16, 0xDC, 0xF3, + 0x9A, 0x4D, 0x8D, 0x0F, 0x5A, 0xD8, 0xE6, 0xA5, 0xEE, 0xC4, 0x24, 0x74, 0x85, 0x24, 0xA8, 0xDB, 0x2D, 0x79, 0x0C, 0x49, 0xD1, 0x54, 0xD6, 0x3E, 0x24, 0xF9, 0x21, 0xA7, 0xB0, 0x6A, 0xBC, 0xE6, + 0x41, 0x47, 0xE3, 0xF8, 0x89, 0xE8, 0x13, 0xDF, 0xF2, 0xC6, 0x7D, 0x1A, 0xA8, 0x52, 0x8D, 0x8B, 0xF5, 0xEB, 0xE8, 0x82, 0xD2, 0x3B, 0xBE, 0xDC, 0x38, 0x60, 0xCB, 0x7D, 0xA0, 0x66, 0x37, 0xB0, + 0xBF, 0x07, 0xB4, 0x97, 0xAE, 0x3A, 0x6A, 0x08, 0x40, 0x14, 0x1A, 0x23, 0x04, 0xE4, 0x59, 0x70, 0x07, 0xBF, 0xAC, 0xF0, 0x1E, 0x8A, 0xDA, 0xFE, 0xB0, 0xFF, 0x9B, 0xE6, 0x71, 0x89, 0x9E, 0x5C, + 0x5E, 0x99, 0x49, 0xEE, 0xDD, 0x3D, 0x11, 0xB9, 0x15, 0x9F, 0xEB, 0xD6, 0xBC, 0x63, 0xB9, 0x09, 0xEC, 0x2B, 0xBE, 0x5D, 0xE6, 0x7A, 0x75, 0xE9, 0x91, 0x62, 0xEF, 0xC5, 0x71, 0x03, 0x92, 0x95, + 0xDE, 0xA1, 0x76, 0x7E, 0x07, 0xD5, 0xDB, 0x2D, 0x8C, 0x5C, 0x0A, 0x63, 0x4B, 0x8D, 0xFC, 0x56, 0xD1, 0xF8, 0x16, 0x90, 0xDB, 0x9E, 0x4B, 0xFE, 0xD3, 0x80, 0xF8, 0x71, 0xB6, 0xAE, 0x5F, 0x82, + 0x03, 0xB9, 0xFE, 0x0A, 0x3F, 0xCD, 0xD2, 0x34, 0x61, 0x79, 0x60, 0x0B, 0x97, 0x0D, 0x68, 0x13, 0x72, 0xF8, 0x55, 0xE0, 0x39, 0x1B, 0x3D, 0xAB, 0x43, 0xAC, 0x96, 0x5A, 0xFF, 0x67, 0xED, 0x7A, + 0x46, 0xAE, 0x34, 0x36, 0xE3, 0x54, 0xA2, 0xFE, 0x46, 0xB4, 0x81, 0x00, 0x2B, 0x40, 0x47, 0xBA, 0xAA, 0x69, 0x2C, 0x6C, 0xEF, 0xB8, 0x58, 0xD8, 0x23, 0x90, 0x89, 0xFE, 0xDA, 0x7A, 0x12, 0x7E, + 0x64, 0xCD, 0xE1, 0x6C, 0x37, 0x33, 0x5A, 0xB4, 0x2E, 0xDE, 0xB7, 0xA9, 0x70, 0x76, 0xCE, 0x78, 0x0F, 0xA7, 0x29, 0xEF, 0xA9, 0xF8, 0xF0, 0x85, 0xB7, 0x50, 0x44, 0xCC, 0xA2, 0x68, 0xA7, 0xDA, + 0x5D, 0x44, 0xAE, 0x59, 0x0D, 0xD3, 0x77, 0x6E, 0x3C, 0x9D, 0xEE, 0x49, 0xCA, 0x67, 0x6C, 0x9B, 0xC3, 0xAD, 0x1A, 0xD4, 0xAC, 0x89, 0x4B, 0xC7, 0x53, 0x9A, 0x4C, 0xF2, 0xFD, 0xB0, 0x06, 0x25, + 0xA6, 0x91, 0x5F, 0x72, 0x2C, 0x83, 0x38, 0x11, 0x0B, 0x99, 0x12, 0x71, 0xC7, 0x1A, 0xE4, 0xFA, 0x47, 0xD0, 0xD2, 0x5C, 0xAC, 0x1D, 0x5F, 0x0E, 0xF7, 0x4A, 0xDB, 0xEC, 0xE8, 0xD8, 0xBC, 0x3D, + 0xA0, 0xEB, 0x1C, 0xEE, 0xF6, 0x0B, 0xAC, 0x6D, 0x41, 0x4A, 0x2A, 0xCE, 0x3F, 0xA8, 0x4C, 0xFA, 0x72, 0x46, 0x29, 0x3F, 0xE9, 0x7A, 0x5B, 0x3A, 0x41, 0x2C, 0xD0, 0xA3, 0x29, 0x49, 0x61, 0x1F, + 0x5A, 0xDC, 0x74, 0x78, 0xF9, 0xEA, 0xF1, 0xDB, 0xF2, 0x78, 0x98, 0x84, 0xBA, 0xF7, 0xE4, 0x06, 0x7D, 0xB4, 0x0F, 0xF9, 0xCA, 0xF9, 0x00, 0x57, 0x3B, 0x23, 0xA2, 0x1F, 0x37, 0x71, 0x2C, 0xA5, + 0xC3, 0xFE, 0x4B, 0x04, 0x73, 0x68, 0xF1, 0x5B, 0xE5, 0xC0, 0x9E, 0x7C, 0xFE, 0xBE, 0x46, 0xFB, 0x9A, 0x16, 0xE0, 0xAB, 0x40, 0x6E, 0x56, 0x50, 0x89, 0xC2, 0x74, 0xBF, 0x2C, 0x5B, 0x15, 0xF2, + 0x5B, 0x9F, 0x8A, 0xC4, 0x75, 0x37, 0x04, 0xCB, 0xB6, 0x81, 0xFE, 0x4E, 0x59, 0xBF, 0xC5, 0x64, 0x7D, 0xE5, 0x04, 0x78, 0xEE, 0x88, 0xF9, 0x20, 0xDA, 0xBC, 0x62, 0xEC, 0xAC, 0x7C, 0xC4, 0xEE, + 0x8C, 0x82, 0xBA, 0xCB, 0x28, 0xAE, 0x8C, 0xAD, 0x3C, 0xC4, 0x83, 0x5E, 0x12, 0x15, 0x98, 0x92, 0xB6, 0xB4, 0x3E, 0x60, 0x6B, 0xD8, 0x8B, 0xCA, 0xAC, 0x8C, 0x47, 0x2D, 0x15, 0x7E, 0x0D, 0x14, + 0x68, 0x98, 0x5B, 0xE0, 0xB1, 0x9B, 0x4C, 0x8B, 0x09, 0x71, 0xE6, 0x31, 0xF5, 0xD8, 0x88, 0x8C, 0x20, 0x39, 0x9A, 0xB3, 0x14, 0x5E, 0x89, 0x31, 0x24, 0x5F, 0x20, 0x11, 0x71, 0x5D, 0xBB, 0x1C, + 0x9D, 0xD7, 0xB0, 0xB4, 0xD2, 0x24, 0x54, 0x85, 0x86, 0xF3, 0xEE, 0x76, 0x4C, 0x23, 0x8E, 0x37, 0x9D, 0x24, 0xC6, 0xF4, 0x23, 0x33, 0x18, 0x45, 0xC4, 0xC8, 0x8D, 0xD8, 0xF9, 0x30, 0x8F, 0x8F, + 0x32, 0x11, 0x9F, 0x06, 0x7F, 0x56, 0x31, 0xF5, 0x3C, 0x9E, 0x16, 0xF6, 0xA8, 0x7E, 0xE1, 0x6A, 0x03, 0x38, 0xEF, 0x9F, 0xB9, 0x63, 0xB9, 0x25, 0xF1, 0xC3, 0xA5, 0x87, 0x2B, 0x61, 0xCE, 0x85, + 0x11, 0x3E, 0x52, 0x8C, 0xB9, 0x6D, 0xDD, 0x6A, 0xD7, 0x79, 0xA7, 0x93, 0x37, 0x4B, 0x51, 0xD1, 0x12, 0x43, 0x15, 0xB6, 0xC1, 0xA6, 0x6B, 0xCB, 0x12, 0xBA, 0x4D, 0xF3, 0x9E, 0x66, 0x14, 0x8E, + 0xF7, 0xA6, 0xA9, 0x5C, 0x0E, 0xB6, 0x7A, 0x39, 0x64, 0x60, 0xBB, 0x06, 0x66, 0x6F, 0xB0, 0xD2, 0x49, 0x8F, 0xD9, 0xC1, 0xFB, 0xED, 0xD0, 0x27, 0x9B, 0x61, 0x7B, 0x76, 0x80, 0x01, 0x21, 0x8A, + 0x22, 0x2C, 0xE0, 0xD6, 0x1D, 0xCC, 0xD1, 0xF2, 0xB4, 0xC6, 0xDC, 0x7B, 0xDB, 0x04, 0x34, 0x86, 0x02, 0xC3, 0x7C, 0xFC, 0x2A, 0x9B, 0x49, 0xB5, 0xC5, 0x0B, 0x49, 0x40, 0x8A, 0x74, 0x2C, 0xD4, + 0xC6, 0x30, 0x00, 0xF7, 0x77, 0x86, 0x10, 0x30, 0xB2, 0xC7, 0x90, 0xDF, 0xD5, 0x4F, 0x95, 0x0B, 0x55, 0xB8, 0x3A, 0x37, 0xEF, 0x69, 0xA3, 0xCF, 0xE1, 0xE2, 0x0F, 0x03, 0x56, 0x18, 0xAA, 0x50, + 0x38, 0x71, 0x9D, 0x4B, 0x83, 0x00, 0x54, 0x0C, 0x9F, 0x82, 0x2C, 0xDC, 0x26, 0x6E, 0xF3, 0x1E, 0xEB, 0x4F, 0x5B, 0x14, 0x9E, 0x6A, 0x35, 0xDF, 0xC2, 0xF8, 0xA9, 0x64, 0xFA, 0x92, 0xC7, 0x20, + 0x84, 0x35, 0x83, 0x4A, 0x2E, 0xBA, 0x34, 0xA6, 0xCD, 0xAC, 0xA0, 0x92, 0xA3, 0x29, 0x3C, 0xA7, 0xBB, 0x60, 0x1D, 0xA0, 0xAF, 0xD1, 0x34, 0x38, 0x6F, 0x69, 0x19, 0x29, 0x35, 0x10, 0xD3, 0xD1, + 0x12, 0x22, 0x31, 0x60, 0x90, 0x93, 0xAD, 0xB0, 0xC6, 0xD0, 0xD9, 0xE1, 0x13, 0x1D, 0x33, 0x38, 0x44, 0x55, 0x71, 0x84, 0x86, 0x8B, 0x9E, 0xB6, 0xBA, 0xD2, 0xDC, 0xE3, 0xFD, 0x08, 0x0F, 0x11, + 0x12, 0x38, 0x59, 0x67, 0x86, 0x93, 0x9C, 0xA6, 0xBB, 0xF0, 0xFA, 0xFB, 0x01, 0x0C, 0x16, 0x1A, 0x38, 0x3F, 0x4F, 0x5F, 0x66, 0x74, 0x86, 0x88, 0x89, 0x90, 0x93, 0xA2, 0xBA, 0xBC, 0xCC, 0xE5, + 0xF8, 0x09, 0x1C, 0x1F, 0x3E, 0x3F, 0x54, 0x62, 0x74, 0x8D, 0x99, 0xB8, 0xE3, 0xF1, 0x21, 0x2C, 0x35, 0x39, 0x3E, 0x45, 0x48, 0x7C, 0x9E, 0xDE, 0xE3, 0xEF, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x1D, 0x2C, 0x41, 0x4E, 0x5B, 0x80, 0x68, + 0x00, 0x02, 0x16, 0xA0, 0x74, 0x00, 0x30, 0xB2, 0x40, 0x10, 0x95, 0x00, 0x0C, 0x00, 0x23, 0x42, 0x13, 0x20, 0x06, 0x06, 0x9C, 0x00, 0x00, 0x25, 0x04, 0x80, 0x09, 0xE2, 0x28, 0x84, 0xA2, 0x32, + 0x13, 0x7D, 0xE1, 0xCE, 0xBE, 0x04 }, + }, +}; + +#define DILITHIUM_TV_NUM sizeof(dilithium_tv)/sizeof(struct DILITHIUM_TEST_VECTOR) + diff --git a/testcases/crypto/dilithium_func.c b/testcases/crypto/dilithium_func.c new file mode 100644 index 0000000..b5db64d --- /dev/null +++ b/testcases/crypto/dilithium_func.c @@ -0,0 +1,739 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2020 + * + * This program is provided under the terms of the Common Public License, + * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this + * software constitutes recipient's acceptance of CPL-1.0 terms which can be + * found in the file LICENSE file or at + * https://opensource.org/licenses/cpl1.0.php + */ + +#include + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "common.c" +#include "defs.h" +#include "dilithium.h" + +/** + * Experimental Support for Dilithium keys and signatures + * with oid = 1.3.6.1.4.1.2.267.1.6.5 + * + * Only SignInit and Sign(Single) is supported with Dilithium. + * SignUpdate/SignFinal are not supported. Same with Verify. + */ +typedef struct signVerifyParam { + CK_MECHANISM_TYPE mechtype; + CK_ULONG inputlen; +} _signVerifyParam; + +_signVerifyParam signVerifyInput[] = { + {CKM_IBM_DILITHIUM, 0}, + {CKM_IBM_DILITHIUM, 1}, + {CKM_IBM_DILITHIUM, 32}, + {CKM_IBM_DILITHIUM, 59}, + {CKM_IBM_DILITHIUM, 5900}, +}; + +CK_RV run_SignVerifyDilithium(CK_SESSION_HANDLE session, + CK_MECHANISM_TYPE mechType, + CK_ULONG inputlen, + CK_OBJECT_HANDLE priv_key, + CK_OBJECT_HANDLE publ_key) +{ + CK_MECHANISM mech; + CK_BYTE_PTR data = NULL, signature = NULL; + CK_ULONG i, signaturelen; + CK_MECHANISM_INFO mech_info; + CK_RV rc; + + mech.mechanism = mechType; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + /* Query the slot, check if this mech if supported */ + rc = funcs->C_GetMechanismInfo(SLOT_ID, mech.mechanism, &mech_info); + if (rc != CKR_OK) { + if (rc == CKR_MECHANISM_INVALID) { + /* no support for Dilithium? skip */ + testcase_skip("Slot %u doesn't support %s", + (unsigned int) SLOT_ID, p11_get_ckm(mechType)); + rc = CKR_OK; + goto testcase_cleanup; + } else { + testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + + data = calloc(sizeof(CK_BYTE), inputlen); + if (data == NULL) { + testcase_error("Can't allocate memory for %lu bytes", + sizeof(CK_BYTE) * inputlen); + rc = -1; + goto testcase_cleanup; + } + + for (i = 0; i < inputlen; i++) { + data[i] = (i + 1) % 255; + } + + /* Sign */ + rc = funcs->C_SignInit(session, &mech, priv_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_Sign(session, data, inputlen, NULL, &signaturelen); + if (rc != CKR_OK) { + testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + signature = calloc(sizeof(CK_BYTE), signaturelen); + if (signature == NULL) { + testcase_error("Can't allocate memory for %lu bytes", + sizeof(CK_BYTE) * signaturelen); + rc = -1; + goto testcase_cleanup; + } + + rc = funcs->C_Sign(session, data, inputlen, signature, &signaturelen); + if (rc != CKR_OK) { + testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /* Verify */ + rc = funcs->C_VerifyInit(session, &mech, publ_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_Verify(session, data, inputlen, signature, signaturelen); + if (rc != CKR_OK) { + testcase_error("C_Verify rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /* Corrupt the signature and re-verify */ + memcpy(signature, "ABCDEFGHIJKLMNOPQRSTUV", + strlen("ABCDEFGHIJKLMNOPQRSTUV")); + + rc = funcs->C_VerifyInit(session, &mech, publ_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_Verify(session, data, inputlen, signature, signaturelen); + if (rc != CKR_SIGNATURE_INVALID) { + testcase_error("C_Verify rc=%s", p11_get_ckr(rc)); + PRINT_ERR(" Expected CKR_SIGNATURE_INVALID\n"); + goto testcase_cleanup; + } + + rc = CKR_OK; + +testcase_cleanup: + if (data) + free(data); + if (signature) + free(signature); + + return rc; +} + +CK_RV run_SignVerifyDilithiumKAT(CK_SESSION_HANDLE session, + CK_ULONG index, + CK_OBJECT_HANDLE priv_key, + CK_OBJECT_HANDLE publ_key) +{ + CK_MECHANISM mech; + CK_BYTE_PTR signature = NULL; + CK_ULONG siglen; + CK_RV rc; + + mech.mechanism = CKM_IBM_DILITHIUM; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + /* Initialize */ + rc = funcs->C_SignInit(session, &mech, priv_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /* Determine signature length */ + rc = funcs->C_Sign(session, dilithium_tv[index].msg, dilithium_tv[index].msg_len, + NULL, &siglen); + if (rc != CKR_OK) { + testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /* Allocate buffer for signature */ + signature = calloc(sizeof(CK_BYTE), siglen); + if (signature == NULL) { + testcase_error("Can't allocate memory for %lu bytes", + sizeof(CK_BYTE) *siglen); + rc = -1; + goto testcase_cleanup; + } + + /* Create signature */ + rc = funcs->C_Sign(session, dilithium_tv[index].msg, dilithium_tv[index].msg_len, + signature, &siglen); + if (rc != CKR_OK) { + testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /* Check if calculated signature len matches with known signature len */ + if (siglen != dilithium_tv[index].sig_len) { + testcase_error("Calculated signature length %ld does not match known length %ld.", + siglen, dilithium_tv[index].sig_len); + goto testcase_cleanup; + } + + /* Check if signature matches with known signature */ + if (memcmp(signature, dilithium_tv[index].sig, siglen) != 0) { + testcase_error("Signature bad."); + goto testcase_cleanup; + } + + /* Verify signature */ + rc = funcs->C_VerifyInit(session, &mech, publ_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_Verify(session, dilithium_tv[index].msg, dilithium_tv[index].msg_len, + signature, siglen); + if (rc != CKR_OK) { + testcase_error("C_Verify rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = CKR_OK; + +testcase_cleanup: + + free(signature); + + return rc; +} + +CK_RV run_GenerateDilithiumKeyPairSignVerify() +{ + CK_MECHANISM mech; + CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE; + CK_SESSION_HANDLE session; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len, j; + CK_FLAGS flags; + CK_MECHANISM_INFO mech_info; + CK_RV rc; + + testcase_begin("Starting Dilithium generate key pair."); + + testcase_rw_session(); + testcase_user_login(); + + mech.mechanism = CKM_IBM_DILITHIUM; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + /* query the slot, check if this mech is supported */ + rc = funcs->C_GetMechanismInfo(SLOT_ID, mech.mechanism, &mech_info); + if (rc != CKR_OK) { + if (rc == CKR_MECHANISM_INVALID) { + /* no support for EC key gen? skip */ + testcase_skip("Slot %u doesn't support CKM_IBM_DILITHIUM ", + (unsigned int) SLOT_ID); + rc = CKR_OK; + goto testcase_cleanup; + } else { + testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + + /* Setup attributes for public/private Dilithium key */ + CK_BBOOL attr_sign = TRUE; + CK_BBOOL attr_verify = TRUE; + CK_ATTRIBUTE dilithium_attr_private[] = { + {CKA_SIGN, &attr_sign, sizeof(CK_BBOOL)}, + }; + CK_ATTRIBUTE dilithium_attr_public[] = { + {CKA_VERIFY, &attr_verify, sizeof(CK_BBOOL)}, + }; + + /* Generate Dilithium key pair */ + rc = funcs->C_GenerateKeyPair(session, &mech, + dilithium_attr_public, 1, + dilithium_attr_private, 1, + &publ_key, &priv_key); + testcase_new_assertion(); + if (rc != CKR_OK) { + testcase_fail + ("C_GenerateKeyPair with valid input failed, rc=%s", + p11_get_ckr(rc)); + goto testcase_cleanup; + } + testcase_pass("*Generate Dilithium key pair passed."); + + /* Sign/verify with this key pair */ + for (j = 0; j < (sizeof(signVerifyInput) / sizeof(_signVerifyParam)); j++) { + testcase_new_assertion(); + rc = run_SignVerifyDilithium(session, + signVerifyInput[j].mechtype, + signVerifyInput[j].inputlen, + priv_key, publ_key); + if (rc != 0) { + testcase_fail("run_SignVerifyDilithium failed index=%lu.", j); + goto testcase_cleanup; + } + testcase_pass("*Sign & verify j=%lu passed.", j); + } + + rc = CKR_OK; + +testcase_cleanup: + if (publ_key != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, publ_key); + if (priv_key != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, priv_key); + + testcase_user_logout(); + testcase_close_session(); + + return rc; +} + +CK_RV run_ImportDilithiumKeyPairSignVerify() +{ + CK_MECHANISM mech; + CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE; + CK_SESSION_HANDLE session; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len, i; + CK_FLAGS flags; + CK_MECHANISM_INFO mech_info; + CK_RV rc; + + testcase_rw_session(); + testcase_user_login(); + + mech.mechanism = CKM_IBM_DILITHIUM; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + /* query the slot, check if this mech is supported */ + rc = funcs->C_GetMechanismInfo(SLOT_ID, mech.mechanism, &mech_info); + if (rc != CKR_OK) { + if (rc == CKR_MECHANISM_INVALID) { + /* no support for EC key gen? skip */ + testcase_skip("Slot %u doesn't support CKM_IBM_DILITHIUM", + (unsigned int) SLOT_ID); + goto testcase_cleanup; + } else { + testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + + for (i = 0; i < DILITHIUM_TV_NUM; i++) { + + testcase_begin("Starting Dilithium import key pair, Sign/Verify, KAT index=%lu", i); + + /* Create Dilithium private key */ + rc = create_DilithiumPrivateKey(session, + dilithium_tv[i].rho, dilithium_tv[i].rho_len, + dilithium_tv[i].seed, dilithium_tv[i].seed_len, + dilithium_tv[i].tr, dilithium_tv[i].tr_len, + dilithium_tv[i].s1, dilithium_tv[i].s1_len, + dilithium_tv[i].s2, dilithium_tv[i].s2_len, + dilithium_tv[i].t0, dilithium_tv[i].t0_len, + dilithium_tv[i].t1, dilithium_tv[i].t1_len, + &priv_key); + testcase_new_assertion(); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject (Dilithium Private Key) failed at i=%lu, " + "rc=%s", i, p11_get_ckr(rc)); + goto testcase_cleanup; + } + testcase_pass("*Import Dilithium private key (%s) index=%lu passed.", + dilithium_tv[i].name, i); + + /* Create Dilithium public key */ + rc = create_DilithiumPublicKey(session, + dilithium_tv[i].rho, dilithium_tv[i].rho_len, + dilithium_tv[i].t1, dilithium_tv[i].t1_len, + &publ_key); + testcase_new_assertion(); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject (Dilithium Public Key) failed at i=%lu, " + "rc=%s", i, p11_get_ckr(rc)); + goto testcase_cleanup; + } + testcase_pass("*Import Dilithium public key (%s) index=%lu passed.", + dilithium_tv[i].name, i); + + /* Test sign/verify with KAT */ + testcase_new_assertion(); + rc = run_SignVerifyDilithiumKAT(session, i, priv_key, publ_key); + if (rc != 0) { + testcase_fail("run_SignVerifyDilithiumKAT failed index=%lu.", i); + goto testcase_cleanup; + } + testcase_pass("*Sign & verify KAT, i=%lu passed.", i); + + /* Clean up */ + rc = funcs->C_DestroyObject(session, publ_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + + rc = funcs->C_DestroyObject(session, priv_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + } + + goto done; + +testcase_cleanup: + if (publ_key != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, publ_key); + if (priv_key != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, priv_key); + +done: + testcase_user_logout(); + testcase_close_session(); + + return rc; +} + +/** + * Wraps the given key with the given secret key using the given wrapping + * mechanism. + */ +CK_RV wrapKey(CK_SESSION_HANDLE session, CK_MECHANISM *wrap_mech, + CK_OBJECT_HANDLE secret_key, CK_OBJECT_HANDLE key_to_wrap, + CK_BYTE_PTR *wrapped_key, CK_ULONG *wrapped_keylen) +{ + CK_BYTE_PTR tmp_key; + CK_ULONG tmp_len; + CK_RV rc; + + /* Determine length of wrapped key */ + rc = funcs->C_WrapKey(session, wrap_mech, secret_key, key_to_wrap, + NULL, &tmp_len); + if (rc != CKR_OK) + goto done; + + /* Allocate memory for wrapped_key */ + tmp_key = calloc(sizeof(CK_BYTE), tmp_len); + if (!tmp_key) { + rc = CKR_HOST_MEMORY; + goto done; + } + + /* Now wrap the key */ + rc = funcs->C_WrapKey(session, wrap_mech, secret_key, key_to_wrap, + tmp_key, &tmp_len); + if (rc != CKR_OK) { + free(tmp_key); + tmp_key = NULL; + goto done; + } + + *wrapped_key = tmp_key; + *wrapped_keylen = tmp_len; + + rc = CKR_OK; + +done: + + return rc; +} + +/** + * Unwraps the given wrapped_key using the given secret_key and wrapping + * mechanism. + */ +CK_RV unwrapKey(CK_SESSION_HANDLE session, CK_MECHANISM *wrap_mech, + CK_BYTE_PTR wrapped_key, CK_ULONG wrapped_keylen, + CK_OBJECT_HANDLE secret_key, CK_OBJECT_HANDLE *unwrapped_key) +{ + CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; + CK_KEY_TYPE key_type = CKK_IBM_PQC_DILITHIUM; + CK_OBJECT_HANDLE tmp_key = CK_INVALID_HANDLE; + CK_BYTE unwrap_label[] = "unwrapped_private_Dilithium_Key"; + CK_BYTE subject[] = {0}; + CK_BYTE id[] = { 123 }; + CK_BBOOL true = TRUE; + CK_RV rc; + + CK_ATTRIBUTE unwrap_tmpl[] = { + {CKA_CLASS, &class, sizeof(class)}, + {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_LABEL, &unwrap_label, sizeof(unwrap_label)}, + {CKA_SUBJECT, subject, sizeof(subject)}, + {CKA_ID, id, sizeof(id)}, + {CKA_SENSITIVE, &true, sizeof(true)}, + {CKA_DECRYPT, &true, sizeof(true)}, + {CKA_SIGN, &true, sizeof(true)}, + }; + + rc = funcs->C_UnwrapKey(session, wrap_mech, secret_key, + wrapped_key, wrapped_keylen, + unwrap_tmpl, + sizeof(unwrap_tmpl) / sizeof(CK_ATTRIBUTE), + &tmp_key); + if (rc != CKR_OK) + goto done; + + *unwrapped_key = tmp_key; + + rc = CKR_OK; + +done: + + return rc; +} + +CK_RV run_TransferDilithiumKeyPairSignVerify() +{ + CK_MECHANISM mech; + CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE; + CK_SESSION_HANDLE session; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len, i; + CK_FLAGS flags; + CK_MECHANISM_INFO mech_info; + CK_RV rc; + CK_OBJECT_HANDLE secret_key = CK_INVALID_HANDLE; + CK_BYTE_PTR wrapped_key = NULL; + CK_ULONG wrapped_keylen; + CK_OBJECT_HANDLE unwrapped_key = CK_INVALID_HANDLE; + CK_MECHANISM wrap_mech, wkey_mech; + + testcase_rw_session(); + testcase_user_login(); + + mech.mechanism = CKM_IBM_DILITHIUM; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + /* query the slot, check if this mech is supported */ + rc = funcs->C_GetMechanismInfo(SLOT_ID, mech.mechanism, &mech_info); + if (rc != CKR_OK) { + if (rc == CKR_MECHANISM_INVALID) { + /* no support for EC key gen? skip */ + testcase_skip("Slot %u doesn't support CKM_IBM_DILITHIUM", + (unsigned int) SLOT_ID); + goto testcase_cleanup; + } else { + testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + + for (i = 0; i < DILITHIUM_TV_NUM; i++) { + + testcase_begin("Starting Dilithium transfer key pair, Sign/Verify KAT index=%ld.",i); + + /* Create Dilithium private key */ + rc = create_DilithiumPrivateKey(session, + dilithium_tv[i].rho, dilithium_tv[i].rho_len, + dilithium_tv[i].seed, dilithium_tv[i].seed_len, + dilithium_tv[i].tr, dilithium_tv[i].tr_len, + dilithium_tv[i].s1, dilithium_tv[i].s1_len, + dilithium_tv[i].s2, dilithium_tv[i].s2_len, + dilithium_tv[i].t0, dilithium_tv[i].t0_len, + dilithium_tv[i].t1, dilithium_tv[i].t1_len, + &priv_key); + testcase_new_assertion(); + if (rc != CKR_OK) { + testcase_fail + ("C_CreateObject (Dilithium Private Key) failed at i=%lu, rc=%s", i, + p11_get_ckr(rc)); + goto testcase_cleanup; + } + testcase_pass("*Import Dilithium private key (%s) index=%lu passed.", + dilithium_tv[i].name, i); + + /* Create Dilithium public key */ + rc = create_DilithiumPublicKey(session, + dilithium_tv[i].rho, dilithium_tv[i].rho_len, + dilithium_tv[i].t1, dilithium_tv[i].t1_len, + &publ_key); + testcase_new_assertion(); + if (rc != CKR_OK) { + testcase_fail + ("C_CreateObject (Dilithium Public Key) failed at i=%lu, rc=%s", i, + p11_get_ckr(rc)); + goto testcase_cleanup; + } + testcase_pass("*Import Dilithium public key (%s) index=%lu passed.", + dilithium_tv[i].name, i); + + /* Create wrapping key (secret key) */ + wkey_mech.mechanism = CKM_AES_KEY_GEN; + wkey_mech.pParameter = NULL; + wkey_mech.ulParameterLen = 0; + rc = generate_AESKey(session, 32, &wkey_mech, &secret_key); + if (rc != CKR_OK) { + testcase_error("generate_AESKey, rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /* Setup wrapping mechanism */ + wrap_mech.mechanism = CKM_AES_CBC_PAD; + wrap_mech.pParameter = "0123456789abcdef"; + wrap_mech.ulParameterLen = 16; + + /* Wrap Dilithium private key with secret key */ + rc = wrapKey(session, &wrap_mech, secret_key, priv_key, + &wrapped_key, &wrapped_keylen); + testcase_new_assertion(); + if (rc != CKR_OK) { + testcase_error("wrapKey, rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + testcase_pass("*Wrap Dilithium private key (%s) index=%lu passed.", + dilithium_tv[i].name, i); + + /* Unwrap Dilithium private key */ + rc = unwrapKey(session, &wrap_mech, wrapped_key, wrapped_keylen, + secret_key, &unwrapped_key); + testcase_new_assertion(); + if (rc != CKR_OK) { + testcase_error("unwrapKey, rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + testcase_pass("*Unwrap Dilithium private key (%s) index=%lu passed.", + dilithium_tv[i].name, i); + + free(wrapped_key); + wrapped_key = NULL; + + /* Test sign/verify using unwrapped private key and untouched public key */ + testcase_new_assertion(); + rc = run_SignVerifyDilithiumKAT(session, i, unwrapped_key, publ_key); + if (rc != 0) { + testcase_fail("Sign & verify KAT using unwrapped key failed, index=%lu, rc=%s.", + i, p11_get_ckr(rc)); + goto testcase_cleanup; + } + testcase_pass("*Sign & verify KAT using unwrapped key, i=%lu passed.", i); + + /* Clean up */ + rc = funcs->C_DestroyObject(session, publ_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + + rc = funcs->C_DestroyObject(session, priv_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + + rc = funcs->C_DestroyObject(session, secret_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + + rc = funcs->C_DestroyObject(session, unwrapped_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + } + + goto done; + +testcase_cleanup: + if (publ_key != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, publ_key); + if (priv_key != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, priv_key); + if (secret_key != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, secret_key); + if (unwrapped_key != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, unwrapped_key); + + if (wrapped_key) + free(wrapped_key); + +done: + testcase_user_logout(); + testcase_close_session(); + + return rc; +} + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + int rc; + CK_RV rv; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: no_init: %d\n", no_init); + + rc = do_GetFunctionList(); + if (!rc) { + PRINT_ERR("ERROR do_GetFunctionList() Failed , rc = 0x%0x\n", rc); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + funcs->C_Initialize(&cinit_args); + + { + CK_SESSION_HANDLE hsess = 0; + + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + } + + testcase_setup(total_assertions); + + rv = run_GenerateDilithiumKeyPairSignVerify(); + + rv = run_ImportDilithiumKeyPairSignVerify(); + + rv = run_TransferDilithiumKeyPairSignVerify(); + + testcase_print_result(); + + funcs->C_Finalize(NULL); + + /* make sure we return non-zero if rv is non-zero */ + return ((rv == 0) || (rv % 256) ? (int)rv : -1); +} diff --git a/testcases/crypto/dsa_func.c b/testcases/crypto/dsa_func.c new file mode 100644 index 0000000..e3b6cb7 --- /dev/null +++ b/testcases/crypto/dsa_func.c @@ -0,0 +1,459 @@ +/* + * 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 + */ + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "common.c" + +// these values are required when generating a PKCS DSA value. they were +// obtained by generating a DSA key pair on the 4758 with the default (random) +// values. these values are in big-endian format +// +CK_BYTE DSA_PUBL_PRIME[128] = { + 0xba, 0xa2, 0x5b, 0xd9, 0x77, 0xb3, 0xf0, 0x2d, 0xa1, 0x65, + 0xf1, 0x83, 0xa7, 0xc9, 0xf0, 0x8a, 0x51, 0x3f, 0x74, 0xe8, + 0xeb, 0x1f, 0xd7, 0x0a, 0xd5, 0x41, 0xfa, 0x52, 0x3c, 0x1f, + 0x79, 0x15, 0x55, 0x18, 0x45, 0x41, 0x29, 0x27, 0x12, 0x4a, + 0xb4, 0x32, 0xa6, 0xd2, 0xec, 0xe2, 0x82, 0x73, 0xf4, 0x30, + 0x66, 0x1a, 0x31, 0x06, 0x37, 0xd2, 0xb0, 0xe4, 0x26, 0x39, + 0x2a, 0x0e, 0x48, 0xf6, 0x77, 0x94, 0x47, 0xea, 0x7d, 0x99, + 0x22, 0xce, 0x65, 0x61, 0x82, 0xd5, 0xe3, 0xfc, 0x15, 0x3f, + 0xff, 0xff, 0xc8, 0xb9, 0x4f, 0x37, 0xbf, 0x7a, 0xa6, 0x6a, + 0xbe, 0xff, 0xa9, 0xdf, 0xfd, 0xed, 0x4a, 0xb6, 0x83, 0xd6, + 0x0f, 0xea, 0xf6, 0x90, 0x4f, 0x12, 0x8e, 0x09, 0x6e, 0x3c, + 0x0a, 0x6d, 0x2e, 0xfb, 0xb3, 0x79, 0x90, 0x8e, 0x39, 0xc0, + 0x86, 0x0e, 0x5d, 0xf0, 0x56, 0xcd, 0x26, 0x45 +}; + +CK_BYTE DSA_PUBL_SUBPRIME[20] = { + 0x9f, 0x3d, 0x47, 0x13, 0xa3, 0xff, 0x93, 0xbb, 0x4a, 0xa6, + 0xb0, 0xf1, 0x7e, 0x54, 0x1e, 0xba, 0xf0, 0x66, 0x03, 0x61 +}; + + +CK_BYTE DSA_PUBL_BASE[128] = { + 0x1a, 0x5b, 0xfe, 0x12, 0xba, 0x85, 0x8e, 0x9b, 0x08, 0x86, + 0xd1, 0x43, 0x9b, 0x4a, 0xaf, 0x44, 0x31, 0xdf, 0xa1, 0x57, + 0xd8, 0xe0, 0xec, 0x34, 0x07, 0x4b, 0x78, 0x8e, 0x3c, 0x62, + 0x47, 0x4c, 0x2f, 0x5d, 0xd3, 0x31, 0x2c, 0xe9, 0xdd, 0x59, + 0xc5, 0xe7, 0x2e, 0x06, 0x40, 0x6c, 0x72, 0x9c, 0x95, 0xc6, + 0xa4, 0x2a, 0x1c, 0x1c, 0x45, 0xb9, 0xf3, 0xdc, 0x83, 0xb6, + 0xc6, 0xdd, 0x94, 0x45, 0x4f, 0x74, 0xc6, 0x55, 0x36, 0x54, + 0xba, 0x20, 0xad, 0x9a, 0xb6, 0xe3, 0x20, 0xf2, 0xdd, 0xd3, + 0x66, 0x19, 0xeb, 0x53, 0xf5, 0x88, 0x35, 0xe1, 0xea, 0xe8, + 0xd4, 0x57, 0xe1, 0x3d, 0xea, 0xd5, 0x00, 0xc2, 0xa4, 0xf5, + 0xff, 0xfb, 0x0b, 0xfb, 0xa2, 0xb9, 0xf1, 0x49, 0x46, 0x9d, + 0x11, 0xa5, 0xb1, 0x94, 0x52, 0x47, 0x6e, 0x2e, 0x79, 0x4b, + 0xc5, 0x18, 0xe9, 0xbc, 0xff, 0xae, 0x34, 0x7f +}; + +// +// +CK_RV do_GenerateDSAKeyPair(void) +{ + CK_SLOT_ID slot_id = SLOT_ID; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_OBJECT_HANDLE publ_key, priv_key; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rc; + + CK_ATTRIBUTE publ_tmpl[] = { + {CKA_PRIME, DSA_PUBL_PRIME, sizeof(DSA_PUBL_PRIME)}, + {CKA_SUBPRIME, DSA_PUBL_SUBPRIME, sizeof(DSA_PUBL_SUBPRIME)}, + {CKA_BASE, DSA_PUBL_BASE, sizeof(DSA_PUBL_BASE)} + }; + + mech.mechanism = CKM_DSA_KEY_PAIR_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + testcase_begin("GenerateDSAKeyPair"); + testcase_rw_session(); + testcase_user_login(); + + testcase_new_assertion(); + + rc = funcs->C_GenerateKeyPair(session, &mech, publ_tmpl, 3, NULL, 0, + &publ_key, &priv_key); + if (rc != CKR_OK) + testcase_fail("C_GenerateKeyPair rc=%s", p11_get_ckr(rc)); + else + testcase_pass("GenerateDSAKeyPair passed"); + +testcase_cleanup: + testcase_user_logout(); + if (funcs->C_CloseAllSessions(slot_id) != CKR_OK) + testcase_error("C_CloseAllSession failed."); + + return rc; +} + + +// the generic DSA mechanism assumes that the data to be signed has already +// been hashed by SHA-1. so the input data length must be 20 bytes +// +CK_RV do_SignDSA(void) +{ + CK_BYTE data1[20]; + CK_BYTE signature[256]; + CK_SLOT_ID slot_id = SLOT_ID; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_OBJECT_HANDLE publ_key, priv_key; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_ULONG i; + CK_ULONG len1, sig_len; + CK_RV rc; + + CK_ATTRIBUTE publ_tmpl[] = { + {CKA_PRIME, DSA_PUBL_PRIME, sizeof(DSA_PUBL_PRIME)}, + {CKA_SUBPRIME, DSA_PUBL_SUBPRIME, sizeof(DSA_PUBL_SUBPRIME)}, + {CKA_BASE, DSA_PUBL_BASE, sizeof(DSA_PUBL_BASE)} + }; + + mech.mechanism = CKM_DSA_KEY_PAIR_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + testcase_begin("DSA Sign/Verify"); + testcase_rw_session(); + testcase_user_login(); + + testcase_new_assertion(); + + rc = funcs->C_GenerateKeyPair(session, &mech, publ_tmpl, 3, NULL, 0, + &publ_key, &priv_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKeyPair rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // now, sign some data + // + len1 = sizeof(data1); + sig_len = sizeof(signature); + + for (i = 0; i < len1; i++) + data1[i] = i % 255; + + mech.mechanism = CKM_DSA; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rc = funcs->C_SignInit(session, &mech, priv_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_Sign(session, data1, len1, signature, &sig_len); + if (rc != CKR_OK) { + testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // now, verify the signature + // + rc = funcs->C_VerifyInit(session, &mech, publ_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_Verify(session, data1, len1, signature, sig_len); + if (rc != CKR_OK) { + testcase_error("C_Verify rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // now, corrupt the signature and try to re-verify. + // + memcpy(signature, "ABCDEFGHIJKLMNOPQRSTUV", + strlen("ABCDEFGHIJKLMNOPQRSTUV")); + + rc = funcs->C_VerifyInit(session, &mech, publ_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_Verify(session, data1, len1, signature, sig_len); + if (rc != CKR_SIGNATURE_INVALID) { + testcase_fail("Verify expected CKR_SIGNATURE_INVALID, got %s", + p11_get_ckr(rc)); + goto testcase_cleanup; + } else { + testcase_pass("DSA Sign/Verify passed"); + } + +testcase_cleanup: + testcase_user_logout(); + if (funcs->C_CloseAllSessions(slot_id) != CKR_OK) + testcase_error("C_CloseAllSessions failed."); + + return rc; +} + +CK_BYTE DSA1024_BASE[128] = { + 0xf7, 0xe1, 0xa0, 0x85, 0xd6, 0x9b, 0x3d, 0xde, 0xcb, 0xbc, + 0xab, 0x5c, 0x36, 0xb8, 0x57, 0xb9, 0x79, 0x94, 0xaf, 0xbb, + 0xfa, 0x3a, 0xea, 0x82, 0xf9, 0x57, 0x4c, 0x0b, 0x3d, 0x07, + 0x82, 0x67, 0x51, 0x59, 0x57, 0x8e, 0xba, 0xd4, 0x59, 0x4f, + 0xe6, 0x71, 0x07, 0x10, 0x81, 0x80, 0xb4, 0x49, 0x16, 0x71, + 0x23, 0xe8, 0x4c, 0x28, 0x16, 0x13, 0xb7, 0xcf, 0x09, 0x32, + 0x8c, 0xc8, 0xa6, 0xe1, 0x3c, 0x16, 0x7a, 0x8b, 0x54, 0x7c, + 0x8d, 0x28, 0xe0, 0xa3, 0xae, 0x1e, 0x2b, 0xb3, 0xa6, 0x75, + 0x91, 0x6e, 0xa3, 0x7f, 0x0b, 0xfa, 0x21, 0x35, 0x62, 0xf1, + 0xfb, 0x62, 0x7a, 0x01, 0x24, 0x3b, 0xcc, 0xa4, 0xf1, 0xbe, + 0xa8, 0x51, 0x90, 0x89, 0xa8, 0x83, 0xdf, 0xe1, 0x5a, 0xe5, + 0x9f, 0x06, 0x92, 0x8b, 0x66, 0x5e, 0x80, 0x7b, 0x55, 0x25, + 0x64, 0x01, 0x4c, 0x3b, 0xfe, 0xcf, 0x49, 0x2a +}; + +CK_BYTE DSA1024_PRIME[128] = { + 0xfd, 0x7f, 0x53, 0x81, 0x1d, 0x75, 0x12, 0x29, 0x52, 0xdf, + 0x4a, 0x9c, 0x2e, 0xec, 0xe4, 0xe7, 0xf6, 0x11, 0xb7, 0x52, + 0x3c, 0xef, 0x44, 0x00, 0xc3, 0x1e, 0x3f, 0x80, 0xb6, 0x51, + 0x26, 0x69, 0x45, 0x5d, 0x40, 0x22, 0x51, 0xfb, 0x59, 0x3d, + 0x8d, 0x58, 0xfa, 0xbf, 0xc5, 0xf5, 0xba, 0x30, 0xf6, 0xcb, + 0x9b, 0x55, 0x6c, 0xd7, 0x81, 0x3b, 0x80, 0x1d, 0x34, 0x6f, + 0xf2, 0x66, 0x60, 0xb7, 0x6b, 0x99, 0x50, 0xa5, 0xa4, 0x9f, + 0x9f, 0xe8, 0x04, 0x7b, 0x10, 0x22, 0xc2, 0x4f, 0xbb, 0xa9, + 0xd7, 0xfe, 0xb7, 0xc6, 0x1b, 0xf8, 0x3b, 0x57, 0xe7, 0xc6, + 0xa8, 0xa6, 0x15, 0x0f, 0x04, 0xfb, 0x83, 0xf6, 0xd3, 0xc5, + 0x1e, 0xc3, 0x02, 0x35, 0x54, 0x13, 0x5a, 0x16, 0x91, 0x32, + 0xf6, 0x75, 0xf3, 0xae, 0x2b, 0x61, 0xd7, 0x2a, 0xef, 0xf2, + 0x22, 0x03, 0x19, 0x9d, 0xd1, 0x48, 0x01, 0xc7 +}; + +CK_BYTE DSA1024_SUBPRIME[20] = { + 0x97, 0x60, 0x50, 0x8f, 0x15, 0x23, 0x0b, 0xcc, 0xb2, 0x92, + 0xb9, 0x82, 0xa2, 0xeb, 0x84, 0x0b, 0xf0, 0x58, 0x1c, 0xf5 +}; + +CK_BYTE DSA1024_PRIVATE[20] = { + 0x87, 0xa0, 0x68, 0x97, 0x5e, 0xf2, 0x51, 0xb4, 0x50, 0x51, + 0x0d, 0xee, 0x08, 0x73, 0x41, 0x19, 0x5c, 0xa6, 0x8c, 0x16 +}; + +CK_BYTE DSA1024_PUBLIC[128] = { + 0xa2, 0x8a, 0x43, 0xb9, 0x5d, 0x73, 0x6b, 0x5a, 0x5a, 0xfe, + 0xb5, 0xa0, 0x7d, 0x2c, 0x89, 0x65, 0xeb, 0xf3, 0x52, 0xa3, + 0xe2, 0x9b, 0xa7, 0xe3, 0x65, 0x11, 0x12, 0x0c, 0xcc, 0xa2, + 0xb7, 0x60, 0x51, 0xcd, 0xfb, 0x87, 0xfd, 0x9e, 0xe7, 0x58, + 0xe5, 0xb1, 0x15, 0x98, 0x66, 0x63, 0x18, 0x6f, 0x46, 0x83, + 0x27, 0xbf, 0x5a, 0xc5, 0x00, 0xf1, 0x89, 0xcb, 0x70, 0x6f, + 0x62, 0x16, 0xab, 0xbc, 0x4b, 0xb7, 0x25, 0x8f, 0x92, 0x15, + 0x06, 0x06, 0x5d, 0xb3, 0x36, 0x98, 0x3c, 0x31, 0x26, 0x7c, + 0xe7, 0x8c, 0x94, 0x27, 0xfa, 0xb8, 0xda, 0xd0, 0xc6, 0x4b, + 0x54, 0xf1, 0xef, 0xf6, 0x0e, 0xc6, 0x01, 0xdd, 0x1a, 0xbc, + 0x25, 0xd9, 0x56, 0x93, 0x80, 0x37, 0x94, 0xd9, 0x67, 0x33, + 0xd5, 0x65, 0x69, 0x93, 0x1f, 0x07, 0xc7, 0x72, 0xa5, 0x13, + 0x23, 0x83, 0xac, 0x6e, 0xab, 0xda, 0xfb, 0xc4 +}; + + +// import a DSA public key +// +CK_RV do_ImportDSAKeyPairSignVerify(void) +{ + CK_SLOT_ID slot_id = SLOT_ID; + CK_SESSION_HANDLE session; + CK_FLAGS flags; + CK_OBJECT_HANDLE publ_key, priv_key; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_MECHANISM mech; + CK_BYTE data1[20]; + CK_BYTE signature[256]; + CK_ULONG len1, sig_len; + CK_ULONG i; + CK_RV rc; + + testcase_begin("DSA Import KeyPair Sign/Verify"); + testcase_rw_session(); + testcase_user_login(); + + testcase_new_assertion(); + + // import the private key + rc = create_DSAPrivateKey(session, + DSA1024_PRIME, sizeof(DSA1024_PRIME), + DSA1024_SUBPRIME, sizeof(DSA1024_SUBPRIME), + DSA1024_BASE, sizeof(DSA1024_BASE), + DSA1024_PRIVATE, sizeof(DSA1024_PRIVATE), + &priv_key); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject (DSA Private Key) failed rc=%s", + p11_get_ckr(rc)); + goto testcase_cleanup; + } + // import the public key + rc = create_DSAPublicKey(session, + DSA1024_PRIME, sizeof(DSA1024_PRIME), + DSA1024_SUBPRIME, sizeof(DSA1024_SUBPRIME), + DSA1024_BASE, sizeof(DSA1024_BASE), + DSA1024_PUBLIC, sizeof(DSA1024_PUBLIC), &publ_key); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject (DSA Public Key) failed rc=%s", + p11_get_ckr(rc)); + goto testcase_cleanup; + } + // now, sign some data + // + len1 = sizeof(data1); + sig_len = sizeof(signature); + + for (i = 0; i < len1; i++) + data1[i] = i % 255; + + mech.mechanism = CKM_DSA; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rc = funcs->C_SignInit(session, &mech, priv_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_Sign(session, data1, len1, signature, &sig_len); + if (rc != CKR_OK) { + testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // now, verify the signature + // + rc = funcs->C_VerifyInit(session, &mech, publ_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_Verify(session, data1, len1, signature, sig_len); + if (rc != CKR_OK) { + testcase_error("C_Verify rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + testcase_pass("DSA Import KeyPair Sign/Verify"); + +testcase_cleanup: + testcase_user_logout(); + if (funcs->C_CloseAllSessions(slot_id) != CKR_OK) + testcase_error("C_CloseAllSessions failed."); + + return rc; +} + +CK_RV dsa_functions() +{ + SYSTEMTIME t1, t2; + CK_RV rc = CKR_OK; + CK_SLOT_ID slot_id; + + /** skip tests if the slot doesn't support this mechanism **/ + slot_id = SLOT_ID; + if (!(mech_supported(slot_id, CKM_DSA))) { + printf("Slot %u doesn't support DSA\n", (unsigned int) slot_id); + return rc; + } + + GetSystemTime(&t1); + rc = do_GenerateDSAKeyPair(); + if (rc) { + PRINT_ERR("ERROR do_GenerateDSAKeyPair failed, rc = 0x%lx\n", rc); + if (!no_stop) + return rc; + } + GetSystemTime(&t2); + process_time(t1, t2); + + GetSystemTime(&t1); + rc = do_SignDSA(); + if (rc) { + PRINT_ERR("ERROR do_SignDSA failed, rc = 0x%lx\n", rc); + if (!no_stop) + return rc; + } + GetSystemTime(&t2); + process_time(t1, t2); + + GetSystemTime(&t1); + rc = do_ImportDSAKeyPairSignVerify(); + if (rc) { + PRINT_ERR("ERROR do_ImportDSAKeyPairSignVerify failed, rc = 0x%lx\n", + rc); + if (!no_stop) + return rc; + } + GetSystemTime(&t2); + process_time(t1, t2); + + return rc; +} + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + int rc; + CK_RV rv; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: no_init: %d\n", no_init); + + rc = do_GetFunctionList(); + if (!rc) { + PRINT_ERR("ERROR do_GetFunctionList() Failed , rc = 0x%0x\n", rc); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + // SAB Add calls to ALL functions before the C_Initialize gets hit + + funcs->C_Initialize(&cinit_args); + + { + CK_SESSION_HANDLE hsess = 0; + + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + } + + testcase_setup(0); + + rv = dsa_functions(); + + testcase_print_result(); + + funcs->C_Finalize(NULL); + + /* make sure we return non-zero if rv is non-zero */ + return ((rv == 0) || (rv % 256) ? (int)rv : -1); +} diff --git a/testcases/crypto/ec.h b/testcases/crypto/ec.h new file mode 100644 index 0000000..db15268 --- /dev/null +++ b/testcases/crypto/ec.h @@ -0,0 +1,1112 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2011-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 + */ + +enum curve_type { + CURVE_BRAINPOOL = 1, + CURVE_PRIME = 2, + CURVE_EDWARDS = 3, + CURVE_MONTGOMERY = 4, +}; + +struct EC_TEST_VECTOR { + CK_BYTE name[32]; + enum curve_type curve_type; + CK_BYTE params[64]; + CK_ULONG params_len; + CK_BYTE privkey[196]; + CK_ULONG privkey_len; + CK_BYTE pubkey[196]; + CK_ULONG pubkey_len; +}; + +struct EC_TEST_VECTOR ec_tv[] = { + { // #0 [PRIME192v1] + .name = "PRIME192v1", + .curve_type = CURVE_PRIME, + .params = {0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x01}, + .params_len = 10, + .privkey = {0x0a, 0x38, 0x68, 0x89, 0xdc, 0xe6, 0xe1, 0x93, + 0xba, 0xc4, 0xcf, 0xd1, 0xd2, 0x0d, 0xd3, 0x2c, + 0xc9, 0xcf, 0x08, 0x14, 0x51, 0x23, 0xd4, 0x7a}, + .privkey_len = 24, + .pubkey = {0x04, 0x31, 0x04, 0xd9, 0xf6, 0x79, 0xa6, 0xc2, + 0xf9, 0x16, 0x11, 0x6e, 0x8a, 0xbe, 0xe6, 0xa2, + 0x2c, 0x64, 0xb7, 0x88, 0xaa, 0xa5, 0x7e, 0x22, + 0x97, 0xc0, 0x0e, 0xf5, 0x6f, 0xe1, 0xd4, 0x4a, + 0x47, 0xb4, 0x76, 0x3e, 0xd6, 0xa3, 0x90, 0x4c, + 0x7d, 0xb4, 0xee, 0x61, 0x9b, 0x01, 0x37, 0x71, + 0xfe, 0x65, 0x37}, + .pubkey_len = 51, + }, + { // #1 [PRIME256v1] + .name = "PRIME256v1", + .curve_type = CURVE_PRIME, + .params = {0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07}, + .params_len = 10, + .privkey = {0x00, 0xd4, 0x37, 0x30, 0xbb, 0x01, 0x9d, 0x1b, + 0xaa, 0x72, 0x9c, 0x31, 0x5f, 0x5d, 0x25, 0xab, + 0x9f, 0x4d, 0xeb, 0x09, 0xc5, 0x1f, 0xaf, 0xa5, + 0xea, 0x8b, 0x37, 0x30, 0xc3, 0x93, 0x2e, 0x08, + 0xf4}, + .privkey_len = 33, + .pubkey = {0x04, 0x41, 0x04, 0x4f, 0x55, 0xee, 0x90, 0xba, + 0x52, 0x17, 0x41, 0xeb, 0x58, 0xf1, 0xf5, 0x75, + 0xc7, 0x90, 0x6b, 0x8f, 0x0e, 0xda, 0x12, 0x11, + 0xa0, 0xed, 0xa9, 0xd0, 0xc3, 0x36, 0xc3, 0xa3, + 0x0c, 0x64, 0x59, 0xa8, 0x8f, 0x18, 0x6f, 0x65, + 0x1c, 0x72, 0x2a, 0xa8, 0x59, 0xeb, 0x6e, 0xe3, + 0x0e, 0xa3, 0x79, 0xf2, 0x04, 0xd0, 0x0f, 0x67, + 0x88, 0xf2, 0x1d, 0x43, 0x24, 0x47, 0x98, 0xf0, + 0xd7, 0xb5, 0x60}, + .pubkey_len = 67, + }, + { // #2 [SECP224r1] + .name = "SECP224r1", + .curve_type = CURVE_PRIME, + .params = {0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x21}, + .params_len = 7, + .privkey = {0x51, 0xbf, 0xef, 0xae, 0xb9, 0x3b, 0xa7, 0xd7, + 0xa0, 0x6d, 0xbf, 0x10, 0xc2, 0x19, 0xa3, 0x83, + 0x79, 0xf8, 0x4d, 0xd7, 0x98, 0x91, 0x7a, 0xcb, + 0x88, 0xed, 0x9d, 0x0d}, + .privkey_len = 28, + .pubkey = {0x04, 0x39, 0x04, 0xa7, 0x21, 0x25, 0xe5, 0xfd, + 0xe4, 0xb9, 0x0d, 0x86, 0xa6, 0x32, 0x43, 0x1d, + 0x75, 0x92, 0x38, 0x8d, 0xd1, 0x17, 0xee, 0xf3, + 0x12, 0x66, 0xde, 0x47, 0x13, 0xde, 0xdb, 0xfc, + 0x26, 0xb2, 0x46, 0xb4, 0xd4, 0x47, 0x61, 0x03, + 0x71, 0x2b, 0xc5, 0xae, 0xd7, 0x63, 0x42, 0xbe, + 0xad, 0x7b, 0x81, 0x9c, 0x70, 0xe5, 0x3c, 0x67, + 0x65, 0x13, 0x0e}, + .pubkey_len = 59, + }, + { // #3 [SECP384r1] + .name = "SECP384r1", + .curve_type = CURVE_PRIME, + .params = {0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22}, + .params_len = 7, + .privkey = {0x00, 0xd4, 0xb1, 0xb8, 0x20, 0xc6, 0x54, 0x2e, + 0x79, 0xe5, 0x6e, 0xae, 0xa5, 0xc5, 0xa3, 0x4e, + 0x67, 0x1e, 0xe2, 0x72, 0xcc, 0x75, 0xf4, 0x7f, + 0xbc, 0x76, 0x3c, 0xbc, 0xe1, 0x20, 0x21, 0x44, + 0xa5, 0x7d, 0xcd, 0xac, 0x5b, 0x10, 0xda, 0xd5, + 0xf8, 0xff, 0x97, 0x08, 0x55, 0x7c, 0x53, 0xb2, + 0x06}, + .privkey_len = 49, + .pubkey = {0x04, 0x61, 0x04, 0x03, 0xc6, 0x87, 0xa9, 0xb2, + 0xff, 0x76, 0x4f, 0xb3, 0x14, 0x8f, 0x5e, 0x5f, + 0x36, 0x38, 0x90, 0xc1, 0x15, 0xc7, 0x61, 0x38, + 0x09, 0xec, 0x16, 0xfd, 0xdd, 0xbf, 0xdf, 0x6b, + 0x10, 0xc6, 0xbb, 0x39, 0x1a, 0x73, 0xd8, 0x7a, + 0x6e, 0xc6, 0xcc, 0x3b, 0x3e, 0x0f, 0x9a, 0x4d, + 0x21, 0xa5, 0x13, 0xfe, 0x6c, 0x65, 0x98, 0x74, + 0xa0, 0x66, 0x7d, 0x9d, 0x6b, 0x35, 0x6a, 0xed, + 0xd3, 0xdf, 0x9c, 0x5e, 0x55, 0xc1, 0xf0, 0x7a, + 0xbf, 0x0e, 0x66, 0xef, 0xd3, 0xb3, 0xc1, 0xf2, + 0x7c, 0xa6, 0x8b, 0x7f, 0x41, 0x43, 0xe8, 0xc0, + 0xf0, 0x82, 0x41, 0x44, 0xe3, 0xe1, 0x94, 0x4c, + 0x75, 0x64, 0x63}, + .pubkey_len = 99, + }, + { // #4 [SECP521r1] + .name = "SECP521r1", + .curve_type = CURVE_PRIME, + .params = {0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23}, + .params_len = 7, + .privkey = {0x01, 0x56, 0xec, 0x45, 0xe0, 0x40, 0x11, 0x58, + 0xbd, 0x4f, 0xf3, 0xba, 0xfa, 0x89, 0x7a, 0xcf, + 0x66, 0x21, 0xe6, 0x3e, 0xc6, 0x30, 0x54, 0x50, + 0xef, 0x0e, 0x4d, 0x7a, 0xb7, 0xa9, 0x71, 0x77, + 0xa8, 0x83, 0xd4, 0x08, 0x37, 0x65, 0xc6, 0xe1, + 0x7e, 0x72, 0x0d, 0x0a, 0xdf, 0xb7, 0x37, 0xc5, + 0x3a, 0xc9, 0x96, 0x2e, 0x34, 0xe5, 0x55, 0x38, + 0x79, 0x18, 0x93, 0x78, 0x48, 0x3f, 0x46, 0xd5, + 0x5a, 0xe8}, + .privkey_len = 66, + .pubkey = {0x04, 0x81, 0x85, 0x04, 0x01, 0x60, 0xe5, 0x4c, + 0xea, 0xbf, 0x54, 0x7e, 0x45, 0xbd, 0x6b, 0xb5, + 0x8d, 0x55, 0xb8, 0x56, 0xd2, 0x0d, 0x88, 0x49, + 0x78, 0x72, 0x46, 0x5c, 0x1e, 0xe6, 0x09, 0x8f, + 0xc5, 0x96, 0x12, 0x16, 0x1c, 0xf4, 0x25, 0x28, + 0x24, 0x18, 0x7c, 0xdd, 0x23, 0xa7, 0x3b, 0x99, + 0x2c, 0xff, 0xa2, 0xd5, 0x25, 0x57, 0xa1, 0x65, + 0x42, 0x47, 0x2c, 0x84, 0x59, 0x8b, 0x4e, 0x14, + 0xea, 0x20, 0x7e, 0xd0, 0x69, 0x6d, 0x00, 0x06, + 0x4a, 0x33, 0x75, 0x2a, 0x72, 0x81, 0x5d, 0xe0, + 0x33, 0xce, 0x7c, 0xa0, 0xa4, 0x83, 0x84, 0xf2, + 0x2f, 0x6f, 0x2b, 0x73, 0x4c, 0x7f, 0xb5, 0x8d, + 0xae, 0xf7, 0xce, 0xdd, 0x35, 0x1d, 0x20, 0x8d, + 0xd6, 0x8c, 0x3f, 0x44, 0x49, 0x1b, 0xd5, 0xc0, + 0x4a, 0x4e, 0x30, 0x6f, 0x54, 0x84, 0x10, 0xb6, + 0x78, 0x8a, 0xfe, 0x1a, 0xdc, 0xd4, 0x49, 0x59, + 0xb0, 0x86, 0xdc, 0x7c, 0x13, 0xd1, 0x6b, 0x2f}, + .pubkey_len = 136, + }, + { // #5 [BrainpoolP160r1] + .name = "BrainpoolP160r1", + .curve_type = CURVE_BRAINPOOL, + .params = {0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, + 0x01, 0x01, 0x01}, + .params_len = 11, + .privkey = {0x00, 0xd7, 0x9e, 0x70, 0x72, 0x32, 0xef, 0x19, + 0x8e, 0xa7, 0x91, 0x3a, 0x52, 0xdd, 0x69, 0x38, + 0x4e, 0xc8, 0x9f, 0x68, 0x49}, + .privkey_len = 21, + .pubkey = {0x04, 0x29, 0x04, 0xa6, 0x1e, 0x8d, 0x7e, 0xfd, + 0xf6, 0x88, 0xb0, 0x88, 0xda, 0x6e, 0x83, 0x35, + 0x82, 0x0d, 0xb7, 0xee, 0xd6, 0x35, 0x7b, 0x78, + 0x3c, 0x8a, 0xce, 0xf9, 0xf7, 0xa3, 0x4a, 0x12, + 0x9d, 0x3f, 0x78, 0x06, 0x75, 0x87, 0x86, 0x17, + 0x70, 0x5c, 0x5e}, + .pubkey_len = 43, + }, + { // #6 [BrainpoolP160t1] + .name = "BrainpoolP160t1", + .curve_type = CURVE_BRAINPOOL, + .params = {0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, + 0x01, 0x01, 0x02}, + .params_len = 11, + .privkey = {0x00, 0xda, 0xc3, 0x24, 0x84, 0x71, 0xd9, 0x46, + 0x80, 0x5c, 0x81, 0xaa, 0x80, 0x22, 0x3e, 0xd2, + 0x36, 0xf0, 0x77, 0x8f, 0xbc}, + .privkey_len = 21, + .pubkey = {0x04, 0x29, 0x04, 0x34, 0xfd, 0xe0, 0x1f, 0x2a, + 0xf0, 0x0c, 0x19, 0x02, 0x96, 0x5e, 0x11, 0xa3, + 0x94, 0xe3, 0xe7, 0xa4, 0x14, 0xa0, 0x27, 0x6b, + 0xc1, 0xdf, 0x9a, 0xe7, 0x8c, 0x79, 0xdf, 0xe4, + 0xcb, 0x9b, 0xa2, 0xd4, 0x4e, 0xa9, 0x21, 0x7b, + 0x87, 0x6b, 0x61}, + .pubkey_len = 43, + }, + { // #7 [BrainpoolP192r1] + .name = "BrainpoolP192r1", + .curve_type = CURVE_BRAINPOOL, + .params = {0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, + 0x01, 0x01, 0x03}, + .params_len = 11, + .privkey = {0x00, 0x96, 0xe2, 0xbc, 0x9b, 0x5d, 0x81, 0x64, + 0xe4, 0x50, 0x4a, 0x9e, 0xa0, 0xe5, 0x70, 0x59, + 0x60, 0x39, 0x71, 0x80, 0x34, 0x2b, 0xce, 0x97, + 0x84}, + .privkey_len = 25, + .pubkey = {0x04, 0x31, 0x04, 0xb4, 0x17, 0xb3, 0x3b, 0x89, + 0xe4, 0x1e, 0x05, 0x55, 0x22, 0x4e, 0x50, 0x91, + 0xa3, 0x10, 0xaa, 0xb3, 0xa9, 0x23, 0xd6, 0x92, + 0xf8, 0xbb, 0xeb, 0xb1, 0xf3, 0x3a, 0xc8, 0xc5, + 0x55, 0x8d, 0x8e, 0x9d, 0x2e, 0xbf, 0x0c, 0x63, + 0xd4, 0x51, 0xe9, 0xd4, 0x9d, 0x5e, 0x9f, 0x37, + 0xf4, 0x03, 0xb0}, + .pubkey_len = 51, + }, + { // #8 [BrainpoolP192t1] + .name = "BrainpoolP192t1", + .curve_type = CURVE_BRAINPOOL, + .params = {0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, + 0x01, 0x01, 0x04}, + .params_len = 11, + .privkey = {0x4c, 0xa7, 0x5b, 0x36, 0x82, 0x71, 0x45, 0x50, + 0x09, 0x9e, 0xc3, 0xe2, 0x7c, 0x38, 0xb3, 0x0d, + 0x94, 0x0d, 0x0e, 0x7b, 0x69, 0x65, 0xf8, 0xab}, + .privkey_len = 24, + .pubkey = {0x04, 0x31, 0x04, 0x5b, 0x04, 0x54, 0xf7, 0xfc, + 0xfe, 0xe8, 0x07, 0x63, 0x97, 0x1f, 0x03, 0x2d, + 0x7e, 0x46, 0xcf, 0xf3, 0xe9, 0x66, 0x5c, 0x4e, + 0xe4, 0x97, 0xcf, 0xc1, 0xac, 0xaa, 0x00, 0xdb, + 0x48, 0x60, 0xa7, 0x18, 0xea, 0x6a, 0x76, 0x18, + 0xd1, 0x06, 0x17, 0xf1, 0x39, 0x58, 0x8b, 0x63, + 0x59, 0x26, 0xd7}, + .pubkey_len = 51, + }, + { // #9 [BrainpoolP224r1] + .name = "BrainpoolP224r1", + .curve_type = CURVE_BRAINPOOL, + .params = {0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, + 0x01, 0x01, 0x05}, + .params_len = 11, + .privkey = {0x51, 0x09, 0x54, 0x86, 0x77, 0x1f, 0x7a, 0x31, + 0x5a, 0xd8, 0x85, 0xa4, 0x00, 0xe1, 0xac, 0xad, + 0xa1, 0xa6, 0x2b, 0x73, 0x8d, 0x32, 0x21, 0xf1, + 0x65, 0xe1, 0x9f, 0x92}, + .privkey_len = 28, + .pubkey = {0x04, 0x39, 0x04, 0x8d, 0x9b, 0xb5, 0xb1, 0x8c, + 0xc6, 0x45, 0xb3, 0x1b, 0xdc, 0x96, 0xfe, 0x2e, + 0xc0, 0xce, 0xe5, 0x02, 0x4c, 0xfe, 0xa1, 0xe3, + 0x52, 0x32, 0xe3, 0xb3, 0xa3, 0xc8, 0x6c, 0x19, + 0x79, 0xc6, 0xa0, 0xdc, 0x2a, 0x5a, 0x04, 0xcf, + 0x1b, 0x39, 0x31, 0x1f, 0x58, 0x96, 0x63, 0x96, + 0x6a, 0x6f, 0x45, 0x96, 0xd7, 0x7c, 0xbe, 0xbf, + 0x83, 0xd3, 0xa2}, + .pubkey_len = 59, + }, + { // #10 [BrainpoolP224t1] + .name = "BrainpoolP224t1", + .curve_type = CURVE_BRAINPOOL, + .params = {0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, + 0x01, 0x01, 0x06}, + .params_len = 11, + .privkey = {0x00, 0xb4, 0xa2, 0x01, 0x0a, 0xfc, 0x53, 0xe8, + 0xe4, 0x3e, 0xf0, 0xfb, 0xc2, 0x56, 0xe8, 0xa8, + 0x43, 0xce, 0x22, 0x65, 0x7a, 0xa7, 0x03, 0xf7, + 0x0f, 0x6e, 0xa2, 0x16, 0x42}, + .privkey_len = 29, + .pubkey = {0x04, 0x39, 0x04, 0xa6, 0x0a, 0x6f, 0x38, 0xec, + 0x7c, 0xa4, 0x62, 0x4d, 0x9b, 0x8e, 0xeb, 0xd8, + 0xf0, 0x80, 0x2e, 0x2d, 0xcf, 0x34, 0x90, 0xac, + 0xb8, 0xf9, 0x0c, 0x84, 0x99, 0x60, 0xb0, 0x69, + 0x1d, 0xf1, 0xa7, 0x82, 0xb5, 0x75, 0x3a, 0x26, + 0x08, 0x89, 0x1f, 0x0c, 0xc2, 0xce, 0x68, 0x23, + 0xad, 0x68, 0xe0, 0x96, 0xe3, 0xc7, 0x23, 0x44, + 0xfe, 0xca, 0xc2}, + .pubkey_len = 59, + }, + { // #11 [BrainpoolP256r1] + .name = "BrainpoolP256r1", + .curve_type = CURVE_BRAINPOOL, + .params = {0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, + 0x01, 0x01, 0x07}, + .params_len = 11, + .privkey = {0x66, 0xbb, 0xbb, 0x8d, 0x08, 0xbd, 0xd7, 0x02, + 0x4a, 0xa0, 0x72, 0x20, 0x1e, 0x05, 0x60, 0x9c, + 0xe4, 0x7a, 0x32, 0xab, 0x66, 0x4a, 0x7c, 0x00, + 0x30, 0x14, 0x92, 0x3a, 0xb1, 0x8e, 0xe1, 0x90}, + .privkey_len = 32, + .pubkey = {0x04, 0x41, 0x04, 0x6e, 0x9e, 0x8b, 0x83, 0xef, + 0xda, 0x7e, 0x7d, 0x4b, 0x0d, 0x91, 0xee, 0x7e, + 0x05, 0xe5, 0x09, 0x03, 0xe4, 0xbd, 0x36, 0x75, + 0x44, 0x20, 0xd8, 0xf8, 0xf8, 0x2f, 0x92, 0x45, + 0x97, 0xf4, 0x59, 0x8e, 0x4c, 0xd3, 0x41, 0x08, + 0x2c, 0x2b, 0x3d, 0x7f, 0xfc, 0x8a, 0x5b, 0x4f, + 0xaa, 0x29, 0xba, 0x4a, 0x0a, 0x99, 0x14, 0x0a, + 0xa6, 0xe7, 0xb4, 0x6c, 0x9d, 0x55, 0xbf, 0x14, + 0xa2, 0x7e, 0xdc}, + .pubkey_len = 67, + }, + { // #12 [BrainpoolP256t1] + .name = "BrainpoolP256t1", + .curve_type = CURVE_BRAINPOOL, + .params = {0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, + 0x01, 0x01, 0x08}, + .params_len = 11, + .privkey = {0x32, 0x73, 0x2a, 0xf1, 0x10, 0xb5, 0x07, 0xf1, + 0x05, 0xc0, 0x3c, 0x16, 0x1c, 0xcc, 0xf6, 0xa9, + 0x0f, 0xdb, 0x3f, 0xeb, 0xc3, 0xd1, 0x69, 0x19, + 0xac, 0x9b, 0x7c, 0x9d, 0xbb, 0x75, 0xfb, 0x40}, + .privkey_len = 32, + .pubkey = {0x04, 0x41, 0x04, 0x91, 0x3b, 0xd0, 0x87, 0xc3, + 0x92, 0x59, 0x00, 0x30, 0x01, 0x7e, 0x93, 0x1f, + 0x79, 0x10, 0xd0, 0x7a, 0xe6, 0xe8, 0x49, 0x78, + 0x62, 0x69, 0x8a, 0x92, 0x12, 0x9a, 0x05, 0x6e, + 0xd3, 0x76, 0x6e, 0x5b, 0xab, 0xf6, 0xe8, 0x23, + 0x34, 0xb0, 0xcb, 0xc6, 0x1c, 0xb3, 0x18, 0x8b, + 0x51, 0x11, 0x2f, 0x6b, 0xca, 0x0a, 0xf7, 0xf4, + 0x27, 0x6d, 0x16, 0x09, 0x7c, 0x27, 0x03, 0xd2, + 0x5e, 0x8e, 0x14}, + .pubkey_len = 67, + }, + { // #13 [BrainpoolP320r1] + .name = "BrainpoolP320r1", + .curve_type = CURVE_BRAINPOOL, + .params = {0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, + 0x01, 0x01, 0x09}, + .params_len = 11, + .privkey = {0x00, 0xa5, 0xba, 0x71, 0x28, 0xa0, 0x90, 0xcd, + 0x5a, 0x8f, 0xda, 0x07, 0xfa, 0xac, 0x9b, 0x00, + 0x81, 0x36, 0x70, 0x6b, 0x0b, 0x32, 0xc9, 0x6b, + 0x4b, 0xc2, 0x58, 0x35, 0xd6, 0x0b, 0x57, 0x12, + 0x43, 0x65, 0x4b, 0xc6, 0xa3, 0x41, 0x7d, 0x7c, + 0xda}, + .privkey_len = 41, + .pubkey = {0x04, 0x51, 0x04, 0xaa, 0x22, 0x58, 0x21, 0xfe, + 0xe3, 0xfc, 0x71, 0x82, 0x2a, 0xb0, 0x52, 0xe5, + 0xe5, 0x6d, 0x7c, 0x01, 0x05, 0x7b, 0x97, 0x7d, + 0xd7, 0xf3, 0xf8, 0x0e, 0xce, 0xe7, 0xd1, 0xfa, + 0xbd, 0x0c, 0x2c, 0xb8, 0x7b, 0x2b, 0xbf, 0xfe, + 0x9e, 0x0b, 0xf1, 0x9e, 0x6a, 0x1a, 0x76, 0xe1, + 0xf3, 0xc6, 0x77, 0x38, 0x58, 0x24, 0xc2, 0x9b, + 0xa0, 0x71, 0xe7, 0x04, 0x8b, 0xe3, 0x96, 0x49, + 0xdd, 0x9d, 0x43, 0xc2, 0x91, 0x20, 0x59, 0xa9, + 0x2b, 0xd2, 0x77, 0x10, 0x16, 0xc3, 0xa6, 0xe3, + 0x89, 0x57, 0xcc}, + .pubkey_len = 83, + }, + { // #14 [BrainpoolP320t1] + .name = "BrainpoolP320t1", + .curve_type = CURVE_BRAINPOOL, + .params = {0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, + 0x01, 0x01, 0x0A}, + .params_len = 11, + .privkey = {0x1d, 0x4c, 0xdc, 0x1e, 0x66, 0x15, 0x35, 0x80, + 0xf8, 0xf2, 0x2e, 0x4f, 0x2c, 0x1a, 0x88, 0xfb, + 0xef, 0xa5, 0xce, 0x29, 0xf2, 0xf9, 0x9b, 0x1f, + 0xc5, 0x9f, 0xf7, 0x18, 0x73, 0x13, 0x84, 0x44, + 0xe5, 0x34, 0x83, 0x4b, 0x73, 0x98, 0x44, 0x3b}, + .privkey_len = 40, + .pubkey = {0x04, 0x51, 0x04, 0x8a, 0x02, 0x82, 0x6d, 0xe4, + 0x33, 0x28, 0xd3, 0x79, 0x8a, 0x39, 0x1f, 0x30, + 0x5b, 0xe7, 0xae, 0xaa, 0x3b, 0xca, 0x2f, 0x64, + 0xc0, 0x1c, 0x8c, 0x83, 0x96, 0x82, 0xfe, 0x1c, + 0x1f, 0x9e, 0x9a, 0x29, 0xc8, 0xb7, 0x8b, 0x36, + 0x0d, 0x20, 0xff, 0x71, 0x22, 0x8b, 0xe7, 0xa6, + 0x28, 0xbf, 0x1f, 0x45, 0x9d, 0xca, 0x67, 0xef, + 0x9b, 0xba, 0xbc, 0x6c, 0x47, 0xa9, 0xf1, 0x9f, + 0x22, 0x57, 0x54, 0x32, 0xd2, 0x3d, 0x43, 0x17, + 0x79, 0x8e, 0x74, 0xb0, 0xd8, 0x67, 0xf7, 0xa1, + 0x4d, 0x29, 0x13}, + .pubkey_len = 83, + }, + { // #15 [BrainpoolP384r1] + .name = "BrainpoolP384r1", + .curve_type = CURVE_BRAINPOOL, + .params = {0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, + 0x01, 0x01, 0x0B}, + .params_len = 11, + .privkey = {0x49, 0x56, 0xb3, 0xba, 0xe7, 0xbb, 0x27, 0xcb, + 0x7f, 0x10, 0x84, 0xc7, 0xb4, 0x14, 0xfe, 0x2c, + 0x8b, 0xc4, 0xbe, 0x94, 0x0d, 0x2e, 0x20, 0xc9, + 0x54, 0x73, 0x17, 0x89, 0x8e, 0x4d, 0xa2, 0x6d, + 0xa8, 0x6d, 0xa0, 0xfb, 0x89, 0x1f, 0xf6, 0xce, + 0x4a, 0x45, 0xe7, 0xa9, 0x02, 0x0c, 0xa2, 0x7b}, + .privkey_len = 48, + .pubkey = {0x04, 0x61, 0x04, 0x31, 0xb9, 0xa2, 0x0a, 0x47, + 0x60, 0xc3, 0xa0, 0x27, 0x87, 0x04, 0x44, 0xdc, + 0x6c, 0xd0, 0xa3, 0x83, 0x09, 0xdb, 0x6d, 0x9c, + 0x48, 0xdf, 0x4d, 0xe5, 0x72, 0x0c, 0x71, 0x69, + 0x28, 0xbb, 0x1f, 0x33, 0x63, 0xdb, 0x9f, 0x94, + 0xb0, 0x28, 0x0e, 0xed, 0x39, 0x41, 0x56, 0x56, + 0x92, 0xba, 0xed, 0x06, 0x3b, 0xb0, 0x1d, 0x68, + 0x20, 0x5d, 0xcc, 0xf4, 0x4a, 0xcd, 0x3f, 0x09, + 0x73, 0x51, 0x12, 0xbb, 0x94, 0x7d, 0xfd, 0x0a, + 0x89, 0xd1, 0xfa, 0xa9, 0xd4, 0xe5, 0x39, 0xcd, + 0x13, 0x8b, 0x23, 0x19, 0xbe, 0x12, 0xae, 0xc7, + 0x41, 0x18, 0x55, 0x04, 0x30, 0xee, 0xb5, 0x4c, + 0x2c, 0x33, 0xe2}, + .pubkey_len = 99, + }, + { // #16 [BrainpoolP384t1] + .name = "BrainpoolP384t1", + .curve_type = CURVE_BRAINPOOL, + .params = {0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, + 0x01, 0x01, 0x0C}, + .params_len = 11, + .privkey = {0x76, 0xe2, 0x62, 0x73, 0x3b, 0xb5, 0x42, 0x2a, + 0x9c, 0x29, 0x3b, 0x8c, 0x07, 0x23, 0xcc, 0x5a, + 0x6b, 0x4f, 0x30, 0x50, 0x1e, 0x00, 0xbf, 0xd6, + 0xab, 0x52, 0xda, 0x1c, 0x76, 0xf0, 0x6e, 0x56, + 0xbd, 0x52, 0x83, 0x05, 0x4b, 0xb0, 0x8c, 0xa8, + 0x69, 0xab, 0x5f, 0x6b, 0x8c, 0x3f, 0xda, 0x09}, + .privkey_len = 48, + .pubkey = {0x04, 0x61, 0x04, 0x49, 0xc3, 0xd5, 0x8d, 0x45, + 0xf1, 0x97, 0x6a, 0xd5, 0xb3, 0x06, 0x93, 0x14, + 0xe2, 0x94, 0x32, 0xb3, 0xe1, 0xdf, 0x7a, 0x35, + 0x98, 0x22, 0x11, 0x90, 0x55, 0x13, 0x77, 0x31, + 0x88, 0xf5, 0xe0, 0x55, 0xdf, 0x49, 0x0e, 0x6b, + 0x84, 0x18, 0xea, 0xe9, 0x49, 0x73, 0x46, 0x86, + 0x9e, 0x6a, 0x3b, 0x3a, 0x80, 0x6e, 0x1c, 0x4c, + 0x3b, 0xd9, 0x78, 0x16, 0x3c, 0x02, 0x11, 0x6e, + 0x1f, 0x59, 0x21, 0xbb, 0x20, 0x89, 0xa2, 0x30, + 0x06, 0x6b, 0x3e, 0x5a, 0x07, 0xf3, 0x80, 0xd3, + 0xc0, 0xb7, 0x5a, 0x84, 0x4b, 0x62, 0x5b, 0x17, + 0xb2, 0xc6, 0xcf, 0x1a, 0x00, 0xdc, 0x87, 0xc2, + 0xcd, 0x59, 0x17}, + .pubkey_len = 99, + }, + { // #17 [BrainpoolP512r1] + .name = "BrainpoolP512r1", + .curve_type = CURVE_BRAINPOOL, + .params = {0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, + 0x01, 0x01, 0x0D}, + .params_len = 11, + .privkey = {0x72, 0xfc, 0xe0, 0x63, 0xea, 0xbc, 0x9a, 0x03, + 0xb5, 0x42, 0x82, 0x00, 0x75, 0xa4, 0x72, 0xcf, + 0x3c, 0x12, 0xe3, 0xf5, 0xf4, 0xf5, 0xc4, 0x9a, + 0xf8, 0xe0, 0xa9, 0x40, 0xfa, 0xe9, 0xe0, 0xf6, + 0x10, 0x99, 0x18, 0x60, 0xce, 0xce, 0x07, 0x08, + 0x0e, 0x02, 0xb8, 0x7c, 0xa6, 0xa2, 0x78, 0x40, + 0x83, 0xf1, 0xa2, 0x53, 0x7b, 0xf3, 0x53, 0x0f, + 0xca, 0xfa, 0x30, 0xe2, 0x9a, 0xae, 0xba, 0x6e}, + .privkey_len = 64, + .pubkey = {0x04, 0x81, 0x81, 0x04, 0x78, 0x38, 0x8a, 0xdf, + 0xbf, 0xe7, 0xd9, 0xf5, 0x23, 0xaf, 0x22, 0x52, + 0xe5, 0xe7, 0x0f, 0x7f, 0x88, 0x50, 0x8b, 0x31, + 0xd3, 0x31, 0x05, 0x4a, 0xc9, 0xb2, 0xed, 0x5d, + 0x93, 0x58, 0x3a, 0x1f, 0x26, 0x77, 0x50, 0x24, + 0x27, 0xc4, 0x89, 0xfb, 0xdb, 0x1a, 0x2d, 0x87, + 0x30, 0x85, 0x4e, 0x68, 0x5b, 0x1b, 0xa3, 0x45, + 0x92, 0x8f, 0x4c, 0x8d, 0x79, 0xd6, 0xd6, 0x12, + 0x35, 0x80, 0xbe, 0x34, 0x1c, 0xa1, 0xec, 0x10, + 0x59, 0xb1, 0x4e, 0x8b, 0xe2, 0xb7, 0x7d, 0x64, + 0x58, 0x00, 0xd1, 0x73, 0xb3, 0x5b, 0x16, 0x97, + 0x42, 0x0b, 0x2b, 0x84, 0xd8, 0x46, 0xd7, 0xa1, + 0x8e, 0x98, 0xd7, 0x59, 0x96, 0x7d, 0x88, 0x9d, + 0x0b, 0xc0, 0x32, 0xaa, 0x76, 0x42, 0x90, 0xd2, + 0x61, 0xe1, 0xe0, 0x8f, 0xa0, 0x57, 0x53, 0xfd, + 0xa4, 0x07, 0xaf, 0x21, 0x8b, 0x77, 0x2e, 0x31, + 0xa4, 0x4b, 0x84, 0xa1}, + .pubkey_len = 132, + }, + { // #18 [BrainpoolP512t1] + .name = "BrainpoolP512t1", + .curve_type = CURVE_BRAINPOOL, + .params = {0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, + 0x01, 0x01, 0x0E}, + .params_len = 11, + .privkey = {0x00, 0xa3, 0xdb, 0xf8, 0x98, 0x71, 0x23, 0x93, + 0x92, 0xf7, 0x62, 0xe5, 0xc7, 0x10, 0xb0, 0xc8, + 0xb0, 0xef, 0xae, 0x4b, 0x0e, 0x99, 0x0d, 0x89, + 0x56, 0x4b, 0xa7, 0x9c, 0xc3, 0x18, 0x0b, 0x13, + 0x00, 0x9f, 0x95, 0x7e, 0x2f, 0x52, 0x20, 0xcc, + 0xcc, 0x55, 0x99, 0x45, 0x9a, 0x8e, 0x0c, 0x5f, + 0xf4, 0xe4, 0x5c, 0x2d, 0xd5, 0xcb, 0x9f, 0xa5, + 0x9f, 0x3f, 0xa3, 0xc2, 0x00, 0xd1, 0xfe, 0xeb, + 0x6c}, + .privkey_len = 65, + .pubkey = {0x04, 0x81, 0x81, 0x04, 0x93, 0x0a, 0x7d, 0xe1, + 0x95, 0x97, 0x84, 0x1d, 0xf3, 0xa9, 0x93, 0xed, + 0x23, 0x86, 0x89, 0x44, 0xb5, 0x7e, 0xec, 0xc9, + 0xd8, 0x92, 0x0d, 0xca, 0xf6, 0x46, 0x5b, 0xd3, + 0x16, 0xc6, 0xc4, 0x05, 0x50, 0x98, 0x99, 0xeb, + 0xab, 0x5e, 0x2a, 0xea, 0x4e, 0x25, 0x60, 0x23, + 0x2c, 0x8a, 0x8a, 0x6f, 0xd3, 0xc4, 0xab, 0xff, + 0x93, 0x34, 0xb2, 0x9c, 0x76, 0x2a, 0x55, 0x00, + 0xb9, 0x16, 0xea, 0xfd, 0x39, 0x17, 0x2e, 0xae, + 0x62, 0x33, 0x5f, 0x62, 0x91, 0xcc, 0x06, 0xcc, + 0xc9, 0x3f, 0x86, 0xbb, 0x11, 0x52, 0x81, 0xfb, + 0xc6, 0x10, 0xef, 0xc5, 0x19, 0x2f, 0xb6, 0x61, + 0x7e, 0xde, 0xad, 0xbe, 0x43, 0x05, 0x0c, 0xfd, + 0xe1, 0x8a, 0x99, 0x26, 0x28, 0x38, 0xaa, 0x3b, + 0x0f, 0x8c, 0x68, 0x7e, 0x4f, 0xfc, 0x47, 0x83, + 0xd7, 0x16, 0x2a, 0x3c, 0x9f, 0x60, 0xf1, 0x59, + 0x82, 0x91, 0x29, 0x0c}, + .pubkey_len = 132, + }, + { // #19 [curve25519] + .name = "curve25519", + .curve_type = CURVE_MONTGOMERY, + .params = {0x06, 0x03, 0x2B, 0x65, 0x6E}, + .params_len = 5, + .privkey = {0x77, 0x07, 0x6D, 0x0A, 0x73, 0x18, 0xA5, 0x7D, + 0x3C, 0x16, 0xC1, 0x72, 0x51, 0xB2, 0x66, 0x45, + 0xDF, 0x4C, 0x2F, 0x87, 0xEB, 0xC0, 0x99, 0x2A, + 0xB1, 0x77, 0xFB, 0xA5, 0x1D, 0xB9, 0x2C, 0x2A}, + .privkey_len = 32, + .pubkey = {0x04, 0x20, 0x85, 0x20, 0xF0, 0x09, 0x89, 0x30, + 0xA7, 0x54, 0x74, 0x8B, 0x7D, 0xDC, 0xB4, 0x3E, + 0xF7, 0x5A, 0x0D, 0xBF, 0x3A, 0x0D, 0x26, 0x38, + 0x1A, 0xF4, 0xEB, 0xA4, 0xA9, 0x8E, 0xAA, 0x9B, + 0x4E, 0x6A}, + .pubkey_len = 34, + }, + { // #20 [curve448] + .name = "curve448", + .curve_type = CURVE_MONTGOMERY, + .params = {0x06, 0x03, 0x2B, 0x65, 0x6F}, + .params_len = 5, + .privkey = {0x9A, 0x8F, 0x49, 0x25, 0xD1, 0x51, 0x9F, 0x57, + 0x75, 0xCF, 0x46, 0xB0, 0x4B, 0x58, 0x00, 0xD4, + 0xEE, 0x9E, 0xE8, 0xBA, 0xE8, 0xBC, 0x55, 0x65, + 0xD4, 0x98, 0xC2, 0x8D, 0xD9, 0xC9, 0xBA, 0xF5, + 0x74, 0xA9, 0x41, 0x97, 0x44, 0x89, 0x73, 0x91, + 0x00, 0x63, 0x82, 0xA6, 0xF1, 0x27, 0xAB, 0x1D, + 0x9A, 0xC2, 0xD8, 0xC0, 0xA5, 0x98, 0x72, 0xEB}, + .privkey_len = 56, + .pubkey = {0x04, 0x38, 0x9B, 0x08, 0xF7, 0xCC, 0x31, 0xB7, + 0xE3, 0xE6, 0x7D, 0x22, 0xD5, 0xAE, 0xA1, 0x21, + 0x07, 0x4A, 0x27, 0x3B, 0xD2, 0xB8, 0x3D, 0xE0, + 0x9C, 0x63, 0xFA, 0xA7, 0x3D, 0x2C, 0x22, 0xC5, + 0xD9, 0xBB, 0xC8, 0x36, 0x64, 0x72, 0x41, 0xD9, + 0x53, 0xD4, 0x0C, 0x5B, 0x12, 0xDA, 0x88, 0x12, + 0x0D, 0x53, 0x17, 0x7F, 0x80, 0xE5, 0x32, 0xC4, + 0x1F, 0xA0 }, + .pubkey_len = 58, + }, + { // #21 [ed25519] + .name = "ed25519", + .curve_type = CURVE_EDWARDS, + .params = {0x06, 0x03, 0x2B, 0x65, 0x70}, + .params_len = 5, + .privkey = {0x9D, 0x61, 0xB1, 0x9D, 0xEF, 0xFD, 0x5A, 0x60, + 0xBA, 0x84, 0x4A, 0xF4, 0x92, 0xEC, 0x2C, 0xC4, + 0x44, 0x49, 0xC5, 0x69, 0x7B, 0x32, 0x69, 0x19, + 0x70, 0x3B, 0xAC, 0x03, 0x1C, 0xAE, 0x7F, 0x60}, + .privkey_len = 32, + .pubkey = {0x04, 0x20, 0xD7, 0x5A, 0x98, 0x01, 0x82, 0xB1, + 0x0A, 0xB7, 0xD5, 0x4B, 0xFE, 0xD3, 0xC9, 0x64, + 0x07, 0x3A, 0x0E, 0xE1, 0x72, 0xF3, 0xDA, 0xA6, + 0x23, 0x25, 0xAF, 0x02, 0x1A, 0x68, 0xF7, 0x07, + 0x51, 0x1A}, + .pubkey_len = 34, + }, + { // #22 [ed448] + .name = "ed448", + .curve_type = CURVE_EDWARDS, + .params = {0x06, 0x03, 0x2B, 0x65, 0x71}, + .params_len = 5, + .privkey = {0x6C, 0x82, 0xA5, 0x62, 0xCB, 0x80, 0x8D, 0x10, + 0xD6, 0x32, 0xBE, 0x89, 0xC8, 0x51, 0x3E, 0xBF, + 0x6C, 0x92, 0x9F, 0x34, 0xDD, 0xFA, 0x8C, 0x9F, + 0x63, 0xC9, 0x96, 0x0E, 0xF6, 0xE3, 0x48, 0xA3, + 0x52, 0x8C, 0x8A, 0x3F, 0xCC, 0x2F, 0x04, 0x4E, + 0x39, 0xA3, 0xFC, 0x5B, 0x94, 0x49, 0x2F, 0x8F, + 0x03, 0x2E, 0x75, 0x49, 0xA2, 0x00, 0x98, 0xF9, + 0x5B}, + .privkey_len = 57, + .pubkey = {0x04, 0x39, 0x5F, 0xD7, 0x44, 0x9B, 0x59, 0xB4, + 0x61, 0xFD, 0x2C, 0xE7, 0x87, 0xEC, 0x61, 0x6A, + 0xD4, 0x6A, 0x1D, 0xA1, 0x34, 0x24, 0x85, 0xA7, + 0x0E, 0x1F, 0x8A, 0x0E, 0xA7, 0x5D, 0x80, 0xE9, + 0x67, 0x78, 0xED, 0xF1, 0x24, 0x76, 0x9B, 0x46, + 0xC7, 0x06, 0x1B, 0xD6, 0x78, 0x3D, 0xF1, 0xE5, + 0x0F, 0x6C, 0xD1, 0xFA, 0x1A, 0xBE, 0xAF, 0xE8, + 0x25, 0x61, 0x80 }, + .pubkey_len = 59, + }, +}; + +#define EC_TV_NUM sizeof(ec_tv)/sizeof(struct EC_TEST_VECTOR) + +// Elliptic Curve lengths in bits +#define CURVE160_LENGTH 0x00A0 +#define CURVE192_LENGTH 0x00C0 +#define CURVE224_LENGTH 0x00E0 +#define CURVE256_LENGTH 0x0100 +#define CURVE320_LENGTH 0x0140 +#define CURVE384_LENGTH 0x0180 +#define CURVE456_LENGTH 0x01C8 +#define CURVE512_LENGTH 0x0200 +#define CURVE521_LENGTH 0x0209 + +// EC test vectors for ECDH +#define NUM_SECRET_KEY_LENGTHS sizeof(secret_key_len)/sizeof(CK_ULONG) +CK_ULONG secret_key_len[] = { 8, 16, 24, 32, 48, 64, 66, 80, 123, 3456, 56789 }; + +#define NUM_SHARED_DATA (sizeof(shared_data)/sizeof(shared_data_t)) + +typedef struct { + unsigned int length; + unsigned char data[128]; +} shared_data_t; + +static shared_data_t shared_data[] = { + {0, {0}}, + {1, {0x00}}, + {2, {0x01,0x02}}, + {16, {0x32,0x3F,0xA3,0x16,0x9D,0x8E,0x9C,0x65,0x93,0xF5,0x94,0x76,0xBC,0x14,0x20,0x00}}, + {64, {0x16,0x30,0x2F,0xF0,0xDB,0xBB,0x5A,0x8D,0x73,0x3D,0xAB,0x71,0x41,0xC1,0xB4,0x5A, + 0xCB,0xC8,0x71,0x59,0x39,0x67,0x7F,0x6A,0x56,0x85,0x0A,0x38,0xBD,0x87,0xBD,0x59, + 0xB0,0x9E,0x80,0x27,0x96,0x09,0xFF,0x33,0x3E,0xB9,0xD4,0xC0,0x61,0x23,0x1F,0xB2, + 0x6F,0x92,0xEE,0xB0,0x49,0x82,0xA5,0xF1,0xD1,0x76,0x4C,0xAD,0x57,0x66,0x54,0x22,}}, + {123, {0xCB,0xC8,0x71,0x59,0x39,0x67,0x7F,0x6A,0x56,0x85,0x0A,0x38,0xBD,0x87,0xBD,0x59, + 0xB0,0x9E,0x80,0x27,0x96,0x09,0xFF,0x33,0x3E,0xB9,0xD4,0xC0,0x61,0x23,0x1F,0xB2, + 0xCB,0xC8,0x71,0x59,0x39,0x67,0x7F,0x6A,0x56,0x85,0x0A,0x38,0xBD,0x87,0xBD,0x59, + 0xB0,0x9E,0x80,0x27,0x96,0x09,0xFF,0x33,0x3E,0xB9,0xD4,0xC0,0x61,0x23,0x1F,0xB2, + 0xCB,0xC8,0x71,0x59,0x39,0x67,0x7F,0x6A,0x56,0x85,0x0A,0x38,0xBD,0x87,0xBD,0x59, + 0xB0,0x9E,0x80,0x27,0x96,0x09,0xFF,0x33,0x3E,0xB9,0xD4,0xC0,0x61,0x23,0x1F,0xB2, + 0xCB,0xC8,0x71,0x59,0x39,0x67,0x7F,0x6A,0x56,0x85,0x0A,0x38,0xBD,0x87,0xBD,0x59, + 0xB0,0x9E,0x80,0x27,0x96,0x09,0xFF,0x33,0x3E,0xB9,0xD4,}}, +}; + +// ECDH KATs +struct ECDH_TEST_VECTOR { + CK_BYTE name[32]; + CK_BYTE params[64]; + CK_ULONG params_len; + CK_BYTE privkeyA[196]; + CK_BYTE pubkeyA[196]; + CK_ULONG privkey_len; + CK_BYTE privkeyB[196]; + CK_BYTE pubkeyB[196]; + CK_ULONG pubkey_len; + CK_ULONG kdf; + CK_BYTE shared_data[196]; + CK_ULONG shared_data_len; + CK_BYTE derived_key[512]; + CK_ULONG derived_key_len; +}; + +/** + * Test vectors for ECDH. + * + * Note: these test vectors contain compressed public keys that get uncompressed + * using openssl. If openssl is built in fips-mode, only few curves are + * supported. Therefore, compressed keys are used only for curves that + * are supported by openssl-fips. + */ +struct ECDH_TEST_VECTOR ecdh_tv[] = { + + { // #0 [PRIME192v1] + .name = "PRIME192v1", + .params = {0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x01}, + .params_len = 10, + .privkeyA = {0x0a,0x38,0x68,0x89,0xdc,0xe6,0xe1,0x93,0xba,0xc4,0xcf,0xd1,0xd2,0x0d,0xd3,0x2c, + 0xc9,0xcf,0x08,0x14,0x51,0x23,0xd4,0x7a}, + .pubkeyA = {0x04,0x31,0x04,0xd9,0xf6,0x79,0xa6,0xc2,0xf9,0x16,0x11,0x6e,0x8a,0xbe,0xe6,0xa2, + 0x2c,0x64,0xb7,0x88,0xaa,0xa5,0x7e,0x22,0x97,0xc0,0x0e,0xf5,0x6f,0xe1,0xd4,0x4a, + 0x47,0xb4,0x76,0x3e,0xd6,0xa3,0x90,0x4c,0x7d,0xb4,0xee,0x61,0x9b,0x01,0x37,0x71, + 0xfe,0x65,0x37}, + .privkey_len = 24, + .privkeyB = {0x63,0x1F,0x95,0xBB,0x4A,0x67,0x63,0x2C,0x9C,0x47,0x6E,0xEE,0x9A,0xB6,0x95,0xAB, + 0x24,0x0A,0x04,0x99,0x30,0x7F,0xCF,0x62,}, + .pubkeyB = {0x04,0x31,0x04,0x51,0x9A,0x12,0x16,0x80,0xE0,0x04,0x54,0x66,0xBA,0x21,0xDF,0x2E, + 0xEE,0x47,0xF5,0x97,0x3B,0x50,0x05,0x77,0xEF,0x13,0xD5,0xFF,0x61,0x3A,0xB4,0xD6, + 0x4C,0xEE,0x3A,0x20,0x87,0x5B,0xDB,0x10,0xF9,0x53,0xF6,0xB3,0x0C,0xA0,0x72,0xC6, + 0x0A,0xA5,0x7F,}, + .pubkey_len = 51, + .kdf = CKD_SHA1_KDF, + .shared_data = {0}, + .shared_data_len = 0, + .derived_key = {0x70,0x39,0xA4,0x26,0x35,0xF2,0xDB,0xE5,0xE6,0x9E,0xB0,0xF1,0xC7,0xD0,0x56,0xD6, + 0x86,0xC0}, + .derived_key_len = 18, + }, + + { // #1 [PRIME256v1] + .name = "PRIME256v1", + .params = {0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07}, + .params_len = 10, + .privkeyA = {0x81,0x42,0x64,0x14,0x5F,0x2F,0x56,0xF2,0xE9,0x6A,0x8E,0x33,0x7A,0x12,0x84,0x99, + 0x3F,0xAF,0x43,0x2A,0x5A,0xBC,0xE5,0x9E,0x86,0x7B,0x72,0x91,0xD5,0x07,0xA3,0xAF,}, + .pubkeyA = {0x04,0x41,0x04,0x2A,0xF5,0x02,0xF3,0xBE,0x89,0x52,0xF2,0xC9,0xB5,0xA8,0xD4,0x16, + 0x0D,0x09,0xE9,0x71,0x65,0xBE,0x50,0xBC,0x42,0xAE,0x4A,0x5E,0x8D,0x3B,0x4B,0xA8, + 0x3A,0xEB,0x15,0xEB,0x0F,0xAF,0x4C,0xA9,0x86,0xC4,0xD3,0x86,0x81,0xA0,0xF9,0x87, + 0x2D,0x79,0xD5,0x67,0x95,0xBD,0x4B,0xFF,0x6E,0x6D,0xE3,0xC0,0xF5,0x01,0x5E,0xCE, + 0x5E,0xFD,0x85,}, + .privkey_len = 32, + .privkeyB = {0x2C,0xE1,0x78,0x8E,0xC1,0x97,0xE0,0x96,0xDB,0x95,0xA2,0x00,0xCC,0x0A,0xB2,0x6A, + 0x19,0xCE,0x6B,0xCC,0xAD,0x56,0x2B,0x8E,0xEE,0x1B,0x59,0x37,0x61,0xCF,0x7F,0x41,}, + .pubkeyB = {0x04,0x41,0x04,0xB1,0x20,0xDE,0x4A,0xA3,0x64,0x92,0x79,0x53,0x46,0xE8,0xDE,0x6C, + 0x2C,0x86,0x46,0xAE,0x06,0xAA,0xEA,0x27,0x9F,0xA7,0x75,0xB3,0xAB,0x07,0x15,0xF6, + 0xCE,0x51,0xB0,0x9F,0x1B,0x7E,0xEC,0xE2,0x0D,0x7B,0x5E,0xD8,0xEC,0x68,0x5F,0xA3, + 0xF0,0x71,0xD8,0x37,0x27,0x02,0x70,0x92,0xA8,0x41,0x13,0x85,0xC3,0x4D,0xDE,0x57, + 0x08,0xB2,0xB6,}, + .pubkey_len = 67, + .kdf = CKD_SHA224_KDF, + .shared_data = {0}, + .shared_data_len = 0, + .derived_key = {0xCA,0x11,0x2E,0x5E,0xDC,0xBE,0x71,0x78,0xB3,0xB7,0xBE,0x67,0xAF,0x54,0xE2,0x58, + 0xB7,0x29,0x2A,0xA1,0x8A,0x85,0xBA,0x4C,0xA1,0xC6,0x58,0x44,0x94,}, + .derived_key_len = 29, + }, + + { // #1a [PRIME256v1 with compressed odd pubkeyA and even pubkeyB, pubkey_len = 33] + .name = "PRIME256v1", + .params = {0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07}, + .params_len = 10, + .privkeyA = {0x81,0x42,0x64,0x14,0x5F,0x2F,0x56,0xF2,0xE9,0x6A,0x8E,0x33,0x7A,0x12,0x84,0x99, + 0x3F,0xAF,0x43,0x2A,0x5A,0xBC,0xE5,0x9E,0x86,0x7B,0x72,0x91,0xD5,0x07,0xA3,0xAF,}, + .pubkeyA = {0x04,0x21,0x03,0x2A,0xF5,0x02,0xF3,0xBE,0x89,0x52,0xF2,0xC9,0xB5,0xA8,0xD4,0x16, + 0x0D,0x09,0xE9,0x71,0x65,0xBE,0x50,0xBC,0x42,0xAE,0x4A,0x5E,0x8D,0x3B,0x4B,0xA8, + 0x3A,0xEB,0x15,}, + .privkey_len = 32, + .privkeyB = {0x2C,0xE1,0x78,0x8E,0xC1,0x97,0xE0,0x96,0xDB,0x95,0xA2,0x00,0xCC,0x0A,0xB2,0x6A, + 0x19,0xCE,0x6B,0xCC,0xAD,0x56,0x2B,0x8E,0xEE,0x1B,0x59,0x37,0x61,0xCF,0x7F,0x41,}, + .pubkeyB = {0x04,0x21,0x02,0xB1,0x20,0xDE,0x4A,0xA3,0x64,0x92,0x79,0x53,0x46,0xE8,0xDE,0x6C, + 0x2C,0x86,0x46,0xAE,0x06,0xAA,0xEA,0x27,0x9F,0xA7,0x75,0xB3,0xAB,0x07,0x15,0xF6, + 0xCE,0x51,0xB0,}, + .pubkey_len = 35, + .kdf = CKD_SHA224_KDF, + .shared_data = {0}, + .shared_data_len = 0, + .derived_key = {0xCA,0x11,0x2E,0x5E,0xDC,0xBE,0x71,0x78,0xB3,0xB7,0xBE,0x67,0xAF,0x54,0xE2,0x58, + 0xB7,0x29,0x2A,0xA1,0x8A,0x85,0xBA,0x4C,0xA1,0xC6,0x58,0x44,0x94,}, + .derived_key_len = 29, + }, + + { // #1b [PRIME256v1 with hybrid odd pubkeyA and even pubkeyB, pubkey_len = 65] + .name = "PRIME256v1", + .params = {0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07}, + .params_len = 10, + .privkeyA = {0x81,0x42,0x64,0x14,0x5F,0x2F,0x56,0xF2,0xE9,0x6A,0x8E,0x33,0x7A,0x12,0x84,0x99, + 0x3F,0xAF,0x43,0x2A,0x5A,0xBC,0xE5,0x9E,0x86,0x7B,0x72,0x91,0xD5,0x07,0xA3,0xAF,}, + .pubkeyA = {0x04,0x41,0x07,0x2A,0xF5,0x02,0xF3,0xBE,0x89,0x52,0xF2,0xC9,0xB5,0xA8,0xD4,0x16, + 0x0D,0x09,0xE9,0x71,0x65,0xBE,0x50,0xBC,0x42,0xAE,0x4A,0x5E,0x8D,0x3B,0x4B,0xA8, + 0x3A,0xEB,0x15,0xEB,0x0F,0xAF,0x4C,0xA9,0x86,0xC4,0xD3,0x86,0x81,0xA0,0xF9,0x87, + 0x2D,0x79,0xD5,0x67,0x95,0xBD,0x4B,0xFF,0x6E,0x6D,0xE3,0xC0,0xF5,0x01,0x5E,0xCE, + 0x5E,0xFD,0x85,}, + .privkey_len = 32, + .privkeyB = {0x2C,0xE1,0x78,0x8E,0xC1,0x97,0xE0,0x96,0xDB,0x95,0xA2,0x00,0xCC,0x0A,0xB2,0x6A, + 0x19,0xCE,0x6B,0xCC,0xAD,0x56,0x2B,0x8E,0xEE,0x1B,0x59,0x37,0x61,0xCF,0x7F,0x41,}, + .pubkeyB = {0x04,0x41,0x06,0xB1,0x20,0xDE,0x4A,0xA3,0x64,0x92,0x79,0x53,0x46,0xE8,0xDE,0x6C, + 0x2C,0x86,0x46,0xAE,0x06,0xAA,0xEA,0x27,0x9F,0xA7,0x75,0xB3,0xAB,0x07,0x15,0xF6, + 0xCE,0x51,0xB0,0x9F,0x1B,0x7E,0xEC,0xE2,0x0D,0x7B,0x5E,0xD8,0xEC,0x68,0x5F,0xA3, + 0xF0,0x71,0xD8,0x37,0x27,0x02,0x70,0x92,0xA8,0x41,0x13,0x85,0xC3,0x4D,0xDE,0x57, + 0x08,0xB2,0xB6,}, + .pubkey_len = 67, + .kdf = CKD_SHA224_KDF, + .shared_data = {0}, + .shared_data_len = 0, + .derived_key = {0xCA,0x11,0x2E,0x5E,0xDC,0xBE,0x71,0x78,0xB3,0xB7,0xBE,0x67,0xAF,0x54,0xE2,0x58, + 0xB7,0x29,0x2A,0xA1,0x8A,0x85,0xBA,0x4C,0xA1,0xC6,0x58,0x44,0x94,}, + .derived_key_len = 29, + }, + + { // #2 [SECP384r1] + .name = "SECP384r1", + .params = {0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22}, + .params_len = 7, + .privkeyA = {0xD2,0x73,0x35,0xEA,0x71,0x66,0x4A,0xF2,0x44,0xDD,0x14,0xE9,0xFD,0x12,0x60,0x71, + 0x5D,0xFD,0x8A,0x79,0x65,0x57,0x1C,0x48,0xD7,0x09,0xEE,0x7A,0x79,0x62,0xA1,0x56, + 0xD7,0x06,0xA9,0x0C,0xBC,0xB5,0xDF,0x29,0x86,0xF0,0x5F,0xEA,0xDB,0x93,0x76,0xF1,}, + .pubkeyA = {0x04,0x61,0x04,0x79,0x31,0x48,0xF1,0x78,0x76,0x34,0xD5,0xDA,0x4C,0x6D,0x90,0x74, + 0x41,0x7D,0x05,0xE0,0x57,0xAB,0x62,0xF8,0x20,0x54,0xD1,0x0E,0xE6,0xB0,0x40,0x3D, + 0x62,0x79,0x54,0x7E,0x6A,0x8E,0xA9,0xD1,0xFD,0x77,0x42,0x7D,0x01,0x6F,0xE2,0x7A, + 0x8B,0x8C,0x66,0xC6,0xC4,0x12,0x94,0x33,0x1D,0x23,0xE6,0xF4,0x80,0xF4,0xFB,0x4C, + 0xD4,0x05,0x04,0xC9,0x47,0x39,0x2E,0x94,0xF4,0xC3,0xF0,0x6B,0x8F,0x39,0x8B,0xB2, + 0x9E,0x42,0x36,0x8F,0x7A,0x68,0x59,0x23,0xDE,0x3B,0x67,0xBA,0xCE,0xD2,0x14,0xA1, + 0xA1,0xD1,0x28,}, + .privkey_len = 48, + .privkeyB = {0x52,0xD1,0x79,0x1F,0xDB,0x4B,0x70,0xF8,0x9C,0x0F,0x00,0xD4,0x56,0xC2,0xF7,0x02, + 0x3B,0x61,0x25,0x26,0x2C,0x36,0xA7,0xDF,0x1F,0x80,0x23,0x11,0x21,0xCC,0xE3,0xD3, + 0x9B,0xE5,0x2E,0x00,0xC1,0x94,0xA4,0x13,0x2C,0x4A,0x6C,0x76,0x8B,0xCD,0x94,0xD2,}, + .pubkeyB = {0x04,0x61,0x04,0x5C,0xD4,0x2A,0xB9,0xC4,0x1B,0x53,0x47,0xF7,0x4B,0x8D,0x4E,0xFB, + 0x70,0x8B,0x3D,0x5B,0x36,0xDB,0x65,0x91,0x53,0x59,0xB4,0x4A,0xBC,0x17,0x64,0x7B, + 0x6B,0x99,0x99,0x78,0x9D,0x72,0xA8,0x48,0x65,0xAE,0x2F,0x22,0x3F,0x12,0xB5,0xA1, + 0xAB,0xC1,0x20,0xE1,0x71,0x45,0x8F,0xEA,0xA9,0x39,0xAA,0xA3,0xA8,0xBF,0xAC,0x46, + 0xB4,0x04,0xBD,0x8F,0x6D,0x5B,0x34,0x8C,0x0F,0xA4,0xD8,0x0C,0xEC,0xA1,0x63,0x56, + 0xCA,0x93,0x32,0x40,0xBD,0xE8,0x72,0x34,0x15,0xA8,0xEC,0xE0,0x35,0xB0,0xED,0xF3, + 0x67,0x55,0xDE,}, + .pubkey_len = 99, + .kdf = CKD_SHA256_KDF, + .shared_data = {0}, + .shared_data_len = 0, + .derived_key = {0xE5,0xCA,0xFD,0x5E,0x16,0x08,0x67,0xCF,0x60,0x3F,0x46,0x0F,0xFC,0x53,0x36,0x08, + 0x29,0xF8,0xDD,0x89,0x04,0x55,0x4A,0xAB,0x4F,0xD4,0x32,0x1A,0x44,0x60,0x5C,0x68, + 0x1B,0xCE,0xAA,0x8C,0x2C,0x97,0x36,0xE4,0x07,0x24,0x2F,0xB0,0x3C,0xA9,0x68,0x2F, + 0xCC,0x31,0xE3,0x4B,0xBC,0xA4,0xF6,0xC0,0x5C,0x1F,0x06,0xF4,0x69,0xE8,0x7B,0xFB, + 0x1B,0xBC,0xB6,0x92,0xB6,0xC7,0x3A,0x87,0xBA,0x51,0x72,0xE2,0xE3,0x83,0xD1,0x93, + 0x8C,0x30,0x8F,0xB9,0x3B,0x8A,0x3A,0x48,0x2E,0xED,0x5F,0x9C,0x08,0x39,0x46,0x52, + 0x00,0xF9,0xA7,0x19,}, + .derived_key_len = 100, + }, + + { // #3 [SECP521r1] + .name = "SECP521r1", + .params = {0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23}, + .params_len = 7, + .privkeyA = {0x00,0x37,0xAD,0xE9,0x31,0x9A,0x89,0xF4,0xDA,0xBD,0xB3,0xEF,0x41,0x1A,0xAC,0xCC, + 0xA5,0x12,0x3C,0x61,0xAC,0xAB,0x57,0xB5,0x39,0x3D,0xCE,0x47,0x60,0x81,0x72,0xA0, + 0x95,0xAA,0x85,0xA3,0x0F,0xE1,0xC2,0x95,0x2C,0x67,0x71,0xD9,0x37,0xBA,0x97,0x77, + 0xF5,0x95,0x7B,0x26,0x39,0xBA,0xB0,0x72,0x46,0x2F,0x68,0xC2,0x7A,0x57,0x38,0x2D, + 0x4A,0x52,}, + .pubkeyA = {0x04,0x81,0x85,0x04,0x00,0x15,0x41,0x7E,0x84,0xDB,0xF2,0x8C,0x0A,0xD3,0xC2,0x78, + 0x71,0x33,0x49,0xDC,0x7D,0xF1,0x53,0xC8,0x97,0xA1,0x89,0x1B,0xD9,0x8B,0xAB,0x43, + 0x57,0xC9,0xEC,0xBE,0xE1,0xE3,0xBF,0x42,0xE0,0x0B,0x8E,0x38,0x0A,0xEA,0xE5,0x7C, + 0x2D,0x10,0x75,0x64,0x94,0x18,0x85,0x94,0x2A,0xF5,0xA7,0xF4,0x60,0x17,0x23,0xC4, + 0x19,0x5D,0x17,0x6C,0xED,0x3E,0x01,0x7C,0xAE,0x20,0xB6,0x64,0x1D,0x2E,0xEB,0x69, + 0x57,0x86,0xD8,0xC9,0x46,0x14,0x62,0x39,0xD0,0x99,0xE1,0x8E,0x1D,0x5A,0x51,0x4C, + 0x73,0x9D,0x7C,0xB4,0xA1,0x0A,0xD8,0xA7,0x88,0x01,0x5A,0xC4,0x05,0xD7,0x79,0x9D, + 0xC7,0x5E,0x7B,0x7D,0x5B,0x6C,0xF2,0x26,0x1A,0x6A,0x7F,0x15,0x07,0x43,0x8B,0xF0, + 0x1B,0xEB,0x6C,0xA3,0x92,0x6F,0x95,0x82,}, + .privkey_len = 66, + .privkeyB = {0x01,0x45,0xBA,0x99,0xA8,0x47,0xAF,0x43,0x79,0x3F,0xDD,0x0E,0x87,0x2E,0x7C,0xDF, + 0xA1,0x6B,0xE3,0x0F,0xDC,0x78,0x0F,0x97,0xBC,0xCC,0x3F,0x07,0x83,0x80,0x20,0x1E, + 0x9C,0x67,0x7D,0x60,0x0B,0x34,0x37,0x57,0xA3,0xBD,0xBF,0x2A,0x31,0x63,0xE4,0xC2, + 0xF8,0x69,0xCC,0xA7,0x45,0x8A,0xA4,0xA4,0xEF,0xFC,0x31,0x1F,0x5C,0xB1,0x51,0x68, + 0x5E,0xB9,}, + .pubkeyB = {0x04,0x81,0x85,0x04,0x00,0xD0,0xB3,0x97,0x5A,0xC4,0xB7,0x99,0xF5,0xBE,0xA1,0x6D, + 0x5E,0x13,0xE9,0xAF,0x97,0x1D,0x5E,0x9B,0x98,0x4C,0x9F,0x39,0x72,0x8B,0x5E,0x57, + 0x39,0x73,0x5A,0x21,0x9B,0x97,0xC3,0x56,0x43,0x6A,0xDC,0x6E,0x95,0xBB,0x03,0x52, + 0xF6,0xBE,0x64,0xA6,0xC2,0x91,0x2D,0x4E,0xF2,0xD0,0x43,0x3C,0xED,0x2B,0x61,0x71, + 0x64,0x00,0x12,0xD9,0x46,0x0F,0x01,0x5C,0x68,0x22,0x63,0x83,0x95,0x6E,0x3B,0xD0, + 0x66,0xE7,0x97,0xB6,0x23,0xC2,0x7C,0xE0,0xEA,0xC2,0xF5,0x51,0xA1,0x0C,0x2C,0x72, + 0x4D,0x98,0x52,0x07,0x7B,0x87,0x22,0x0B,0x65,0x36,0xC5,0xC4,0x08,0xA1,0xD2,0xAE, + 0xBB,0x8E,0x86,0xD6,0x78,0xAE,0x49,0xCB,0x57,0x09,0x1F,0x47,0x32,0x29,0x65,0x79, + 0xAB,0x44,0xFC,0xD1,0x7F,0x0F,0xC5,0x6A,}, + .pubkey_len = 136, + .kdf = CKD_SHA384_KDF, + .shared_data = {0x01,0x02,0x03}, + .shared_data_len = 3, + .derived_key = {0xA6,0x39,0x99,0x84,0xAD,0xC3,0xAA,0x63,0x6C,0xE1,0x43,0x78,0x32,0x9C,0xAF,0x8D, + 0x1A,0x74,0xE8,0x3E,0xCE,0xB8,0x58,0xCC,0xF7,0x5B,0x02,0x22,0x70,0x58,0x09,0xF5, + 0x04,0xFC,0xBE,0x47,0xE7,0xB0,0x45,0xCB,0x69,0x3D,0x3F,0x84,0xDE,0x04,0xCA,0x19, + 0xB6,0x23,0xAA,0x55,0xEA,0xE4,0x0F,0x1A,0x9C,0xD8,0xCF,0x63,0x07,0x08,0xB6,0x34, + 0x6F,0x5E,0x38,0x7A,0xE9,0xF7,0xFF,0x44,0x3F,0xF3,0x15,0xFD,0x1E,0xE9,0xA0,0xFA, + 0x95,0xB7,0xD7,0xC1,0xC1,0x14,0xC0,0xC9,0x22,0x01,0xF7,0xF6,0xDC,0xB9,0x0D,0xD6, + 0x8D,0xEA,0x41,0x2A,0xAC,0x19,0xB6,0xF3,0x09,0x85,0x61,0x61,0x4E,0xF1,0x5D,0x23, + 0x9F,0xD8,0x4E,0xC8,0xED,0x53,0x2F,0xCA,0x65,0x36,0x3E,0x1F,0xE6,0xB8,0x54,0x42, + 0x3E,0xA5,0x38,0xB4,}, + .derived_key_len = 132, + }, + + { // #3a [SECP521r1 with compressed even pubkeyA and pubkeyB: pubkey_len = 67] + .name = "SECP521r1", + .params = {0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23}, + .params_len = 7, + .privkeyA = {0x00,0x37,0xAD,0xE9,0x31,0x9A,0x89,0xF4,0xDA,0xBD,0xB3,0xEF,0x41,0x1A,0xAC,0xCC, + 0xA5,0x12,0x3C,0x61,0xAC,0xAB,0x57,0xB5,0x39,0x3D,0xCE,0x47,0x60,0x81,0x72,0xA0, + 0x95,0xAA,0x85,0xA3,0x0F,0xE1,0xC2,0x95,0x2C,0x67,0x71,0xD9,0x37,0xBA,0x97,0x77, + 0xF5,0x95,0x7B,0x26,0x39,0xBA,0xB0,0x72,0x46,0x2F,0x68,0xC2,0x7A,0x57,0x38,0x2D, + 0x4A,0x52,}, + .pubkeyA = {0x04,0x43,0x02,0x00,0x15,0x41,0x7E,0x84,0xDB,0xF2,0x8C,0x0A,0xD3,0xC2,0x78,0x71, + 0x33,0x49,0xDC,0x7D,0xF1,0x53,0xC8,0x97,0xA1,0x89,0x1B,0xD9,0x8B,0xAB,0x43,0x57, + 0xC9,0xEC,0xBE,0xE1,0xE3,0xBF,0x42,0xE0,0x0B,0x8E,0x38,0x0A,0xEA,0xE5,0x7C,0x2D, + 0x10,0x75,0x64,0x94,0x18,0x85,0x94,0x2A,0xF5,0xA7,0xF4,0x60,0x17,0x23,0xC4,0x19, + 0x5D,0x17,0x6C,0xED,0x3E,}, + .privkey_len = 66, + .privkeyB = {0x01,0x45,0xBA,0x99,0xA8,0x47,0xAF,0x43,0x79,0x3F,0xDD,0x0E,0x87,0x2E,0x7C,0xDF, + 0xA1,0x6B,0xE3,0x0F,0xDC,0x78,0x0F,0x97,0xBC,0xCC,0x3F,0x07,0x83,0x80,0x20,0x1E, + 0x9C,0x67,0x7D,0x60,0x0B,0x34,0x37,0x57,0xA3,0xBD,0xBF,0x2A,0x31,0x63,0xE4,0xC2, + 0xF8,0x69,0xCC,0xA7,0x45,0x8A,0xA4,0xA4,0xEF,0xFC,0x31,0x1F,0x5C,0xB1,0x51,0x68, + 0x5E,0xB9,}, + .pubkeyB = {0x04,0x43,0x02,0x00,0xD0,0xB3,0x97,0x5A,0xC4,0xB7,0x99,0xF5,0xBE,0xA1,0x6D,0x5E, + 0x13,0xE9,0xAF,0x97,0x1D,0x5E,0x9B,0x98,0x4C,0x9F,0x39,0x72,0x8B,0x5E,0x57,0x39, + 0x73,0x5A,0x21,0x9B,0x97,0xC3,0x56,0x43,0x6A,0xDC,0x6E,0x95,0xBB,0x03,0x52,0xF6, + 0xBE,0x64,0xA6,0xC2,0x91,0x2D,0x4E,0xF2,0xD0,0x43,0x3C,0xED,0x2B,0x61,0x71,0x64, + 0x00,0x12,0xD9,0x46,0x0F,}, + .pubkey_len = 69, + .kdf = CKD_SHA384_KDF, + .shared_data = {0x01,0x02,0x03}, + .shared_data_len = 3, + .derived_key = {0xA6,0x39,0x99,0x84,0xAD,0xC3,0xAA,0x63,0x6C,0xE1,0x43,0x78,0x32,0x9C,0xAF,0x8D, + 0x1A,0x74,0xE8,0x3E,0xCE,0xB8,0x58,0xCC,0xF7,0x5B,0x02,0x22,0x70,0x58,0x09,0xF5, + 0x04,0xFC,0xBE,0x47,0xE7,0xB0,0x45,0xCB,0x69,0x3D,0x3F,0x84,0xDE,0x04,0xCA,0x19, + 0xB6,0x23,0xAA,0x55,0xEA,0xE4,0x0F,0x1A,0x9C,0xD8,0xCF,0x63,0x07,0x08,0xB6,0x34, + 0x6F,0x5E,0x38,0x7A,0xE9,0xF7,0xFF,0x44,0x3F,0xF3,0x15,0xFD,0x1E,0xE9,0xA0,0xFA, + 0x95,0xB7,0xD7,0xC1,0xC1,0x14,0xC0,0xC9,0x22,0x01,0xF7,0xF6,0xDC,0xB9,0x0D,0xD6, + 0x8D,0xEA,0x41,0x2A,0xAC,0x19,0xB6,0xF3,0x09,0x85,0x61,0x61,0x4E,0xF1,0x5D,0x23, + 0x9F,0xD8,0x4E,0xC8,0xED,0x53,0x2F,0xCA,0x65,0x36,0x3E,0x1F,0xE6,0xB8,0x54,0x42, + 0x3E,0xA5,0x38,0xB4,}, + .derived_key_len = 132, + }, + + { // #3b [SECP521r1 without format byte in pubkeyA and pubkeyB, pubkey_len = 132] + .name = "SECP521r1", + .params = {0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23}, + .params_len = 7, + .privkeyA = {0x00,0x37,0xAD,0xE9,0x31,0x9A,0x89,0xF4,0xDA,0xBD,0xB3,0xEF,0x41,0x1A,0xAC,0xCC, + 0xA5,0x12,0x3C,0x61,0xAC,0xAB,0x57,0xB5,0x39,0x3D,0xCE,0x47,0x60,0x81,0x72,0xA0, + 0x95,0xAA,0x85,0xA3,0x0F,0xE1,0xC2,0x95,0x2C,0x67,0x71,0xD9,0x37,0xBA,0x97,0x77, + 0xF5,0x95,0x7B,0x26,0x39,0xBA,0xB0,0x72,0x46,0x2F,0x68,0xC2,0x7A,0x57,0x38,0x2D, + 0x4A,0x52,}, + .pubkeyA = {0x04,0x81,0x84,0x00,0x15,0x41,0x7E,0x84,0xDB,0xF2,0x8C,0x0A,0xD3,0xC2,0x78,0x71, + 0x33,0x49,0xDC,0x7D,0xF1,0x53,0xC8,0x97,0xA1,0x89,0x1B,0xD9,0x8B,0xAB,0x43,0x57, + 0xC9,0xEC,0xBE,0xE1,0xE3,0xBF,0x42,0xE0,0x0B,0x8E,0x38,0x0A,0xEA,0xE5,0x7C,0x2D, + 0x10,0x75,0x64,0x94,0x18,0x85,0x94,0x2A,0xF5,0xA7,0xF4,0x60,0x17,0x23,0xC4,0x19, + 0x5D,0x17,0x6C,0xED,0x3E,0x01,0x7C,0xAE,0x20,0xB6,0x64,0x1D,0x2E,0xEB,0x69,0x57, + 0x86,0xD8,0xC9,0x46,0x14,0x62,0x39,0xD0,0x99,0xE1,0x8E,0x1D,0x5A,0x51,0x4C,0x73, + 0x9D,0x7C,0xB4,0xA1,0x0A,0xD8,0xA7,0x88,0x01,0x5A,0xC4,0x05,0xD7,0x79,0x9D,0xC7, + 0x5E,0x7B,0x7D,0x5B,0x6C,0xF2,0x26,0x1A,0x6A,0x7F,0x15,0x07,0x43,0x8B,0xF0,0x1B, + 0xEB,0x6C,0xA3,0x92,0x6F,0x95,0x82,}, + .privkey_len = 66, + .privkeyB = {0x01,0x45,0xBA,0x99,0xA8,0x47,0xAF,0x43,0x79,0x3F,0xDD,0x0E,0x87,0x2E,0x7C,0xDF, + 0xA1,0x6B,0xE3,0x0F,0xDC,0x78,0x0F,0x97,0xBC,0xCC,0x3F,0x07,0x83,0x80,0x20,0x1E, + 0x9C,0x67,0x7D,0x60,0x0B,0x34,0x37,0x57,0xA3,0xBD,0xBF,0x2A,0x31,0x63,0xE4,0xC2, + 0xF8,0x69,0xCC,0xA7,0x45,0x8A,0xA4,0xA4,0xEF,0xFC,0x31,0x1F,0x5C,0xB1,0x51,0x68, + 0x5E,0xB9,}, + .pubkeyB = {0x04,0x81,0x84,0x00,0xD0,0xB3,0x97,0x5A,0xC4,0xB7,0x99,0xF5,0xBE,0xA1,0x6D,0x5E, + 0x13,0xE9,0xAF,0x97,0x1D,0x5E,0x9B,0x98,0x4C,0x9F,0x39,0x72,0x8B,0x5E,0x57,0x39, + 0x73,0x5A,0x21,0x9B,0x97,0xC3,0x56,0x43,0x6A,0xDC,0x6E,0x95,0xBB,0x03,0x52,0xF6, + 0xBE,0x64,0xA6,0xC2,0x91,0x2D,0x4E,0xF2,0xD0,0x43,0x3C,0xED,0x2B,0x61,0x71,0x64, + 0x00,0x12,0xD9,0x46,0x0F,0x01,0x5C,0x68,0x22,0x63,0x83,0x95,0x6E,0x3B,0xD0,0x66, + 0xE7,0x97,0xB6,0x23,0xC2,0x7C,0xE0,0xEA,0xC2,0xF5,0x51,0xA1,0x0C,0x2C,0x72,0x4D, + 0x98,0x52,0x07,0x7B,0x87,0x22,0x0B,0x65,0x36,0xC5,0xC4,0x08,0xA1,0xD2,0xAE,0xBB, + 0x8E,0x86,0xD6,0x78,0xAE,0x49,0xCB,0x57,0x09,0x1F,0x47,0x32,0x29,0x65,0x79,0xAB, + 0x44,0xFC,0xD1,0x7F,0x0F,0xC5,0x6A,}, + .pubkey_len = 135, + .kdf = CKD_SHA384_KDF, + .shared_data = {0x01,0x02,0x03}, + .shared_data_len = 3, + .derived_key = {0xA6,0x39,0x99,0x84,0xAD,0xC3,0xAA,0x63,0x6C,0xE1,0x43,0x78,0x32,0x9C,0xAF,0x8D, + 0x1A,0x74,0xE8,0x3E,0xCE,0xB8,0x58,0xCC,0xF7,0x5B,0x02,0x22,0x70,0x58,0x09,0xF5, + 0x04,0xFC,0xBE,0x47,0xE7,0xB0,0x45,0xCB,0x69,0x3D,0x3F,0x84,0xDE,0x04,0xCA,0x19, + 0xB6,0x23,0xAA,0x55,0xEA,0xE4,0x0F,0x1A,0x9C,0xD8,0xCF,0x63,0x07,0x08,0xB6,0x34, + 0x6F,0x5E,0x38,0x7A,0xE9,0xF7,0xFF,0x44,0x3F,0xF3,0x15,0xFD,0x1E,0xE9,0xA0,0xFA, + 0x95,0xB7,0xD7,0xC1,0xC1,0x14,0xC0,0xC9,0x22,0x01,0xF7,0xF6,0xDC,0xB9,0x0D,0xD6, + 0x8D,0xEA,0x41,0x2A,0xAC,0x19,0xB6,0xF3,0x09,0x85,0x61,0x61,0x4E,0xF1,0x5D,0x23, + 0x9F,0xD8,0x4E,0xC8,0xED,0x53,0x2F,0xCA,0x65,0x36,0x3E,0x1F,0xE6,0xB8,0x54,0x42, + 0x3E,0xA5,0x38,0xB4,}, + .derived_key_len = 132, + }, + + { // #3c [SECP521r1 without format byte and leading nulls in pubkeyA and pubkeyB, pubkey_len = 131] + .name = "SECP521r1", + .params = {0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23}, + .params_len = 7, + .privkeyA = {0x00,0x37,0xAD,0xE9,0x31,0x9A,0x89,0xF4,0xDA,0xBD,0xB3,0xEF,0x41,0x1A,0xAC,0xCC, + 0xA5,0x12,0x3C,0x61,0xAC,0xAB,0x57,0xB5,0x39,0x3D,0xCE,0x47,0x60,0x81,0x72,0xA0, + 0x95,0xAA,0x85,0xA3,0x0F,0xE1,0xC2,0x95,0x2C,0x67,0x71,0xD9,0x37,0xBA,0x97,0x77, + 0xF5,0x95,0x7B,0x26,0x39,0xBA,0xB0,0x72,0x46,0x2F,0x68,0xC2,0x7A,0x57,0x38,0x2D, + 0x4A,0x52,}, + .pubkeyA = {0x04,0x81,0x83,0x15,0x41,0x7E,0x84,0xDB,0xF2,0x8C,0x0A,0xD3,0xC2,0x78,0x71,0x33, + 0x49,0xDC,0x7D,0xF1,0x53,0xC8,0x97,0xA1,0x89,0x1B,0xD9,0x8B,0xAB,0x43,0x57,0xC9, + 0xEC,0xBE,0xE1,0xE3,0xBF,0x42,0xE0,0x0B,0x8E,0x38,0x0A,0xEA,0xE5,0x7C,0x2D,0x10, + 0x75,0x64,0x94,0x18,0x85,0x94,0x2A,0xF5,0xA7,0xF4,0x60,0x17,0x23,0xC4,0x19,0x5D, + 0x17,0x6C,0xED,0x3E,0x01,0x7C,0xAE,0x20,0xB6,0x64,0x1D,0x2E,0xEB,0x69,0x57,0x86, + 0xD8,0xC9,0x46,0x14,0x62,0x39,0xD0,0x99,0xE1,0x8E,0x1D,0x5A,0x51,0x4C,0x73,0x9D, + 0x7C,0xB4,0xA1,0x0A,0xD8,0xA7,0x88,0x01,0x5A,0xC4,0x05,0xD7,0x79,0x9D,0xC7,0x5E, + 0x7B,0x7D,0x5B,0x6C,0xF2,0x26,0x1A,0x6A,0x7F,0x15,0x07,0x43,0x8B,0xF0,0x1B,0xEB, + 0x6C,0xA3,0x92,0x6F,0x95,0x82,}, + .privkey_len = 66, + .privkeyB = {0x01,0x45,0xBA,0x99,0xA8,0x47,0xAF,0x43,0x79,0x3F,0xDD,0x0E,0x87,0x2E,0x7C,0xDF, + 0xA1,0x6B,0xE3,0x0F,0xDC,0x78,0x0F,0x97,0xBC,0xCC,0x3F,0x07,0x83,0x80,0x20,0x1E, + 0x9C,0x67,0x7D,0x60,0x0B,0x34,0x37,0x57,0xA3,0xBD,0xBF,0x2A,0x31,0x63,0xE4,0xC2, + 0xF8,0x69,0xCC,0xA7,0x45,0x8A,0xA4,0xA4,0xEF,0xFC,0x31,0x1F,0x5C,0xB1,0x51,0x68, + 0x5E,0xB9,}, + .pubkeyB = {0x04,0x81,0x83,0xD0,0xB3,0x97,0x5A,0xC4,0xB7,0x99,0xF5,0xBE,0xA1,0x6D,0x5E,0x13, + 0xE9,0xAF,0x97,0x1D,0x5E,0x9B,0x98,0x4C,0x9F,0x39,0x72,0x8B,0x5E,0x57,0x39,0x73, + 0x5A,0x21,0x9B,0x97,0xC3,0x56,0x43,0x6A,0xDC,0x6E,0x95,0xBB,0x03,0x52,0xF6,0xBE, + 0x64,0xA6,0xC2,0x91,0x2D,0x4E,0xF2,0xD0,0x43,0x3C,0xED,0x2B,0x61,0x71,0x64,0x00, + 0x12,0xD9,0x46,0x0F,0x01,0x5C,0x68,0x22,0x63,0x83,0x95,0x6E,0x3B,0xD0,0x66,0xE7, + 0x97,0xB6,0x23,0xC2,0x7C,0xE0,0xEA,0xC2,0xF5,0x51,0xA1,0x0C,0x2C,0x72,0x4D,0x98, + 0x52,0x07,0x7B,0x87,0x22,0x0B,0x65,0x36,0xC5,0xC4,0x08,0xA1,0xD2,0xAE,0xBB,0x8E, + 0x86,0xD6,0x78,0xAE,0x49,0xCB,0x57,0x09,0x1F,0x47,0x32,0x29,0x65,0x79,0xAB,0x44, + 0xFC,0xD1,0x7F,0x0F,0xC5,0x6A,}, + .pubkey_len = 134, + .kdf = CKD_SHA384_KDF, + .shared_data = {0x01,0x02,0x03}, + .shared_data_len = 3, + .derived_key = {0xA6,0x39,0x99,0x84,0xAD,0xC3,0xAA,0x63,0x6C,0xE1,0x43,0x78,0x32,0x9C,0xAF,0x8D, + 0x1A,0x74,0xE8,0x3E,0xCE,0xB8,0x58,0xCC,0xF7,0x5B,0x02,0x22,0x70,0x58,0x09,0xF5, + 0x04,0xFC,0xBE,0x47,0xE7,0xB0,0x45,0xCB,0x69,0x3D,0x3F,0x84,0xDE,0x04,0xCA,0x19, + 0xB6,0x23,0xAA,0x55,0xEA,0xE4,0x0F,0x1A,0x9C,0xD8,0xCF,0x63,0x07,0x08,0xB6,0x34, + 0x6F,0x5E,0x38,0x7A,0xE9,0xF7,0xFF,0x44,0x3F,0xF3,0x15,0xFD,0x1E,0xE9,0xA0,0xFA, + 0x95,0xB7,0xD7,0xC1,0xC1,0x14,0xC0,0xC9,0x22,0x01,0xF7,0xF6,0xDC,0xB9,0x0D,0xD6, + 0x8D,0xEA,0x41,0x2A,0xAC,0x19,0xB6,0xF3,0x09,0x85,0x61,0x61,0x4E,0xF1,0x5D,0x23, + 0x9F,0xD8,0x4E,0xC8,0xED,0x53,0x2F,0xCA,0x65,0x36,0x3E,0x1F,0xE6,0xB8,0x54,0x42, + 0x3E,0xA5,0x38,0xB4,}, + .derived_key_len = 132, + }, + + { // #4 [BrainpoolP256r1] + .name = "BrainpoolP256r1", + .params = {0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07}, + .params_len = 11, + .privkeyA = {0x81,0xDB,0x1E,0xE1,0x00,0x15,0x0F,0xF2,0xEA,0x33,0x8D,0x70,0x82,0x71,0xBE,0x38, + 0x30,0x0C,0xB5,0x42,0x41,0xD7,0x99,0x50,0xF7,0x7B,0x06,0x30,0x39,0x80,0x4F,0x1D,}, + .pubkeyA = {0x04,0x41,0x04,0x44,0x10,0x6E,0x91,0x3F,0x92,0xBC,0x02,0xA1,0x70,0x5D,0x99,0x53, + 0xA8,0x41,0x4D,0xB9,0x5E,0x1A,0xAA,0x49,0xE8,0x1D,0x9E,0x85,0xF9,0x29,0xA8,0xE3, + 0x10,0x0B,0xE5,0x8A,0xB4,0x84,0x6F,0x11,0xCA,0xCC,0xB7,0x3C,0xE4,0x9C,0xBD,0xD1, + 0x20,0xF5,0xA9,0x00,0xA6,0x9F,0xD3,0x2C,0x27,0x22,0x23,0xF7,0x89,0xEF,0x10,0xEB, + 0x08,0x9B,0xDC,}, + .privkey_len = 32, + .privkeyB = {0x55,0xE4,0x0B,0xC4,0x1E,0x37,0xE3,0xE2,0xAD,0x25,0xC3,0xC6,0x65,0x45,0x11,0xFF, + 0xA8,0x47,0x4A,0x91,0xA0,0x03,0x20,0x87,0x59,0x38,0x52,0xD3,0xE7,0xD7,0x6B,0xD3,}, + .pubkeyB = {0x04,0x41,0x04,0x8D,0x2D,0x68,0x8C,0x6C,0xF9,0x3E,0x11,0x60,0xAD,0x04,0xCC,0x44, + 0x29,0x11,0x7D,0xC2,0xC4,0x18,0x25,0xE1,0xE9,0xFC,0xA0,0xAD,0xDD,0x34,0xE6,0xF1, + 0xB3,0x9F,0x7B,0x99,0x0C,0x57,0x52,0x08,0x12,0xBE,0x51,0x26,0x41,0xE4,0x70,0x34, + 0x83,0x21,0x06,0xBC,0x7D,0x3E,0x8D,0xD0,0xE4,0xC7,0xF1,0x13,0x6D,0x70,0x06,0x54, + 0x7C,0xEC,0x6A,}, + .pubkey_len = 67, + .kdf = CKD_SHA512_KDF, + .shared_data = {0x16,0x30,0x2F,0xF0,0xDB,0xBB,0x5A,0x8D,0x73,0x3D,0xAB,0x71,0x41,0xC1,0xB4,0x5A, + 0xCB,0xC8,0x71,0x59,0x39,0x67,0x7F,0x6A,0x56,0x85,0x0A,0x38,0xBD,0x87,0xBD,0x59, + 0xB0,0x9E,0x80,0x27,0x96,0x09,0xFF,0x33,0x3E,0xB9,0xD4,0xC0,0x61,0x23,0x1F,0xB2, + 0x6F,0x92,0xEE,0xB0,0x49,0x82,0xA5,0xF1,0xD1,0x76,0x4C,0xAD,0x57,0x66,0x54,0x22, + 0xBB,0xEF,0xCA}, + .shared_data_len = 67, + .derived_key = {0x01,0x11,0xC7,0xD3,0xAC,0x19,0x45,0x20,0x8C,0x55,0xCB,0xCB,0x95,0x2E,0xFF,0x02, + 0x10,0x08,0xF1,0x1D,0xFE,0xF3,0xB1,0x09,0x5D,0x1D,0xE5,0x96,0xEB,0xE7,0x9D,0x1E, + 0xC9,0x35,0xD4,0x2D,0x41,0x12,0xC3,0xEA,0xE6,0x8F,0xDA,0xB6,0xAE,0xB5,0xB7,0x44, + 0x98,0x14,0xDE,0x5B,0x8B,0xDB,0x3E,0x10,0x28,0x69,0x9F,0xEC,0x28,0x13,0x0F,0x27, + 0x31,0xCE,0x09,0x3C,0x74,0x7A,0x08,0xAB,0x93,0x80,0xE9,0x0A,0x0C,0xA0,0xFA,0xD5, + 0xB2,0x28,0x59,0x50,0x4F,0x6E,0x22,0xD0,0x25,0x8F,0xEF,0x1F,0x9F,0xC0,0x9B,0x06, + 0x15,0x72,0x82,0x3F,0x5E,0xD1,0xB5,0xA9,0x5D,0x0E,0x5B,0x42,0xFC,0x05,0x8D,0x94, + 0xD0,0x0B,0x60,0xAF,0xAD,0x34,0xCF,0xFF,0xFF,0x4D,0x9B,0x44,0x79,0xF6,0x54,0x4A, + 0x49,0x55,0x3E,0xD4,0x6A,0x67,0xB3,0x58,0xD0,0x63,0x4D,0xB1,0xE3,0x75,0xF2,0xEE, + 0xC7,0x4A,0xE0,0x57,0x35,0x74,0xF8,0x24,0x1F,0xD9,0x71,0x9A,0x26,0x73,0xEE,0x33, + 0x3A,0xAD,0x56,0x63,0x5E,0x6C,0xDE,0x38,0x99,0x18,0x13,0x94,0x75,0x97,0x4A,0x7E, + 0xC2,0x63,0x05,0x9D,0x4B,0xAA,0xFC,0x2C,0xF5,0xD2,0xCB,0x9E,0x91,0x26,0x29,0x85, + 0x1E,0x7D,0x38,0xDD,0x26,0xAA,0x94,0x10,0x35,0x2A,0xCB,0x98,0x13,0xE9,0x62,0xAB, + 0xB5,0xE4,0xF6,0xFB,0x37,0xA1,0xCF,0xC2,0x16,0xB2,0x60,0xA7,0xC7,0xB7,0xBE,0x01, + 0xA8,0x97,0x46,0xD1,0x59,0xB8,0xD1,0xC8,0x1B,0x4C,0x1C,0x46,0xE5,0x2C,0xAF,0xF3, + 0xB8,0x25,0xA9,0x43,0xB4,0x3C,0x31,0x2C,0xF8,0xAC,0x7F,0x96,0x40,0x23,0x36,0x66, + 0xDB,0x15,0x48,0x53,0xCF,0xE3,0x15,0xDA,0x66,0x66,0x03,0x5C,0x01,0x8B,0x41,0xCB, + 0x6B,0xF7,0xD5,0x4B,0x51,0x15,0xED,0x37,0x30,0xAC,0xE1,0xF3,0x14,0x5F,0x8B,0xA9, + 0x63,0x4E,0x49,0xC0,0x49,0x1F,0x42,0x7E,0x6C,0xB1,0x1E,0x55,0xC3,0x6F,0xE2,0xBC, + 0x99,0x3F,0xA2,0xA6,0xD3,0x0A,0x27,0x0A,0x2B,0x73,0xED,0x3F,0xF7,0x5A,0xD8,0xF2, + 0xE2,0x75,0xE5,0x01,0x9F,0x26,0x78,0x90,0x9A,0xB9,0x18,0xF3,0x6F,0x11,0x9E,0xE4, + 0x86,0x5D,0xBE,0xA0,0xC9,0x06,0x90,0xBA,0x28,}, + .derived_key_len = 345, + }, + + { // #5 [BrainpoolP384r1] + .name = "BrainpoolP384r1", + .params = {0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B}, + .params_len = 11, + .privkeyA = {0x1E,0x20,0xF5,0xE0,0x48,0xA5,0x88,0x6F,0x1F,0x15,0x7C,0x74,0xE9,0x1B,0xDE,0x2B, + 0x98,0xC8,0xB5,0x2D,0x58,0xE5,0x00,0x3D,0x57,0x05,0x3F,0xC4,0xB0,0xBD,0x65,0xD6, + 0xF1,0x5E,0xB5,0xD1,0xEE,0x16,0x10,0xDF,0x87,0x07,0x95,0x14,0x36,0x27,0xD0,0x42,}, + .pubkeyA = {0x04,0x61,0x04,0x68,0xB6,0x65,0xDD,0x91,0xC1,0x95,0x80,0x06,0x50,0xCD,0xD3,0x63, + 0xC6,0x25,0xF4,0xE7,0x42,0xE8,0x13,0x46,0x67,0xB7,0x67,0xB1,0xB4,0x76,0x79,0x35, + 0x88,0xF8,0x85,0xAB,0x69,0x8C,0x85,0x2D,0x4A,0x6E,0x77,0xA2,0x52,0xD6,0x38,0x0F, + 0xCA,0xF0,0x68,0x55,0xBC,0x91,0xA3,0x9C,0x9E,0xC0,0x1D,0xEE,0x36,0x01,0x7B,0x7D, + 0x67,0x3A,0x93,0x12,0x36,0xD2,0xF1,0xF5,0xC8,0x39,0x42,0xD0,0x49,0xE3,0xFA,0x20, + 0x60,0x74,0x93,0xE0,0xD0,0x38,0xFF,0x2F,0xD3,0x0C,0x2A,0xB6,0x7D,0x15,0xC8,0x5F, + 0x7F,0xAA,0x59,}, + .privkey_len = 48, + .privkeyB = {0x03,0x26,0x40,0xBC,0x60,0x03,0xC5,0x92,0x60,0xF7,0x25,0x0C,0x3D,0xB5,0x8C,0xE6, + 0x47,0xF9,0x8E,0x12,0x60,0xAC,0xCE,0x4A,0xCD,0xA3,0xDD,0x86,0x9F,0x74,0xE0,0x1F, + 0x8B,0xA5,0xE0,0x32,0x43,0x09,0xDB,0x6A,0x98,0x31,0x49,0x7A,0xBA,0xC9,0x66,0x70,}, + .pubkeyB = {0x04,0x61,0x04,0x4D,0x44,0x32,0x6F,0x26,0x9A,0x59,0x7A,0x5B,0x58,0xBB,0xA5,0x65, + 0xDA,0x55,0x56,0xED,0x7F,0xD9,0xA8,0xA9,0xEB,0x76,0xC2,0x5F,0x46,0xDB,0x69,0xD1, + 0x9D,0xC8,0xCE,0x6A,0xD1,0x8E,0x40,0x4B,0x15,0x73,0x8B,0x20,0x86,0xDF,0x37,0xE7, + 0x1D,0x1E,0xB4,0x62,0xD6,0x92,0x13,0x6D,0xE5,0x6C,0xBE,0x93,0xBF,0x5F,0xA3,0x18, + 0x8E,0xF5,0x8B,0xC8,0xA3,0xA0,0xEC,0x6C,0x1E,0x15,0x1A,0x21,0x03,0x8A,0x42,0xE9, + 0x18,0x53,0x29,0xB5,0xB2,0x75,0x90,0x3D,0x19,0x2F,0x8D,0x4E,0x1F,0x32,0xFE,0x9C, + 0xC7,0x8C,0x48,}, + .pubkey_len = 99, + .kdf = CKD_SHA384_KDF, + .shared_data = {0x70,0xE6,0xD8,0x9A,0x6D,0x75,0xD2,0x91,0xB6,0x99,0xAB}, + .shared_data_len = 11, + .derived_key = {0xAC,0xEA,0x1C,0xE5,0xF2,0x3C,0x62,0xC9,0x68,0xF5,0x77,0x8B,0x94,0x67,0x2C,0xD8, + 0x3D,0xE1,0x65,0xBC,0x9C,0x4D,0xB9,0xA4,0x3B,0x92,0x18,0x1A,0x0B,0x0E,0x07,0x55, + 0x8A,0xB4,0x8C,0xF1,0xF8,0x65,0x7D,0xAF,0xF3,0x3F,0xAE,0x60,0x8C,0x4A,0xA9,0x12, + 0xEE,0x33,0xDF,0xE2,0x15,0x20,0xDF,0x27,0xE3,0x47,0xA6,0x04,0xC3,0x06,0xCA,0x41, + 0x6A,0x4B,0x52,0x50,0x32,0x72,0xAD,0x77,0x22,0xA9,0xB5,0xA8,0x6C,0x1F,0xA8,0x1E, + 0xB9,0xC9,0x83,0xC4,0x77,0x7F,0x89,0xF6,0x77,}, + .derived_key_len = 89, + }, + + { // #6 [BrainpoolP512r1] + .name = "BrainpoolP512r1", + .params = {0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D}, + .params_len = 11, + .privkeyA = {0x16,0x30,0x2F,0xF0,0xDB,0xBB,0x5A,0x8D,0x73,0x3D,0xAB,0x71,0x41,0xC1,0xB4,0x5A, + 0xCB,0xC8,0x71,0x59,0x39,0x67,0x7F,0x6A,0x56,0x85,0x0A,0x38,0xBD,0x87,0xBD,0x59, + 0xB0,0x9E,0x80,0x27,0x96,0x09,0xFF,0x33,0x3E,0xB9,0xD4,0xC0,0x61,0x23,0x1F,0xB2, + 0x6F,0x92,0xEE,0xB0,0x49,0x82,0xA5,0xF1,0xD1,0x76,0x4C,0xAD,0x57,0x66,0x54,0x22,}, + .pubkeyA = {0x04,0x81,0x81,0x04,0x0A,0x42,0x05,0x17,0xE4,0x06,0xAA,0xC0,0xAC,0xDC,0xE9,0x0F, + 0xCD,0x71,0x48,0x77,0x18,0xD3,0xB9,0x53,0xEF,0xD7,0xFB,0xEC,0x5F,0x7F,0x27,0xE2, + 0x8C,0x61,0x49,0x99,0x93,0x97,0xE9,0x1E,0x02,0x9E,0x06,0x45,0x7D,0xB2,0xD3,0xE6, + 0x40,0x66,0x8B,0x39,0x2C,0x2A,0x7E,0x73,0x7A,0x7F,0x0B,0xF0,0x44,0x36,0xD1,0x16, + 0x40,0xFD,0x09,0xFD,0x72,0xE6,0x88,0x2E,0x8D,0xB2,0x8A,0xAD,0x36,0x23,0x7C,0xD2, + 0x5D,0x58,0x0D,0xB2,0x37,0x83,0x96,0x1C,0x8D,0xC5,0x2D,0xFA,0x2E,0xC1,0x38,0xAD, + 0x47,0x2A,0x0F,0xCE,0xF3,0x88,0x7C,0xF6,0x2B,0x62,0x3B,0x2A,0x87,0xDE,0x5C,0x58, + 0x83,0x01,0xEA,0x3E,0x5F,0xC2,0x69,0xB3,0x73,0xB6,0x07,0x24,0xF5,0xE8,0x2A,0x6A, + 0xD1,0x47,0xFD,0xE7,}, + .privkey_len = 64, + .privkeyB = {0x23,0x0E,0x18,0xE1,0xBC,0xC8,0x8A,0x36,0x2F,0xA5,0x4E,0x4E,0xA3,0x90,0x20,0x09, + 0x29,0x2F,0x7F,0x80,0x33,0x62,0x4F,0xD4,0x71,0xB5,0xD8,0xAC,0xE4,0x9D,0x12,0xCF, + 0xAB,0xBC,0x19,0x96,0x3D,0xAB,0x8E,0x2F,0x1E,0xBA,0x00,0xBF,0xFB,0x29,0xE4,0xD7, + 0x2D,0x13,0xF2,0x22,0x45,0x62,0xF4,0x05,0xCB,0x80,0x50,0x36,0x66,0xB2,0x54,0x29,}, + .pubkeyB = {0x04,0x81,0x81,0x04,0x9D,0x45,0xF6,0x6D,0xE5,0xD6,0x7E,0x2E,0x6D,0xB6,0xE9,0x3A, + 0x59,0xCE,0x0B,0xB4,0x81,0x06,0x09,0x7F,0xF7,0x8A,0x08,0x1D,0xE7,0x81,0xCD,0xB3, + 0x1F,0xCE,0x8C,0xCB,0xAA,0xEA,0x8D,0xD4,0x32,0x0C,0x41,0x19,0xF1,0xE9,0xCD,0x43, + 0x7A,0x2E,0xAB,0x37,0x31,0xFA,0x96,0x68,0xAB,0x26,0x8D,0x87,0x1D,0xED,0xA5,0x5A, + 0x54,0x73,0x19,0x9F,0x2F,0xDC,0x31,0x30,0x95,0xBC,0xDD,0x5F,0xB3,0xA9,0x16,0x36, + 0xF0,0x7A,0x95,0x9C,0x8E,0x86,0xB5,0x63,0x6A,0x1E,0x93,0x0E,0x83,0x96,0x04,0x9C, + 0xB4,0x81,0x96,0x1D,0x36,0x5C,0xC1,0x14,0x53,0xA0,0x6C,0x71,0x98,0x35,0x47,0x5B, + 0x12,0xCB,0x52,0xFC,0x3C,0x38,0x3B,0xCE,0x35,0xE2,0x7E,0xF1,0x94,0x51,0x2B,0x71, + 0x87,0x62,0x85,0xFA,}, + .pubkey_len = 132, + .kdf = CKD_SHA1_KDF, + .shared_data = {0x70,0xE6,0xD8,0x9A,0x6D,0x75,0xD2,0x91,0xB6,0x99,0xAB,0xAC,0xEA,0x1C,0xE5,0xF2, + 0x3C,0x62,0xDD}, + .shared_data_len = 19, + .derived_key = {0xE4,0x3B,0xDD,0xDC,0x03,0x13,0xBA,0xB8,0x8C,0x25,0x22,0x73,0xA5,0x14,0x29,0xC9, + 0xB2,0x9F,0x41,0x05,0x78,0x1B,0x74,0x45,0xC8,0xE6,0x1F,0xC7,0x09,0x0A,0xAA,0x44, + 0xEA,0x99,0x1D,0x32,0xC2,0x7A,0x70,0x75,0xEB,0x3D,0xFC,0xF0,0xF4,0x03,0xA8,0x2C, + 0x93,0x4B,0x0B,0x73,0x60,0x51,0x96,0xA2,0xA2,0x14,0x71,0x74,0x9F,0xA2,0xAD,0x86, + 0x49,0x85,0xB0,0x05,0xBA,0x23,0x8F,0x59,0x07,0xB1,0xA5,0x46,0xBF,0x59,0xB6,0xE1, + 0x1E,}, + .derived_key_len = 81, + }, +}; + +#define ECDH_TV_NUM sizeof(ecdh_tv)/sizeof(struct ECDH_TEST_VECTOR) diff --git a/testcases/crypto/ec_func.c b/testcases/crypto/ec_func.c new file mode 100644 index 0000000..1160f38 --- /dev/null +++ b/testcases/crypto/ec_func.c @@ -0,0 +1,1739 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2011-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 + */ + +#include + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "common.c" +#include "ec.h" +#include "defs.h" +#include "ec_curves.h" + +/* + * Below is a list for the OIDs and DER encodings of the brainpool. + * Beginning of each DER encoding should be 06 for OID and 09 for the length. + * For example brainpoolP160r1 should be 06092B2403030208010101 + * brainpoolP160r1 + * 1.3.36.3.3.2.8.1.1.1 + * 2B2403030208010101 + * brainpoolP160t1 + * 1.3.36.3.3.2.8.1.1.2 + * 2B2403030208010102 + * brainpoolP192r1 + * 1.3.36.3.3.2.8.1.1.3 + * 2B2403030208010103 + * brainpoolP192t1 + * 1.3.36.3.3.2.8.1.1.4 + * 2B2403030208010104 + * brainpoolP224r1 + * 1.3.36.3.3.2.8.1.1.5 + * 2B2403030208010105 + * brainpoolP224t1 + * 1.3.36.3.3.2.8.1.1.6 + * 2B2403030208010106 + * brainpoolP256r1 + * 1.3.36.3.3.2.8.1.1.7 + * 2B2403030208010107 + * brainpoolP256t1 + * 1.3.36.3.3.2.8.1.1.8 + * 2B2403030208010108 + * brainpoolP320r1 + * 1.3.36.3.3.2.8.1.1.9 + * 2B2403030208010109 + * brainpoolP320t1 + * 1.3.36.3.3.2.8.1.1.10 + * 2B240303020801010A + * brainpoolP384r1 + * 1.3.36.3.3.2.8.1.1.11 + * 2B240303020801010B + * brainpoolP384t1 + * 1.3.36.3.3.2.8.1.1.12 + * 2B240303020801010C + * brainpoolP512r1 + * 1.3.36.3.3.2.8.1.1.13 + * 2B240303020801010D + * brainpoolP512t1 + * 1.3.36.3.3.2.8.1.1.14 + * 2B240303020801010E + * prime192 + * 1.2.840.10045.3.1.1 + * 2A8648CE3D030101 + * secp224 + * 1.3.132.0.33 + * 2B81040021 + * prime256 + * 1.2.840.10045.3.1.7 + * 2A8648CE3D030107 + * secp384 + * 1.3.132.0.34 + * 2B81040022 + * secp521 + * 1.3.132.0.35 + * 2B81040023 + * secp256k1 + * 1.3.132.0.10 + * 2B8104000A + * curve25519 + * 1.3.101.110 + * 06032B656E + * curve448[] + * 1.3.101.111 + * 06032B656F + * ed25519[] + * 1.3.101.112 + * 06032B6570 + * ed448 + * 1.3.101.113 + * 06032B6571 + */ + +CK_ULONG total_assertions = 65; + +typedef struct ec_struct { + void const *curve; + CK_ULONG size; + CK_BBOOL twisted; + enum curve_type type; + CK_ULONG bit_len; + char *name; +} _ec_struct; + +/* Supported Elliptic Curves */ +#define NUMEC 24 +const CK_BYTE brainpoolP160r1[] = OCK_BRAINPOOL_P160R1; +const CK_BYTE brainpoolP160t1[] = OCK_BRAINPOOL_P160T1; +const CK_BYTE brainpoolP192r1[] = OCK_BRAINPOOL_P192R1; +const CK_BYTE brainpoolP192t1[] = OCK_BRAINPOOL_P192T1; +const CK_BYTE brainpoolP224r1[] = OCK_BRAINPOOL_P224R1; +const CK_BYTE brainpoolP224t1[] = OCK_BRAINPOOL_P224T1; +const CK_BYTE brainpoolP256r1[] = OCK_BRAINPOOL_P256R1; +const CK_BYTE brainpoolP256t1[] = OCK_BRAINPOOL_P256T1; +const CK_BYTE brainpoolP320r1[] = OCK_BRAINPOOL_P320R1; +const CK_BYTE brainpoolP320t1[] = OCK_BRAINPOOL_P320T1; +const CK_BYTE brainpoolP384r1[] = OCK_BRAINPOOL_P384R1; +const CK_BYTE brainpoolP384t1[] = OCK_BRAINPOOL_P384T1; +const CK_BYTE brainpoolP512r1[] = OCK_BRAINPOOL_P512R1; +const CK_BYTE brainpoolP512t1[] = OCK_BRAINPOOL_P512T1; +const CK_BYTE prime192v1[] = OCK_PRIME192V1; +const CK_BYTE secp224r1[] = OCK_SECP224R1; +const CK_BYTE prime256v1[] = OCK_PRIME256V1; +const CK_BYTE secp384r1[] = OCK_SECP384R1; +const CK_BYTE secp521r1[] = OCK_SECP521R1; +const CK_BYTE secp256k1[] = OCK_SECP256K1; +const CK_BYTE curve25519[] = OCK_CURVE25519; +const CK_BYTE curve448[] = OCK_CURVE448; +const CK_BYTE ed25519[] = OCK_ED25519; +const CK_BYTE ed448[] = OCK_ED448; + +const _ec_struct der_ec_supported[NUMEC] = { + {&brainpoolP160r1, sizeof(brainpoolP160r1), CK_FALSE, CURVE_BRAINPOOL, + CURVE160_LENGTH, "brainpoolP160r1"}, + {&brainpoolP160t1, sizeof(brainpoolP160t1), CK_TRUE, CURVE_BRAINPOOL, + CURVE160_LENGTH, "brainpoolP160t1"}, + {&brainpoolP192r1, sizeof(brainpoolP192r1), CK_FALSE, CURVE_BRAINPOOL, + CURVE192_LENGTH, "brainpoolP192r1"}, + {&brainpoolP192t1, sizeof(brainpoolP192t1), CK_TRUE, CURVE_BRAINPOOL, + CURVE192_LENGTH, "brainpoolP192t1"}, + {&brainpoolP224r1, sizeof(brainpoolP224r1), CK_FALSE, CURVE_BRAINPOOL, + CURVE224_LENGTH, "brainpoolP224r1"}, + {&brainpoolP224t1, sizeof(brainpoolP224t1), CK_TRUE, CURVE_BRAINPOOL, + CURVE224_LENGTH, "brainpoolP224t1"}, + {&brainpoolP256r1, sizeof(brainpoolP256r1), CK_FALSE, CURVE_BRAINPOOL, + CURVE256_LENGTH, "brainpoolP256r1"}, + {&brainpoolP256t1, sizeof(brainpoolP256t1), CK_TRUE, CURVE_BRAINPOOL, + CURVE256_LENGTH, "brainpoolP256t1"}, + {&brainpoolP320r1, sizeof(brainpoolP320r1), CK_FALSE, CURVE_BRAINPOOL, + CURVE320_LENGTH, "brainpoolP320r1"}, + {&brainpoolP320t1, sizeof(brainpoolP320t1), CK_TRUE, CURVE_BRAINPOOL, + CURVE320_LENGTH, "brainpoolP320t1"}, + {&brainpoolP384r1, sizeof(brainpoolP384r1), CK_FALSE, CURVE_BRAINPOOL, + CURVE384_LENGTH, "brainpoolP384r1"}, + {&brainpoolP384t1, sizeof(brainpoolP384t1), CK_TRUE, CURVE_BRAINPOOL, + CURVE384_LENGTH, "brainpoolP384t1"}, + {&brainpoolP512r1, sizeof(brainpoolP512r1), CK_FALSE, CURVE_BRAINPOOL, + CURVE512_LENGTH, "brainpoolP512r1"}, + {&brainpoolP512t1, sizeof(brainpoolP512t1), CK_TRUE, CURVE_BRAINPOOL, + CURVE512_LENGTH, "brainpoolP512t1"}, + {&prime192v1, sizeof(prime192v1), CK_FALSE, CURVE_PRIME, + CURVE192_LENGTH, "prime192v1"}, + {&secp224r1, sizeof(secp224r1), CK_FALSE, CURVE_PRIME, + CURVE224_LENGTH , "secp224r1"}, + {&prime256v1, sizeof(prime256v1), CK_FALSE, CURVE_PRIME, + CURVE256_LENGTH, "prime256v1"}, + {&secp384r1, sizeof(secp384r1), CK_FALSE, CURVE_PRIME, + CURVE384_LENGTH, "secp384r1"}, + {&secp521r1, sizeof(secp521r1), CK_FALSE, CURVE_PRIME, + CURVE521_LENGTH + 8, "secp521r1"}, + {&secp256k1, sizeof(secp256k1), CK_FALSE, CURVE_PRIME, + CURVE256_LENGTH, "secp256k1"}, + {&curve25519, sizeof(curve25519), CK_FALSE, CURVE_MONTGOMERY, + CURVE256_LENGTH, "curve25519"}, + {&curve448, sizeof(curve448), CK_FALSE, CURVE_MONTGOMERY, + CURVE456_LENGTH, "curve448"}, + {&ed25519, sizeof(ed25519), CK_FALSE, CURVE_EDWARDS, + CURVE256_LENGTH, "ed25519"}, + {&ed448, sizeof(ed448), CK_FALSE, CURVE_EDWARDS, + CURVE456_LENGTH, "ed448"}, +}; + +/* Invalid curves */ +#define NUMECINVAL 4 +const CK_BYTE invalidCurve[] = + { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x08, 0x08, 0x01, 0x01, 0x01 }; +const CK_BYTE invalidLen1[] = + { 0x06, 0x0A, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x01 }; +const CK_BYTE invalidLen2[] = + { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01 }; +const CK_BYTE invalidOIDfield[] = + { 0x05, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x01 }; + +const _ec_struct der_ec_notsupported[NUMECINVAL] = { + {&invalidCurve, sizeof(invalidCurve), CK_FALSE, CURVE_BRAINPOOL, + CURVE256_LENGTH, "invalidCurve"}, + {&invalidLen1, sizeof(invalidLen1), CK_FALSE, CURVE_BRAINPOOL, + CURVE256_LENGTH, "invalidLen1"}, + {&invalidLen2, sizeof(invalidLen2), CK_FALSE, CURVE_BRAINPOOL, + CURVE256_LENGTH, "invalidLen2"}, + {&invalidOIDfield, sizeof(invalidOIDfield), CK_FALSE, CURVE_BRAINPOOL, + CURVE256_LENGTH, "invalidOIDfield"} +}; + +typedef struct signVerifyParam { + CK_MECHANISM_TYPE mechtype; + CK_ULONG inputlen; + CK_ULONG parts; /* 0 means process in 1 chunk via C_Sign, + * >0 means process in n chunks via + * C_SignUpdate/C_SignFinal + */ +} _signVerifyParam; + + +_signVerifyParam signVerifyInput[] = { + {CKM_ECDSA, 20, 0}, + {CKM_ECDSA, 32, 0}, + {CKM_ECDSA, 48, 0}, + {CKM_ECDSA, 64, 0}, + {CKM_ECDSA_SHA1, 100, 0}, + {CKM_ECDSA_SHA1, 100, 4}, + {CKM_ECDSA_SHA224, 100, 0}, + {CKM_ECDSA_SHA224, 100, 4}, + {CKM_ECDSA_SHA256, 100, 0}, + {CKM_ECDSA_SHA256, 100, 4}, + {CKM_ECDSA_SHA384, 100, 0}, + {CKM_ECDSA_SHA384, 100, 4}, + {CKM_ECDSA_SHA512, 100, 0}, + {CKM_ECDSA_SHA512, 100, 4}, + {CKM_IBM_EDDSA_SHA512, 100, 0}, + {CKM_IBM_ED448_SHA3, 100, 0}, +}; + +#define NUM_KDFS sizeof(kdfs)/sizeof(CK_EC_KDF_TYPE) +static CK_EC_KDF_TYPE kdfs[] = { + CKD_NULL, + CKD_SHA1_KDF, + CKD_SHA224_KDF, + CKD_SHA256_KDF, + CKD_SHA384_KDF, + CKD_SHA512_KDF, +}; + +static const char *p11_get_ckd(CK_EC_KDF_TYPE kdf) +{ + switch (kdf) { + case CKD_NULL: + return "CKD_NULL"; + case CKD_SHA1_KDF: + return "CKD_SHA1_KDF"; + case CKD_SHA224_KDF: + return "CKD_SHA224_KDF"; + case CKD_SHA256_KDF: + return "CKD_SHA256_KDF"; + case CKD_SHA384_KDF: + return "CKD_SHA384_KDF"; + case CKD_SHA512_KDF: + return "CKD_SHA512_KDF"; + default: + return "UNKNOWN"; + } +} + +static unsigned int curve_len(int index) +{ + if (index >= NUMEC) + return 0; + + return der_ec_supported[index].bit_len / 8; +} + +static CK_RV curve_supported(const char *name) +{ + if (name[strlen(name) - 2] == 'r' || name[strlen(name) - 2] == 'v') + return 1; + + return 0; +} + + +/** + * A test is skipped, when no KDF is used and the derived key length + * shall be bigger than the shared secret (z-value). Without a KDF, max + * z-length key bytes can be derived. + */ +static unsigned int too_many_key_bytes_requested(unsigned int curve, + unsigned int kdf, + unsigned int keylen) +{ + if (kdf > 0 || keylen <= curve_len(curve)) + return 0; + + return 1; +} + +/* + * Generate EC key-pairs for parties A and B. + * Derive shared secrets based on Diffie Hellman key agreement defined in PKCS#3 + */ +CK_RV run_DeriveECDHKey() +{ + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_FLAGS flags; + CK_OBJECT_HANDLE publ_keyA = CK_INVALID_HANDLE, + priv_keyA = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE publ_keyB = CK_INVALID_HANDLE, + priv_keyB = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE secret_keyA = CK_INVALID_HANDLE, + secret_keyB = CK_INVALID_HANDLE; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rc = CKR_OK; + CK_ECDH1_DERIVE_PARAMS ecdh_parmA, ecdh_parmB; + CK_BBOOL true = CK_TRUE; + CK_BBOOL false = CK_FALSE; + CK_BYTE pubkeyA_value[256]; + CK_BYTE pubkeyB_value[256]; + CK_BYTE secretA_value[80000]; //enough space for lengths in secret_key_len[] + CK_BYTE deriveB_value[80000]; + CK_OBJECT_CLASS class = CKO_SECRET_KEY; + CK_KEY_TYPE key_type = CKK_GENERIC_SECRET; + CK_ULONG i, j, k, m; + CK_MECHANISM_TYPE derive_mech_type; + + testcase_begin("starting run_DeriveECDHKey..."); + testcase_rw_session(); + testcase_user_login(); + + if (!mech_supported(SLOT_ID, CKM_EC_KEY_PAIR_GEN)) { + testcase_skip("Slot %u doesn't support CKM_EC_KEY_PAIR_GEN\n", + (unsigned int) SLOT_ID); + goto testcase_cleanup; + } + + for (i=0; iC_GenerateKeyPair(session, &mech, + pub_attr, pub_attr_len, + prv_attr, prv_attr_len, + &publ_keyA, &priv_keyA); + if (rc != CKR_OK) { + if (rc == CKR_MECHANISM_PARAM_INVALID || + rc == CKR_ATTRIBUTE_VALUE_INVALID) { + testcase_skip("Slot %u doesn't support this curve: %s", + (unsigned int) SLOT_ID, der_ec_supported[i].name); + continue; + } + testcase_fail("C_GenerateKeyPair with valid input failed at i=%lu " + "(%s), rc=%s", i, der_ec_supported[i].name, + p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // Extract public key A + rc = funcs->C_GetAttributeValue(session, publ_keyA, + extr1_tmpl, extr1_tmpl_len); + if (rc != CKR_OK) { + testcase_error("C_GetAttributeValue #1: rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // Now generate the EC key pair for party B + mech.mechanism = CKM_EC_KEY_PAIR_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rc = funcs->C_GenerateKeyPair(session, &mech, + pub_attr, pub_attr_len, + prv_attr, prv_attr_len, + &publ_keyB, &priv_keyB); + if (rc != CKR_OK) { + testcase_fail("C_GenerateKeyPair with valid input failed at i=%lu " + "(%s), rc=%s", i, der_ec_supported[i].name, + p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // Extract public key B + rc = funcs->C_GetAttributeValue(session, publ_keyB, + extr2_tmpl, extr2_tmpl_len); + if (rc != CKR_OK) { + testcase_error("C_GetAttributeValue #1: rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // Check if the key lengths are equal + if (extr1_tmpl->ulValueLen != extr2_tmpl->ulValueLen) { + testcase_error("Length of public key A not equal to length of " + "public key B"); + goto testcase_cleanup; + } + + // Testcase #2 - Now derive the secrets... + + for (j=0; j < NUM_KDFS; j++) { + + for (k=0; k 8) { + testcase_skip("EP11 cannot provide %lu key bytes with " + "curve %s\n", secret_key_len[k], + der_ec_supported[i].name); + continue; + } + + CK_ATTRIBUTE secretA_tmpl[] = { + {CKA_VALUE, secretA_value, sizeof(secretA_value)}, + }; + CK_ULONG secretA_tmpl_len = + sizeof(secretA_tmpl) / sizeof(CK_ATTRIBUTE); + + CK_ATTRIBUTE secretB_tmpl[] = { + {CKA_VALUE, deriveB_value, sizeof(deriveB_value)}, + }; + CK_ULONG secretB_tmpl_len = + sizeof(secretB_tmpl) / sizeof(CK_ATTRIBUTE); + + CK_ATTRIBUTE derive_tmpl[] = { + {CKA_CLASS, &class, sizeof(class)}, + {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, + {CKA_VALUE_LEN, &(secret_key_len[k]), sizeof(CK_ULONG)}, + {CKA_SENSITIVE, &false, sizeof(false)}, + }; + CK_ULONG secret_tmpl_len = + sizeof(derive_tmpl) / sizeof(CK_ATTRIBUTE); + + for (m=0; m < (kdfs[j] == CKD_NULL ? 1 : NUM_SHARED_DATA); m++) { + + testcase_new_assertion(); + testcase_begin("Starting with curve=%s, kdf=%s, keylen=%lu, " + "shared_data=%u, mech=%s", + der_ec_supported[i].name, + p11_get_ckd(kdfs[j]), secret_key_len[k], + shared_data[m].length, + p11_get_ckm(derive_mech_type)); + + // Now, derive a generic secret key using party A's private + // key and B's public key + ecdh_parmA.kdf = kdfs[j]; + ecdh_parmA.pPublicData = extr2_tmpl->pValue; + ecdh_parmA.ulPublicDataLen = extr2_tmpl->ulValueLen; + ecdh_parmA.pSharedData = + shared_data[m].length == 0 ? + NULL : (CK_BYTE_PTR) &shared_data[m].data; + ecdh_parmA.ulSharedDataLen = shared_data[m].length; + + if (kdfs[j] == CKD_NULL) { + ecdh_parmA.pSharedData = NULL; + ecdh_parmA.ulSharedDataLen = 0; + } + + mech.mechanism = derive_mech_type; + mech.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS); + mech.pParameter = &ecdh_parmA; + + rc = funcs->C_DeriveKey(session, &mech, + priv_keyA, derive_tmpl, + secret_tmpl_len, &secret_keyA); + if (rc != CKR_OK) { + if (is_ep11_token(SLOT_ID) && + rc == CKR_MECHANISM_PARAM_INVALID && + (kdfs[j] != CKD_NULL || + shared_data[m].length > 0)) { + testcase_skip("EP11 does not support KDFs and " + "shared data with older firmware " + "versions\n"); + continue; + } + + testcase_fail("C_DeriveKey #1: rc = %s", + p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // Now, derive a generic secret key using B's private key + // and A's public key + ecdh_parmB.kdf = kdfs[j]; + ecdh_parmB.pPublicData = extr1_tmpl->pValue; + ecdh_parmB.ulPublicDataLen = extr1_tmpl->ulValueLen; + ecdh_parmB.pSharedData = + shared_data[m].length == 0 ? + NULL : (CK_BYTE_PTR)&shared_data[m].data; + ecdh_parmB.ulSharedDataLen = shared_data[m].length; + + if (kdfs[j] == CKD_NULL) { + ecdh_parmB.pSharedData = NULL; + ecdh_parmB.ulSharedDataLen = 0; + } + + mech.mechanism = derive_mech_type; + mech.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS); + mech.pParameter = &ecdh_parmB; + + rc = funcs->C_DeriveKey(session, &mech, + priv_keyB, derive_tmpl, + secret_tmpl_len, &secret_keyB); + if (rc != CKR_OK) { + if (is_ep11_token(SLOT_ID) && + rc == CKR_MECHANISM_PARAM_INVALID && + (kdfs[j] != CKD_NULL || + shared_data[m].length > 0)) { + testcase_skip("EP11 does not support KDFs and " + "shared data with older firmware " + "versions\n"); + if (secret_keyA != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, secret_keyA); + continue; + } + + testcase_fail("C_DeriveKey #2: rc = %s", + p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // Extract the derived secret A + rc = funcs->C_GetAttributeValue(session, secret_keyA, + secretA_tmpl, + secretA_tmpl_len); + if (rc != CKR_OK) { + testcase_error("C_GetAttributeValue #3:rc = %s", + p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // Extract the derived secret B + rc = funcs->C_GetAttributeValue(session, secret_keyB, + secretB_tmpl, + secretB_tmpl_len); + if (rc != CKR_OK) { + testcase_error("C_GetAttributeValue #4:rc = %s", + p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // Compare lengths of derived secrets from key object + if (secretA_tmpl[0].ulValueLen != + secretB_tmpl[0].ulValueLen) { + testcase_fail("ERROR: derived key #1 length = %ld, " + "derived key #2 length = %ld", + secretA_tmpl[0].ulValueLen, + secretB_tmpl[0].ulValueLen); + goto testcase_cleanup; + } + + // Compare derive secrets A and B + if (memcmp(secretA_tmpl[0].pValue, + secretB_tmpl[0].pValue, + secretA_tmpl[0].ulValueLen) != 0) { + testcase_fail("ERROR: derived key mismatch, curve=%s, " + "kdf=%s, keylen=%lu, shared_data=%u", + der_ec_supported[i].name, + p11_get_ckd(kdfs[j]), secret_key_len[k], + shared_data[m].length); + goto testcase_cleanup; + } + + testcase_pass("*Derive shared secret curve=%s, kdf=%s, " + "keylen=%lu, shared_data=%u, mech=%s passed.", + der_ec_supported[i].name, + p11_get_ckd(kdfs[j]), secret_key_len[k], + shared_data[m].length, + p11_get_ckm(derive_mech_type)); + + if (secret_keyA != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, secret_keyA); + if (secret_keyB != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, secret_keyB); + } + } + } + + if (publ_keyA != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, publ_keyA); + if (priv_keyA != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, priv_keyA); + if (priv_keyB != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, priv_keyB); + if (publ_keyB != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, publ_keyB); + } + +testcase_cleanup: + if (publ_keyA != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, publ_keyA); + if (priv_keyA != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, priv_keyA); + if (priv_keyB != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, priv_keyB); + if (publ_keyB != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, publ_keyB); + if (secret_keyA != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, secret_keyA); + if (secret_keyB != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, secret_keyB); + + testcase_user_logout(); + testcase_close_session(); + + return rc; +} /* end run_DeriveECDHKey() */ + +/* + * Run some ECDH known answer tests. + */ +CK_RV run_DeriveECDHKeyKAT() +{ + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_FLAGS flags; + CK_OBJECT_HANDLE publ_keyA = CK_INVALID_HANDLE, + priv_keyA = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE publ_keyB = CK_INVALID_HANDLE, + priv_keyB = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE secret_keyA = CK_INVALID_HANDLE, + secret_keyB = CK_INVALID_HANDLE; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_KEY_TYPE secret_key_type = CKK_GENERIC_SECRET; + CK_OBJECT_CLASS class = CKO_SECRET_KEY; + CK_ECDH1_DERIVE_PARAMS ecdh_parmA, ecdh_parmB; + CK_BBOOL false = CK_FALSE; + CK_ULONG user_pin_len; + CK_RV rc = CKR_OK; + CK_BYTE secretA_value[1000]; // enough space for key lengths in ecdh_tv[] + CK_BYTE secretB_value[1000]; + CK_ULONG i; + + testcase_begin("starting run_DeriveECDHKeyKAT..."); + testcase_rw_session(); + testcase_user_login(); + + if (!mech_supported(SLOT_ID, CKM_ECDH1_DERIVE)) { + testcase_skip("Slot %u doesn't support CKM_ECDH1_DERIVE\n", + (unsigned int) SLOT_ID); + goto testcase_cleanup; + } + + if (is_ep11_token(SLOT_ID) || is_cca_token(SLOT_ID)) { + testcase_skip("Slot %u is a secure key token, can not run known answer " + "tests with CKM_ECDH1_DERIVE on it\n", + (unsigned int) SLOT_ID); + goto testcase_cleanup; + } + + for (i=0; iC_DeriveKey(session, &mech, + priv_keyA, derive_tmpl, + derive_tmpl_len, &secret_keyA); + if (rc != CKR_OK) { + if (is_ep11_token(SLOT_ID) && + rc == CKR_MECHANISM_PARAM_INVALID && + (ecdh_tv[i].kdf != CKD_NULL || + ecdh_tv[i].shared_data_len > 0)) { + testcase_skip("EP11 does not support KDFs and shared data with " + "older firmware versions\n"); + if (priv_keyA != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, priv_keyA); + if (publ_keyA != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, publ_keyA); + if (priv_keyB != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, priv_keyB); + if (publ_keyB != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, publ_keyB); + continue; + } + + testcase_fail("C_DeriveKey #1: rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // Now, derive a generic secret key using B's private key and + // A's public key + ecdh_parmB.kdf = ecdh_tv[i].kdf; + ecdh_parmB.pPublicData = ecdh_tv[i].pubkeyA; + ecdh_parmB.ulPublicDataLen = ecdh_tv[i].pubkey_len; + ecdh_parmB.pSharedData = + ecdh_tv[i].shared_data_len == 0 ? + NULL : (CK_BYTE_PTR)&ecdh_tv[i].shared_data; + ecdh_parmB.ulSharedDataLen = ecdh_tv[i].shared_data_len; + + if (ecdh_tv[i].kdf == CKD_NULL) { + ecdh_parmB.pSharedData = NULL; + ecdh_parmB.ulSharedDataLen = 0; + } + + mech.mechanism = CKM_ECDH1_DERIVE; + mech.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS); + mech.pParameter = &ecdh_parmB; + + rc = funcs->C_DeriveKey(session, &mech, + priv_keyB, derive_tmpl, + derive_tmpl_len, &secret_keyB); + if (rc != CKR_OK) { + if (is_ep11_token(SLOT_ID) && + rc == CKR_MECHANISM_PARAM_INVALID && + (ecdh_tv[i].kdf != CKD_NULL || + ecdh_tv[i].shared_data_len > 0)) { + testcase_skip("EP11 does not support KDFs and shared data with " + "older firmware versions\n"); + if (secret_keyA != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, secret_keyA); + if (priv_keyA != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, priv_keyA); + if (publ_keyA != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, publ_keyA); + if (priv_keyB != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, priv_keyB); + if (publ_keyB != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, publ_keyB); + continue; + } + + testcase_fail("C_DeriveKey #2: rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // Extract the derived secret A + rc = funcs->C_GetAttributeValue(session, secret_keyA, + secretA_tmpl, secretA_tmpl_len); + if (rc != CKR_OK) { + testcase_error("C_GetAttributeValue #3:rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // Compare lengths of derived secret from key object + if (ecdh_tv[i].derived_key_len != secretA_tmpl[0].ulValueLen) { + testcase_fail("ERROR:derived key #1 length = %ld, " + "derived key #2 length = %ld", + ecdh_tv[i].derived_key_len, + secretA_tmpl[0].ulValueLen); + goto testcase_cleanup; + } + + // Compare with known value + if (memcmp(secretA_tmpl[0].pValue, + ecdh_tv[i].derived_key, ecdh_tv[i].derived_key_len) != 0) { + testcase_fail("ERROR:derived key mismatch, i=%lu",i); + goto testcase_cleanup; + } + + // Extract the derived secret B + rc = funcs->C_GetAttributeValue(session, secret_keyB, + secretB_tmpl, secretB_tmpl_len); + if (rc != CKR_OK) { + testcase_error("C_GetAttributeValue #4:rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // Compare lengths of derived secret from key object + if (ecdh_tv[i].derived_key_len != secretB_tmpl[0].ulValueLen) { + testcase_fail("ERROR:derived key #1 length = %ld, derived key #2 " + "length = %ld", ecdh_tv[i].derived_key_len, + secretB_tmpl[0].ulValueLen); + goto testcase_cleanup; + } + + // Compare with known value + if (memcmp(secretB_tmpl[0].pValue, + ecdh_tv[i].derived_key, ecdh_tv[i].derived_key_len) != 0) { + testcase_fail("ERROR:derived key mismatch, i=%lu",i); + goto testcase_cleanup; + } + + testcase_pass("*Derive shared secret i=%lu passed.", i); + + if (priv_keyA != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, priv_keyA); + if (publ_keyA != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, publ_keyA); + if (priv_keyB != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, priv_keyB); + if (publ_keyB != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, publ_keyB); + if (secret_keyA != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, secret_keyA); + if (secret_keyB != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, secret_keyB); + } + +testcase_cleanup: + if (priv_keyA != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, priv_keyA); + if (publ_keyA != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, publ_keyA); + if (priv_keyB != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, priv_keyB); + if (publ_keyB != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, publ_keyB); + if (secret_keyA != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, secret_keyA); + if (secret_keyB != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, secret_keyB); + + testcase_user_logout(); + testcase_close_session(); + + return rc; +} /* end run_DeriveECDHKeyKAT() */ + +CK_RV run_GenerateSignVerifyECC(CK_SESSION_HANDLE session, + CK_MECHANISM_TYPE mechType, + CK_ULONG inputlen, + CK_ULONG parts, + CK_OBJECT_HANDLE priv_key, + CK_OBJECT_HANDLE publ_key, + enum curve_type curve_type) +{ + CK_MECHANISM mech2; + CK_BYTE_PTR data = NULL, signature = NULL; + CK_ULONG i, signaturelen; + CK_MECHANISM_INFO mech_info; + CK_RV rc; + + testcase_begin("Starting with mechtype='%s', inputlen=%lu parts=%lu", + p11_get_ckm(mechType), inputlen, parts); + + mech2.mechanism = mechType; + mech2.ulParameterLen = 0; + mech2.pParameter = NULL; + + /* query the slot, check if this mech if supported */ + rc = funcs->C_GetMechanismInfo(SLOT_ID, mech2.mechanism, &mech_info); + if (rc != CKR_OK) { + if (rc == CKR_MECHANISM_INVALID) { + /* no support for EC key gen? skip */ + testcase_skip("Slot %u doesn't support %s", + (unsigned int) SLOT_ID, p11_get_ckm(mechType)); + rc = CKR_OK; + goto testcase_cleanup; + } else { + testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + + if ((mechType == CKM_IBM_EDDSA_SHA512 || mechType == CKM_IBM_ED448_SHA3)) { + if (curve_type != CURVE_EDWARDS) { + /* Mechanism does not match to curve type, skip */ + testcase_skip("Mechanism %s can only be used with Edwards curves", + p11_get_ckm(mechType)); + rc = CKR_OK; + goto testcase_cleanup; + } + } else { + if (curve_type == CURVE_EDWARDS || curve_type == CURVE_MONTGOMERY) { + /* Mechanism does not match to curve type, skip */ + testcase_skip("Mechanism %s can not be used with Edwards/Montogmery curves", + p11_get_ckm(mechType)); + rc = CKR_OK; + goto testcase_cleanup; + } + } + + data = calloc(sizeof(CK_BYTE), inputlen); + if (data == NULL) { + testcase_error("Can't allocate memory for %lu bytes", + sizeof(CK_BYTE) * inputlen); + rc = -1; + goto testcase_cleanup; + } + + for (i = 0; i < inputlen; i++) { + data[i] = (i + 1) % 255; + } + + rc = funcs->C_SignInit(session, &mech2, priv_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + if (parts > 0) { + for (i = 0; i < parts; i++) { + rc = funcs->C_SignUpdate(session, data, inputlen); + if (rc != CKR_OK) { + testcase_error("C_SignUpdate rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + + /* get signature length */ + rc = funcs->C_SignFinal(session, signature, &signaturelen); + if (rc != CKR_OK) { + testcase_error("C_SignFinal rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } else { + rc = funcs->C_Sign(session, data, inputlen, NULL, &signaturelen); + if (rc != CKR_OK) { + testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + + signature = calloc(sizeof(CK_BYTE), signaturelen); + if (signature == NULL) { + testcase_error("Can't allocate memory for %lu bytes", + sizeof(CK_BYTE) * signaturelen); + rc = -1; + goto testcase_cleanup; + } + + if (parts > 0) { + rc = funcs->C_SignFinal(session, signature, &signaturelen); + if (rc != CKR_OK) { + testcase_error("C_SignFinal rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } else { + rc = funcs->C_Sign(session, data, inputlen, signature, &signaturelen); + if (rc != CKR_OK) { + testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + + /****** Verify *******/ + rc = funcs->C_VerifyInit(session, &mech2, publ_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + if (parts > 0) { + for (i = 0; i < parts; i++) { + rc = funcs->C_VerifyUpdate(session, data, inputlen); + if (rc != CKR_OK) { + testcase_error("C_VerifyUpdate rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + + rc = funcs->C_VerifyFinal(session, signature, signaturelen); + if (rc != CKR_OK) { + testcase_error("C_VerifyFinal rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } else { + rc = funcs->C_Verify(session, data, inputlen, signature, signaturelen); + if (rc != CKR_OK) { + testcase_error("C_Verify rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + + // corrupt the signature and re-verify + memcpy(signature, "ABCDEFGHIJKLMNOPQRSTUV", + strlen("ABCDEFGHIJKLMNOPQRSTUV")); + + rc = funcs->C_VerifyInit(session, &mech2, publ_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + if (parts > 0) { + for (i = 0; i < parts; i++) { + rc = funcs->C_VerifyUpdate(session, data, inputlen); + if (rc != CKR_OK) { + testcase_error("C_VerifyUpdate rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + + rc = funcs->C_VerifyFinal(session, signature, signaturelen); + if (rc != CKR_SIGNATURE_INVALID) { + testcase_error("C_VerifyFinal rc=%s", p11_get_ckr(rc)); + PRINT_ERR(" Expected CKR_SIGNATURE_INVALID\n"); + goto testcase_cleanup; + } + } else { + rc = funcs->C_Verify(session, data, inputlen, signature, signaturelen); + if (rc != CKR_SIGNATURE_INVALID) { + testcase_error("C_Verify rc=%s", p11_get_ckr(rc)); + PRINT_ERR(" Expected CKR_SIGNATURE_INVALID\n"); + goto testcase_cleanup; + } + } + + rc = CKR_OK; + +testcase_cleanup: + if (data) + free(data); + if (signature) + free(signature); + + return rc; +} + +CK_RV run_GenerateECCKeyPairSignVerify() +{ + CK_MECHANISM mech; + CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE; + CK_SESSION_HANDLE session; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len, i, j; + CK_FLAGS flags; + CK_MECHANISM_INFO mech_info; + CK_RV rc; + + testcase_begin("Starting ECC generate key pair."); + + testcase_rw_session(); + testcase_user_login(); + + mech.mechanism = CKM_EC_KEY_PAIR_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + /* query the slot, check if this mech is supported */ + rc = funcs->C_GetMechanismInfo(SLOT_ID, mech.mechanism, &mech_info); + if (rc != CKR_OK) { + if (rc == CKR_MECHANISM_INVALID) { + /* no support for EC key gen? skip */ + testcase_skip("Slot %u doesn't support CKM_EC_KEY_PAIR_GEN", + (unsigned int) SLOT_ID); + rc = CKR_OK; + goto testcase_cleanup; + } else { + testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + + for (i = 0; i < NUMEC; i++) { + + if (der_ec_supported[i].type == CURVE_MONTGOMERY) { + testcase_skip("Montgomery curves can not be used for sign/verify"); + continue; + } + + if (!is_ep11_token(SLOT_ID)) { + if (der_ec_supported[i].twisted) { + testcase_skip("Slot %u doesn't support this curve: %s", + (unsigned int) SLOT_ID, der_ec_supported[i].name); + continue; + } + if (der_ec_supported[i].curve == secp256k1) { + testcase_skip("Slot %u doesn't support this curve: %s", + (unsigned int) SLOT_ID, der_ec_supported[i].name); + continue; + } + if (der_ec_supported[i].type != CURVE_BRAINPOOL && + der_ec_supported[i].type != CURVE_PRIME ) { + testcase_skip("Slot %u doesn't support this curve: %s", + (unsigned int) SLOT_ID,der_ec_supported[i].name); + continue; + } + } + + CK_ATTRIBUTE ec_attr[] = { + {CKA_ECDSA_PARAMS, (CK_VOID_PTR)der_ec_supported[i].curve, + der_ec_supported[i].size} + }; + + rc = funcs->C_GenerateKeyPair(session, &mech, ec_attr, 1, NULL, 0, + &publ_key, &priv_key); + testcase_new_assertion(); + if (rc != CKR_OK) { + if (rc == CKR_MECHANISM_PARAM_INVALID || + rc == CKR_ATTRIBUTE_VALUE_INVALID) { + testcase_skip("Slot %u doesn't support this curve: %s", + (unsigned int) SLOT_ID, der_ec_supported[i].name); + continue; + } + testcase_fail + ("C_GenerateKeyPair with valid input failed at i=%lu (%s), " + "rc=%s", i, der_ec_supported[i].name, p11_get_ckr(rc)); + goto testcase_cleanup; + } + testcase_pass("*Generate supported key pair index=%lu passed.", i); + + for (j = 0; + j < (sizeof(signVerifyInput) / sizeof(_signVerifyParam)); j++) { + testcase_new_assertion(); + rc = run_GenerateSignVerifyECC(session, + signVerifyInput[j].mechtype, + signVerifyInput[j].inputlen, + signVerifyInput[j].parts, + priv_key, publ_key, + der_ec_supported[i].type); + if (rc != 0) { + testcase_fail("run_GenerateSignVerifyECC failed index=%lu.", j); + goto testcase_cleanup; + } + testcase_pass("*Sign & verify i=%lu, j=%lu passed.", i, j); + } + } + + 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); + testcase_new_assertion(); + if (rc == CKR_OK) { + testcase_fail + ("C_GenerateKeyPair with invalid input failed at i=%lu (%s)", + i, der_ec_supported[i].name); + goto testcase_cleanup; + } + testcase_pass("*Generate unsupported key pair curve=%s passed.", + der_ec_supported[i].name); + } + + rc = CKR_OK; + +testcase_cleanup: + if (publ_key != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, publ_key); + if (priv_key != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, priv_key); + + testcase_close_session(); + + return rc; +} + +CK_RV run_ImportECCKeyPairSignVerify() +{ + CK_MECHANISM mech; + CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE; + CK_SESSION_HANDLE session; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len, i, j; + CK_FLAGS flags; + CK_MECHANISM_INFO mech_info; + CK_RV rc; + + testcase_begin("Starting ECC import key pair."); + + testcase_rw_session(); + testcase_user_login(); + + mech.mechanism = CKM_ECDSA; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + /* query the slot, check if this mech is supported */ + rc = funcs->C_GetMechanismInfo(SLOT_ID, mech.mechanism, &mech_info); + if (rc != CKR_OK) { + if (rc == CKR_MECHANISM_INVALID) { + /* no support for EC key gen? skip */ + testcase_skip("Slot %u doesn't support CKM_ECDSA", + (unsigned int) SLOT_ID); + goto testcase_cleanup; + } else { + testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + + for (i = 0; i < EC_TV_NUM; i++) { + if ((is_ica_token(SLOT_ID) || is_cca_token(SLOT_ID))) { + if (!curve_supported((char *)ec_tv[i].name)) { + testcase_skip("Slot %u doesn't support this curve: %s", + (unsigned int)SLOT_ID,ec_tv[i].name); + continue; + } + } + + rc = create_ECPrivateKey(session, ec_tv[i].params, ec_tv[i].params_len, + ec_tv[i].privkey, ec_tv[i].privkey_len, + ec_tv[i].pubkey, ec_tv[i].pubkey_len, + &priv_key); + + testcase_new_assertion(); + if (rc != CKR_OK) { + if (is_ep11_token(SLOT_ID) && + rc == CKR_ENCRYPTED_DATA_INVALID && + (ec_tv[i].curve_type == CURVE_EDWARDS || + ec_tv[i].curve_type == CURVE_MONTGOMERY)) { + testcase_skip("Slot %u doesn't support this curve %s with " + "older firmware versions", + (unsigned int)SLOT_ID, ec_tv[i].name); + continue; + } + + testcase_fail("C_CreateObject (EC Private Key) failed at i=%lu " + "(%s), rc=%s", i, ec_tv[i].name, p11_get_ckr(rc)); + goto testcase_cleanup; + } + testcase_pass("*Import EC private key (%s) index=%lu passed.", + ec_tv[i].name, i); + + rc = create_ECPublicKey(session, ec_tv[i].params, ec_tv[i].params_len, + ec_tv[i].pubkey, ec_tv[i].pubkey_len, + &publ_key); + + testcase_new_assertion(); + if (rc != CKR_OK) { + if (is_ep11_token(SLOT_ID) && + rc == CKR_ENCRYPTED_DATA_INVALID && + (ec_tv[i].curve_type == CURVE_EDWARDS || + ec_tv[i].curve_type == CURVE_MONTGOMERY)) { + testcase_skip("Slot %u doesn't support this curve %s with " + "older firmware versions", + (unsigned int)SLOT_ID, ec_tv[i].name); + funcs->C_DestroyObject(session, priv_key); + continue; + } + + testcase_fail("C_CreateObject (EC Public Key) failed at i=%lu " + "(%s), rc=%s", i, ec_tv[i].name, p11_get_ckr(rc)); + goto testcase_cleanup; + } + testcase_pass("*Import EC public key (%s) index=%lu passed.", + ec_tv[i].name, i); + + /* create signature with private key */ + for (j = 0; + j < (sizeof(signVerifyInput) / sizeof(_signVerifyParam)); j++) { + testcase_new_assertion(); + rc = run_GenerateSignVerifyECC(session, + signVerifyInput[j].mechtype, + signVerifyInput[j].inputlen, + signVerifyInput[j].parts, + priv_key, publ_key, + ec_tv[i].curve_type); + if (rc != 0) { + testcase_fail("run_GenerateSignVerifyECC failed index=%lu.", j); + goto testcase_cleanup; + } + testcase_pass("*Sign & verify i=%lu, j=%lu passed.", i, j); + } + + // clean up + rc = funcs->C_DestroyObject(session, publ_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + + rc = funcs->C_DestroyObject(session, priv_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + } + + goto done; + +testcase_cleanup: + if (publ_key != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, publ_key); + if (priv_key != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, priv_key); + +done: + testcase_user_logout(); + testcase_close_session(); + + return rc; +} + +CK_RV run_TransferECCKeyPairSignVerify() +{ + CK_MECHANISM mech; + CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE, priv_key = CK_INVALID_HANDLE; + CK_SESSION_HANDLE session; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len, i, j; + CK_FLAGS flags; + CK_MECHANISM_INFO mech_info; + CK_RV rc; + CK_MECHANISM aes_keygen_mech; + CK_OBJECT_HANDLE secret_key = CK_INVALID_HANDLE; + CK_BYTE_PTR wrapped_key = NULL; + CK_ULONG wrapped_keylen; + CK_OBJECT_HANDLE unwrapped_key = CK_INVALID_HANDLE; + CK_MECHANISM wrap_mech; + + testcase_begin("Starting ECC transfer key pair."); + + testcase_rw_session(); + testcase_user_login(); + + mech.mechanism = CKM_ECDSA; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + /* query the slot, check if this mech is supported */ + rc = funcs->C_GetMechanismInfo(SLOT_ID, mech.mechanism, &mech_info); + if (rc != CKR_OK) { + if (rc == CKR_MECHANISM_INVALID) { + /* no support for EC key gen? skip */ + testcase_skip("Slot %u doesn't support CKM_ECDSA", + (unsigned int) SLOT_ID); + goto testcase_cleanup; + } else { + testcase_error("C_GetMechanismInfo() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + + for (i = 0; i < EC_TV_NUM; i++) { + if (!(is_ep11_token(SLOT_ID))) { + if (strstr((char *)ec_tv[i].name, "t1") != NULL) { + testcase_skip("Slot %u doesn't support curve %s", + (unsigned int)SLOT_ID, ec_tv[i].name); + continue; + } + if (ec_tv[i].curve_type == CURVE_EDWARDS || + ec_tv[i].curve_type == CURVE_MONTGOMERY) { + testcase_skip("Slot %u doesn't support curve %s", + (unsigned int)SLOT_ID, ec_tv[i].name); + continue; + } + } + + rc = create_ECPrivateKey(session, ec_tv[i].params, ec_tv[i].params_len, + ec_tv[i].privkey, ec_tv[i].privkey_len, + ec_tv[i].pubkey, ec_tv[i].pubkey_len, + &priv_key); + + testcase_new_assertion(); + if (rc != CKR_OK) { + if (is_ep11_token(SLOT_ID) && + rc == CKR_ENCRYPTED_DATA_INVALID && + (ec_tv[i].curve_type == CURVE_EDWARDS || + ec_tv[i].curve_type == CURVE_MONTGOMERY)) { + testcase_skip("Slot %u doesn't support this curve %s with " + "older firmware versions", + (unsigned int)SLOT_ID, ec_tv[i].name); + continue; + } + + testcase_fail + ("C_CreateObject (EC Private Key) failed at i=%lu, rc=%s", i, + p11_get_ckr(rc)); + goto testcase_cleanup; + } + testcase_pass("*Import EC private key (%s) index=%lu passed.", + ec_tv[i].name, i); + + rc = create_ECPublicKey(session, ec_tv[i].params, ec_tv[i].params_len, + ec_tv[i].pubkey, ec_tv[i].pubkey_len, + &publ_key); + + testcase_new_assertion(); + if (rc != CKR_OK) { + if (is_ep11_token(SLOT_ID) && + rc == CKR_ENCRYPTED_DATA_INVALID && + (ec_tv[i].curve_type == CURVE_EDWARDS || + ec_tv[i].curve_type == CURVE_MONTGOMERY)) { + testcase_skip("Slot %u doesn't support this curve %s with " + "older firmware versions", + (unsigned int)SLOT_ID, ec_tv[i].name); + funcs->C_DestroyObject(session, priv_key); + continue; + } + + testcase_fail + ("C_CreateObject (EC Public Key) failed at i=%lu, rc=%s", i, + p11_get_ckr(rc)); + goto testcase_cleanup; + } + testcase_pass("*Import EC public key (%s) index=%lu passed.", + ec_tv[i].name, i); + + /* create wrapping key (secret key) */ + aes_keygen_mech.mechanism = CKM_AES_KEY_GEN; + + CK_OBJECT_CLASS wkclass = CKO_SECRET_KEY; + CK_ULONG keylen = 32; + CK_BBOOL true = TRUE; + CK_BYTE wrap_key_label[] = "Wrap_Key"; + CK_ATTRIBUTE secret_tmpl[] = { + {CKA_CLASS, &wkclass, sizeof(wkclass)}, + {CKA_VALUE_LEN, &keylen, sizeof(keylen)}, + {CKA_LABEL, &wrap_key_label, sizeof(wrap_key_label)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_WRAP, &true, sizeof(true)}, + {CKA_UNWRAP, &true, sizeof(true)} + }; + + rc = funcs->C_GenerateKey(session, &aes_keygen_mech, secret_tmpl, + sizeof(secret_tmpl) / sizeof(CK_ATTRIBUTE), + &secret_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKey, rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /* wrap/unwrap private and public EC key with a transport key */ + + // length only + wrap_mech.mechanism = CKM_AES_CBC_PAD; + wrap_mech.pParameter = "0123456789abcdef"; + wrap_mech.ulParameterLen = 16; + rc = funcs->C_WrapKey(session, &wrap_mech, secret_key, priv_key, + NULL, &wrapped_keylen); + if (rc != CKR_OK) { + testcase_error("C_WrapKey(), rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // allocate memory for wrapped_key + wrapped_key = calloc(sizeof(CK_BYTE), wrapped_keylen); + if (wrapped_key == NULL) { + testcase_error("Can't allocate memory for %lu bytes.", + sizeof(CK_BYTE) * wrapped_keylen); + rc = CKR_HOST_MEMORY; + goto testcase_cleanup; + } + // wrap key + // + rc = funcs->C_WrapKey(session, &wrap_mech, secret_key, priv_key, + wrapped_key, &wrapped_keylen); + if (rc != CKR_OK) { + testcase_fail("C_WrapKey, rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // unwrap key + // + CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; + CK_KEY_TYPE key_type = CKK_EC; + CK_BYTE unwrap_label[] = "unwrapped_private_EC_Key"; + CK_BYTE subject[] = {0}; + CK_BYTE id[] = { 123 }; + + CK_ATTRIBUTE unwrap_tmpl[] = { + {CKA_CLASS, &class, sizeof(class)}, + {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_LABEL, &unwrap_label, sizeof(unwrap_label)}, + {CKA_SUBJECT, subject, sizeof(subject)}, + {CKA_ID, id, sizeof(id)}, + {CKA_SENSITIVE, &true, sizeof(true)}, + {CKA_DECRYPT, &true, sizeof(true)}, + {CKA_SIGN, &true, sizeof(true)}, + }; + + rc = funcs->C_UnwrapKey(session, &wrap_mech, secret_key, + wrapped_key, wrapped_keylen, + unwrap_tmpl, + sizeof(unwrap_tmpl) / sizeof(CK_ATTRIBUTE), + &unwrapped_key); + if (rc != CKR_OK) { + testcase_fail("C_UnwrapKey, rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + if (wrapped_key) { + free(wrapped_key); + wrapped_key = NULL; + } + + /* create signature with unwrapped private key and verify with + * public key */ + for (j = 0; + j < (sizeof(signVerifyInput) / sizeof(_signVerifyParam)); j++) { + testcase_new_assertion(); + rc = run_GenerateSignVerifyECC(session, + signVerifyInput[j].mechtype, + signVerifyInput[j].inputlen, + signVerifyInput[j].parts, + unwrapped_key, publ_key, + ec_tv[i].curve_type); + if (rc != 0) { + testcase_fail("run_GenerateSignVerifyECC failed index=%lu.", j); + goto testcase_cleanup; + } + testcase_pass("*Sign & verify i=%lu, j=%lu passed.", i, j); + } + + // clean up + rc = funcs->C_DestroyObject(session, publ_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + + rc = funcs->C_DestroyObject(session, priv_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + + rc = funcs->C_DestroyObject(session, secret_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + rc = funcs->C_DestroyObject(session, unwrapped_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + } + + goto done; + +testcase_cleanup: + if (publ_key != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, publ_key); + if (priv_key != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, priv_key); + if (secret_key != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, secret_key); + if (unwrapped_key != CK_INVALID_HANDLE) + funcs->C_DestroyObject(session, unwrapped_key); + + if (wrapped_key) + free(wrapped_key); + +done: + testcase_user_logout(); + testcase_close_session(); + + return rc; +} + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + int rc; + CK_RV rv; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: no_init: %d\n", no_init); + + rc = do_GetFunctionList(); + if (!rc) { + PRINT_ERR("ERROR do_GetFunctionList() Failed , rc = 0x%0x\n", rc); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + // SAB Add calls to ALL functions before the C_Initialize gets hit + + funcs->C_Initialize(&cinit_args); + + { + CK_SESSION_HANDLE hsess = 0; + + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + } + + testcase_setup(total_assertions); + + rv = run_GenerateECCKeyPairSignVerify(); + + rv = run_ImportECCKeyPairSignVerify(); + + rv = run_TransferECCKeyPairSignVerify(); + + rv = run_DeriveECDHKey(); + + rv = run_DeriveECDHKeyKAT(); + + testcase_print_result(); + + funcs->C_Finalize(NULL); + + /* make sure we return non-zero if rv is non-zero */ + return ((rv == 0) || (rv % 256) ? (int)rv : -1); +} diff --git a/testcases/crypto/rsa.h b/testcases/crypto/rsa.h new file mode 100644 index 0000000..f59724f --- /dev/null +++ b/testcases/crypto/rsa.h @@ -0,0 +1,8770 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2011-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 + */ + +#ifndef _RSA_H_ +#define _RSA_H_ +#endif + +#include "pkcs11types.h" +#define MAX_MODULUS_SIZE 256 +#define MAX_EXPONENT_SIZE 256 +#define MAX_MESSAGE_SIZE 512 +#define MAX_SIGNATURE_SIZE 512 +#define MAX_PRIME_SIZE 128 +#define MAX_COEFFICIENT_SIZE 128 +#define PKCS11_MAX_KEY_LEN 512 +#define MAX_CHUNKS 8 + + +struct RSA_GENERATED_TEST_VECTOR { + CK_ULONG modbits; + CK_ULONG publ_exp_len; + CK_BYTE publ_exp[4]; + CK_ULONG inputlen; + CK_MECHANISM keytype; + CK_ULONG keylen; + CK_RSA_PKCS_OAEP_PARAMS oaep_params; + CK_RSA_PKCS_PSS_PARAMS pss_params; + int chunks[MAX_CHUNKS]; + int num_chunks; +}; + +struct GENERATED_TEST_SUITE_INFO { + const char *name; + unsigned int tvcount; + struct RSA_GENERATED_TEST_VECTOR *tv; + CK_MECHANISM mech; +}; + +struct RSA_GENERATED_TEST_VECTOR rsa_oaep_generated_tv[] = { + { // #0 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 28, + .oaep_params = {CKM_SHA_1, CKG_MGF1_SHA1, CKZ_DATA_SPECIFIED, NULL, 0}, + .keylen = 24, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0} + }, + { // #1 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 16, + .oaep_params = {CKM_SHA_1, CKG_MGF1_SHA1, CKZ_DATA_SPECIFIED, + "abcdefghijkl", 12}, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0} + }, + { // #2 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 36, + .oaep_params = {CKM_SHA_1, CKG_MGF1_SHA1, CKZ_DATA_SPECIFIED, + "abcdefghijklmnopqrstuvwxyz", 26}, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0} + }, + { // #3 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 28, + .oaep_params = {CKM_SHA224, CKG_MGF1_SHA224, CKZ_DATA_SPECIFIED, NULL, 0}, + .keylen = 24, + .keytype = {CKM_AES_KEY_GEN, 0, 0} + }, + { // #4 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 16, + .oaep_params = {CKM_SHA224, CKG_MGF1_SHA224, CKZ_DATA_SPECIFIED, + "abcdefghijkl", 12}, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0} + }, + { // #5 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 36, + .oaep_params = {CKM_SHA224, CKG_MGF1_SHA224, CKZ_DATA_SPECIFIED, + "abcdefghijklmnopqrstuvwxyz", 26}, + .keylen = 32, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0} + }, + { // #6 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 28, + .oaep_params = {CKM_SHA256, CKG_MGF1_SHA256, CKZ_DATA_SPECIFIED, NULL, 0}, + .keylen = 24, + .keytype = {CKM_AES_KEY_GEN, 0, 0} + }, + { // #7 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 16, + .oaep_params = {CKM_SHA256, CKG_MGF1_SHA256, CKZ_DATA_SPECIFIED, + "abcdefghijkl", 12}, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0} + }, + { // #8 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 36, + .oaep_params = {CKM_SHA256, CKG_MGF1_SHA256, CKZ_DATA_SPECIFIED, + "abcdefghijklmnopqrstuvwxyz", 26}, + .keylen = 32, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0} + }, + { // #9 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 28, + .oaep_params = {CKM_SHA384, CKG_MGF1_SHA384, CKZ_DATA_SPECIFIED, NULL, 0}, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0} + }, + { // #10 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 16, + .oaep_params = {CKM_SHA384, CKG_MGF1_SHA384, CKZ_DATA_SPECIFIED, + "abcdefghijkl", 12}, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0} + }, + { // #11 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 36, + .oaep_params = {CKM_SHA384, CKG_MGF1_SHA384, CKZ_DATA_SPECIFIED, + "abcdefghijklmnopqrstuvwxyz", 26}, + .keylen = 24, + .keytype = {CKM_AES_KEY_GEN, 0, 0} + }, + { // #12 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 28, + .oaep_params = {CKM_SHA512, CKG_MGF1_SHA512, CKZ_DATA_SPECIFIED, NULL, 0}, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0} + }, + { // #13 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 16, + .oaep_params = {CKM_SHA512, CKG_MGF1_SHA512, CKZ_DATA_SPECIFIED, + "abcdefghijkl", 12}, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, + { // #14 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 36, + .oaep_params = {CKM_SHA512, CKG_MGF1_SHA512, CKZ_DATA_SPECIFIED, + "abcdefghijklmnopqrstuvwxyz", 26}, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0} + } +}; + +#define NUM_OF_GENERATED_OAEP_TESTSUITES 1 +struct GENERATED_TEST_SUITE_INFO generated_oaep_test_suites[] = { + { + .name = "RSA PKCS OAEP", + .tvcount = 15, + .tv = rsa_oaep_generated_tv, + .mech = {CKM_RSA_PKCS_OAEP, 0, 0}, + } +}; + +struct RSA_GENERATED_TEST_VECTOR rsa_pss_generated_tv[] = { + { // #0 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 13, + .pss_params = {CKM_SHA_1, CKG_MGF1_SHA1, 20} + }, + { // #1 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 156, + .pss_params = {CKM_SHA_1, CKG_MGF1_SHA1, 0} + }, + { // #2 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 65, + .pss_params = {CKM_SHA_1, CKG_MGF1_SHA1, 20} + }, + { // #3 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 28, + .pss_params = {CKM_SHA224, CKG_MGF1_SHA224, 28} + }, + { // #4 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 70, + .pss_params = {CKM_SHA224, CKG_MGF1_SHA224, 0} + }, + { // #5 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 128, + .pss_params = {CKM_SHA224, CKG_MGF1_SHA224, 28} + }, + { // #6 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 28, + .pss_params = {CKM_SHA256, CKG_MGF1_SHA256, 32} + }, + { // #7 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 70, + .pss_params = {CKM_SHA256, CKG_MGF1_SHA256, 0} + }, + { // #8 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 128, + .pss_params = {CKM_SHA256, CKG_MGF1_SHA256, 32} + }, + { // #9 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 12, + .pss_params = {CKM_SHA384, CKG_MGF1_SHA384, 48} + }, + { // #10 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 200, + .pss_params = {CKM_SHA384, CKG_MGF1_SHA384, 0} + }, + { // #11 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 65, + .pss_params = {CKM_SHA384, CKG_MGF1_SHA384, 48} + }, + { // #12 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 28, + .pss_params = {CKM_SHA512, CKG_MGF1_SHA512, 64} + }, + { // #13 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 90, + .pss_params = {CKM_SHA512, CKG_MGF1_SHA512, 0} + }, + { // #14 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 185, + .pss_params = {CKM_SHA512, CKG_MGF1_SHA512, 64} + } +}; + +struct RSA_GENERATED_TEST_VECTOR sha1_rsa_pss_generated_tv[] = { + { // #0 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 13, + .chunks = {13, 0}, + .num_chunks = 2, + .pss_params = {CKM_SHA_1, CKG_MGF1_SHA1, 20} + }, + { // #1 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 156, + .chunks = {25, 25, 75, -1, 26}, + .num_chunks = 5, + .pss_params = {CKM_SHA_1, CKG_MGF1_SHA1, 0} + }, + { // #2 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 65, + .chunks = {15, 30, 0, 20}, + .num_chunks = 4, + .pss_params = {CKM_SHA_1, CKG_MGF1_SHA1, 20} + } +}; + +struct RSA_GENERATED_TEST_VECTOR sha224_rsa_pss_generated_tv[] = { + { // #0 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 28, + .chunks = {0, 28}, + .num_chunks = 2, + .pss_params = {CKM_SHA224, CKG_MGF1_SHA224, 28} + }, + { // #1 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 70, + .chunks = {20, 20, -1, 10, 0}, + .num_chunks = 5, + .pss_params = {CKM_SHA224, CKG_MGF1_SHA224, 0} + }, + { // #2 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 128, + .chunks = {46, 61, 0, 21}, + .num_chunks = 4, + .pss_params = {CKM_SHA224, CKG_MGF1_SHA224, 28} + } +}; + +struct RSA_GENERATED_TEST_VECTOR sha256_rsa_pss_generated_tv[] = { + { // #0 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 28, + .chunks = {0, 28}, + .num_chunks = 2, + .pss_params = {CKM_SHA256, CKG_MGF1_SHA256, 32} + }, + { // #1 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 70, + .chunks = {20, 20, -1, 10, 0}, + .num_chunks = 5, + .pss_params = {CKM_SHA256, CKG_MGF1_SHA256, 0} + }, + { // #2 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 128, + .chunks = {46, 61, 0, 21}, + .num_chunks = 4, + .pss_params = {CKM_SHA256, CKG_MGF1_SHA256, 32} + } +}; + +struct RSA_GENERATED_TEST_VECTOR sha384_rsa_pss_generated_tv[] = { + { // #0 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 12, + .chunks = {12, -1}, + .num_chunks = 2, + .pss_params = {CKM_SHA384, CKG_MGF1_SHA384, 48} + }, + { // #1 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 200, + .chunks = {10, 0, 190}, + .num_chunks = 3, + .pss_params = {CKM_SHA384, CKG_MGF1_SHA384, 0} + }, + { // #2 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 65, + .chunks = {20, 20, 25, 0}, + .num_chunks = 4, + .pss_params = {CKM_SHA384, CKG_MGF1_SHA384, 48} + } +}; + +struct RSA_GENERATED_TEST_VECTOR sha512_rsa_pss_generated_tv[] = { + { // #0 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 28, + .chunks = {28, -1}, + .num_chunks = 2, + .pss_params = {CKM_SHA512, CKG_MGF1_SHA512, 64} + }, + { // #1 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 90, + .chunks = {20, 20, 20, 20, 10}, + .num_chunks = 5, + .pss_params = {CKM_SHA512, CKG_MGF1_SHA512, 0} + }, + { // #2 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 185, + .chunks = {50, 0, 100, 35}, + .num_chunks = 4, + .pss_params = {CKM_SHA512, CKG_MGF1_SHA512, 64} + } +}; + +#define NUM_OF_GENERATED_PSS_TESTSUITES 6 +struct GENERATED_TEST_SUITE_INFO generated_pss_test_suites[] = { + { + .name = "RSA PKCS PSS", + .tvcount = 15, + .tv = rsa_pss_generated_tv, + .mech = {CKM_RSA_PKCS_PSS, 0, 0}, + }, + { + .name = "SHA1 RSA PKCS PSS", + .tvcount = 3, + .tv = sha1_rsa_pss_generated_tv, + .mech = {CKM_SHA1_RSA_PKCS_PSS, 0, 0}, + }, + { + .name = "SHA224 RSA PKCS PSS", + .tvcount = 3, + .tv = sha224_rsa_pss_generated_tv, + .mech = {CKM_SHA224_RSA_PKCS_PSS, 0, 0}, + }, + { + .name = "SHA256 RSA PKCS PSS", + .tvcount = 3, + .tv = sha256_rsa_pss_generated_tv, + .mech = {CKM_SHA256_RSA_PKCS_PSS, 0, 0}, + }, + { + .name = "SHA384 RSA PKCS PSS", + .tvcount = 3, + .tv = sha384_rsa_pss_generated_tv, + .mech = {CKM_SHA384_RSA_PKCS_PSS, 0, 0}, + }, + { + .name = "SHA512 RSA PKCS PSS", + .tvcount = 3, + .tv = sha512_rsa_pss_generated_tv, + .mech = {CKM_SHA512_RSA_PKCS_PSS, 0, 0}, + } +}; + + +#define NUM_OF_GENERATED_PSS_UPDATE_TESTSUITES 5 +struct GENERATED_TEST_SUITE_INFO generated_pss_update_test_suites[] = { + { + .name = "SHA1 RSA PKCS PSS", + .tvcount = 3, + .tv = sha1_rsa_pss_generated_tv, + .mech = {CKM_SHA1_RSA_PKCS_PSS, 0, 0}, + }, + { + .name = "SHA224 RSA PKCS PSS", + .tvcount = 3, + .tv = sha224_rsa_pss_generated_tv, + .mech = {CKM_SHA224_RSA_PKCS_PSS, 0, 0}, + }, + { + .name = "SHA256 RSA PKCS PSS", + .tvcount = 3, + .tv = sha256_rsa_pss_generated_tv, + .mech = {CKM_SHA256_RSA_PKCS_PSS, 0, 0}, + }, + { + .name = "SHA384 RSA PKCS PSS", + .tvcount = 3, + .tv = sha384_rsa_pss_generated_tv, + .mech = {CKM_SHA384_RSA_PKCS_PSS, 0, 0}, + }, + { + .name = "SHA512 RSA PKCS PSS", + .tvcount = 3, + .tv = sha512_rsa_pss_generated_tv, + .mech = {CKM_SHA512_RSA_PKCS_PSS, 0, 0}, + } +}; + + +static struct RSA_GENERATED_TEST_VECTOR rsa_keywrap_generated_tv[] = { + { // 0 + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 10, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 1 + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, + { // 2 + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, + { // 3 + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, + { // 4 + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 5 + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 6 + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 32, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 7 + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, + { // 8 + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, + { // 9 + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, + { // 10 + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 11 + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 12 + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 10, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 13 + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, + { // 14 + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, + { // 15 + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, + { // 16 + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 17 + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 18 + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 10, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0} + }, + { // 19 + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, + { // 20 + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, + { // 21 + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, + { // 22 + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 23 + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 24 + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 64, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 25 + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 10, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 26 + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, + { // 27 + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, + { // 28 + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0} + }, + { // 29 + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 30 + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 31 + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 64, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 32 + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 10, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 33 + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, + { // 34 + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, + { // 35 + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, + { // 36 + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 37 + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 38 + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 10, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 39 + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, + { // 40 + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, + { // 41 + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, + { // 42 + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 43 + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 44 + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 96, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 45 + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 10, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 46 + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, + { // 47 + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, + { // 48 + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, + { // 49 + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 50 + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 51 + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 64, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 52 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 10, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 53 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, + { // 54 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, + { // 55 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, + { // 56 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 57 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 58 + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 32, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 59 + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 10, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 60 + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, + { // 61 + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, + { // 62 + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, + { // 63 + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 64 + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 65 + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 64, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 66 + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 10, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 67 + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, + { // 68 + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, + { // 69 + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, + { // 70 + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 71 + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 72 + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 128, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 73 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 10, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 74 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, + { // 75 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, + { // 76 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, + { // 77 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 78 + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 79 + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 10, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 80 + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, + { // 81 + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, + { // 82 + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, + { // 83 + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 84 + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 85 + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 10, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 86 + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, + { // 87 + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, + { // 88 + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, + { // 89 + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 90 + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 91 + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .keylen = 256, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 92 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 10, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + }, + { // 93 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 8, + .keytype = {CKM_CDMF_KEY_GEN, 0, 0}, + }, + { // 94 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 8, + .keytype = {CKM_DES_KEY_GEN, 0, 0}, + }, + { // 95 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 24, + .keytype = {CKM_DES3_KEY_GEN, 0, 0}, + }, + { // 96 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 16, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 97 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 32, + .keytype = {CKM_AES_KEY_GEN, 0, 0}, + }, + { // 98 + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .keylen = 256, + .keytype = {CKM_GENERIC_SECRET_KEY_GEN, 0, 0}, + } +}; + +static struct RSA_GENERATED_TEST_VECTOR rsa_generated_tv[] = { + { // tv[0] + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 1, + }, + { //tv[1] + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 53, + .chunks = {25, 25, 0, 3}, + .num_chunks = 4, + }, + { //tv[2] + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 1, + }, + { //tv[3] + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 53, + .chunks = {25, 25, 0, 3}, + .num_chunks = 4, + }, + { //tv[4] + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = {0x03, 0x00, 0x01}, + .inputlen = 1, + }, + { //tv[5] + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = {0x03, 0x00, 0x01}, + .inputlen = 53, + .chunks = {25, 25, 0, 3}, + .num_chunks = 4, + }, + { //tv[6] + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 1, + }, + { //tv[7] + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 85, + .chunks = {0, 20, 20, 20, 20, 5, -1}, + .num_chunks = 7, + }, + { //tv[8] + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 1, + }, + { //tv[9] + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 85, + .chunks = {0, 20, 20, 20, 20, 5, -1}, + .num_chunks = 7, + }, + { //tv[10] + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 1, + }, + { //tv[11] + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 85, + .chunks = {0, 20, 20, 20, 20, 5, -1}, + .num_chunks = 7, + }, + { //tv[12] + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 1, + }, + { //tv[13] + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 117, + .chunks = {30, 17, 30, 0, 30, 10}, + .num_chunks = 6, + }, + { //tv[14] + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 1, + }, + { //tv[15] + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 117, + .chunks = {30, 17, 30, 0, 30, 10}, + .num_chunks = 6, + }, + { //tv[16] + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 1, + }, + { //tv[17] + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 117, + .chunks = {30, 17, 30, 0, 30, 10}, + .num_chunks = 6, + }, + { //tv[18] + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 1, + }, + { //tv[19] + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 245, + .chunks = {100, 145}, + .num_chunks = 2 + }, + { //tv[20] + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 1, + }, + { //tv[21] + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 245, + .chunks = {100, 145}, + .num_chunks = 2 + }, + { //tv[22] + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 1, + }, + { //tv[23] + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 245, + .chunks = {100, 145}, + .num_chunks = 2 + }, + { //tv[24] + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 1, + }, + { //tv[25] + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 501, + .chunks = {125, 125, 125, 125, 1}, + .num_chunks = 5, + }, + { //tv[26] + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 1, + }, + { //tv[27] + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 501, + .chunks = {125, 125, 125, 125, 1}, + .num_chunks = 5, + }, + { //tv[28] + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 1, + }, + { //tv[29] + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 501, + .chunks = {125, 125, 125, 125, 1}, + .num_chunks = 5, + }, +}; + +static struct RSA_GENERATED_TEST_VECTOR rsa_x509_generated_tv[] = { + { // tv[0] + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 1, + }, + { // tv[1] + .modbits = 512, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 64, + }, + { // tv[2] + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 1, + }, + { // tv[3] + .modbits = 512, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 64, + }, + { // tv[4] + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 1, + }, + { // tv[5] + .modbits = 512, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 64, + }, + { // tv[6] + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 1, + }, + { // tv[7] + .modbits = 768, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 96, + }, + { // tv[8] + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 1, + }, + { // tv[9] + .modbits = 768, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 96, + }, + { // tv[10] + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 1, + }, + { // tv[11] + .modbits = 768, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 96, + }, + { // tv[12] + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 1 + }, + { // tv[13] + .modbits = 1024, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 128, + }, + { // tv[14] + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 1, + }, + { // tv[15] + .modbits = 1024, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 128, + }, + { // tv[16] + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 1 + }, + { // tv[17] + .modbits = 1024, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 128, + }, + { // tv[18] + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 1 + }, + { // tv[19] + .modbits = 2048, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 256, + }, + { // tv[20] + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 1, + }, + { // tv[21] + .modbits = 2048, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 256, + }, + { // tv[22] + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 1 + }, + { // tv[23] + .modbits = 2048, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 256, + }, + { // tv[24] + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 1 + }, + { // tv[25] + .modbits = 4096, + .publ_exp_len = 1, + .publ_exp = {0x03}, + .inputlen = 512, + }, + { // tv[26] + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 1, + }, + { // tv[27] + .modbits = 4096, + .publ_exp_len = 2, + .publ_exp = {0x00, 0x11}, + .inputlen = 512, + }, + { // tv[28] + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 1 + }, + { // tv[29] + .modbits = 4096, + .publ_exp_len = 3, + .publ_exp = {0x01, 0x00, 0x01}, + .inputlen = 512, + } +}; + +#define NUM_OF_GENERATED_KEYWRAP_TESTSUITES 2 +struct GENERATED_TEST_SUITE_INFO generated_keywrap_test_suites[] = { + { + .name = "RSA PKCS", + .tvcount = 99, + .tv = rsa_keywrap_generated_tv, + .mech = {CKM_RSA_PKCS, 0, 0}, + }, + { + .name = "RSA X.509", + .tvcount = 99, + .tv = rsa_keywrap_generated_tv, + .mech = {CKM_RSA_X_509, 0, 0}, + } +}; + + +#define NUM_OF_GENERATED_SIGVER_TESTSUITES 7 +struct GENERATED_TEST_SUITE_INFO generated_sigver_test_suites[] = { + { + .name = "RSA PKCS", + .tvcount = 30, + .tv = rsa_generated_tv, + .mech = {CKM_RSA_PKCS, 0, 0}, + }, + { + .name = "RSA SHA1 PKCS", + .tvcount = 30, + .tv = rsa_generated_tv, + .mech = {CKM_SHA1_RSA_PKCS, 0, 0}, + }, + { + .name = "RSA SHA224 PKCS", + .tvcount = 30, + .tv = rsa_generated_tv, + .mech = {CKM_SHA224_RSA_PKCS, 0, 0}, + }, + { + .name = "RSA SHA256 PKCS", + .tvcount = 30, + .tv = rsa_generated_tv, + .mech = {CKM_SHA256_RSA_PKCS, 0, 0}, + }, + { + .name = "RSA MD2 PKCS", + .tvcount = 30, + .tv = rsa_generated_tv, + .mech = {CKM_MD2_RSA_PKCS, 0, 0}, + }, + { + .name = "RSA MD5 PKCS", + .tvcount = 30, + .tv = rsa_generated_tv, + .mech = {CKM_MD5_RSA_PKCS, 0, 0}, + }, + { + .name = "RSA X.509", + .tvcount = 30, + .tv = rsa_x509_generated_tv, + .mech = {CKM_RSA_X_509, 0, 0}, + } +}; + + +#define NUM_OF_GENERATED_SIGVER_UPDATE_TESTSUITES 5 +struct GENERATED_TEST_SUITE_INFO generated_sigver_update_test_suites[] = { + { + .name = "RSA SHA1 PKCS", + .tvcount = 30, + .tv = rsa_generated_tv, + .mech = {CKM_SHA1_RSA_PKCS, 0, 0}, + }, + { + .name = "RSA SHA224 PKCS", + .tvcount = 30, + .tv = rsa_generated_tv, + .mech = {CKM_SHA224_RSA_PKCS, 0, 0}, + }, + { + .name = "RSA SHA256 PKCS", + .tvcount = 30, + .tv = rsa_generated_tv, + .mech = {CKM_SHA256_RSA_PKCS, 0, 0}, + }, + { + .name = "RSA MD2 PKCS", + .tvcount = 30, + .tv = rsa_generated_tv, + .mech = {CKM_MD2_RSA_PKCS, 0, 0}, + }, + { + .name = "RSA MD5 PKCS", + .tvcount = 30, + .tv = rsa_generated_tv, + .mech = {CKM_MD5_RSA_PKCS, 0, 0}, + } +}; + +#define NUM_OF_GENERATED_CRYPTO_TESTSUITES 2 +struct GENERATED_TEST_SUITE_INFO generated_crypto_test_suites[] = { + { + .name = "RSA PKCS", + .tvcount = 30, + .tv = rsa_generated_tv, + .mech = {CKM_RSA_PKCS, 0, 0}, + }, + { + .name = "RSA X.509", + .tvcount = 30, + .tv = rsa_x509_generated_tv, + .mech = {CKM_RSA_X_509, 0, 0}, + } +}; + +struct RSA_PUBLISHED_TEST_VECTOR { + CK_BYTE mod[MAX_MODULUS_SIZE]; // n + CK_ULONG mod_len; + CK_BYTE prime1[MAX_PRIME_SIZE]; // p + CK_ULONG prime1_len; + CK_BYTE prime2[MAX_PRIME_SIZE]; // q + CK_ULONG prime2_len; + CK_BYTE exp1[MAX_EXPONENT_SIZE]; // d % (p-1) + CK_ULONG exp1_len; + CK_BYTE exp2[MAX_EXPONENT_SIZE]; // d % (q-1) + CK_ULONG exp2_len; + CK_BYTE coef[MAX_COEFFICIENT_SIZE]; // (q^-1) % p + CK_ULONG coef_len; + CK_BYTE pub_exp[MAX_EXPONENT_SIZE]; // e + CK_ULONG pubexp_len; + CK_BYTE priv_exp[MAX_EXPONENT_SIZE]; // d + CK_ULONG privexp_len; + CK_BYTE msg[MAX_MESSAGE_SIZE]; + CK_ULONG msg_len; + CK_BYTE sig[MAX_SIGNATURE_SIZE]; + CK_ULONG sig_len; + int chunks[MAX_CHUNKS]; + int num_chunks; +}; +//ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15sign-vectors.txt +struct RSA_PUBLISHED_TEST_VECTOR rsa_sha1_pkcs_sigver_published_tv[] = { + { // 0 + .mod = {0xa5, 0x6e, 0x4a, 0x0e, 0x70, 0x10, 0x17, 0x58, + 0x9a, 0x51, 0x87, 0xdc, 0x7e, 0xa8, 0x41, 0xd1, + 0x56, 0xf2, 0xec, 0x0e, 0x36, 0xad, 0x52, 0xa4, + 0x4d, 0xfe, 0xb1, 0xe6, 0x1f, 0x7a, 0xd9, 0x91, + 0xd8, 0xc5, 0x10, 0x56, 0xff, 0xed, 0xb1, 0x62, + 0xb4, 0xc0, 0xf2, 0x83, 0xa1, 0x2a, 0x88, 0xa3, + 0x94, 0xdf, 0xf5, 0x26, 0xab, 0x72, 0x91, 0xcb, + 0xb3, 0x07, 0xce, 0xab, 0xfc, 0xe0, 0xb1, 0xdf, + 0xd5, 0xcd, 0x95, 0x08, 0x09, 0x6d, 0x5b, 0x2b, + 0x8b, 0x6d, 0xf5, 0xd6, 0x71, 0xef, 0x63, 0x77, + 0xc0, 0x92, 0x1c, 0xb2, 0x3c, 0x27, 0x0a, 0x70, + 0xe2, 0x59, 0x8e, 0x6f, 0xf8, 0x9d, 0x19, 0xf1, + 0x05, 0xac, 0xc2, 0xd3, 0xf0, 0xcb, 0x35, 0xf2, + 0x92, 0x80, 0xe1, 0x38, 0x6b, 0x6f, 0x64, 0xc4, + 0xef, 0x22, 0xe1, 0xe1, 0xf2, 0x0d, 0x0c, 0xe8, + 0xcf, 0xfb, 0x22, 0x49, 0xbd, 0x9a, 0x21, 0x37}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x33, 0xa5, 0x04, 0x2a, 0x90, 0xb2, 0x7d, 0x4f, + 0x54, 0x51, 0xca, 0x9b, 0xbb, 0xd0, 0xb4, 0x47, + 0x71, 0xa1, 0x01, 0xaf, 0x88, 0x43, 0x40, 0xae, + 0xf9, 0x88, 0x5f, 0x2a, 0x4b, 0xbe, 0x92, 0xe8, + 0x94, 0xa7, 0x24, 0xac, 0x3c, 0x56, 0x8c, 0x8f, + 0x97, 0x85, 0x3a, 0xd0, 0x7c, 0x02, 0x66, 0xc8, + 0xc6, 0xa3, 0xca, 0x09, 0x29, 0xf1, 0xe8, 0xf1, + 0x12, 0x31, 0x88, 0x44, 0x29, 0xfc, 0x4d, 0x9a, + 0xe5, 0x5f, 0xee, 0x89, 0x6a, 0x10, 0xce, 0x70, + 0x7c, 0x3e, 0xd7, 0xe7, 0x34, 0xe4, 0x47, 0x27, + 0xa3, 0x95, 0x74, 0x50, 0x1a, 0x53, 0x26, 0x83, + 0x10, 0x9c, 0x2a, 0xba, 0xca, 0xba, 0x28, 0x3c, + 0x31, 0xb4, 0xbd, 0x2f, 0x53, 0xc3, 0xee, 0x37, + 0xe3, 0x52, 0xce, 0xe3, 0x4f, 0x9e, 0x50, 0x3b, + 0xd8, 0x0c, 0x06, 0x22, 0xad, 0x79, 0xc6, 0xdc, + 0xee, 0x88, 0x35, 0x47, 0xc6, 0xa3, 0xb3, 0x25}, + .privexp_len = 128, + .prime1 = {0xe7, 0xe8, 0x94, 0x27, 0x20, 0xa8, 0x77, 0x51, + 0x72, 0x73, 0xa3, 0x56, 0x05, 0x3e, 0xa2, 0xa1, + 0xbc, 0x0c, 0x94, 0xaa, 0x72, 0xd5, 0x5c, 0x6e, + 0x86, 0x29, 0x6b, 0x2d, 0xfc, 0x96, 0x79, 0x48, + 0xc0, 0xa7, 0x2c, 0xbc, 0xcc, 0xa7, 0xea, 0xcb, + 0x35, 0x70, 0x6e, 0x09, 0xa1, 0xdf, 0x55, 0xa1, + 0x53, 0x5b, 0xd9, 0xb3, 0xcc, 0x34, 0x16, 0x0b, + 0x3b, 0x6d, 0xcd, 0x3e, 0xda, 0x8e, 0x64, 0x43}, + .prime1_len = 64, + .prime2 = {0xb6, 0x9d, 0xca, 0x1c, 0xf7, 0xd4, 0xd7, 0xec, + 0x81, 0xe7, 0x5b, 0x90, 0xfc, 0xca, 0x87, 0x4a, + 0xbc, 0xde, 0x12, 0x3f, 0xd2, 0x70, 0x01, 0x80, + 0xaa, 0x90, 0x47, 0x9b, 0x6e, 0x48, 0xde, 0x8d, + 0x67, 0xed, 0x24, 0xf9, 0xf1, 0x9d, 0x85, 0xba, + 0x27, 0x58, 0x74, 0xf5, 0x42, 0xcd, 0x20, 0xdc, + 0x72, 0x3e, 0x69, 0x63, 0x36, 0x4a, 0x1f, 0x94, + 0x25, 0x45, 0x2b, 0x26, 0x9a, 0x67, 0x99, 0xfd}, + .prime2_len = 64, + .exp1 = {0x28, 0xfa, 0x13, 0x93, 0x86, 0x55, 0xbe, 0x1f, + 0x8a, 0x15, 0x9c, 0xba, 0xca, 0x5a, 0x72, 0xea, + 0x19, 0x0c, 0x30, 0x08, 0x9e, 0x19, 0xcd, 0x27, + 0x4a, 0x55, 0x6f, 0x36, 0xc4, 0xf6, 0xe1, 0x9f, + 0x55, 0x4b, 0x34, 0xc0, 0x77, 0x79, 0x04, 0x27, + 0xbb, 0xdd, 0x8d, 0xd3, 0xed, 0xe2, 0x44, 0x83, + 0x28, 0xf3, 0x85, 0xd8, 0x1b, 0x30, 0xe8, 0xe4, + 0x3b, 0x2f, 0xff, 0xa0, 0x27, 0x86, 0x19, 0x79}, + .exp1_len = 64, + .exp2 = {0x1a, 0x8b, 0x38, 0xf3, 0x98, 0xfa, 0x71, 0x20, + 0x49, 0x89, 0x8d, 0x7f, 0xb7, 0x9e, 0xe0, 0xa7, + 0x76, 0x68, 0x79, 0x12, 0x99, 0xcd, 0xfa, 0x09, + 0xef, 0xc0, 0xe5, 0x07, 0xac, 0xb2, 0x1e, 0xd7, + 0x43, 0x01, 0xef, 0x5b, 0xfd, 0x48, 0xbe, 0x45, + 0x5e, 0xae, 0xb6, 0xe1, 0x67, 0x82, 0x55, 0x82, + 0x75, 0x80, 0xa8, 0xe4, 0xe8, 0xe1, 0x41, 0x51, + 0xd1, 0x51, 0x0a, 0x82, 0xa3, 0xf2, 0xe7, 0x29}, + .exp2_len = 64, + .coef = {0x27, 0x15, 0x6a, 0xba, 0x41, 0x26, 0xd2, 0x4a, + 0x81, 0xf3, 0xa5, 0x28, 0xcb, 0xfb, 0x27, 0xf5, + 0x68, 0x86, 0xf8, 0x40, 0xa9, 0xf6, 0xe8, 0x6e, + 0x17, 0xa4, 0x4b, 0x94, 0xfe, 0x93, 0x19, 0x58, + 0x4b, 0x8e, 0x22, 0xfd, 0xde, 0x1e, 0x5a, 0x2e, + 0x3b, 0xd8, 0xaa, 0x5b, 0xa8, 0xd8, 0x58, 0x41, + 0x94, 0xeb, 0x21, 0x90, 0xac, 0xf8, 0x32, 0xb8, + 0x47, 0xf1, 0x3a, 0x3d, 0x24, 0xa7, 0x9f, 0x4d}, + .coef_len = 64, + .msg = {0xcd, 0xc8, 0x7d, 0xa2, 0x23, 0xd7, 0x86, 0xdf, + 0x3b, 0x45, 0xe0, 0xbb, 0xbc, 0x72, 0x13, 0x26, + 0xd1, 0xee, 0x2a, 0xf8, 0x06, 0xcc, 0x31, 0x54, + 0x75, 0xcc, 0x6f, 0x0d, 0x9c, 0x66, 0xe1, 0xb6, + 0x23, 0x71, 0xd4, 0x5c, 0xe2, 0x39, 0x2e, 0x1a, + 0xc9, 0x28, 0x44, 0xc3, 0x10, 0x10, 0x2f, 0x15, + 0x6a, 0x0d, 0x8d, 0x52, 0xc1, 0xf4, 0xc4, 0x0b, + 0xa3, 0xaa, 0x65, 0x09, 0x57, 0x86, 0xcb, 0x76, + 0x97, 0x57, 0xa6, 0x56, 0x3b, 0xa9, 0x58, 0xfe, + 0xd0, 0xbc, 0xc9, 0x84, 0xe8, 0xb5, 0x17, 0xa3, + 0xd5, 0xf5, 0x15, 0xb2, 0x3b, 0x8a, 0x41, 0xe7, + 0x4a, 0xa8, 0x67, 0x69, 0x3f, 0x90, 0xdf, 0xb0, + 0x61, 0xa6, 0xe8, 0x6d, 0xfa, 0xae, 0xe6, 0x44, + 0x72, 0xc0, 0x0e, 0x5f, 0x20, 0x94, 0x57, 0x29, + 0xcb, 0xeb, 0xe7, 0x7f, 0x06, 0xce, 0x78, 0xe0, + 0x8f, 0x40, 0x98, 0xfb, 0xa4, 0x1f, 0x9d, 0x61, + 0x93, 0xc0, 0x31, 0x7e, 0x8b, 0x60, 0xd4, 0xb6, + 0x08, 0x4a, 0xcb, 0x42, 0xd2, 0x9e, 0x38, 0x08, + 0xa3, 0xbc, 0x37, 0x2d, 0x85, 0xe3, 0x31, 0x17, + 0x0f, 0xcb, 0xf7, 0xcc, 0x72, 0xd0, 0xb7, 0x1c, + 0x29, 0x66, 0x48, 0xb3, 0xa4, 0xd1, 0x0f, 0x41, + 0x62, 0x95, 0xd0, 0x80, 0x7a, 0xa6, 0x25, 0xca, + 0xb2, 0x74, 0x4f, 0xd9, 0xea, 0x8f, 0xd2, 0x23, + 0xc4, 0x25, 0x37, 0x02, 0x98, 0x28, 0xbd, 0x16, + 0xbe, 0x02, 0x54, 0x6f, 0x13, 0x0f, 0xd2, 0xe3, + 0x3b, 0x93, 0x6d, 0x26, 0x76, 0xe0, 0x8a, 0xed, + 0x1b, 0x73, 0x31, 0x8b, 0x75, 0x0a, 0x01, 0x67, + 0xd0}, + .msg_len = 217, + .sig = {0x6b, 0xc3, 0xa0, 0x66, 0x56, 0x84, 0x29, 0x30, + 0xa2, 0x47, 0xe3, 0x0d, 0x58, 0x64, 0xb4, 0xd8, + 0x19, 0x23, 0x6b, 0xa7, 0xc6, 0x89, 0x65, 0x86, + 0x2a, 0xd7, 0xdb, 0xc4, 0xe2, 0x4a, 0xf2, 0x8e, + 0x86, 0xbb, 0x53, 0x1f, 0x03, 0x35, 0x8b, 0xe5, + 0xfb, 0x74, 0x77, 0x7c, 0x60, 0x86, 0xf8, 0x50, + 0xca, 0xef, 0x89, 0x3f, 0x0d, 0x6f, 0xcc, 0x2d, + 0x0c, 0x91, 0xec, 0x01, 0x36, 0x93, 0xb4, 0xea, + 0x00, 0xb8, 0x0c, 0xd4, 0x9a, 0xac, 0x4e, 0xcb, + 0x5f, 0x89, 0x11, 0xaf, 0xe5, 0x39, 0xad, 0xa4, + 0xa8, 0xf3, 0x82, 0x3d, 0x1d, 0x13, 0xe4, 0x72, + 0xd1, 0x49, 0x05, 0x47, 0xc6, 0x59, 0xc7, 0x61, + 0x7f, 0x3d, 0x24, 0x08, 0x7d, 0xdb, 0x6f, 0x2b, + 0x72, 0x09, 0x61, 0x67, 0xfc, 0x09, 0x7c, 0xab, + 0x18, 0xe9, 0xa4, 0x58, 0xfc, 0xb6, 0x34, 0xcd, + 0xce, 0x8e, 0xe3, 0x58, 0x94, 0xc4, 0x84, 0xd7}, + .sig_len = 128, + .chunks = {50, 50, 50, 50, 17}, + .num_chunks = 5, + }, + { // 1 + .mod = {0xa5, 0x6e, 0x4a, 0x0e, 0x70, 0x10, 0x17, 0x58, + 0x9a, 0x51, 0x87, 0xdc, 0x7e, 0xa8, 0x41, 0xd1, + 0x56, 0xf2, 0xec, 0x0e, 0x36, 0xad, 0x52, 0xa4, + 0x4d, 0xfe, 0xb1, 0xe6, 0x1f, 0x7a, 0xd9, 0x91, + 0xd8, 0xc5, 0x10, 0x56, 0xff, 0xed, 0xb1, 0x62, + 0xb4, 0xc0, 0xf2, 0x83, 0xa1, 0x2a, 0x88, 0xa3, + 0x94, 0xdf, 0xf5, 0x26, 0xab, 0x72, 0x91, 0xcb, + 0xb3, 0x07, 0xce, 0xab, 0xfc, 0xe0, 0xb1, 0xdf, + 0xd5, 0xcd, 0x95, 0x08, 0x09, 0x6d, 0x5b, 0x2b, + 0x8b, 0x6d, 0xf5, 0xd6, 0x71, 0xef, 0x63, 0x77, + 0xc0, 0x92, 0x1c, 0xb2, 0x3c, 0x27, 0x0a, 0x70, + 0xe2, 0x59, 0x8e, 0x6f, 0xf8, 0x9d, 0x19, 0xf1, + 0x05, 0xac, 0xc2, 0xd3, 0xf0, 0xcb, 0x35, 0xf2, + 0x92, 0x80, 0xe1, 0x38, 0x6b, 0x6f, 0x64, 0xc4, + 0xef, 0x22, 0xe1, 0xe1, 0xf2, 0x0d, 0x0c, 0xe8, + 0xcf, 0xfb, 0x22, 0x49, 0xbd, 0x9a, 0x21, 0x37}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x33, 0xa5, 0x04, 0x2a, 0x90, 0xb2, 0x7d, 0x4f, + 0x54, 0x51, 0xca, 0x9b, 0xbb, 0xd0, 0xb4, 0x47, + 0x71, 0xa1, 0x01, 0xaf, 0x88, 0x43, 0x40, 0xae, + 0xf9, 0x88, 0x5f, 0x2a, 0x4b, 0xbe, 0x92, 0xe8, + 0x94, 0xa7, 0x24, 0xac, 0x3c, 0x56, 0x8c, 0x8f, + 0x97, 0x85, 0x3a, 0xd0, 0x7c, 0x02, 0x66, 0xc8, + 0xc6, 0xa3, 0xca, 0x09, 0x29, 0xf1, 0xe8, 0xf1, + 0x12, 0x31, 0x88, 0x44, 0x29, 0xfc, 0x4d, 0x9a, + 0xe5, 0x5f, 0xee, 0x89, 0x6a, 0x10, 0xce, 0x70, + 0x7c, 0x3e, 0xd7, 0xe7, 0x34, 0xe4, 0x47, 0x27, + 0xa3, 0x95, 0x74, 0x50, 0x1a, 0x53, 0x26, 0x83, + 0x10, 0x9c, 0x2a, 0xba, 0xca, 0xba, 0x28, 0x3c, + 0x31, 0xb4, 0xbd, 0x2f, 0x53, 0xc3, 0xee, 0x37, + 0xe3, 0x52, 0xce, 0xe3, 0x4f, 0x9e, 0x50, 0x3b, + 0xd8, 0x0c, 0x06, 0x22, 0xad, 0x79, 0xc6, 0xdc, + 0xee, 0x88, 0x35, 0x47, 0xc6, 0xa3, 0xb3, 0x25}, + .privexp_len = 128, + .prime1 = {0xe7, 0xe8, 0x94, 0x27, 0x20, 0xa8, 0x77, 0x51, + 0x72, 0x73, 0xa3, 0x56, 0x05, 0x3e, 0xa2, 0xa1, + 0xbc, 0x0c, 0x94, 0xaa, 0x72, 0xd5, 0x5c, 0x6e, + 0x86, 0x29, 0x6b, 0x2d, 0xfc, 0x96, 0x79, 0x48, + 0xc0, 0xa7, 0x2c, 0xbc, 0xcc, 0xa7, 0xea, 0xcb, + 0x35, 0x70, 0x6e, 0x09, 0xa1, 0xdf, 0x55, 0xa1, + 0x53, 0x5b, 0xd9, 0xb3, 0xcc, 0x34, 0x16, 0x0b, + 0x3b, 0x6d, 0xcd, 0x3e, 0xda, 0x8e, 0x64, 0x43}, + .prime1_len = 64, + .prime2 = {0xb6, 0x9d, 0xca, 0x1c, 0xf7, 0xd4, 0xd7, 0xec, + 0x81, 0xe7, 0x5b, 0x90, 0xfc, 0xca, 0x87, 0x4a, + 0xbc, 0xde, 0x12, 0x3f, 0xd2, 0x70, 0x01, 0x80, + 0xaa, 0x90, 0x47, 0x9b, 0x6e, 0x48, 0xde, 0x8d, + 0x67, 0xed, 0x24, 0xf9, 0xf1, 0x9d, 0x85, 0xba, + 0x27, 0x58, 0x74, 0xf5, 0x42, 0xcd, 0x20, 0xdc, + 0x72, 0x3e, 0x69, 0x63, 0x36, 0x4a, 0x1f, 0x94, + 0x25, 0x45, 0x2b, 0x26, 0x9a, 0x67, 0x99, 0xfd}, + .prime2_len = 64, + .exp1 = {0x28, 0xfa, 0x13, 0x93, 0x86, 0x55, 0xbe, 0x1f, + 0x8a, 0x15, 0x9c, 0xba, 0xca, 0x5a, 0x72, 0xea, + 0x19, 0x0c, 0x30, 0x08, 0x9e, 0x19, 0xcd, 0x27, + 0x4a, 0x55, 0x6f, 0x36, 0xc4, 0xf6, 0xe1, 0x9f, + 0x55, 0x4b, 0x34, 0xc0, 0x77, 0x79, 0x04, 0x27, + 0xbb, 0xdd, 0x8d, 0xd3, 0xed, 0xe2, 0x44, 0x83, + 0x28, 0xf3, 0x85, 0xd8, 0x1b, 0x30, 0xe8, 0xe4, + 0x3b, 0x2f, 0xff, 0xa0, 0x27, 0x86, 0x19, 0x79}, + .exp1_len = 64, + .exp2 = {0x1a, 0x8b, 0x38, 0xf3, 0x98, 0xfa, 0x71, 0x20, + 0x49, 0x89, 0x8d, 0x7f, 0xb7, 0x9e, 0xe0, 0xa7, + 0x76, 0x68, 0x79, 0x12, 0x99, 0xcd, 0xfa, 0x09, + 0xef, 0xc0, 0xe5, 0x07, 0xac, 0xb2, 0x1e, 0xd7, + 0x43, 0x01, 0xef, 0x5b, 0xfd, 0x48, 0xbe, 0x45, + 0x5e, 0xae, 0xb6, 0xe1, 0x67, 0x82, 0x55, 0x82, + 0x75, 0x80, 0xa8, 0xe4, 0xe8, 0xe1, 0x41, 0x51, + 0xd1, 0x51, 0x0a, 0x82, 0xa3, 0xf2, 0xe7, 0x29}, + .exp2_len = 64, + .coef = {0x27, 0x15, 0x6a, 0xba, 0x41, 0x26, 0xd2, 0x4a, + 0x81, 0xf3, 0xa5, 0x28, 0xcb, 0xfb, 0x27, 0xf5, + 0x68, 0x86, 0xf8, 0x40, 0xa9, 0xf6, 0xe8, 0x6e, + 0x17, 0xa4, 0x4b, 0x94, 0xfe, 0x93, 0x19, 0x58, + 0x4b, 0x8e, 0x22, 0xfd, 0xde, 0x1e, 0x5a, 0x2e, + 0x3b, 0xd8, 0xaa, 0x5b, 0xa8, 0xd8, 0x58, 0x41, + 0x94, 0xeb, 0x21, 0x90, 0xac, 0xf8, 0x32, 0xb8, + 0x47, 0xf1, 0x3a, 0x3d, 0x24, 0xa7, 0x9f, 0x4d}, + .coef_len = 64, + .msg = {0x85, 0x13, 0x84, 0xcd, 0xfe, 0x81, 0x9c, 0x22, + 0xed, 0x6c, 0x4c, 0xcb, 0x30, 0xda, 0xeb, 0x5c, + 0xf0, 0x59, 0xbc, 0x8e, 0x11, 0x66, 0xb7, 0xe3, + 0x53, 0x0c, 0x4c, 0x23, 0x3e, 0x2b, 0x5f, 0x8f, + 0x71, 0xa1, 0xcc, 0xa5, 0x82, 0xd4, 0x3e, 0xcc, + 0x72, 0xb1, 0xbc, 0xa1, 0x6d, 0xfc, 0x70, 0x13, + 0x22, 0x6b, 0x9e}, + .msg_len = 51, + .sig = {0x84, 0xfd, 0x2c, 0xe7, 0x34, 0xec, 0x1d, 0xa8, + 0x28, 0xd0, 0xf1, 0x5b, 0xf4, 0x9a, 0x87, 0x07, + 0xc1, 0x5d, 0x05, 0x94, 0x81, 0x36, 0xde, 0x53, + 0x7a, 0x3d, 0xb4, 0x21, 0x38, 0x41, 0x67, 0xc8, + 0x6f, 0xae, 0x02, 0x25, 0x87, 0xee, 0x9e, 0x13, + 0x7d, 0xae, 0xe7, 0x54, 0x73, 0x82, 0x62, 0x93, + 0x2d, 0x27, 0x1c, 0x74, 0x4c, 0x6d, 0x3a, 0x18, + 0x9a, 0xd4, 0x31, 0x1b, 0xdb, 0x02, 0x04, 0x92, + 0xe3, 0x22, 0xfb, 0xdd, 0xc4, 0x04, 0x06, 0xea, + 0x86, 0x0d, 0x4e, 0x8e, 0xa2, 0xa4, 0x08, 0x4a, + 0xa9, 0x8b, 0x96, 0x22, 0xa4, 0x46, 0x75, 0x6f, + 0xdb, 0x74, 0x0d, 0xdb, 0x3d, 0x91, 0xdb, 0x76, + 0x70, 0xe2, 0x11, 0x66, 0x1b, 0xbf, 0x87, 0x09, + 0xb1, 0x1c, 0x08, 0xa7, 0x07, 0x71, 0x42, 0x2d, + 0x1a, 0x12, 0xde, 0xf2, 0x9f, 0x06, 0x88, 0xa1, + 0x92, 0xae, 0xbd, 0x89, 0xe0, 0xf8, 0x96, 0xf8}, + .sig_len = 128, + .chunks = {50, 1, 0}, + .num_chunks = 3, + }, + { // 2 + .mod = {0xa5, 0x6e, 0x4a, 0x0e, 0x70, 0x10, 0x17, 0x58, + 0x9a, 0x51, 0x87, 0xdc, 0x7e, 0xa8, 0x41, 0xd1, + 0x56, 0xf2, 0xec, 0x0e, 0x36, 0xad, 0x52, 0xa4, + 0x4d, 0xfe, 0xb1, 0xe6, 0x1f, 0x7a, 0xd9, 0x91, + 0xd8, 0xc5, 0x10, 0x56, 0xff, 0xed, 0xb1, 0x62, + 0xb4, 0xc0, 0xf2, 0x83, 0xa1, 0x2a, 0x88, 0xa3, + 0x94, 0xdf, 0xf5, 0x26, 0xab, 0x72, 0x91, 0xcb, + 0xb3, 0x07, 0xce, 0xab, 0xfc, 0xe0, 0xb1, 0xdf, + 0xd5, 0xcd, 0x95, 0x08, 0x09, 0x6d, 0x5b, 0x2b, + 0x8b, 0x6d, 0xf5, 0xd6, 0x71, 0xef, 0x63, 0x77, + 0xc0, 0x92, 0x1c, 0xb2, 0x3c, 0x27, 0x0a, 0x70, + 0xe2, 0x59, 0x8e, 0x6f, 0xf8, 0x9d, 0x19, 0xf1, + 0x05, 0xac, 0xc2, 0xd3, 0xf0, 0xcb, 0x35, 0xf2, + 0x92, 0x80, 0xe1, 0x38, 0x6b, 0x6f, 0x64, 0xc4, + 0xef, 0x22, 0xe1, 0xe1, 0xf2, 0x0d, 0x0c, 0xe8, + 0xcf, 0xfb, 0x22, 0x49, 0xbd, 0x9a, 0x21, 0x37}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x33, 0xa5, 0x04, 0x2a, 0x90, 0xb2, 0x7d, 0x4f, + 0x54, 0x51, 0xca, 0x9b, 0xbb, 0xd0, 0xb4, 0x47, + 0x71, 0xa1, 0x01, 0xaf, 0x88, 0x43, 0x40, 0xae, + 0xf9, 0x88, 0x5f, 0x2a, 0x4b, 0xbe, 0x92, 0xe8, + 0x94, 0xa7, 0x24, 0xac, 0x3c, 0x56, 0x8c, 0x8f, + 0x97, 0x85, 0x3a, 0xd0, 0x7c, 0x02, 0x66, 0xc8, + 0xc6, 0xa3, 0xca, 0x09, 0x29, 0xf1, 0xe8, 0xf1, + 0x12, 0x31, 0x88, 0x44, 0x29, 0xfc, 0x4d, 0x9a, + 0xe5, 0x5f, 0xee, 0x89, 0x6a, 0x10, 0xce, 0x70, + 0x7c, 0x3e, 0xd7, 0xe7, 0x34, 0xe4, 0x47, 0x27, + 0xa3, 0x95, 0x74, 0x50, 0x1a, 0x53, 0x26, 0x83, + 0x10, 0x9c, 0x2a, 0xba, 0xca, 0xba, 0x28, 0x3c, + 0x31, 0xb4, 0xbd, 0x2f, 0x53, 0xc3, 0xee, 0x37, + 0xe3, 0x52, 0xce, 0xe3, 0x4f, 0x9e, 0x50, 0x3b, + 0xd8, 0x0c, 0x06, 0x22, 0xad, 0x79, 0xc6, 0xdc, + 0xee, 0x88, 0x35, 0x47, 0xc6, 0xa3, 0xb3, 0x25}, + .privexp_len = 128, + .prime1 = {0xe7, 0xe8, 0x94, 0x27, 0x20, 0xa8, 0x77, 0x51, + 0x72, 0x73, 0xa3, 0x56, 0x05, 0x3e, 0xa2, 0xa1, + 0xbc, 0x0c, 0x94, 0xaa, 0x72, 0xd5, 0x5c, 0x6e, + 0x86, 0x29, 0x6b, 0x2d, 0xfc, 0x96, 0x79, 0x48, + 0xc0, 0xa7, 0x2c, 0xbc, 0xcc, 0xa7, 0xea, 0xcb, + 0x35, 0x70, 0x6e, 0x09, 0xa1, 0xdf, 0x55, 0xa1, + 0x53, 0x5b, 0xd9, 0xb3, 0xcc, 0x34, 0x16, 0x0b, + 0x3b, 0x6d, 0xcd, 0x3e, 0xda, 0x8e, 0x64, 0x43}, + .prime1_len = 64, + .prime2 = {0xb6, 0x9d, 0xca, 0x1c, 0xf7, 0xd4, 0xd7, 0xec, + 0x81, 0xe7, 0x5b, 0x90, 0xfc, 0xca, 0x87, 0x4a, + 0xbc, 0xde, 0x12, 0x3f, 0xd2, 0x70, 0x01, 0x80, + 0xaa, 0x90, 0x47, 0x9b, 0x6e, 0x48, 0xde, 0x8d, + 0x67, 0xed, 0x24, 0xf9, 0xf1, 0x9d, 0x85, 0xba, + 0x27, 0x58, 0x74, 0xf5, 0x42, 0xcd, 0x20, 0xdc, + 0x72, 0x3e, 0x69, 0x63, 0x36, 0x4a, 0x1f, 0x94, + 0x25, 0x45, 0x2b, 0x26, 0x9a, 0x67, 0x99, 0xfd}, + .prime2_len = 64, + .exp1 = {0x28, 0xfa, 0x13, 0x93, 0x86, 0x55, 0xbe, 0x1f, + 0x8a, 0x15, 0x9c, 0xba, 0xca, 0x5a, 0x72, 0xea, + 0x19, 0x0c, 0x30, 0x08, 0x9e, 0x19, 0xcd, 0x27, + 0x4a, 0x55, 0x6f, 0x36, 0xc4, 0xf6, 0xe1, 0x9f, + 0x55, 0x4b, 0x34, 0xc0, 0x77, 0x79, 0x04, 0x27, + 0xbb, 0xdd, 0x8d, 0xd3, 0xed, 0xe2, 0x44, 0x83, + 0x28, 0xf3, 0x85, 0xd8, 0x1b, 0x30, 0xe8, 0xe4, + 0x3b, 0x2f, 0xff, 0xa0, 0x27, 0x86, 0x19, 0x79}, + .exp1_len = 64, + .exp2 = {0x1a, 0x8b, 0x38, 0xf3, 0x98, 0xfa, 0x71, 0x20, + 0x49, 0x89, 0x8d, 0x7f, 0xb7, 0x9e, 0xe0, 0xa7, + 0x76, 0x68, 0x79, 0x12, 0x99, 0xcd, 0xfa, 0x09, + 0xef, 0xc0, 0xe5, 0x07, 0xac, 0xb2, 0x1e, 0xd7, + 0x43, 0x01, 0xef, 0x5b, 0xfd, 0x48, 0xbe, 0x45, + 0x5e, 0xae, 0xb6, 0xe1, 0x67, 0x82, 0x55, 0x82, + 0x75, 0x80, 0xa8, 0xe4, 0xe8, 0xe1, 0x41, 0x51, + 0xd1, 0x51, 0x0a, 0x82, 0xa3, 0xf2, 0xe7, 0x29}, + .exp2_len = 64, + .coef = {0x27, 0x15, 0x6a, 0xba, 0x41, 0x26, 0xd2, 0x4a, + 0x81, 0xf3, 0xa5, 0x28, 0xcb, 0xfb, 0x27, 0xf5, + 0x68, 0x86, 0xf8, 0x40, 0xa9, 0xf6, 0xe8, 0x6e, + 0x17, 0xa4, 0x4b, 0x94, 0xfe, 0x93, 0x19, 0x58, + 0x4b, 0x8e, 0x22, 0xfd, 0xde, 0x1e, 0x5a, 0x2e, + 0x3b, 0xd8, 0xaa, 0x5b, 0xa8, 0xd8, 0x58, 0x41, + 0x94, 0xeb, 0x21, 0x90, 0xac, 0xf8, 0x32, 0xb8, + 0x47, 0xf1, 0x3a, 0x3d, 0x24, 0xa7, 0x9f, 0x4d}, + .coef_len = 64, + .msg = {0xa4, 0xb1, 0x59, 0x94, 0x17, 0x61, 0xc4, 0x0c, + 0x6a, 0x82, 0xf2, 0xb8, 0x0d, 0x1b, 0x94, 0xf5, + 0xaa, 0x26, 0x54, 0xfd, 0x17, 0xe1, 0x2d, 0x58, + 0x88, 0x64, 0x67, 0x9b, 0x54, 0xcd, 0x04, 0xef, + 0x8b, 0xd0, 0x30, 0x12, 0xbe, 0x8d, 0xc3, 0x7f, + 0x4b, 0x83, 0xaf, 0x79, 0x63, 0xfa, 0xff, 0x0d, + 0xfa, 0x22, 0x54, 0x77, 0x43, 0x7c, 0x48, 0x01, + 0x7f, 0xf2, 0xbe, 0x81, 0x91, 0xcf, 0x39, 0x55, + 0xfc, 0x07, 0x35, 0x6e, 0xab, 0x3f, 0x32, 0x2f, + 0x7f, 0x62, 0x0e, 0x21, 0xd2, 0x54, 0xe5, 0xdb, + 0x43, 0x24, 0x27, 0x9f, 0xe0, 0x67, 0xe0, 0x91, + 0x0e, 0x2e, 0x81, 0xca, 0x2c, 0xab, 0x31, 0xc7, + 0x45, 0xe6, 0x7a, 0x54, 0x05, 0x8e, 0xb5, 0x0d, + 0x99, 0x3c, 0xdb, 0x9e, 0xd0, 0xb4, 0xd0, 0x29, + 0xc0, 0x6d, 0x21, 0xa9, 0x4c, 0xa6, 0x61, 0xc3, + 0xce, 0x27, 0xfa, 0xe1, 0xd6, 0xcb, 0x20, 0xf4, + 0x56, 0x4d, 0x66, 0xce, 0x47, 0x67, 0x58, 0x3d, + 0x0e, 0x5f, 0x06, 0x02, 0x15, 0xb5, 0x90, 0x17, + 0xbe, 0x85, 0xea, 0x84, 0x89, 0x39, 0x12, 0x7b, + 0xd8, 0xc9, 0xc4, 0xd4, 0x7b, 0x51, 0x05, 0x6c, + 0x03, 0x1c, 0xf3, 0x36, 0xf1, 0x7c, 0x99, 0x80, + 0xf3, 0xb8, 0xf5, 0xb9, 0xb6, 0x87, 0x8e, 0x8b, + 0x79, 0x7a, 0xa4, 0x3b, 0x88, 0x26, 0x84, 0x33, + 0x3e, 0x17, 0x89, 0x3f, 0xe9, 0xca, 0xa6, 0xaa, + 0x29, 0x9f, 0x7e, 0xd1, 0xa1, 0x8e, 0xe2, 0xc5, + 0x48, 0x64, 0xb7, 0xb2, 0xb9, 0x9b, 0x72, 0x61, + 0x8f, 0xb0, 0x25, 0x74, 0xd1, 0x39, 0xef, 0x50, + 0xf0, 0x19, 0xc9, 0xee, 0xf4, 0x16, 0x97, 0x13, + 0x38, 0xe7, 0xd4, 0x70}, + .msg_len = 228, + .sig = {0x0b, 0x1f, 0x2e, 0x51, 0x80, 0xe5, 0xc7, 0xb4, + 0xb5, 0xe6, 0x72, 0x92, 0x9f, 0x66, 0x4c, 0x48, + 0x96, 0xe5, 0x0c, 0x35, 0x13, 0x4b, 0x6d, 0xe4, + 0xd5, 0xa9, 0x34, 0x25, 0x2a, 0x3a, 0x24, 0x5f, + 0xf4, 0x83, 0x40, 0x92, 0x0e, 0x10, 0x34, 0xb7, + 0xd5, 0xa5, 0xb5, 0x24, 0xeb, 0x0e, 0x1c, 0xf1, + 0x2b, 0xef, 0xef, 0x49, 0xb2, 0x7b, 0x73, 0x2d, + 0x2c, 0x19, 0xe1, 0xc4, 0x32, 0x17, 0xd6, 0xe1, + 0x41, 0x73, 0x81, 0x11, 0x1a, 0x1d, 0x36, 0xde, + 0x63, 0x75, 0xcf, 0x45, 0x5b, 0x3c, 0x98, 0x12, + 0x63, 0x9d, 0xbc, 0x27, 0x60, 0x0c, 0x75, 0x19, + 0x94, 0xfb, 0x61, 0x79, 0x9e, 0xcf, 0x7d, 0xa6, + 0xbc, 0xf5, 0x15, 0x40, 0xaf, 0xd0, 0x17, 0x4d, + 0xb4, 0x03, 0x31, 0x88, 0x55, 0x66, 0x75, 0xb1, + 0xd7, 0x63, 0x36, 0x0a, 0xf4, 0x6f, 0xee, 0xca, + 0x5b, 0x60, 0xf8, 0x82, 0x82, 0x9e, 0xe7, 0xb2}, + .sig_len = 128, + .chunks = {100, 75, -1, 53}, + .num_chunks = 4, + }, + { // 3 + .mod = {0xac, 0x13, 0xd9, 0xfd, 0xae, 0x7b, 0x73, 0x35, + 0xb6, 0x9c, 0xd9, 0x85, 0x67, 0xe9, 0x64, 0x7d, + 0x99, 0xbf, 0x37, 0x3a, 0x9e, 0x05, 0xce, 0x34, + 0x35, 0xd6, 0x64, 0x65, 0xf3, 0x28, 0xb7, 0xf7, + 0x33, 0x4b, 0x79, 0x2a, 0xee, 0x7e, 0xfa, 0x04, + 0x4e, 0xbc, 0x4c, 0x7a, 0x30, 0xb2, 0x1a, 0x5d, + 0x7a, 0x89, 0xcd, 0xb3, 0xa3, 0x0d, 0xfc, 0xd9, + 0xfe, 0xe9, 0x99, 0x5e, 0x09, 0x41, 0x5e, 0xdc, + 0x0b, 0xf9, 0xe5, 0xb4, 0xc3, 0xf7, 0x4f, 0xf5, + 0x3f, 0xb4, 0xd2, 0x94, 0x41, 0xbf, 0x1b, 0x7e, + 0xd6, 0xcb, 0xdd, 0x4a, 0x47, 0xf9, 0x25, 0x22, + 0x69, 0xe1, 0x64, 0x6f, 0x6c, 0x1a, 0xee, 0x05, + 0x14, 0xe9, 0x3f, 0x6c, 0xb9, 0xdf, 0x71, 0xd0, + 0x6c, 0x06, 0x0a, 0x21, 0x04, 0xb4, 0x7b, 0x72, + 0x60, 0xac, 0x37, 0xc1, 0x06, 0x86, 0x1d, 0xc7, + 0x8c, 0xa5, 0xa2, 0x5f, 0xaa, 0x9c, 0xb2, 0xe3}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x04, 0x84, 0xcc, 0xef, 0xad, 0x7a, 0x4e, 0x6f, + 0x35, 0xa9, 0x6e, 0xc8, 0xe3, 0x0e, 0xac, 0xf5, + 0xe3, 0x68, 0xb3, 0x11, 0x95, 0xfe, 0xbf, 0x08, + 0x7d, 0xf5, 0x70, 0x53, 0x81, 0x0c, 0x2b, 0xb0, + 0x91, 0x27, 0x45, 0x3a, 0x4c, 0x63, 0x07, 0x3b, + 0xbf, 0xb9, 0x90, 0x24, 0x91, 0x4c, 0xcc, 0x06, + 0x72, 0x66, 0x56, 0x01, 0x86, 0xa1, 0xa2, 0x67, + 0x33, 0x1b, 0x7d, 0x4c, 0x8b, 0xdf, 0xac, 0x96, + 0xfd, 0xa9, 0xf3, 0xf7, 0x0b, 0xec, 0x4e, 0xea, + 0xbc, 0xe7, 0xcd, 0x52, 0x19, 0x34, 0x3c, 0x2e, + 0x49, 0x1c, 0xce, 0x82, 0x7e, 0x44, 0xee, 0x23, + 0x0e, 0x4f, 0x69, 0x58, 0x9e, 0x57, 0x5a, 0xe9, + 0x06, 0x30, 0x30, 0x44, 0x2a, 0x31, 0xc8, 0x2c, + 0xde, 0x30, 0xdc, 0x9c, 0x79, 0xcf, 0x64, 0xe7, + 0xa0, 0x97, 0x5e, 0x75, 0xe1, 0x6e, 0xa4, 0x58, + 0x15, 0x48, 0x8b, 0x45, 0x52, 0x56, 0xee, 0xb1}, + .privexp_len = 128, + .prime1 = {0xdf, 0x85, 0xf4, 0xa0, 0xb4, 0x33, 0xbd, 0x37, + 0x43, 0x3c, 0xd7, 0x97, 0x8c, 0x9b, 0x37, 0xf9, + 0xe4, 0x17, 0x29, 0xd8, 0x3a, 0x26, 0x2b, 0x98, + 0x46, 0x53, 0x8e, 0x50, 0x39, 0xe6, 0x59, 0x68, + 0xb5, 0x95, 0xa4, 0x62, 0x72, 0xbd, 0x5f, 0x4a, + 0x2c, 0x3a, 0xbf, 0x89, 0x0a, 0x35, 0x50, 0x8a, + 0x5b, 0xcb, 0x4c, 0x29, 0xef, 0xbd, 0x91, 0x02, + 0x85, 0x03, 0x83, 0x4c, 0xfa, 0xb2, 0xc0, 0xf9}, + .prime1_len = 64, + .prime2 = {0xc5, 0x14, 0x59, 0xa6, 0x72, 0xed, 0x8b, 0x72, + 0x4c, 0x6a, 0x8f, 0x28, 0x5c, 0xbb, 0x8e, 0xa7, + 0x6a, 0x23, 0x93, 0x91, 0x79, 0x28, 0xbe, 0x56, + 0xc0, 0xdc, 0xdf, 0xc9, 0x43, 0xc3, 0x0b, 0xda, + 0x3c, 0xee, 0xfb, 0x86, 0xdc, 0xc8, 0xc4, 0x55, + 0x67, 0x8c, 0xfe, 0x88, 0x25, 0xf3, 0x88, 0x77, + 0xa3, 0x72, 0x8a, 0x1f, 0x10, 0x29, 0x1f, 0x54, + 0x7b, 0x1e, 0x8b, 0x16, 0x04, 0x83, 0xe5, 0xbb}, + .prime2_len = 64, + .exp1 = {0xb6, 0xba, 0x83, 0xa9, 0x7c, 0xa7, 0x6f, 0x5f, + 0xe6, 0x0f, 0xaf, 0x0f, 0xad, 0x5a, 0x97, 0x00, + 0x2a, 0x7e, 0xe5, 0x2e, 0x67, 0x1b, 0x1d, 0x38, + 0x77, 0x05, 0x87, 0xa9, 0xfe, 0x2b, 0x59, 0x9c, + 0x48, 0x15, 0xf5, 0x34, 0xa6, 0x28, 0x39, 0xe6, + 0x21, 0x12, 0x45, 0xd2, 0x7a, 0x0d, 0xeb, 0xb1, + 0xb0, 0x29, 0x1a, 0x32, 0x8e, 0x52, 0xa2, 0x61, + 0x34, 0xec, 0x12, 0x42, 0xb4, 0x0f, 0xbd, 0xc1}, + .exp1_len = 64, + .exp2 = {0xb9, 0xb1, 0xc6, 0x13, 0x2e, 0xe1, 0x22, 0x6e, + 0x6d, 0x10, 0x4e, 0x99, 0x72, 0x5f, 0x0b, 0x38, + 0x35, 0xab, 0x15, 0xe5, 0x91, 0x6a, 0xd1, 0x85, + 0xbe, 0xad, 0x9f, 0x72, 0xed, 0x95, 0x3f, 0x7a, + 0xbf, 0xc5, 0x52, 0x5c, 0xad, 0x75, 0xc2, 0x80, + 0xd2, 0x54, 0x28, 0x94, 0xb2, 0x65, 0xb8, 0x65, + 0x3a, 0x2d, 0xb7, 0x75, 0x33, 0x6d, 0xfb, 0xe6, + 0x47, 0x27, 0xed, 0x57, 0xae, 0xa3, 0x74, 0xf7}, + .exp2_len = 64, + .coef = {0x7b, 0x8d, 0x15, 0xa5, 0xdd, 0x28, 0x90, 0xa6, + 0x7d, 0x1b, 0x54, 0x9c, 0x93, 0x5f, 0x58, 0x5a, + 0x38, 0xda, 0x56, 0xf7, 0xc8, 0x15, 0x5a, 0x51, + 0x9d, 0xc8, 0xf1, 0xf6, 0xad, 0xe5, 0x53, 0xd6, + 0x37, 0x93, 0xc7, 0x8a, 0x0e, 0xce, 0x8d, 0x53, + 0x72, 0x4e, 0x62, 0xae, 0x50, 0x3a, 0xd5, 0x25, + 0xbf, 0xaf, 0x10, 0xcf, 0x61, 0x6a, 0x47, 0x73, + 0xce, 0x7c, 0xcd, 0x5c, 0x1b, 0x31, 0x51, 0xbd}, + .coef_len = 64, + .msg = {0xe1, 0xc0, 0xf9, 0x8d, 0x53, 0xf8, 0xf8, 0xb1, + 0x41, 0x90, 0x57, 0xd5, 0xb9, 0xb1, 0x0b, 0x07, + 0xfe, 0xea, 0xec, 0x32, 0xc0, 0x46, 0x3a, 0x4d, + 0x68, 0x38, 0x2f, 0x53, 0x1b, 0xa1, 0xd6, 0xcf, + 0xe4, 0xed, 0x38, 0xa2, 0x69, 0x4a, 0x34, 0xb9, + 0xc8, 0x05, 0xad, 0xf0, 0x72, 0xff, 0xbc, 0xeb, + 0xe2, 0x1d, 0x8d, 0x4b, 0x5c, 0x0e, 0x8c, 0x33, + 0x45, 0x2d, 0xd8, 0xf9, 0xc9, 0xbf, 0x45, 0xd1, + 0xe6, 0x33, 0x75, 0x11, 0x33, 0x58, 0x82, 0x29, + 0xd2, 0x93, 0xc6, 0x49, 0x6b, 0x7c, 0x98, 0x3c, + 0x2c, 0x72, 0xbd, 0x21, 0xd3, 0x39, 0x27, 0x2d, + 0x78, 0x28, 0xb0, 0xd0, 0x9d, 0x01, 0x0b, 0xba, + 0xd3, 0x18, 0xd9, 0x98, 0xf7, 0x04, 0x79, 0x67, + 0x33, 0x8a, 0xce, 0xfd, 0x01, 0xe8, 0x74, 0xac, + 0xe5, 0xf8, 0x6d, 0x2a, 0x60, 0xf3, 0xb3, 0xca, + 0xe1, 0x3f, 0xc5, 0xc6, 0x65, 0x08, 0xcf, 0xb7, + 0x23, 0x78, 0xfd, 0xd6, 0xc8, 0xde, 0x24, 0x97, + 0x65, 0x10, 0x3c, 0xe8, 0xfe, 0x7c, 0xd3, 0x3a, + 0xd0, 0xef, 0x16, 0x86, 0xfe, 0xb2, 0x5e, 0x6a, + 0x35, 0xfb, 0x64, 0xe0, 0x96, 0xa4}, + .msg_len = 158, + .sig = {0x64, 0xac, 0x09, 0x39, 0x71, 0xf8, 0xf0, 0x96, + 0xa4, 0xc1, 0xd4, 0xa5, 0x43, 0x66, 0x2a, 0x2e, + 0x5a, 0x12, 0x81, 0xc9, 0x50, 0x98, 0x7d, 0xe8, + 0x98, 0x70, 0x7f, 0x02, 0x9c, 0x15, 0x9b, 0xd8, + 0x32, 0xca, 0xc5, 0x5d, 0x91, 0x36, 0xe0, 0xe9, + 0xb4, 0xa8, 0x0b, 0xf6, 0xf2, 0x1b, 0x68, 0xcf, + 0x97, 0x70, 0xa6, 0x34, 0x9a, 0xe5, 0x1e, 0x7f, + 0x09, 0xdb, 0xda, 0x9d, 0x59, 0xc4, 0x58, 0x37, + 0x37, 0x47, 0x2d, 0x4d, 0x65, 0x32, 0xc7, 0x17, + 0x7e, 0xe9, 0x81, 0x08, 0xd2, 0xcf, 0x42, 0xcd, + 0x08, 0x5a, 0xbb, 0x49, 0x22, 0xeb, 0x29, 0xd9, + 0x6f, 0x3d, 0x0f, 0x6b, 0x1d, 0x0d, 0x43, 0xc7, + 0x39, 0xcc, 0xf1, 0xba, 0x65, 0x16, 0x75, 0xe1, + 0x96, 0x8b, 0x50, 0x7d, 0x51, 0x90, 0x2f, 0x38, + 0xcd, 0xec, 0x0b, 0x61, 0x32, 0x72, 0x90, 0x45, + 0x32, 0x5f, 0xc1, 0xfb, 0x8f, 0xd5, 0x58, 0xe8}, + .sig_len = 128, + }, + { // 4 + .mod = {0xac, 0x13, 0xd9, 0xfd, 0xae, 0x7b, 0x73, 0x35, + 0xb6, 0x9c, 0xd9, 0x85, 0x67, 0xe9, 0x64, 0x7d, + 0x99, 0xbf, 0x37, 0x3a, 0x9e, 0x05, 0xce, 0x34, + 0x35, 0xd6, 0x64, 0x65, 0xf3, 0x28, 0xb7, 0xf7, + 0x33, 0x4b, 0x79, 0x2a, 0xee, 0x7e, 0xfa, 0x04, + 0x4e, 0xbc, 0x4c, 0x7a, 0x30, 0xb2, 0x1a, 0x5d, + 0x7a, 0x89, 0xcd, 0xb3, 0xa3, 0x0d, 0xfc, 0xd9, + 0xfe, 0xe9, 0x99, 0x5e, 0x09, 0x41, 0x5e, 0xdc, + 0x0b, 0xf9, 0xe5, 0xb4, 0xc3, 0xf7, 0x4f, 0xf5, + 0x3f, 0xb4, 0xd2, 0x94, 0x41, 0xbf, 0x1b, 0x7e, + 0xd6, 0xcb, 0xdd, 0x4a, 0x47, 0xf9, 0x25, 0x22, + 0x69, 0xe1, 0x64, 0x6f, 0x6c, 0x1a, 0xee, 0x05, + 0x14, 0xe9, 0x3f, 0x6c, 0xb9, 0xdf, 0x71, 0xd0, + 0x6c, 0x06, 0x0a, 0x21, 0x04, 0xb4, 0x7b, 0x72, + 0x60, 0xac, 0x37, 0xc1, 0x06, 0x86, 0x1d, 0xc7, + 0x8c, 0xa5, 0xa2, 0x5f, 0xaa, 0x9c, 0xb2, 0xe3}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x04, 0x84, 0xcc, 0xef, 0xad, 0x7a, 0x4e, 0x6f, + 0x35, 0xa9, 0x6e, 0xc8, 0xe3, 0x0e, 0xac, 0xf5, + 0xe3, 0x68, 0xb3, 0x11, 0x95, 0xfe, 0xbf, 0x08, + 0x7d, 0xf5, 0x70, 0x53, 0x81, 0x0c, 0x2b, 0xb0, + 0x91, 0x27, 0x45, 0x3a, 0x4c, 0x63, 0x07, 0x3b, + 0xbf, 0xb9, 0x90, 0x24, 0x91, 0x4c, 0xcc, 0x06, + 0x72, 0x66, 0x56, 0x01, 0x86, 0xa1, 0xa2, 0x67, + 0x33, 0x1b, 0x7d, 0x4c, 0x8b, 0xdf, 0xac, 0x96, + 0xfd, 0xa9, 0xf3, 0xf7, 0x0b, 0xec, 0x4e, 0xea, + 0xbc, 0xe7, 0xcd, 0x52, 0x19, 0x34, 0x3c, 0x2e, + 0x49, 0x1c, 0xce, 0x82, 0x7e, 0x44, 0xee, 0x23, + 0x0e, 0x4f, 0x69, 0x58, 0x9e, 0x57, 0x5a, 0xe9, + 0x06, 0x30, 0x30, 0x44, 0x2a, 0x31, 0xc8, 0x2c, + 0xde, 0x30, 0xdc, 0x9c, 0x79, 0xcf, 0x64, 0xe7, + 0xa0, 0x97, 0x5e, 0x75, 0xe1, 0x6e, 0xa4, 0x58, + 0x15, 0x48, 0x8b, 0x45, 0x52, 0x56, 0xee, 0xb1}, + .privexp_len = 128, + .prime1 = {0xdf, 0x85, 0xf4, 0xa0, 0xb4, 0x33, 0xbd, 0x37, + 0x43, 0x3c, 0xd7, 0x97, 0x8c, 0x9b, 0x37, 0xf9, + 0xe4, 0x17, 0x29, 0xd8, 0x3a, 0x26, 0x2b, 0x98, + 0x46, 0x53, 0x8e, 0x50, 0x39, 0xe6, 0x59, 0x68, + 0xb5, 0x95, 0xa4, 0x62, 0x72, 0xbd, 0x5f, 0x4a, + 0x2c, 0x3a, 0xbf, 0x89, 0x0a, 0x35, 0x50, 0x8a, + 0x5b, 0xcb, 0x4c, 0x29, 0xef, 0xbd, 0x91, 0x02, + 0x85, 0x03, 0x83, 0x4c, 0xfa, 0xb2, 0xc0, 0xf9}, + .prime1_len = 64, + .prime2 = {0xc5, 0x14, 0x59, 0xa6, 0x72, 0xed, 0x8b, 0x72, + 0x4c, 0x6a, 0x8f, 0x28, 0x5c, 0xbb, 0x8e, 0xa7, + 0x6a, 0x23, 0x93, 0x91, 0x79, 0x28, 0xbe, 0x56, + 0xc0, 0xdc, 0xdf, 0xc9, 0x43, 0xc3, 0x0b, 0xda, + 0x3c, 0xee, 0xfb, 0x86, 0xdc, 0xc8, 0xc4, 0x55, + 0x67, 0x8c, 0xfe, 0x88, 0x25, 0xf3, 0x88, 0x77, + 0xa3, 0x72, 0x8a, 0x1f, 0x10, 0x29, 0x1f, 0x54, + 0x7b, 0x1e, 0x8b, 0x16, 0x04, 0x83, 0xe5, 0xbb}, + .prime2_len = 64, + .exp1 = {0xb6, 0xba, 0x83, 0xa9, 0x7c, 0xa7, 0x6f, 0x5f, + 0xe6, 0x0f, 0xaf, 0x0f, 0xad, 0x5a, 0x97, 0x00, + 0x2a, 0x7e, 0xe5, 0x2e, 0x67, 0x1b, 0x1d, 0x38, + 0x77, 0x05, 0x87, 0xa9, 0xfe, 0x2b, 0x59, 0x9c, + 0x48, 0x15, 0xf5, 0x34, 0xa6, 0x28, 0x39, 0xe6, + 0x21, 0x12, 0x45, 0xd2, 0x7a, 0x0d, 0xeb, 0xb1, + 0xb0, 0x29, 0x1a, 0x32, 0x8e, 0x52, 0xa2, 0x61, + 0x34, 0xec, 0x12, 0x42, 0xb4, 0x0f, 0xbd, 0xc1}, + .exp1_len = 64, + .exp2 = {0xb9, 0xb1, 0xc6, 0x13, 0x2e, 0xe1, 0x22, 0x6e, + 0x6d, 0x10, 0x4e, 0x99, 0x72, 0x5f, 0x0b, 0x38, + 0x35, 0xab, 0x15, 0xe5, 0x91, 0x6a, 0xd1, 0x85, + 0xbe, 0xad, 0x9f, 0x72, 0xed, 0x95, 0x3f, 0x7a, + 0xbf, 0xc5, 0x52, 0x5c, 0xad, 0x75, 0xc2, 0x80, + 0xd2, 0x54, 0x28, 0x94, 0xb2, 0x65, 0xb8, 0x65, + 0x3a, 0x2d, 0xb7, 0x75, 0x33, 0x6d, 0xfb, 0xe6, + 0x47, 0x27, 0xed, 0x57, 0xae, 0xa3, 0x74, 0xf7}, + .exp2_len = 64, + .coef = {0x7b, 0x8d, 0x15, 0xa5, 0xdd, 0x28, 0x90, 0xa6, + 0x7d, 0x1b, 0x54, 0x9c, 0x93, 0x5f, 0x58, 0x5a, + 0x38, 0xda, 0x56, 0xf7, 0xc8, 0x15, 0x5a, 0x51, + 0x9d, 0xc8, 0xf1, 0xf6, 0xad, 0xe5, 0x53, 0xd6, + 0x37, 0x93, 0xc7, 0x8a, 0x0e, 0xce, 0x8d, 0x53, + 0x72, 0x4e, 0x62, 0xae, 0x50, 0x3a, 0xd5, 0x25, + 0xbf, 0xaf, 0x10, 0xcf, 0x61, 0x6a, 0x47, 0x73, + 0xce, 0x7c, 0xcd, 0x5c, 0x1b, 0x31, 0x51, 0xbd}, + .coef_len = 64, + .msg = {0xc1, 0x11, 0x46, 0x4e, 0x00, 0x2e, 0x4e, 0xc6, + 0x18, 0xa8, 0xe2, 0x63, 0xdb, 0xcc, 0xa9, 0x1f, + 0xb1, 0x8a, 0x00, 0xa1, 0x8b, 0x44, 0x0c, 0x4b, + 0x55, 0x97, 0xbe, 0xe7, 0xdb, 0x2a, 0xed, 0xa8, + 0x31, 0xe6, 0x21, 0xfc, 0xac, 0x8d, 0xd8, 0x1c, + 0xee, 0x35, 0x03, 0x24, 0x2b, 0x33, 0xb0, 0xda, + 0xa9, 0x87, 0xfe, 0x2f, 0x54, 0x93, 0xad, 0x2d, + 0x06, 0xa1, 0x50, 0x07, 0x59, 0x00, 0x40, 0xce, + 0x3c, 0x22, 0x77, 0x64, 0x2f, 0xd2, 0x7f, 0x3f, + 0x25, 0x5e, 0x3d, 0x98, 0xd8, 0x9d, 0xfa, 0xeb, + 0x86, 0xbe, 0x34, 0xe0, 0xb8, 0xfb, 0xb9, 0x35, + 0xfb, 0x92, 0x85, 0x60, 0xfa, 0x29, 0x2d, 0x26, + 0x34, 0x62, 0x5a, 0x50, 0x7d, 0xd5, 0x80, 0xa8, + 0x91, 0x24, 0xb9, 0x21, 0x29, 0x3e, 0x8d, 0xfe, + 0xdd, 0xc2, 0x81, 0xd7, 0x9e, 0xb3, 0xa5, 0x69, + 0xd5, 0x9e, 0x0d, 0xb8, 0x01, 0x3e, 0x53, 0xf7, + 0xd4, 0xc2, 0xf9, 0x6e, 0x5f, 0x2e, 0xc2, 0x7f, + 0xd8, 0xdd, 0xb0, 0x18, 0x25, 0xd1, 0x7f, 0xca, + 0x40, 0x6d, 0xaa, 0x62, 0x24, 0xc7, 0x60, 0x6d, + 0x2c, 0x91, 0x52, 0x82, 0x09, 0x6a, 0x78, 0x05, + 0x5a, 0x49, 0x62, 0x15, 0x37, 0xb4, 0xf0, 0x25, + 0xa6, 0xe5, 0xb2, 0x12, 0x9b, 0xc8, 0xc1, 0xa4, + 0x07}, + .msg_len = 177, + .sig = {0x6e, 0x7e, 0xaa, 0xd8, 0x04, 0x94, 0x5e, 0xb0, + 0x46, 0x70, 0xdd, 0x86, 0x76, 0xb7, 0x05, 0x7d, + 0x03, 0xac, 0x3e, 0x22, 0x64, 0x65, 0xb1, 0xfb, + 0x84, 0x03, 0xe6, 0xae, 0x79, 0x83, 0xe0, 0xa4, + 0x6a, 0x89, 0xa4, 0xeb, 0x32, 0xbd, 0xc8, 0xe7, + 0xae, 0x5a, 0x53, 0xd4, 0x8a, 0xa6, 0x4b, 0xc9, + 0xc3, 0xdb, 0xc8, 0xcf, 0x9c, 0xd6, 0xdc, 0x6a, + 0x68, 0xfc, 0xea, 0xe9, 0xe2, 0x9f, 0x47, 0x45, + 0xfa, 0x49, 0xe1, 0x8d, 0x18, 0x4d, 0xc5, 0xd2, + 0x6c, 0x4f, 0xeb, 0x35, 0x1f, 0xb4, 0xb2, 0x28, + 0xc4, 0xc1, 0x8c, 0xab, 0xdb, 0xde, 0x86, 0x01, + 0x72, 0x4a, 0xe3, 0x80, 0x3d, 0xb3, 0x05, 0xf2, + 0xa0, 0x76, 0xfa, 0x8a, 0x57, 0xf4, 0x61, 0x0b, + 0x8a, 0x6e, 0x0e, 0xd4, 0x35, 0x75, 0xbe, 0x5d, + 0x5b, 0xfc, 0x16, 0x30, 0x47, 0x9d, 0xf3, 0xbc, + 0xbc, 0x51, 0x51, 0x77, 0xaf, 0xe4, 0x99, 0x4a}, + .sig_len = 128, + .chunks = {25, 25, 50, 25, 25, 25, 0, 2}, + .num_chunks = 8, + }, + { // 5 + .mod = {0xac, 0x13, 0xd9, 0xfd, 0xae, 0x7b, 0x73, 0x35, + 0xb6, 0x9c, 0xd9, 0x85, 0x67, 0xe9, 0x64, 0x7d, + 0x99, 0xbf, 0x37, 0x3a, 0x9e, 0x05, 0xce, 0x34, + 0x35, 0xd6, 0x64, 0x65, 0xf3, 0x28, 0xb7, 0xf7, + 0x33, 0x4b, 0x79, 0x2a, 0xee, 0x7e, 0xfa, 0x04, + 0x4e, 0xbc, 0x4c, 0x7a, 0x30, 0xb2, 0x1a, 0x5d, + 0x7a, 0x89, 0xcd, 0xb3, 0xa3, 0x0d, 0xfc, 0xd9, + 0xfe, 0xe9, 0x99, 0x5e, 0x09, 0x41, 0x5e, 0xdc, + 0x0b, 0xf9, 0xe5, 0xb4, 0xc3, 0xf7, 0x4f, 0xf5, + 0x3f, 0xb4, 0xd2, 0x94, 0x41, 0xbf, 0x1b, 0x7e, + 0xd6, 0xcb, 0xdd, 0x4a, 0x47, 0xf9, 0x25, 0x22, + 0x69, 0xe1, 0x64, 0x6f, 0x6c, 0x1a, 0xee, 0x05, + 0x14, 0xe9, 0x3f, 0x6c, 0xb9, 0xdf, 0x71, 0xd0, + 0x6c, 0x06, 0x0a, 0x21, 0x04, 0xb4, 0x7b, 0x72, + 0x60, 0xac, 0x37, 0xc1, 0x06, 0x86, 0x1d, 0xc7, + 0x8c, 0xa5, 0xa2, 0x5f, 0xaa, 0x9c, 0xb2, 0xe3}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x04, 0x84, 0xcc, 0xef, 0xad, 0x7a, 0x4e, 0x6f, + 0x35, 0xa9, 0x6e, 0xc8, 0xe3, 0x0e, 0xac, 0xf5, + 0xe3, 0x68, 0xb3, 0x11, 0x95, 0xfe, 0xbf, 0x08, + 0x7d, 0xf5, 0x70, 0x53, 0x81, 0x0c, 0x2b, 0xb0, + 0x91, 0x27, 0x45, 0x3a, 0x4c, 0x63, 0x07, 0x3b, + 0xbf, 0xb9, 0x90, 0x24, 0x91, 0x4c, 0xcc, 0x06, + 0x72, 0x66, 0x56, 0x01, 0x86, 0xa1, 0xa2, 0x67, + 0x33, 0x1b, 0x7d, 0x4c, 0x8b, 0xdf, 0xac, 0x96, + 0xfd, 0xa9, 0xf3, 0xf7, 0x0b, 0xec, 0x4e, 0xea, + 0xbc, 0xe7, 0xcd, 0x52, 0x19, 0x34, 0x3c, 0x2e, + 0x49, 0x1c, 0xce, 0x82, 0x7e, 0x44, 0xee, 0x23, + 0x0e, 0x4f, 0x69, 0x58, 0x9e, 0x57, 0x5a, 0xe9, + 0x06, 0x30, 0x30, 0x44, 0x2a, 0x31, 0xc8, 0x2c, + 0xde, 0x30, 0xdc, 0x9c, 0x79, 0xcf, 0x64, 0xe7, + 0xa0, 0x97, 0x5e, 0x75, 0xe1, 0x6e, 0xa4, 0x58, + 0x15, 0x48, 0x8b, 0x45, 0x52, 0x56, 0xee, 0xb1}, + .privexp_len = 128, + .prime1 = {0xdf, 0x85, 0xf4, 0xa0, 0xb4, 0x33, 0xbd, 0x37, + 0x43, 0x3c, 0xd7, 0x97, 0x8c, 0x9b, 0x37, 0xf9, + 0xe4, 0x17, 0x29, 0xd8, 0x3a, 0x26, 0x2b, 0x98, + 0x46, 0x53, 0x8e, 0x50, 0x39, 0xe6, 0x59, 0x68, + 0xb5, 0x95, 0xa4, 0x62, 0x72, 0xbd, 0x5f, 0x4a, + 0x2c, 0x3a, 0xbf, 0x89, 0x0a, 0x35, 0x50, 0x8a, + 0x5b, 0xcb, 0x4c, 0x29, 0xef, 0xbd, 0x91, 0x02, + 0x85, 0x03, 0x83, 0x4c, 0xfa, 0xb2, 0xc0, 0xf9}, + .prime1_len = 64, + .prime2 = {0xc5, 0x14, 0x59, 0xa6, 0x72, 0xed, 0x8b, 0x72, + 0x4c, 0x6a, 0x8f, 0x28, 0x5c, 0xbb, 0x8e, 0xa7, + 0x6a, 0x23, 0x93, 0x91, 0x79, 0x28, 0xbe, 0x56, + 0xc0, 0xdc, 0xdf, 0xc9, 0x43, 0xc3, 0x0b, 0xda, + 0x3c, 0xee, 0xfb, 0x86, 0xdc, 0xc8, 0xc4, 0x55, + 0x67, 0x8c, 0xfe, 0x88, 0x25, 0xf3, 0x88, 0x77, + 0xa3, 0x72, 0x8a, 0x1f, 0x10, 0x29, 0x1f, 0x54, + 0x7b, 0x1e, 0x8b, 0x16, 0x04, 0x83, 0xe5, 0xbb}, + .prime2_len = 64, + .exp1 = {0xb6, 0xba, 0x83, 0xa9, 0x7c, 0xa7, 0x6f, 0x5f, + 0xe6, 0x0f, 0xaf, 0x0f, 0xad, 0x5a, 0x97, 0x00, + 0x2a, 0x7e, 0xe5, 0x2e, 0x67, 0x1b, 0x1d, 0x38, + 0x77, 0x05, 0x87, 0xa9, 0xfe, 0x2b, 0x59, 0x9c, + 0x48, 0x15, 0xf5, 0x34, 0xa6, 0x28, 0x39, 0xe6, + 0x21, 0x12, 0x45, 0xd2, 0x7a, 0x0d, 0xeb, 0xb1, + 0xb0, 0x29, 0x1a, 0x32, 0x8e, 0x52, 0xa2, 0x61, + 0x34, 0xec, 0x12, 0x42, 0xb4, 0x0f, 0xbd, 0xc1}, + .exp1_len = 64, + .exp2 = {0xb9, 0xb1, 0xc6, 0x13, 0x2e, 0xe1, 0x22, 0x6e, + 0x6d, 0x10, 0x4e, 0x99, 0x72, 0x5f, 0x0b, 0x38, + 0x35, 0xab, 0x15, 0xe5, 0x91, 0x6a, 0xd1, 0x85, + 0xbe, 0xad, 0x9f, 0x72, 0xed, 0x95, 0x3f, 0x7a, + 0xbf, 0xc5, 0x52, 0x5c, 0xad, 0x75, 0xc2, 0x80, + 0xd2, 0x54, 0x28, 0x94, 0xb2, 0x65, 0xb8, 0x65, + 0x3a, 0x2d, 0xb7, 0x75, 0x33, 0x6d, 0xfb, 0xe6, + 0x47, 0x27, 0xed, 0x57, 0xae, 0xa3, 0x74, 0xf7}, + .exp2_len = 64, + .coef = {0x7b, 0x8d, 0x15, 0xa5, 0xdd, 0x28, 0x90, 0xa6, + 0x7d, 0x1b, 0x54, 0x9c, 0x93, 0x5f, 0x58, 0x5a, + 0x38, 0xda, 0x56, 0xf7, 0xc8, 0x15, 0x5a, 0x51, + 0x9d, 0xc8, 0xf1, 0xf6, 0xad, 0xe5, 0x53, 0xd6, + 0x37, 0x93, 0xc7, 0x8a, 0x0e, 0xce, 0x8d, 0x53, + 0x72, 0x4e, 0x62, 0xae, 0x50, 0x3a, 0xd5, 0x25, + 0xbf, 0xaf, 0x10, 0xcf, 0x61, 0x6a, 0x47, 0x73, + 0xce, 0x7c, 0xcd, 0x5c, 0x1b, 0x31, 0x51, 0xbd}, + .coef_len = 64, + .msg = {0x29, 0xb8, 0x5b, 0x14, 0xb2, 0xda, 0x94, 0x7a, + 0x4c, 0x3a, 0xd1, 0xe5, 0x93, 0x7d, 0xa1, 0x92, + 0xc6, 0x05, 0x08, 0x65, 0xaf, 0x95, 0x04, 0xa5, + 0x44, 0x53, 0x70, 0xe4, 0x3d, 0x3a, 0x8d, 0xa5, + 0xd3, 0x55, 0xfd, 0x58, 0x76, 0x6b, 0x25, 0x43, + 0xac, 0x6f, 0x93, 0x10, 0x87, 0x83, 0xc1, 0x3f, + 0xf2, 0x8b, 0x2b, 0xe5, 0x60, 0x83, 0xf0, 0x29, + 0x82, 0x39, 0xe0, 0xee, 0x96, 0x81, 0xee, 0x47, + 0xc6}, + .msg_len = 65, + .sig = {0x80, 0xb3, 0x8c, 0xe7, 0x35, 0x12, 0x6c, 0x85, + 0x45, 0xd9, 0x1d, 0x18, 0xec, 0x90, 0x37, 0x65, + 0x4d, 0x46, 0xe4, 0xf3, 0xc5, 0x1a, 0x6b, 0x86, + 0x18, 0xe1, 0x5f, 0x72, 0xcd, 0x20, 0x75, 0x00, + 0xa4, 0x70, 0x01, 0x75, 0x77, 0xd0, 0xa8, 0xc5, + 0x5a, 0x2b, 0xa3, 0x34, 0x38, 0x3f, 0x1f, 0x8d, + 0x99, 0xfc, 0xe2, 0x46, 0x0b, 0x32, 0x97, 0xbc, + 0x03, 0x7e, 0xf6, 0x4a, 0xc4, 0xa3, 0x09, 0x8c, + 0x6a, 0xaa, 0x24, 0xa4, 0xd0, 0x14, 0x4a, 0xf1, + 0x02, 0xd0, 0xdd, 0xa1, 0x7e, 0x07, 0xdc, 0x69, + 0x59, 0x23, 0x93, 0x2e, 0x56, 0x8a, 0xda, 0x00, + 0xdc, 0x4f, 0x7d, 0xbf, 0xbc, 0xde, 0xc4, 0x3c, + 0xc9, 0x08, 0x38, 0x80, 0x17, 0xd2, 0xee, 0xf0, + 0x4e, 0x60, 0xdf, 0xe4, 0xd5, 0x73, 0x40, 0xfa, + 0xb9, 0x16, 0xe2, 0xb8, 0x11, 0x24, 0x4c, 0xb1, + 0xe4, 0xa5, 0x52, 0x38, 0x6f, 0xe3, 0xed, 0x4c}, + .sig_len = 128, + }, + { // 6 + .mod = {0xb5, 0xd7, 0x07, 0xb7, 0x92, 0xe0, 0x56, 0xf7, + 0x2f, 0xd7, 0x6d, 0x8d, 0xa8, 0x89, 0xa5, 0x3c, + 0xe4, 0xd8, 0xeb, 0xaa, 0x08, 0x2a, 0xee, 0xb2, + 0x30, 0x32, 0xe3, 0xc5, 0xd8, 0xeb, 0xc4, 0xc1, + 0x55, 0x61, 0x31, 0x9b, 0xe8, 0xdf, 0xe1, 0x88, + 0x99, 0x1a, 0x89, 0x51, 0xd4, 0xb2, 0x3a, 0x51, + 0xe8, 0xa9, 0x38, 0x2c, 0x80, 0x5e, 0x4c, 0xfd, + 0x49, 0x0e, 0xbb, 0xce, 0xaa, 0x20, 0x80, 0x2a, + 0xd6, 0x83, 0xb0, 0x5a, 0x10, 0x0f, 0x29, 0x98, + 0x5f, 0x01, 0x1c, 0x3c, 0x8a, 0x44, 0x26, 0x25, + 0x52, 0xd8, 0x3d, 0x9a, 0x1b, 0x7c, 0x27, 0x31, + 0x5e, 0x14, 0x4a, 0xd8, 0xdf, 0x5c, 0xbe, 0x8b, + 0xc6, 0x40, 0x0f, 0xd9, 0xcb, 0xe7, 0x6b, 0x74, + 0x21, 0xd7, 0x08, 0xaa, 0x64, 0xf0, 0x40, 0xba, + 0xe0, 0x7b, 0x7b, 0xd6, 0xf9, 0x22, 0x18, 0xf9, + 0xa7, 0x29, 0x28, 0x4c, 0xc5, 0x98, 0xcd, 0xd1}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x45, 0x17, 0x92, 0xb5, 0x94, 0x47, 0xcc, 0x93, + 0x78, 0xa8, 0xa4, 0xd6, 0x45, 0xfb, 0x22, 0xff, + 0x4b, 0xbf, 0x06, 0x70, 0x61, 0x51, 0x1a, 0xc8, + 0x36, 0xdb, 0x27, 0x43, 0xa6, 0x24, 0x13, 0x6b, + 0x18, 0x6b, 0x69, 0x43, 0xa1, 0xcc, 0xeb, 0x6f, + 0x91, 0x29, 0x0d, 0x93, 0x3b, 0xbb, 0x8a, 0xc0, + 0x53, 0xa4, 0x74, 0x95, 0x28, 0x23, 0x6c, 0xa2, + 0x72, 0xcf, 0x77, 0xd9, 0xd3, 0x37, 0xad, 0x2a, + 0xb3, 0x6a, 0x87, 0xa9, 0x15, 0x3c, 0x5e, 0x16, + 0x71, 0x6e, 0x09, 0xba, 0x0b, 0xea, 0xa6, 0x4b, + 0x31, 0x25, 0x26, 0xd4, 0xa8, 0xc2, 0xdc, 0x68, + 0xfe, 0x09, 0xe3, 0x7e, 0x50, 0x74, 0xa0, 0x90, + 0x9d, 0x3f, 0x04, 0xab, 0x73, 0x90, 0x8a, 0x98, + 0x0d, 0xec, 0x1d, 0xa7, 0xeb, 0x45, 0x05, 0xa4, + 0x8b, 0xca, 0xd3, 0xb6, 0x0d, 0x01, 0x60, 0x84, + 0x58, 0x64, 0xa6, 0x51, 0x1f, 0xf5, 0x59, 0xa7}, + .privexp_len = 128, + .prime1 = {0xff, 0xa9, 0xf8, 0xe8, 0xb0, 0x82, 0x17, 0x0b, + 0x63, 0x73, 0xf0, 0x0d, 0x73, 0xc4, 0x23, 0x86, + 0xd4, 0x02, 0xf2, 0x80, 0x8b, 0x39, 0x3b, 0x32, + 0xf7, 0x8f, 0x86, 0xea, 0xf6, 0x4b, 0x21, 0xbf, + 0xdd, 0x33, 0x4f, 0xb9, 0xaa, 0xd1, 0x6b, 0xa6, + 0xd9, 0xda, 0xdb, 0xc8, 0x94, 0x3a, 0x29, 0xe6, + 0x63, 0xc8, 0xb3, 0x9c, 0x09, 0x59, 0x69, 0x02, + 0x5b, 0xb9, 0xb2, 0xd9, 0xd6, 0xfe, 0x67, 0xb7}, + .prime1_len = 64, + .prime2 = {0xb6, 0x14, 0x37, 0x8d, 0x5e, 0x3d, 0xa5, 0xa8, + 0x0a, 0x6d, 0x73, 0x52, 0xfc, 0x66, 0xa5, 0x64, + 0x59, 0x7b, 0x06, 0x8f, 0xc9, 0xd3, 0xaf, 0x5d, + 0xb0, 0xe4, 0xe7, 0x35, 0xbe, 0xf8, 0x81, 0xdd, + 0x40, 0x17, 0xee, 0x70, 0x82, 0x96, 0x19, 0x0b, + 0x6f, 0xdc, 0x84, 0x04, 0xf0, 0x7b, 0xd9, 0xdc, + 0x5c, 0xd5, 0xd2, 0xbe, 0x48, 0x86, 0xa7, 0xcb, + 0xbc, 0xb2, 0x1d, 0x8c, 0x3d, 0x64, 0xa6, 0xb7}, + .prime2_len = 64, + .exp1 = {0x51, 0x0e, 0x68, 0x96, 0x0d, 0x70, 0x11, 0x32, + 0x51, 0x23, 0xae, 0xd5, 0xf5, 0x00, 0x18, 0x6b, + 0x64, 0xc8, 0x52, 0x6e, 0x22, 0xb5, 0xd0, 0x69, + 0x06, 0x48, 0x00, 0xf4, 0x79, 0x85, 0xb4, 0x7b, + 0x89, 0xfb, 0xfc, 0xa8, 0xd6, 0xd9, 0x72, 0x92, + 0x01, 0xbb, 0xfb, 0xb6, 0x8a, 0x18, 0x2e, 0xb4, + 0x96, 0xaa, 0x49, 0x17, 0x8d, 0x77, 0x45, 0x6d, + 0xb3, 0xfb, 0x1a, 0x13, 0x2a, 0xb0, 0x99, 0xdd}, + .exp1_len = 64, + .exp2 = {0x57, 0xeb, 0xbf, 0x3f, 0x76, 0x48, 0x52, 0x5b, + 0xa8, 0x5d, 0x5d, 0x98, 0xae, 0xe4, 0x69, 0xec, + 0xe1, 0x00, 0x75, 0x14, 0xad, 0xa2, 0x98, 0x45, + 0xa7, 0x8b, 0x80, 0xd2, 0x05, 0x1b, 0x3e, 0xaa, + 0x35, 0xae, 0xd8, 0xa6, 0x5f, 0x88, 0x57, 0x23, + 0x9c, 0xaa, 0x60, 0xdd, 0x79, 0xba, 0x74, 0x62, + 0xe2, 0x39, 0x26, 0x00, 0x58, 0x49, 0x1d, 0x71, + 0x55, 0xf6, 0xb4, 0x29, 0xe9, 0xe3, 0x56, 0x55}, + .exp2_len = 64, + .coef = {0xee, 0x10, 0x7d, 0xc7, 0xef, 0xec, 0xe9, 0xa6, + 0x5c, 0x0e, 0x87, 0x78, 0x9a, 0xf5, 0x59, 0x0c, + 0x93, 0x83, 0x9d, 0xfe, 0x82, 0x85, 0x20, 0xda, + 0x17, 0x74, 0xff, 0x80, 0xf7, 0xe5, 0x14, 0x55, + 0x7f, 0xff, 0x10, 0xbd, 0x8c, 0xae, 0x18, 0x46, + 0xef, 0xee, 0x7c, 0x10, 0xd7, 0xa1, 0x2c, 0x4a, + 0x05, 0x5c, 0xc1, 0x36, 0xe4, 0xa4, 0xef, 0x25, + 0xfd, 0x3e, 0xd9, 0xd0, 0xcd, 0xdf, 0x74, 0xf9}, + .coef_len = 64, + .msg = {0x98, 0x6e, 0x7c, 0x43, 0xdb, 0xb6, 0x71, 0xbd, + 0x41, 0xb9, 0xa7, 0xf4, 0xb6, 0xaf, 0xc8, 0x0e, + 0x80, 0x5f, 0x24, 0x23, 0x48, 0x8f, 0xb4, 0x31, + 0xf5, 0xee, 0x79, 0x2b, 0x6c, 0x2a, 0xc7, 0xdb, + 0x53, 0xcc, 0x42, 0x86, 0x55, 0xae, 0xb3, 0x2d, + 0x03, 0xf4, 0xe8, 0x89, 0xc5, 0xc2, 0x5d, 0xe6, + 0x83, 0xc4, 0x61, 0xb5, 0x3a, 0xcf, 0x89, 0xf9, + 0xf8, 0xd3, 0xaa, 0xbd, 0xf6, 0xb9, 0xf0, 0xc2, + 0xa1, 0xde, 0x12, 0xe1, 0x5b, 0x49, 0xed, 0xb3, + 0x91, 0x9a, 0x65, 0x2f, 0xe9, 0x49, 0x1c, 0x25, + 0xa7, 0xfc}, + .msg_len = 82, + .sig = {0x62, 0x75, 0xe8, 0x73, 0x97, 0xe3, 0x09, 0x2a, + 0xab, 0x36, 0x98, 0xbb, 0x1b, 0x5c, 0xf2, 0x4b, + 0x8c, 0xd7, 0x71, 0x2b, 0xec, 0xac, 0x35, 0xe3, + 0x22, 0x03, 0xd5, 0x43, 0x14, 0xe5, 0x47, 0x0e, + 0xa9, 0xaa, 0xbc, 0x86, 0x57, 0xf5, 0x64, 0x34, + 0xe5, 0xaf, 0x9f, 0xae, 0x77, 0x8f, 0xf6, 0x04, + 0x5c, 0x20, 0xe2, 0xe1, 0xef, 0x7c, 0xbd, 0xf8, + 0x8f, 0x00, 0x75, 0xf3, 0x3e, 0xa9, 0x92, 0x77, + 0x7c, 0xb7, 0xe9, 0x2f, 0x7d, 0xa1, 0x8a, 0x0f, + 0xfd, 0x00, 0xaa, 0x46, 0x71, 0xed, 0x63, 0x91, + 0x1f, 0xe9, 0xe9, 0x2f, 0xb4, 0xa7, 0x6e, 0x77, + 0xdc, 0x6e, 0x0a, 0x91, 0x65, 0x76, 0x71, 0x6c, + 0x15, 0xea, 0xef, 0x08, 0x9a, 0x71, 0xa0, 0xae, + 0xa3, 0x5b, 0xed, 0x94, 0x47, 0xa6, 0xc1, 0x7f, + 0x2a, 0xad, 0xb7, 0x27, 0xfd, 0x42, 0xf0, 0xac, + 0xc8, 0x24, 0x62, 0x38, 0x1d, 0x9f, 0xa2, 0xef}, + .sig_len = 128, + .chunks = {40, 42}, + .num_chunks = 2, + }, + { // 7 + .mod = {0xb5, 0xd7, 0x07, 0xb7, 0x92, 0xe0, 0x56, 0xf7, + 0x2f, 0xd7, 0x6d, 0x8d, 0xa8, 0x89, 0xa5, 0x3c, + 0xe4, 0xd8, 0xeb, 0xaa, 0x08, 0x2a, 0xee, 0xb2, + 0x30, 0x32, 0xe3, 0xc5, 0xd8, 0xeb, 0xc4, 0xc1, + 0x55, 0x61, 0x31, 0x9b, 0xe8, 0xdf, 0xe1, 0x88, + 0x99, 0x1a, 0x89, 0x51, 0xd4, 0xb2, 0x3a, 0x51, + 0xe8, 0xa9, 0x38, 0x2c, 0x80, 0x5e, 0x4c, 0xfd, + 0x49, 0x0e, 0xbb, 0xce, 0xaa, 0x20, 0x80, 0x2a, + 0xd6, 0x83, 0xb0, 0x5a, 0x10, 0x0f, 0x29, 0x98, + 0x5f, 0x01, 0x1c, 0x3c, 0x8a, 0x44, 0x26, 0x25, + 0x52, 0xd8, 0x3d, 0x9a, 0x1b, 0x7c, 0x27, 0x31, + 0x5e, 0x14, 0x4a, 0xd8, 0xdf, 0x5c, 0xbe, 0x8b, + 0xc6, 0x40, 0x0f, 0xd9, 0xcb, 0xe7, 0x6b, 0x74, + 0x21, 0xd7, 0x08, 0xaa, 0x64, 0xf0, 0x40, 0xba, + 0xe0, 0x7b, 0x7b, 0xd6, 0xf9, 0x22, 0x18, 0xf9, + 0xa7, 0x29, 0x28, 0x4c, 0xc5, 0x98, 0xcd, 0xd1}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x45, 0x17, 0x92, 0xb5, 0x94, 0x47, 0xcc, 0x93, + 0x78, 0xa8, 0xa4, 0xd6, 0x45, 0xfb, 0x22, 0xff, + 0x4b, 0xbf, 0x06, 0x70, 0x61, 0x51, 0x1a, 0xc8, + 0x36, 0xdb, 0x27, 0x43, 0xa6, 0x24, 0x13, 0x6b, + 0x18, 0x6b, 0x69, 0x43, 0xa1, 0xcc, 0xeb, 0x6f, + 0x91, 0x29, 0x0d, 0x93, 0x3b, 0xbb, 0x8a, 0xc0, + 0x53, 0xa4, 0x74, 0x95, 0x28, 0x23, 0x6c, 0xa2, + 0x72, 0xcf, 0x77, 0xd9, 0xd3, 0x37, 0xad, 0x2a, + 0xb3, 0x6a, 0x87, 0xa9, 0x15, 0x3c, 0x5e, 0x16, + 0x71, 0x6e, 0x09, 0xba, 0x0b, 0xea, 0xa6, 0x4b, + 0x31, 0x25, 0x26, 0xd4, 0xa8, 0xc2, 0xdc, 0x68, + 0xfe, 0x09, 0xe3, 0x7e, 0x50, 0x74, 0xa0, 0x90, + 0x9d, 0x3f, 0x04, 0xab, 0x73, 0x90, 0x8a, 0x98, + 0x0d, 0xec, 0x1d, 0xa7, 0xeb, 0x45, 0x05, 0xa4, + 0x8b, 0xca, 0xd3, 0xb6, 0x0d, 0x01, 0x60, 0x84, + 0x58, 0x64, 0xa6, 0x51, 0x1f, 0xf5, 0x59, 0xa7}, + .privexp_len = 128, + .prime1 = {0xff, 0xa9, 0xf8, 0xe8, 0xb0, 0x82, 0x17, 0x0b, + 0x63, 0x73, 0xf0, 0x0d, 0x73, 0xc4, 0x23, 0x86, + 0xd4, 0x02, 0xf2, 0x80, 0x8b, 0x39, 0x3b, 0x32, + 0xf7, 0x8f, 0x86, 0xea, 0xf6, 0x4b, 0x21, 0xbf, + 0xdd, 0x33, 0x4f, 0xb9, 0xaa, 0xd1, 0x6b, 0xa6, + 0xd9, 0xda, 0xdb, 0xc8, 0x94, 0x3a, 0x29, 0xe6, + 0x63, 0xc8, 0xb3, 0x9c, 0x09, 0x59, 0x69, 0x02, + 0x5b, 0xb9, 0xb2, 0xd9, 0xd6, 0xfe, 0x67, 0xb7}, + .prime1_len = 64, + .prime2 = {0xb6, 0x14, 0x37, 0x8d, 0x5e, 0x3d, 0xa5, 0xa8, + 0x0a, 0x6d, 0x73, 0x52, 0xfc, 0x66, 0xa5, 0x64, + 0x59, 0x7b, 0x06, 0x8f, 0xc9, 0xd3, 0xaf, 0x5d, + 0xb0, 0xe4, 0xe7, 0x35, 0xbe, 0xf8, 0x81, 0xdd, + 0x40, 0x17, 0xee, 0x70, 0x82, 0x96, 0x19, 0x0b, + 0x6f, 0xdc, 0x84, 0x04, 0xf0, 0x7b, 0xd9, 0xdc, + 0x5c, 0xd5, 0xd2, 0xbe, 0x48, 0x86, 0xa7, 0xcb, + 0xbc, 0xb2, 0x1d, 0x8c, 0x3d, 0x64, 0xa6, 0xb7}, + .prime2_len = 64, + .exp1 = {0x51, 0x0e, 0x68, 0x96, 0x0d, 0x70, 0x11, 0x32, + 0x51, 0x23, 0xae, 0xd5, 0xf5, 0x00, 0x18, 0x6b, + 0x64, 0xc8, 0x52, 0x6e, 0x22, 0xb5, 0xd0, 0x69, + 0x06, 0x48, 0x00, 0xf4, 0x79, 0x85, 0xb4, 0x7b, + 0x89, 0xfb, 0xfc, 0xa8, 0xd6, 0xd9, 0x72, 0x92, + 0x01, 0xbb, 0xfb, 0xb6, 0x8a, 0x18, 0x2e, 0xb4, + 0x96, 0xaa, 0x49, 0x17, 0x8d, 0x77, 0x45, 0x6d, + 0xb3, 0xfb, 0x1a, 0x13, 0x2a, 0xb0, 0x99, 0xdd}, + .exp1_len = 64, + .exp2 = {0x57, 0xeb, 0xbf, 0x3f, 0x76, 0x48, 0x52, 0x5b, + 0xa8, 0x5d, 0x5d, 0x98, 0xae, 0xe4, 0x69, 0xec, + 0xe1, 0x00, 0x75, 0x14, 0xad, 0xa2, 0x98, 0x45, + 0xa7, 0x8b, 0x80, 0xd2, 0x05, 0x1b, 0x3e, 0xaa, + 0x35, 0xae, 0xd8, 0xa6, 0x5f, 0x88, 0x57, 0x23, + 0x9c, 0xaa, 0x60, 0xdd, 0x79, 0xba, 0x74, 0x62, + 0xe2, 0x39, 0x26, 0x00, 0x58, 0x49, 0x1d, 0x71, + 0x55, 0xf6, 0xb4, 0x29, 0xe9, 0xe3, 0x56, 0x55}, + .exp2_len = 64, + .coef = {0xee, 0x10, 0x7d, 0xc7, 0xef, 0xec, 0xe9, 0xa6, + 0x5c, 0x0e, 0x87, 0x78, 0x9a, 0xf5, 0x59, 0x0c, + 0x93, 0x83, 0x9d, 0xfe, 0x82, 0x85, 0x20, 0xda, + 0x17, 0x74, 0xff, 0x80, 0xf7, 0xe5, 0x14, 0x55, + 0x7f, 0xff, 0x10, 0xbd, 0x8c, 0xae, 0x18, 0x46, + 0xef, 0xee, 0x7c, 0x10, 0xd7, 0xa1, 0x2c, 0x4a, + 0x05, 0x5c, 0xc1, 0x36, 0xe4, 0xa4, 0xef, 0x25, + 0xfd, 0x3e, 0xd9, 0xd0, 0xcd, 0xdf, 0x74, 0xf9}, + .coef_len = 64, + .msg = {0x4c, 0x7b, 0x98, 0x12, 0x0c, 0x87, 0x50, 0x90, + 0x87, 0xc4, 0x78}, + .msg_len = 11, + .sig = {0x59, 0xe5, 0xcb, 0xe7, 0x33, 0x1b, 0x92, 0xe0, + 0xcb, 0x8f, 0x68, 0x9e, 0xae, 0xbb, 0x30, 0xf2, + 0xb3, 0x34, 0xa7, 0x46, 0xa6, 0x57, 0x05, 0x59, + 0x12, 0xff, 0x1c, 0x92, 0x76, 0x0b, 0x0b, 0x85, + 0xbc, 0x42, 0x82, 0xf3, 0x18, 0x4b, 0x9a, 0x81, + 0x4f, 0x44, 0x37, 0xf8, 0x25, 0xae, 0x07, 0xd3, + 0x56, 0xba, 0xc6, 0x9e, 0x54, 0x0c, 0x90, 0x94, + 0x2c, 0x7f, 0x7e, 0x6f, 0xf4, 0x4f, 0xe5, 0x74, + 0xf1, 0x21, 0x25, 0x0a, 0xd2, 0x30, 0xf4, 0xb5, + 0x0c, 0x78, 0x31, 0x1e, 0x4f, 0xd3, 0xc9, 0xe2, + 0x65, 0xf5, 0x17, 0xce, 0x32, 0x97, 0xc3, 0xe1, + 0xdd, 0xdb, 0x5c, 0x86, 0x9c, 0x69, 0x8f, 0x44, + 0xaf, 0x52, 0x5e, 0x73, 0x64, 0x01, 0xa8, 0x1b, + 0x45, 0x9f, 0x19, 0x8a, 0xd1, 0x80, 0x8c, 0xcd, + 0x92, 0x9d, 0x49, 0x04, 0x74, 0xca, 0xf7, 0x00, + 0x5f, 0x91, 0x0d, 0xac, 0xde, 0x21, 0xb0, 0x77}, + .sig_len = 128, + .chunks = {5, 3, 0, 3}, + .num_chunks = 4, + }, + { // 8 + .mod = {0xb5, 0xd7, 0x07, 0xb7, 0x92, 0xe0, 0x56, 0xf7, + 0x2f, 0xd7, 0x6d, 0x8d, 0xa8, 0x89, 0xa5, 0x3c, + 0xe4, 0xd8, 0xeb, 0xaa, 0x08, 0x2a, 0xee, 0xb2, + 0x30, 0x32, 0xe3, 0xc5, 0xd8, 0xeb, 0xc4, 0xc1, + 0x55, 0x61, 0x31, 0x9b, 0xe8, 0xdf, 0xe1, 0x88, + 0x99, 0x1a, 0x89, 0x51, 0xd4, 0xb2, 0x3a, 0x51, + 0xe8, 0xa9, 0x38, 0x2c, 0x80, 0x5e, 0x4c, 0xfd, + 0x49, 0x0e, 0xbb, 0xce, 0xaa, 0x20, 0x80, 0x2a, + 0xd6, 0x83, 0xb0, 0x5a, 0x10, 0x0f, 0x29, 0x98, + 0x5f, 0x01, 0x1c, 0x3c, 0x8a, 0x44, 0x26, 0x25, + 0x52, 0xd8, 0x3d, 0x9a, 0x1b, 0x7c, 0x27, 0x31, + 0x5e, 0x14, 0x4a, 0xd8, 0xdf, 0x5c, 0xbe, 0x8b, + 0xc6, 0x40, 0x0f, 0xd9, 0xcb, 0xe7, 0x6b, 0x74, + 0x21, 0xd7, 0x08, 0xaa, 0x64, 0xf0, 0x40, 0xba, + 0xe0, 0x7b, 0x7b, 0xd6, 0xf9, 0x22, 0x18, 0xf9, + 0xa7, 0x29, 0x28, 0x4c, 0xc5, 0x98, 0xcd, 0xd1}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x45, 0x17, 0x92, 0xb5, 0x94, 0x47, 0xcc, 0x93, + 0x78, 0xa8, 0xa4, 0xd6, 0x45, 0xfb, 0x22, 0xff, + 0x4b, 0xbf, 0x06, 0x70, 0x61, 0x51, 0x1a, 0xc8, + 0x36, 0xdb, 0x27, 0x43, 0xa6, 0x24, 0x13, 0x6b, + 0x18, 0x6b, 0x69, 0x43, 0xa1, 0xcc, 0xeb, 0x6f, + 0x91, 0x29, 0x0d, 0x93, 0x3b, 0xbb, 0x8a, 0xc0, + 0x53, 0xa4, 0x74, 0x95, 0x28, 0x23, 0x6c, 0xa2, + 0x72, 0xcf, 0x77, 0xd9, 0xd3, 0x37, 0xad, 0x2a, + 0xb3, 0x6a, 0x87, 0xa9, 0x15, 0x3c, 0x5e, 0x16, + 0x71, 0x6e, 0x09, 0xba, 0x0b, 0xea, 0xa6, 0x4b, + 0x31, 0x25, 0x26, 0xd4, 0xa8, 0xc2, 0xdc, 0x68, + 0xfe, 0x09, 0xe3, 0x7e, 0x50, 0x74, 0xa0, 0x90, + 0x9d, 0x3f, 0x04, 0xab, 0x73, 0x90, 0x8a, 0x98, + 0x0d, 0xec, 0x1d, 0xa7, 0xeb, 0x45, 0x05, 0xa4, + 0x8b, 0xca, 0xd3, 0xb6, 0x0d, 0x01, 0x60, 0x84, + 0x58, 0x64, 0xa6, 0x51, 0x1f, 0xf5, 0x59, 0xa7}, + .privexp_len = 128, + .prime1 = {0xff, 0xa9, 0xf8, 0xe8, 0xb0, 0x82, 0x17, 0x0b, + 0x63, 0x73, 0xf0, 0x0d, 0x73, 0xc4, 0x23, 0x86, + 0xd4, 0x02, 0xf2, 0x80, 0x8b, 0x39, 0x3b, 0x32, + 0xf7, 0x8f, 0x86, 0xea, 0xf6, 0x4b, 0x21, 0xbf, + 0xdd, 0x33, 0x4f, 0xb9, 0xaa, 0xd1, 0x6b, 0xa6, + 0xd9, 0xda, 0xdb, 0xc8, 0x94, 0x3a, 0x29, 0xe6, + 0x63, 0xc8, 0xb3, 0x9c, 0x09, 0x59, 0x69, 0x02, + 0x5b, 0xb9, 0xb2, 0xd9, 0xd6, 0xfe, 0x67, 0xb7}, + .prime1_len = 64, + .prime2 = {0xb6, 0x14, 0x37, 0x8d, 0x5e, 0x3d, 0xa5, 0xa8, + 0x0a, 0x6d, 0x73, 0x52, 0xfc, 0x66, 0xa5, 0x64, + 0x59, 0x7b, 0x06, 0x8f, 0xc9, 0xd3, 0xaf, 0x5d, + 0xb0, 0xe4, 0xe7, 0x35, 0xbe, 0xf8, 0x81, 0xdd, + 0x40, 0x17, 0xee, 0x70, 0x82, 0x96, 0x19, 0x0b, + 0x6f, 0xdc, 0x84, 0x04, 0xf0, 0x7b, 0xd9, 0xdc, + 0x5c, 0xd5, 0xd2, 0xbe, 0x48, 0x86, 0xa7, 0xcb, + 0xbc, 0xb2, 0x1d, 0x8c, 0x3d, 0x64, 0xa6, 0xb7}, + .prime2_len = 64, + .exp1 = {0x51, 0x0e, 0x68, 0x96, 0x0d, 0x70, 0x11, 0x32, + 0x51, 0x23, 0xae, 0xd5, 0xf5, 0x00, 0x18, 0x6b, + 0x64, 0xc8, 0x52, 0x6e, 0x22, 0xb5, 0xd0, 0x69, + 0x06, 0x48, 0x00, 0xf4, 0x79, 0x85, 0xb4, 0x7b, + 0x89, 0xfb, 0xfc, 0xa8, 0xd6, 0xd9, 0x72, 0x92, + 0x01, 0xbb, 0xfb, 0xb6, 0x8a, 0x18, 0x2e, 0xb4, + 0x96, 0xaa, 0x49, 0x17, 0x8d, 0x77, 0x45, 0x6d, + 0xb3, 0xfb, 0x1a, 0x13, 0x2a, 0xb0, 0x99, 0xdd}, + .exp1_len = 64, + .exp2 = {0x57, 0xeb, 0xbf, 0x3f, 0x76, 0x48, 0x52, 0x5b, + 0xa8, 0x5d, 0x5d, 0x98, 0xae, 0xe4, 0x69, 0xec, + 0xe1, 0x00, 0x75, 0x14, 0xad, 0xa2, 0x98, 0x45, + 0xa7, 0x8b, 0x80, 0xd2, 0x05, 0x1b, 0x3e, 0xaa, + 0x35, 0xae, 0xd8, 0xa6, 0x5f, 0x88, 0x57, 0x23, + 0x9c, 0xaa, 0x60, 0xdd, 0x79, 0xba, 0x74, 0x62, + 0xe2, 0x39, 0x26, 0x00, 0x58, 0x49, 0x1d, 0x71, + 0x55, 0xf6, 0xb4, 0x29, 0xe9, 0xe3, 0x56, 0x55}, + .exp2_len = 64, + .coef = {0xee, 0x10, 0x7d, 0xc7, 0xef, 0xec, 0xe9, 0xa6, + 0x5c, 0x0e, 0x87, 0x78, 0x9a, 0xf5, 0x59, 0x0c, + 0x93, 0x83, 0x9d, 0xfe, 0x82, 0x85, 0x20, 0xda, + 0x17, 0x74, 0xff, 0x80, 0xf7, 0xe5, 0x14, 0x55, + 0x7f, 0xff, 0x10, 0xbd, 0x8c, 0xae, 0x18, 0x46, + 0xef, 0xee, 0x7c, 0x10, 0xd7, 0xa1, 0x2c, 0x4a, + 0x05, 0x5c, 0xc1, 0x36, 0xe4, 0xa4, 0xef, 0x25, + 0xfd, 0x3e, 0xd9, 0xd0, 0xcd, 0xdf, 0x74, 0xf9}, + .coef_len = 64, + .msg = {0x66, 0xf7, 0x07, 0x54, 0x22, 0xc8, 0xec, 0x42, + 0x16, 0xa9, 0xc4, 0xff, 0x49, 0x42, 0x7d, 0x48, + 0x3c, 0xae, 0x10, 0xc8, 0x53, 0x4a, 0x41, 0xb2, + 0xfd, 0x15, 0xfe, 0xe0, 0x69, 0x60, 0xec, 0x6f, + 0xb3, 0xf7, 0xa7, 0xe9, 0x4a, 0x2f, 0x8a, 0x2e, + 0x3e, 0x43, 0xdc, 0x4a, 0x40, 0x57, 0x6c, 0x30, + 0x97, 0xac, 0x95, 0x3b, 0x1d, 0xe8, 0x6f, 0x0b, + 0x4e, 0xd3, 0x6d, 0x64, 0x4f, 0x23, 0xae, 0x14, + 0x42, 0x55, 0x29, 0x62, 0x24, 0x64, 0xca, 0x0c, + 0xbf, 0x0b, 0x17, 0x41, 0x34, 0x72, 0x38, 0x15, + 0x7f, 0xab, 0x59, 0xe4, 0xde, 0x55, 0x24, 0x09, + 0x6d, 0x62, 0xba, 0xec, 0x63, 0xac, 0x64, 0x50, + 0x32, 0x7e, 0xfe, 0xc6, 0x29, 0x2f, 0x98, 0x01, + 0x9f, 0xc6, 0x7a, 0x2a, 0x66, 0x38, 0x56, 0x3e, + 0x9b, 0x6e, 0x2d, 0x15, 0xef, 0xd2, 0x37, 0xbb, + 0x09, 0x8a, 0x44, 0x3a, 0xee, 0xb2, 0xbf, 0x6c, + 0x3f, 0x8c, 0x81, 0xb8, 0xc0, 0x1b, 0x7f, 0xcb, + 0x3f, 0xeb, 0xb0, 0xde, 0x3f, 0xc2, 0x5b, 0x65, + 0xf5, 0xaf, 0x96, 0xb1, 0xd5, 0xcc, 0x3b, 0x27, + 0xd0, 0xc6, 0x05, 0x30, 0x87, 0xb3, 0x96, 0x80, + 0xe4, 0x92, 0xa4, 0xab, 0x23, 0x67, 0x47, 0x11, + 0x69, 0xe5, 0x28, 0x38, 0x94, 0x5d, 0xba, 0x9d, + 0xd7, 0x72, 0x3f, 0x4e, 0x62, 0x4a, 0x05, 0xf7, + 0x37, 0x5b, 0x92, 0x7a, 0x87, 0xab, 0xe6, 0xa8, + 0x93, 0xa1, 0x65, 0x8f, 0xd4, 0x9f, 0x47, 0xf6, + 0xc7, 0xb0, 0xfa, 0x59, 0x6c, 0x65, 0xfa, 0x68, + 0xa2, 0x3f, 0x0a, 0xb4, 0x32, 0x96, 0x2d, 0x18, + 0xd4, 0x34, 0x3b, 0xd6, 0xfd, 0x67, 0xd0, 0x0b, + 0x25, 0xb8, 0x1b, 0x09, 0xb5, 0x62, 0x03, 0x85, + 0x64}, + .msg_len = 233, + .sig = {0x59, 0x9e, 0x69, 0xc1, 0x54, 0xe4, 0xfe, 0x66, + 0xb3, 0x6a, 0x69, 0x04, 0x92, 0xfa, 0xeb, 0xb2, + 0xbb, 0xe7, 0x34, 0xe0, 0x41, 0x5d, 0x9f, 0x3c, + 0xf7, 0xe3, 0x78, 0x28, 0xf5, 0x3e, 0x61, 0x13, + 0x04, 0x49, 0x17, 0x3a, 0x33, 0x46, 0x0c, 0x6b, + 0x4c, 0x8d, 0xc7, 0xd6, 0x81, 0xca, 0x6f, 0x4d, + 0xaf, 0x1c, 0xb8, 0x16, 0xd4, 0x0a, 0xa9, 0x08, + 0x2e, 0xe1, 0x93, 0x7b, 0xe4, 0xbc, 0x6a, 0x09, + 0xc6, 0xde, 0x79, 0x8c, 0x82, 0x86, 0xfc, 0xd2, + 0xa2, 0xb2, 0x19, 0x6c, 0x59, 0x99, 0x4c, 0x93, + 0x7f, 0x37, 0x13, 0x07, 0x52, 0x61, 0x2c, 0x6b, + 0xff, 0x6d, 0xbb, 0x53, 0xe0, 0x64, 0x7f, 0x88, + 0x58, 0xbc, 0x38, 0x38, 0x64, 0x02, 0x1e, 0x6d, + 0x56, 0x68, 0x19, 0x20, 0x24, 0x92, 0x97, 0x82, + 0x22, 0x46, 0xa0, 0xf5, 0x28, 0xaa, 0xb3, 0xed, + 0x18, 0x5e, 0xeb, 0xce, 0x91, 0x9c, 0xf8, 0x3e}, + .sig_len = 128, + }, + { // 9 + .mod = {0xd1, 0x31, 0xe0, 0x92, 0x43, 0x37, 0x0d, 0xd2, + 0xcd, 0x54, 0x25, 0xc8, 0xd0, 0x30, 0xf9, 0x9a, + 0xdb, 0x10, 0x5b, 0x14, 0x7b, 0x8a, 0x3d, 0x00, + 0x67, 0xc6, 0x16, 0x44, 0x3b, 0x7d, 0x4b, 0x96, + 0x82, 0x38, 0xe0, 0x6d, 0xbb, 0x5f, 0x20, 0x28, + 0xe8, 0x53, 0x57, 0x4b, 0x7c, 0x14, 0xbe, 0x10, + 0x83, 0xc1, 0xe5, 0x7e, 0x13, 0x2c, 0x1d, 0xf4, + 0xa3, 0xa2, 0x71, 0x32, 0x63, 0xfa, 0xde, 0x12, + 0xf7, 0x11, 0x4f, 0x43, 0x69, 0xbb, 0xf0, 0x56, + 0x20, 0x55, 0x48, 0x41, 0x33, 0x1e, 0xd8, 0x11, + 0x00, 0x50, 0x52, 0x19, 0x25, 0x72, 0xce, 0xb4, + 0x8d, 0x66, 0x24, 0x07, 0xfd, 0x30, 0x81, 0xcf, + 0xab, 0x8b, 0x48, 0xc7, 0xe9, 0x2d, 0x3c, 0x4a, + 0x26, 0xa9, 0x64, 0x5a, 0x38, 0xe6, 0xde, 0xe8, + 0x8b, 0xb0, 0x07, 0x59, 0x75, 0xa4, 0xda, 0xd9, + 0x64, 0x6b, 0x21, 0x60, 0x38, 0x40, 0xaf, 0x5f}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x56, 0xb5, 0x31, 0xbb, 0xee, 0x18, 0x37, 0xa6, + 0x94, 0x6c, 0xb8, 0x6c, 0x8f, 0xbe, 0x7c, 0xf6, + 0xee, 0xad, 0xcc, 0xd2, 0xa4, 0x92, 0x1b, 0xce, + 0xbb, 0x34, 0xa3, 0xae, 0x0c, 0x6a, 0x56, 0x96, + 0x3f, 0xcb, 0x8b, 0x5a, 0x70, 0x3b, 0x71, 0x7d, + 0x03, 0x2e, 0xe8, 0x13, 0xe5, 0x8e, 0x43, 0x69, + 0x5c, 0xf3, 0x55, 0x47, 0xf8, 0x72, 0x64, 0xc8, + 0x2d, 0xba, 0xfa, 0xe8, 0x44, 0x00, 0x8b, 0x62, + 0xd9, 0x12, 0x2e, 0x9d, 0xe8, 0x95, 0x85, 0x60, + 0xc8, 0xdb, 0xb0, 0x07, 0x72, 0x7e, 0x71, 0x39, + 0xe0, 0xa9, 0x82, 0xe0, 0x75, 0x88, 0x14, 0x11, + 0x3d, 0xe5, 0x4b, 0xa0, 0xa4, 0x55, 0x17, 0x51, + 0xfc, 0xa0, 0xfc, 0xb1, 0x2d, 0x8d, 0xe3, 0x0d, + 0x78, 0xb8, 0xb1, 0x12, 0x98, 0xa7, 0xf7, 0x8f, + 0x0b, 0x08, 0x8f, 0x16, 0x87, 0x05, 0x3c, 0x84, + 0xa5, 0x76, 0x2f, 0x62, 0xa4, 0xbd, 0x05, 0xc1}, + .privexp_len = 128, + .prime1 = {0xee, 0x22, 0xa4, 0x24, 0x62, 0xf7, 0x71, 0x8d, + 0xfe, 0xcf, 0x02, 0x4b, 0x17, 0xc9, 0x26, 0x76, + 0x78, 0x05, 0x91, 0x71, 0x33, 0x9c, 0xc0, 0x07, + 0x06, 0x52, 0x60, 0xd3, 0x04, 0x7e, 0x5f, 0x89, + 0xfe, 0xd9, 0x10, 0x34, 0x28, 0x43, 0x37, 0x8c, + 0x22, 0x68, 0x5d, 0x53, 0x2e, 0x84, 0xd2, 0x59, + 0x3a, 0x7c, 0x8c, 0x02, 0x6a, 0x87, 0x66, 0xc5, + 0xa2, 0xb2, 0xed, 0x55, 0x8e, 0x88, 0x23, 0x19}, + .prime1_len = 64, + .prime2 = {0xe0, 0xe3, 0x70, 0x0c, 0x99, 0xa3, 0xe8, 0x15, + 0xd7, 0x4b, 0x75, 0x2a, 0x84, 0xfb, 0x42, 0xec, + 0x20, 0xe5, 0x20, 0x3c, 0xa7, 0xc1, 0xaf, 0x97, + 0xfb, 0xf3, 0x97, 0xb9, 0x5d, 0x11, 0x05, 0x37, + 0x6c, 0xf5, 0xd6, 0x3e, 0x3c, 0x57, 0xbf, 0xa6, + 0x58, 0x55, 0xe5, 0x08, 0x14, 0x6c, 0x86, 0xdb, + 0xaa, 0xb2, 0x89, 0xc9, 0x5b, 0xc0, 0x45, 0x5a, + 0x58, 0x2d, 0xd8, 0xf5, 0x3f, 0xfb, 0xed, 0x37}, + .prime2_len = 64, + .exp1 = {0xd1, 0xf1, 0x34, 0x68, 0xe7, 0xdf, 0x62, 0xfb, + 0x5e, 0xb3, 0xbe, 0x3f, 0xd9, 0xde, 0x7a, 0xcc, + 0x63, 0x0f, 0xf5, 0xa3, 0xa9, 0x6e, 0xfe, 0x54, + 0xb3, 0x1c, 0x19, 0x44, 0xb0, 0x67, 0x81, 0x6f, + 0x35, 0x80, 0xc4, 0xaa, 0x56, 0xfc, 0xbb, 0x92, + 0x0e, 0x1b, 0x98, 0x7b, 0x67, 0x3d, 0xad, 0xfd, + 0x00, 0x75, 0x21, 0x32, 0x58, 0x1c, 0xbb, 0x5c, + 0x6e, 0x0d, 0xf4, 0xf3, 0x42, 0xcf, 0x7e, 0xb1}, + .exp1_len = 64, + .exp2 = {0xac, 0xd0, 0xda, 0x38, 0x34, 0x90, 0xea, 0x36, + 0x6e, 0x7d, 0xc4, 0x09, 0xea, 0xab, 0x13, 0x20, + 0x55, 0x9e, 0xfd, 0x88, 0xde, 0xf9, 0x4e, 0x30, + 0xa3, 0x22, 0xec, 0x03, 0x3b, 0xeb, 0x6a, 0x70, + 0xcf, 0x40, 0x93, 0x64, 0xbc, 0x06, 0x4a, 0x76, + 0x50, 0x07, 0xa1, 0xba, 0xf5, 0xc6, 0xf8, 0x53, + 0x31, 0xf7, 0x85, 0x3e, 0xc1, 0x4d, 0x1d, 0x7e, + 0x71, 0xa8, 0xb9, 0xc2, 0xad, 0x6a, 0xb1, 0x3d}, + .exp2_len = 64, + .coef = {0x1e, 0xda, 0x83, 0xd4, 0xa6, 0xd0, 0x99, 0xb6, + 0x0b, 0x2b, 0x2b, 0x84, 0xc6, 0xae, 0x41, 0x65, + 0xc7, 0x22, 0x50, 0x3e, 0xbd, 0x37, 0x3c, 0x83, + 0x6f, 0x97, 0x35, 0xca, 0x3b, 0x20, 0xa3, 0xeb, + 0x08, 0x1b, 0x31, 0xe7, 0x83, 0x04, 0x13, 0x20, + 0xdf, 0xc6, 0xdd, 0xf9, 0x05, 0x14, 0xca, 0xb6, + 0xec, 0x4b, 0x80, 0xae, 0x0c, 0x05, 0x2d, 0xd1, + 0xe7, 0xce, 0x34, 0x18, 0xae, 0xee, 0x24, 0xa4}, + .coef_len = 64, + .msg = {0x2c, 0x93, 0x6b, 0xf6, 0x13, 0x3a, 0x96, 0x93, + 0xf1, 0x46, 0xee, 0x5a, 0x1a, 0x91, 0xc2, 0xf1, + 0x69, 0xb2, 0xe6, 0x44, 0xa5, 0x18, 0xe8, 0x5a, + 0x75, 0xf6, 0xe4, 0x3b, 0x56, 0x0d, 0x4a, 0x72, + 0xf3, 0x8c, 0x64, 0xf8, 0x4c, 0x05, 0x24, 0x0e, + 0x8b, 0x4e, 0x55, 0x78, 0x61, 0x63, 0xe7, 0x27, + 0x62, 0x65, 0xba, 0x21, 0x3b, 0xa9, 0x3d, 0xee, + 0x1b, 0x2e, 0x10, 0x21, 0x35, 0xa9, 0x89, 0xb6, + 0x24, 0x8e, 0x88, 0x32, 0x7e, 0x30, 0x03, 0x61, + 0xa7, 0x4f, 0x2e, 0x9b, 0xc4, 0x1f, 0x2a, 0x37, + 0x68, 0x3f, 0x1a, 0x1a, 0x15, 0xf9, 0xdd, 0x47, + 0x2e, 0x11, 0x8e, 0x1c, 0x4b, 0x3e, 0xde, 0x58, + 0xdd, 0x70, 0xf3, 0xba, 0xcc, 0x25, 0x2e, 0x0c, + 0x65, 0x4b, 0x0f, 0x7a, 0x6e, 0x41, 0xa9, 0x28, + 0x75, 0x10, 0xef, 0xa0, 0x3b, 0xc9, 0x2e, 0x80, + 0x5e, 0x5b, 0x2c, 0x91, 0x3f, 0x51, 0xe2, 0x5c, + 0x7f, 0x85, 0x86, 0x40, 0xca, 0xfa, 0xc9, 0xd3, + 0xc9, 0x17, 0x68, 0x65, 0x07, 0xfa, 0x94, 0xf8, + 0x86, 0x6f, 0x86, 0x9a, 0x4e, 0x5a, 0x6a, 0x3d, + 0x4f, 0x9d, 0x97, 0xed, 0x81, 0x37, 0xf4, 0x14, + 0xd1, 0x44, 0x7a, 0x86, 0xee, 0xf9, 0xe1, 0x49, + 0x69, 0x94, 0xad, 0x2d, 0xa5, 0x97}, + .msg_len = 174, + .sig = {0x9e, 0x93, 0xf7, 0xac, 0xc5, 0x0f, 0xb3, 0xa0, + 0xb1, 0x24, 0x3d, 0xc3, 0x38, 0xc8, 0xcc, 0xb1, + 0x2b, 0xca, 0xb4, 0xaa, 0x45, 0x04, 0x40, 0xb6, + 0x30, 0x6c, 0x81, 0xb5, 0x0b, 0x8f, 0x95, 0xa9, + 0x36, 0xdd, 0x16, 0x63, 0x30, 0xc6, 0x99, 0xb2, + 0x85, 0x80, 0xda, 0x1b, 0xe2, 0x75, 0x61, 0x64, + 0x02, 0xda, 0x85, 0xbf, 0xd8, 0xee, 0xfc, 0xd6, + 0x99, 0x35, 0x87, 0xe6, 0x09, 0x28, 0x65, 0xd8, + 0x25, 0x3b, 0x04, 0x08, 0x1d, 0x57, 0x2f, 0x26, + 0x27, 0x59, 0xf5, 0x56, 0xdf, 0xb9, 0x11, 0xe8, + 0xd9, 0x4e, 0x92, 0xe5, 0x5a, 0xf6, 0xd5, 0x89, + 0x80, 0x18, 0xff, 0x33, 0xe5, 0xf6, 0xb1, 0xf9, + 0x90, 0x19, 0x96, 0xe9, 0x2f, 0xaf, 0x33, 0x6e, + 0x2d, 0xcc, 0xe3, 0xab, 0x0a, 0x93, 0xdb, 0x93, + 0x2e, 0x94, 0x2c, 0xc6, 0x47, 0x8d, 0x6c, 0xc2, + 0xfb, 0x66, 0x08, 0x11, 0x91, 0x0c, 0xcd, 0x17}, + .sig_len = 128, + .chunks = {25, 25, 25, 75, 23, 1, 0}, + .num_chunks = 7, + }, + { // 10 + .mod = {0xd1, 0x31, 0xe0, 0x92, 0x43, 0x37, 0x0d, 0xd2, + 0xcd, 0x54, 0x25, 0xc8, 0xd0, 0x30, 0xf9, 0x9a, + 0xdb, 0x10, 0x5b, 0x14, 0x7b, 0x8a, 0x3d, 0x00, + 0x67, 0xc6, 0x16, 0x44, 0x3b, 0x7d, 0x4b, 0x96, + 0x82, 0x38, 0xe0, 0x6d, 0xbb, 0x5f, 0x20, 0x28, + 0xe8, 0x53, 0x57, 0x4b, 0x7c, 0x14, 0xbe, 0x10, + 0x83, 0xc1, 0xe5, 0x7e, 0x13, 0x2c, 0x1d, 0xf4, + 0xa3, 0xa2, 0x71, 0x32, 0x63, 0xfa, 0xde, 0x12, + 0xf7, 0x11, 0x4f, 0x43, 0x69, 0xbb, 0xf0, 0x56, + 0x20, 0x55, 0x48, 0x41, 0x33, 0x1e, 0xd8, 0x11, + 0x00, 0x50, 0x52, 0x19, 0x25, 0x72, 0xce, 0xb4, + 0x8d, 0x66, 0x24, 0x07, 0xfd, 0x30, 0x81, 0xcf, + 0xab, 0x8b, 0x48, 0xc7, 0xe9, 0x2d, 0x3c, 0x4a, + 0x26, 0xa9, 0x64, 0x5a, 0x38, 0xe6, 0xde, 0xe8, + 0x8b, 0xb0, 0x07, 0x59, 0x75, 0xa4, 0xda, 0xd9, + 0x64, 0x6b, 0x21, 0x60, 0x38, 0x40, 0xaf, 0x5f}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x56, 0xb5, 0x31, 0xbb, 0xee, 0x18, 0x37, 0xa6, + 0x94, 0x6c, 0xb8, 0x6c, 0x8f, 0xbe, 0x7c, 0xf6, + 0xee, 0xad, 0xcc, 0xd2, 0xa4, 0x92, 0x1b, 0xce, + 0xbb, 0x34, 0xa3, 0xae, 0x0c, 0x6a, 0x56, 0x96, + 0x3f, 0xcb, 0x8b, 0x5a, 0x70, 0x3b, 0x71, 0x7d, + 0x03, 0x2e, 0xe8, 0x13, 0xe5, 0x8e, 0x43, 0x69, + 0x5c, 0xf3, 0x55, 0x47, 0xf8, 0x72, 0x64, 0xc8, + 0x2d, 0xba, 0xfa, 0xe8, 0x44, 0x00, 0x8b, 0x62, + 0xd9, 0x12, 0x2e, 0x9d, 0xe8, 0x95, 0x85, 0x60, + 0xc8, 0xdb, 0xb0, 0x07, 0x72, 0x7e, 0x71, 0x39, + 0xe0, 0xa9, 0x82, 0xe0, 0x75, 0x88, 0x14, 0x11, + 0x3d, 0xe5, 0x4b, 0xa0, 0xa4, 0x55, 0x17, 0x51, + 0xfc, 0xa0, 0xfc, 0xb1, 0x2d, 0x8d, 0xe3, 0x0d, + 0x78, 0xb8, 0xb1, 0x12, 0x98, 0xa7, 0xf7, 0x8f, + 0x0b, 0x08, 0x8f, 0x16, 0x87, 0x05, 0x3c, 0x84, + 0xa5, 0x76, 0x2f, 0x62, 0xa4, 0xbd, 0x05, 0xc1}, + .privexp_len = 128, + .prime1 = {0xee, 0x22, 0xa4, 0x24, 0x62, 0xf7, 0x71, 0x8d, + 0xfe, 0xcf, 0x02, 0x4b, 0x17, 0xc9, 0x26, 0x76, + 0x78, 0x05, 0x91, 0x71, 0x33, 0x9c, 0xc0, 0x07, + 0x06, 0x52, 0x60, 0xd3, 0x04, 0x7e, 0x5f, 0x89, + 0xfe, 0xd9, 0x10, 0x34, 0x28, 0x43, 0x37, 0x8c, + 0x22, 0x68, 0x5d, 0x53, 0x2e, 0x84, 0xd2, 0x59, + 0x3a, 0x7c, 0x8c, 0x02, 0x6a, 0x87, 0x66, 0xc5, + 0xa2, 0xb2, 0xed, 0x55, 0x8e, 0x88, 0x23, 0x19}, + .prime1_len = 64, + .prime2 = {0xe0, 0xe3, 0x70, 0x0c, 0x99, 0xa3, 0xe8, 0x15, + 0xd7, 0x4b, 0x75, 0x2a, 0x84, 0xfb, 0x42, 0xec, + 0x20, 0xe5, 0x20, 0x3c, 0xa7, 0xc1, 0xaf, 0x97, + 0xfb, 0xf3, 0x97, 0xb9, 0x5d, 0x11, 0x05, 0x37, + 0x6c, 0xf5, 0xd6, 0x3e, 0x3c, 0x57, 0xbf, 0xa6, + 0x58, 0x55, 0xe5, 0x08, 0x14, 0x6c, 0x86, 0xdb, + 0xaa, 0xb2, 0x89, 0xc9, 0x5b, 0xc0, 0x45, 0x5a, + 0x58, 0x2d, 0xd8, 0xf5, 0x3f, 0xfb, 0xed, 0x37}, + .prime2_len = 64, + .exp1 = {0xd1, 0xf1, 0x34, 0x68, 0xe7, 0xdf, 0x62, 0xfb, + 0x5e, 0xb3, 0xbe, 0x3f, 0xd9, 0xde, 0x7a, 0xcc, + 0x63, 0x0f, 0xf5, 0xa3, 0xa9, 0x6e, 0xfe, 0x54, + 0xb3, 0x1c, 0x19, 0x44, 0xb0, 0x67, 0x81, 0x6f, + 0x35, 0x80, 0xc4, 0xaa, 0x56, 0xfc, 0xbb, 0x92, + 0x0e, 0x1b, 0x98, 0x7b, 0x67, 0x3d, 0xad, 0xfd, + 0x00, 0x75, 0x21, 0x32, 0x58, 0x1c, 0xbb, 0x5c, + 0x6e, 0x0d, 0xf4, 0xf3, 0x42, 0xcf, 0x7e, 0xb1}, + .exp1_len = 64, + .exp2 = {0xac, 0xd0, 0xda, 0x38, 0x34, 0x90, 0xea, 0x36, + 0x6e, 0x7d, 0xc4, 0x09, 0xea, 0xab, 0x13, 0x20, + 0x55, 0x9e, 0xfd, 0x88, 0xde, 0xf9, 0x4e, 0x30, + 0xa3, 0x22, 0xec, 0x03, 0x3b, 0xeb, 0x6a, 0x70, + 0xcf, 0x40, 0x93, 0x64, 0xbc, 0x06, 0x4a, 0x76, + 0x50, 0x07, 0xa1, 0xba, 0xf5, 0xc6, 0xf8, 0x53, + 0x31, 0xf7, 0x85, 0x3e, 0xc1, 0x4d, 0x1d, 0x7e, + 0x71, 0xa8, 0xb9, 0xc2, 0xad, 0x6a, 0xb1, 0x3d}, + .exp2_len = 64, + .coef = {0x1e, 0xda, 0x83, 0xd4, 0xa6, 0xd0, 0x99, 0xb6, + 0x0b, 0x2b, 0x2b, 0x84, 0xc6, 0xae, 0x41, 0x65, + 0xc7, 0x22, 0x50, 0x3e, 0xbd, 0x37, 0x3c, 0x83, + 0x6f, 0x97, 0x35, 0xca, 0x3b, 0x20, 0xa3, 0xeb, + 0x08, 0x1b, 0x31, 0xe7, 0x83, 0x04, 0x13, 0x20, + 0xdf, 0xc6, 0xdd, 0xf9, 0x05, 0x14, 0xca, 0xb6, + 0xec, 0x4b, 0x80, 0xae, 0x0c, 0x05, 0x2d, 0xd1, + 0xe7, 0xce, 0x34, 0x18, 0xae, 0xee, 0x24, 0xa4}, + .coef_len = 64, + .msg = {0x94, 0x32, 0x3f, 0x7c, 0x38, 0xb9, 0x95, 0xcc, + 0x6b, 0xd8, 0x5d, 0x47, 0x9f, 0x8d, 0xe2, 0xde, + 0xc1, 0xef, 0x2e, 0x84, 0xb1, 0xfe, 0xef, 0xec, + 0xf3, 0x91, 0x50, 0xb5, 0xd9, 0xf2, 0xcb, 0x15, + 0x85, 0xac, 0x0d, 0x71, 0x9a, 0xb3, 0x48, 0xbd, + 0xc9, 0x75, 0x0d, 0xdb, 0x8e, 0x32, 0x76, 0xdb, + 0x89, 0x81, 0x87, 0x35, 0xbd, 0x62, 0x31, 0x41, + 0x3c, 0xbc, 0xa2, 0xde, 0x94, 0x1b, 0x55, 0xe8, + 0xcf, 0xa1, 0xab, 0x13, 0x2c, 0xc7, 0x8a, 0xa4, + 0xf2, 0xb5, 0x1f, 0xd6, 0x57, 0x8e, 0xe2, 0xe0, + 0x32, 0xe9, 0x0e, 0x34, 0x08, 0x0f, 0x0f, 0x8e, + 0x3d, 0xb1, 0x4d, 0x1b, 0x56, 0xf3, 0xd0, 0x77, + 0xf2, 0x9d, 0xbc, 0x02, 0x16, 0xa4, 0x13, 0x44, + 0x99, 0x8c, 0x0f, 0xe1, 0xab, 0x41, 0x22, 0x47, + 0xdf, 0x21, 0xe7, 0x4e, 0xc2, 0x2f, 0x5d, 0xb0, + 0x14, 0x8e, 0xca, 0xf4, 0x73, 0xee, 0xec, 0xcc, + 0x14, 0xff, 0x9e, 0x45, 0xd5, 0x8c, 0x2e, 0x62, + 0xb5, 0xfe, 0x6a, 0x50, 0x1a, 0xb9, 0x6f, 0xd7, + 0xc5, 0xed, 0xde, 0xf1, 0x4a, 0xa8, 0x92, 0x66, + 0x69, 0x2e}, + .msg_len = 154, + .sig = {0x09, 0x40, 0x2a, 0x43, 0x56, 0xbe, 0x73, 0x44, + 0x9b, 0x46, 0x9e, 0x36, 0x31, 0xe1, 0xb0, 0x23, + 0x07, 0xc5, 0xca, 0xc2, 0xce, 0x15, 0x28, 0xd7, + 0x84, 0xfa, 0xb9, 0x26, 0xdf, 0xf5, 0x1f, 0x86, + 0x24, 0x1b, 0x9d, 0x66, 0xf7, 0x9d, 0x6d, 0x8e, + 0xee, 0xeb, 0x24, 0x9d, 0x76, 0xfa, 0x9f, 0x16, + 0x6f, 0xf9, 0xa8, 0xc6, 0xa3, 0x9e, 0x83, 0x2d, + 0x5d, 0x14, 0xb9, 0xd7, 0xec, 0x5a, 0x3d, 0xc2, + 0x8f, 0x01, 0xeb, 0xb0, 0x6e, 0x39, 0xd5, 0x9e, + 0x84, 0x61, 0xb9, 0x55, 0xb2, 0xa7, 0xf5, 0xb1, + 0xf2, 0x04, 0xb0, 0x4c, 0xc6, 0xcc, 0x62, 0x64, + 0x61, 0x61, 0xac, 0x1c, 0x2b, 0xf5, 0xba, 0xb5, + 0x0f, 0x06, 0x8c, 0x90, 0x8d, 0x28, 0xde, 0x5e, + 0xae, 0xf7, 0xe8, 0xeb, 0xfc, 0xab, 0xb0, 0x9b, + 0x7d, 0x75, 0xd8, 0x35, 0x40, 0xdd, 0x4b, 0x35, + 0x4d, 0x13, 0x1d, 0x86, 0xf0, 0x77, 0x07, 0x17}, + .sig_len = 128, + .chunks = {0, 54, -1, 100}, + .num_chunks = 4, + }, + { // 11 + .mod = {0xd1, 0x31, 0xe0, 0x92, 0x43, 0x37, 0x0d, 0xd2, + 0xcd, 0x54, 0x25, 0xc8, 0xd0, 0x30, 0xf9, 0x9a, + 0xdb, 0x10, 0x5b, 0x14, 0x7b, 0x8a, 0x3d, 0x00, + 0x67, 0xc6, 0x16, 0x44, 0x3b, 0x7d, 0x4b, 0x96, + 0x82, 0x38, 0xe0, 0x6d, 0xbb, 0x5f, 0x20, 0x28, + 0xe8, 0x53, 0x57, 0x4b, 0x7c, 0x14, 0xbe, 0x10, + 0x83, 0xc1, 0xe5, 0x7e, 0x13, 0x2c, 0x1d, 0xf4, + 0xa3, 0xa2, 0x71, 0x32, 0x63, 0xfa, 0xde, 0x12, + 0xf7, 0x11, 0x4f, 0x43, 0x69, 0xbb, 0xf0, 0x56, + 0x20, 0x55, 0x48, 0x41, 0x33, 0x1e, 0xd8, 0x11, + 0x00, 0x50, 0x52, 0x19, 0x25, 0x72, 0xce, 0xb4, + 0x8d, 0x66, 0x24, 0x07, 0xfd, 0x30, 0x81, 0xcf, + 0xab, 0x8b, 0x48, 0xc7, 0xe9, 0x2d, 0x3c, 0x4a, + 0x26, 0xa9, 0x64, 0x5a, 0x38, 0xe6, 0xde, 0xe8, + 0x8b, 0xb0, 0x07, 0x59, 0x75, 0xa4, 0xda, 0xd9, + 0x64, 0x6b, 0x21, 0x60, 0x38, 0x40, 0xaf, 0x5f}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x56, 0xb5, 0x31, 0xbb, 0xee, 0x18, 0x37, 0xa6, + 0x94, 0x6c, 0xb8, 0x6c, 0x8f, 0xbe, 0x7c, 0xf6, + 0xee, 0xad, 0xcc, 0xd2, 0xa4, 0x92, 0x1b, 0xce, + 0xbb, 0x34, 0xa3, 0xae, 0x0c, 0x6a, 0x56, 0x96, + 0x3f, 0xcb, 0x8b, 0x5a, 0x70, 0x3b, 0x71, 0x7d, + 0x03, 0x2e, 0xe8, 0x13, 0xe5, 0x8e, 0x43, 0x69, + 0x5c, 0xf3, 0x55, 0x47, 0xf8, 0x72, 0x64, 0xc8, + 0x2d, 0xba, 0xfa, 0xe8, 0x44, 0x00, 0x8b, 0x62, + 0xd9, 0x12, 0x2e, 0x9d, 0xe8, 0x95, 0x85, 0x60, + 0xc8, 0xdb, 0xb0, 0x07, 0x72, 0x7e, 0x71, 0x39, + 0xe0, 0xa9, 0x82, 0xe0, 0x75, 0x88, 0x14, 0x11, + 0x3d, 0xe5, 0x4b, 0xa0, 0xa4, 0x55, 0x17, 0x51, + 0xfc, 0xa0, 0xfc, 0xb1, 0x2d, 0x8d, 0xe3, 0x0d, + 0x78, 0xb8, 0xb1, 0x12, 0x98, 0xa7, 0xf7, 0x8f, + 0x0b, 0x08, 0x8f, 0x16, 0x87, 0x05, 0x3c, 0x84, + 0xa5, 0x76, 0x2f, 0x62, 0xa4, 0xbd, 0x05, 0xc1}, + .privexp_len = 128, + .prime1 = {0xee, 0x22, 0xa4, 0x24, 0x62, 0xf7, 0x71, 0x8d, + 0xfe, 0xcf, 0x02, 0x4b, 0x17, 0xc9, 0x26, 0x76, + 0x78, 0x05, 0x91, 0x71, 0x33, 0x9c, 0xc0, 0x07, + 0x06, 0x52, 0x60, 0xd3, 0x04, 0x7e, 0x5f, 0x89, + 0xfe, 0xd9, 0x10, 0x34, 0x28, 0x43, 0x37, 0x8c, + 0x22, 0x68, 0x5d, 0x53, 0x2e, 0x84, 0xd2, 0x59, + 0x3a, 0x7c, 0x8c, 0x02, 0x6a, 0x87, 0x66, 0xc5, + 0xa2, 0xb2, 0xed, 0x55, 0x8e, 0x88, 0x23, 0x19}, + .prime1_len = 64, + .prime2 = {0xe0, 0xe3, 0x70, 0x0c, 0x99, 0xa3, 0xe8, 0x15, + 0xd7, 0x4b, 0x75, 0x2a, 0x84, 0xfb, 0x42, 0xec, + 0x20, 0xe5, 0x20, 0x3c, 0xa7, 0xc1, 0xaf, 0x97, + 0xfb, 0xf3, 0x97, 0xb9, 0x5d, 0x11, 0x05, 0x37, + 0x6c, 0xf5, 0xd6, 0x3e, 0x3c, 0x57, 0xbf, 0xa6, + 0x58, 0x55, 0xe5, 0x08, 0x14, 0x6c, 0x86, 0xdb, + 0xaa, 0xb2, 0x89, 0xc9, 0x5b, 0xc0, 0x45, 0x5a, + 0x58, 0x2d, 0xd8, 0xf5, 0x3f, 0xfb, 0xed, 0x37}, + .prime2_len = 64, + .exp1 = {0xd1, 0xf1, 0x34, 0x68, 0xe7, 0xdf, 0x62, 0xfb, + 0x5e, 0xb3, 0xbe, 0x3f, 0xd9, 0xde, 0x7a, 0xcc, + 0x63, 0x0f, 0xf5, 0xa3, 0xa9, 0x6e, 0xfe, 0x54, + 0xb3, 0x1c, 0x19, 0x44, 0xb0, 0x67, 0x81, 0x6f, + 0x35, 0x80, 0xc4, 0xaa, 0x56, 0xfc, 0xbb, 0x92, + 0x0e, 0x1b, 0x98, 0x7b, 0x67, 0x3d, 0xad, 0xfd, + 0x00, 0x75, 0x21, 0x32, 0x58, 0x1c, 0xbb, 0x5c, + 0x6e, 0x0d, 0xf4, 0xf3, 0x42, 0xcf, 0x7e, 0xb1}, + .exp1_len = 64, + .exp2 = {0xac, 0xd0, 0xda, 0x38, 0x34, 0x90, 0xea, 0x36, + 0x6e, 0x7d, 0xc4, 0x09, 0xea, 0xab, 0x13, 0x20, + 0x55, 0x9e, 0xfd, 0x88, 0xde, 0xf9, 0x4e, 0x30, + 0xa3, 0x22, 0xec, 0x03, 0x3b, 0xeb, 0x6a, 0x70, + 0xcf, 0x40, 0x93, 0x64, 0xbc, 0x06, 0x4a, 0x76, + 0x50, 0x07, 0xa1, 0xba, 0xf5, 0xc6, 0xf8, 0x53, + 0x31, 0xf7, 0x85, 0x3e, 0xc1, 0x4d, 0x1d, 0x7e, + 0x71, 0xa8, 0xb9, 0xc2, 0xad, 0x6a, 0xb1, 0x3d}, + .exp2_len = 64, + .coef = {0x1e, 0xda, 0x83, 0xd4, 0xa6, 0xd0, 0x99, 0xb6, + 0x0b, 0x2b, 0x2b, 0x84, 0xc6, 0xae, 0x41, 0x65, + 0xc7, 0x22, 0x50, 0x3e, 0xbd, 0x37, 0x3c, 0x83, + 0x6f, 0x97, 0x35, 0xca, 0x3b, 0x20, 0xa3, 0xeb, + 0x08, 0x1b, 0x31, 0xe7, 0x83, 0x04, 0x13, 0x20, + 0xdf, 0xc6, 0xdd, 0xf9, 0x05, 0x14, 0xca, 0xb6, + 0xec, 0x4b, 0x80, 0xae, 0x0c, 0x05, 0x2d, 0xd1, + 0xe7, 0xce, 0x34, 0x18, 0xae, 0xee, 0x24, 0xa4}, + .coef_len = 64, + .msg = {0x0e, 0x23, 0x3b, 0x25, 0x49, 0xbd, 0xd2, 0x1b, + 0xa5, 0x14, 0x80, 0xda, 0x8e, 0x3d, 0xce, 0xf4, + 0xdb, 0x20, 0xe0, 0xdc, 0xc0, 0x5e, 0xe2, 0x37, + 0x35, 0x1e, 0xdb, 0xc9, 0xa5, 0x3c, 0x52, 0xf6, + 0x74, 0xd1, 0x05, 0xfe, 0xc0, 0x93, 0x9d, 0x36, + 0x99, 0x64, 0x7e, 0xfc, 0x1e, 0x25, 0xcb, 0x4e, + 0x9b, 0x1a, 0xb7, 0x52, 0xab, 0x6f, 0xe2, 0x88, + 0x69, 0xff, 0x73, 0xf2, 0x3e, 0x01, 0xee, 0xf8, + 0x67, 0x4c, 0x53, 0x5c, 0x4c, 0x93, 0x35, 0xf7, + 0x98, 0xf1, 0xde, 0xec, 0xd4, 0x89, 0xd0, 0x6d, + 0xc8, 0x8f, 0xd6, 0xbc, 0x1d, 0x49, 0x96, 0xef, + 0xf7, 0x2b, 0x43, 0x9e, 0x3c, 0x01, 0x4d, 0xd1, + 0x4c, 0xbf, 0x17, 0x71, 0x5c, 0x15, 0x89, 0x43, + 0xde, 0x2e, 0x6f, 0x97, 0x1c, 0x34, 0x99, 0x87, + 0xa1, 0xb3, 0x95, 0xd6, 0x82, 0xc3, 0xb0, 0xc1, + 0x7b, 0x66, 0xcd, 0x3c, 0xa4, 0x10, 0x60, 0xb5, + 0x71, 0x11, 0xe2, 0x28, 0x31, 0x4b, 0x2d, 0x34, + 0xb5, 0xe4, 0x4e, 0x55, 0xf1, 0xc1, 0x1c, 0x31, + 0xa6, 0xeb, 0x80, 0xb5, 0xf8, 0x2d, 0x96, 0xbd, + 0x4a, 0x17}, + .msg_len = 154, + .sig = {0xd0, 0x75, 0xbe, 0x06, 0xcb, 0xd6, 0x22, 0x3e, + 0x87, 0x1b, 0x0f, 0x33, 0x62, 0xa7, 0x97, 0xde, + 0x28, 0x2d, 0xa5, 0xc4, 0x03, 0x23, 0xf3, 0x7c, + 0x2c, 0xc3, 0x74, 0x65, 0xa1, 0xa8, 0x63, 0x68, + 0xdd, 0xcf, 0xa6, 0xda, 0xa1, 0x35, 0x86, 0x6c, + 0x32, 0x03, 0xd0, 0x47, 0x22, 0x60, 0xb2, 0x9c, + 0x3c, 0x9b, 0x1b, 0x88, 0x94, 0x08, 0x5d, 0x54, + 0x7c, 0x5e, 0xb9, 0x31, 0x42, 0x4f, 0x24, 0x14, + 0x0a, 0x5c, 0xba, 0x15, 0x3b, 0xde, 0xd4, 0xb9, + 0xce, 0x7d, 0xae, 0xdc, 0x64, 0x5d, 0x39, 0x80, + 0xc5, 0xf5, 0x83, 0xf7, 0x67, 0x11, 0xc6, 0x7b, + 0x19, 0x3a, 0x52, 0x12, 0xf2, 0xa9, 0x35, 0x4a, + 0x67, 0x96, 0xaf, 0x09, 0x08, 0x20, 0x91, 0x31, + 0x34, 0xec, 0xf3, 0x05, 0xbe, 0xfb, 0x65, 0x32, + 0xcd, 0x48, 0xd4, 0x11, 0x3a, 0x0e, 0xc4, 0x86, + 0x9a, 0x0a, 0x56, 0x55, 0xdb, 0xdc, 0x72, 0x59}, + .sig_len = 128, + }, + { // 12 + .mod = {0xc5, 0x5f, 0xfb, 0xdd, 0x6a, 0x27, 0x53, 0xbc, + 0x02, 0xaf, 0x20, 0xae, 0x18, 0xea, 0x0d, 0xaf, + 0x23, 0x0b, 0xb6, 0xf8, 0x79, 0x5d, 0x05, 0xef, + 0xec, 0xc8, 0x15, 0xba, 0xec, 0xe2, 0x2b, 0x38, + 0x79, 0x99, 0x5f, 0x6d, 0x97, 0x64, 0xc1, 0xdf, + 0x8f, 0x97, 0x85, 0x13, 0x81, 0x68, 0x62, 0x66, + 0xb8, 0x09, 0x2f, 0xb6, 0x01, 0x18, 0x98, 0xa7, + 0x67, 0x07, 0xa4, 0xd1, 0xd5, 0xbd, 0xa0, 0x8d, + 0x24, 0x6c, 0x68, 0x7a, 0x8b, 0xba, 0xfa, 0x63, + 0x98, 0xac, 0x9e, 0xa2, 0x72, 0x68, 0x23, 0x71, + 0x4a, 0x0c, 0x39, 0x34, 0xca, 0x6e, 0x5f, 0x8c, + 0xe3, 0x39, 0x87, 0xb5, 0x34, 0x85, 0x7e, 0xa9, + 0xf8, 0x5c, 0xc4, 0xe1, 0x9a, 0x1d, 0x21, 0x83, + 0xe0, 0xe4, 0xc8, 0xaa, 0x55, 0xcb, 0x22, 0x7b, + 0x0e, 0x56, 0xce, 0xb2, 0xb6, 0x2b, 0x30, 0xef, + 0xc7, 0x88, 0x64, 0xb2, 0xf9, 0xfb, 0x92, 0x49}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x07, 0xe3, 0xfa, 0x71, 0xb3, 0x98, 0xb6, 0xe4, + 0x41, 0x47, 0x37, 0x0b, 0x3e, 0xbb, 0xbc, 0xa8, + 0x4f, 0xc2, 0x5c, 0x22, 0x3a, 0xd7, 0xd9, 0x30, + 0xea, 0x4a, 0x65, 0x73, 0xff, 0x9c, 0x5b, 0x15, + 0xfa, 0xe6, 0x82, 0xc6, 0x22, 0xd3, 0x48, 0x5c, + 0xe3, 0xa4, 0xaf, 0x11, 0x44, 0x8f, 0x23, 0xbf, + 0xef, 0x83, 0x8e, 0x80, 0xbc, 0x32, 0x7b, 0x87, + 0xd5, 0xba, 0x9c, 0x80, 0x37, 0x07, 0x49, 0xaf, + 0xc8, 0xc1, 0xc0, 0x17, 0x54, 0x6f, 0xc6, 0xb6, + 0x59, 0x31, 0xb7, 0x59, 0xca, 0x43, 0x41, 0xfa, + 0x5e, 0x5e, 0x10, 0xb2, 0x40, 0x87, 0xe6, 0xe2, + 0xc0, 0xf4, 0xdb, 0xb7, 0x90, 0x69, 0x52, 0x99, + 0x9c, 0xbd, 0x90, 0xd2, 0x43, 0x5f, 0xca, 0xcc, + 0x9c, 0x82, 0xe4, 0x8f, 0xdf, 0x24, 0xe4, 0x95, + 0xcf, 0xf3, 0x0a, 0xd4, 0x19, 0xe7, 0x12, 0x3e, + 0x3a, 0xc9, 0x42, 0x27, 0x2e, 0x1a, 0xba, 0xb1}, + .privexp_len = 128, + .prime1 = {0xf7, 0xf7, 0xc0, 0x02, 0xf0, 0x19, 0x6e, 0xcd, + 0xd7, 0x1b, 0xa5, 0xad, 0x74, 0x2b, 0x69, 0x48, + 0x27, 0xd2, 0x88, 0xaf, 0x1b, 0x1b, 0xb6, 0x9c, + 0x5e, 0xd7, 0xfb, 0x22, 0x9d, 0xee, 0x4b, 0x7a, + 0x32, 0xf2, 0xf7, 0x56, 0x8a, 0x6f, 0xca, 0xf3, + 0x83, 0xd8, 0x9a, 0xda, 0x9f, 0xc1, 0x4a, 0x7b, + 0xa5, 0xd0, 0xa4, 0xa4, 0x6c, 0x2c, 0x54, 0x3e, + 0xec, 0x17, 0x75, 0x49, 0xc8, 0xa0, 0x48, 0xb7}, + .prime1_len = 64, + .prime2 = {0xcb, 0xc4, 0xb2, 0x86, 0x04, 0x76, 0xa2, 0xd3, + 0xe8, 0xa4, 0xda, 0x21, 0x00, 0x16, 0xca, 0xce, + 0xd0, 0xe3, 0x67, 0xcb, 0x86, 0x77, 0x10, 0xa4, + 0xb5, 0xaa, 0x2d, 0xf2, 0xb8, 0xe5, 0xda, 0xf5, + 0xfd, 0xc6, 0x47, 0x80, 0x7d, 0x4d, 0x5e, 0xbb, + 0x6c, 0x56, 0xb9, 0x76, 0x3c, 0xcd, 0xae, 0x4d, + 0xea, 0x33, 0x08, 0xeb, 0x0a, 0xc2, 0xa8, 0x95, + 0x01, 0xcb, 0x20, 0x9d, 0x26, 0x39, 0xfc, 0xff}, + .prime2_len = 64, + .exp1 = {0x6c, 0x76, 0x27, 0xbc, 0xa1, 0x3c, 0xde, 0xa4, + 0x96, 0xa4, 0x77, 0x31, 0x89, 0x90, 0xbb, 0x7a, + 0x5e, 0x40, 0xce, 0x9c, 0x99, 0x24, 0xe4, 0x19, + 0x3d, 0xbb, 0x07, 0x14, 0x3b, 0x34, 0x52, 0x3b, + 0x5f, 0x31, 0xbb, 0x52, 0x55, 0x37, 0x54, 0xf4, + 0x73, 0x05, 0x39, 0xa6, 0xcb, 0x1e, 0x06, 0xf0, + 0x52, 0xb5, 0x12, 0x6f, 0x01, 0x09, 0xda, 0xc7, + 0xb3, 0x09, 0x07, 0xba, 0x80, 0x50, 0xeb, 0xbd}, + .exp1_len = 64, + .exp2 = {0x40, 0x92, 0x74, 0x80, 0x43, 0xa9, 0xd4, 0xaf, + 0x92, 0x69, 0xab, 0x36, 0x09, 0xf1, 0x2f, 0x13, + 0x9a, 0xde, 0x75, 0x65, 0xe9, 0x96, 0x91, 0x8f, + 0xa0, 0x81, 0xed, 0x4d, 0x9d, 0x8a, 0x39, 0x78, + 0xfa, 0x92, 0x7a, 0xd6, 0x1c, 0xdf, 0x07, 0xc6, + 0x1c, 0xee, 0xde, 0x96, 0xb9, 0x6d, 0xf4, 0x6e, + 0x7c, 0x68, 0xef, 0xca, 0x8b, 0xfe, 0x63, 0xad, + 0xd4, 0x83, 0xaa, 0x32, 0x22, 0x8a, 0xfd, 0xc1}, + .exp2_len = 64, + .coef = {0x2a, 0x61, 0x94, 0xca, 0x29, 0x70, 0x72, 0x38, + 0x45, 0xff, 0xf3, 0x8c, 0xa1, 0xa9, 0xa3, 0xb5, + 0x66, 0xb4, 0x24, 0x5d, 0xe2, 0xf9, 0x01, 0x34, + 0xb8, 0xe6, 0xae, 0xc8, 0xae, 0x07, 0xf3, 0xbb, + 0x7c, 0x5e, 0x5a, 0xe6, 0xe1, 0x83, 0x34, 0x85, + 0xe5, 0x5d, 0x8c, 0xa6, 0x0c, 0xe1, 0x64, 0x2f, + 0x72, 0x75, 0x96, 0x8e, 0x66, 0x12, 0x38, 0x35, + 0x52, 0x11, 0xc6, 0x38, 0x48, 0x94, 0x0f, 0x3c}, + .coef_len = 64, + .msg = {0xea, 0xe9, 0xa4, 0x0b, 0xff, 0x18, 0x3f, 0x41, + 0x14, 0x73, 0x2e, 0x7b, 0x3b, 0xa5, 0x56, 0xf4, + 0xce, 0x28, 0x8d, 0xaa, 0x83, 0xe3, 0xff, 0x23, + 0x61, 0x12, 0x44, 0xa7, 0xa0, 0x90, 0x1f, 0x11, + 0x7d, 0x86, 0xc0, 0x9c, 0x33, 0xa5, 0x23, 0x2b, + 0xd3, 0x20, 0xfa, 0x37, 0xa2, 0x38, 0xa8, 0xaa, + 0x62, 0xdd, 0x21, 0xab, 0xbf, 0xac, 0xdb, 0x93, + 0xfa, 0x1c, 0x44, 0xcc, 0x55, 0xac, 0x61, 0xbe, + 0xa2, 0x4a, 0x6a, 0x34, 0xcc, 0x64, 0x76, 0x75, + 0x38, 0x37, 0xe1, 0x6f, 0xac, 0xd8, 0x2e, 0xb4, + 0x9e, 0x1c, 0x57, 0xc9, 0x58, 0xfb, 0xbf, 0xf5, + 0x68, 0x88, 0x7c, 0xf8, 0x2e, 0xeb, 0xe9, 0x61, + 0xe5, 0x80, 0xe0, 0x64, 0xdb, 0x9c, 0xbe, 0xc3, + 0xb5, 0x3d, 0xf1, 0xf2, 0x71, 0x99, 0xe4, 0x9a, + 0x04, 0xcb, 0xe5, 0x9c, 0x69, 0xa2, 0x65, 0xcf, + 0xac, 0x8c, 0xe4, 0xf9, 0x1c, 0xa9, 0x5d, 0x52, + 0xb1, 0x14, 0x5c, 0x8b, 0x9f, 0x44, 0x40, 0xb3, + 0x9c, 0x18, 0x50, 0x94, 0xbe, 0x18, 0x48, 0x74, + 0xda, 0x59, 0x71, 0xd7, 0xd7, 0x63, 0xfe, 0x07, + 0xce, 0x16, 0xe5, 0x7f, 0x1e, 0x50, 0xd2, 0x28, + 0x65, 0x04, 0xb4, 0x81, 0xe2, 0xc6, 0x85, 0xbc, + 0x9d, 0x9c, 0x01, 0x49, 0x3f, 0xd3, 0xa6, 0xd8, + 0xbb, 0x9b, 0x2e, 0x96, 0xbf, 0xde, 0xb6, 0xc9, + 0x29, 0x14, 0xca}, + .msg_len = 187, + .sig = {0x44, 0xce, 0xb4, 0x42, 0x24, 0x2b, 0xae, 0x08, + 0x59, 0x94, 0xea, 0xd0, 0x7b, 0x70, 0x95, 0x43, + 0xea, 0x23, 0x95, 0xa6, 0xe8, 0xd4, 0x64, 0x73, + 0xd7, 0x0d, 0xf3, 0x4a, 0x95, 0x55, 0xaa, 0x56, + 0x7f, 0x4d, 0xa1, 0x38, 0xe9, 0x63, 0xfe, 0x92, + 0x86, 0xa8, 0x4f, 0xb7, 0xc5, 0xcf, 0x82, 0x00, + 0x03, 0x59, 0x04, 0xb5, 0x0c, 0x32, 0x40, 0x3c, + 0xae, 0x51, 0x7b, 0xfa, 0x7f, 0xca, 0x8a, 0x66, + 0xfc, 0xfd, 0x63, 0x2a, 0xf7, 0x47, 0xc4, 0x9c, + 0xdf, 0xb0, 0xb9, 0xae, 0xe3, 0x52, 0x28, 0xb7, + 0xdc, 0x4c, 0x21, 0x00, 0x39, 0x69, 0xb0, 0xa0, + 0x13, 0xed, 0xe1, 0x29, 0x2b, 0x65, 0xd1, 0x0a, + 0x50, 0xc9, 0x02, 0x63, 0xfb, 0x0b, 0xf4, 0xf4, + 0xb8, 0x37, 0x66, 0x41, 0xb0, 0x3e, 0x1f, 0xaf, + 0xb8, 0x83, 0xf0, 0x38, 0xf4, 0x32, 0x3d, 0xfe, + 0x5b, 0xea, 0xc4, 0x68, 0xde, 0xea, 0x99, 0xc3}, + .sig_len = 128, + .chunks = {7, 100, 80}, + .num_chunks = 3, + }, + { // 13 + .mod = {0xc5, 0x5f, 0xfb, 0xdd, 0x6a, 0x27, 0x53, 0xbc, + 0x02, 0xaf, 0x20, 0xae, 0x18, 0xea, 0x0d, 0xaf, + 0x23, 0x0b, 0xb6, 0xf8, 0x79, 0x5d, 0x05, 0xef, + 0xec, 0xc8, 0x15, 0xba, 0xec, 0xe2, 0x2b, 0x38, + 0x79, 0x99, 0x5f, 0x6d, 0x97, 0x64, 0xc1, 0xdf, + 0x8f, 0x97, 0x85, 0x13, 0x81, 0x68, 0x62, 0x66, + 0xb8, 0x09, 0x2f, 0xb6, 0x01, 0x18, 0x98, 0xa7, + 0x67, 0x07, 0xa4, 0xd1, 0xd5, 0xbd, 0xa0, 0x8d, + 0x24, 0x6c, 0x68, 0x7a, 0x8b, 0xba, 0xfa, 0x63, + 0x98, 0xac, 0x9e, 0xa2, 0x72, 0x68, 0x23, 0x71, + 0x4a, 0x0c, 0x39, 0x34, 0xca, 0x6e, 0x5f, 0x8c, + 0xe3, 0x39, 0x87, 0xb5, 0x34, 0x85, 0x7e, 0xa9, + 0xf8, 0x5c, 0xc4, 0xe1, 0x9a, 0x1d, 0x21, 0x83, + 0xe0, 0xe4, 0xc8, 0xaa, 0x55, 0xcb, 0x22, 0x7b, + 0x0e, 0x56, 0xce, 0xb2, 0xb6, 0x2b, 0x30, 0xef, + 0xc7, 0x88, 0x64, 0xb2, 0xf9, 0xfb, 0x92, 0x49}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x07, 0xe3, 0xfa, 0x71, 0xb3, 0x98, 0xb6, 0xe4, + 0x41, 0x47, 0x37, 0x0b, 0x3e, 0xbb, 0xbc, 0xa8, + 0x4f, 0xc2, 0x5c, 0x22, 0x3a, 0xd7, 0xd9, 0x30, + 0xea, 0x4a, 0x65, 0x73, 0xff, 0x9c, 0x5b, 0x15, + 0xfa, 0xe6, 0x82, 0xc6, 0x22, 0xd3, 0x48, 0x5c, + 0xe3, 0xa4, 0xaf, 0x11, 0x44, 0x8f, 0x23, 0xbf, + 0xef, 0x83, 0x8e, 0x80, 0xbc, 0x32, 0x7b, 0x87, + 0xd5, 0xba, 0x9c, 0x80, 0x37, 0x07, 0x49, 0xaf, + 0xc8, 0xc1, 0xc0, 0x17, 0x54, 0x6f, 0xc6, 0xb6, + 0x59, 0x31, 0xb7, 0x59, 0xca, 0x43, 0x41, 0xfa, + 0x5e, 0x5e, 0x10, 0xb2, 0x40, 0x87, 0xe6, 0xe2, + 0xc0, 0xf4, 0xdb, 0xb7, 0x90, 0x69, 0x52, 0x99, + 0x9c, 0xbd, 0x90, 0xd2, 0x43, 0x5f, 0xca, 0xcc, + 0x9c, 0x82, 0xe4, 0x8f, 0xdf, 0x24, 0xe4, 0x95, + 0xcf, 0xf3, 0x0a, 0xd4, 0x19, 0xe7, 0x12, 0x3e, + 0x3a, 0xc9, 0x42, 0x27, 0x2e, 0x1a, 0xba, 0xb1}, + .privexp_len = 128, + .prime1 = {0xf7, 0xf7, 0xc0, 0x02, 0xf0, 0x19, 0x6e, 0xcd, + 0xd7, 0x1b, 0xa5, 0xad, 0x74, 0x2b, 0x69, 0x48, + 0x27, 0xd2, 0x88, 0xaf, 0x1b, 0x1b, 0xb6, 0x9c, + 0x5e, 0xd7, 0xfb, 0x22, 0x9d, 0xee, 0x4b, 0x7a, + 0x32, 0xf2, 0xf7, 0x56, 0x8a, 0x6f, 0xca, 0xf3, + 0x83, 0xd8, 0x9a, 0xda, 0x9f, 0xc1, 0x4a, 0x7b, + 0xa5, 0xd0, 0xa4, 0xa4, 0x6c, 0x2c, 0x54, 0x3e, + 0xec, 0x17, 0x75, 0x49, 0xc8, 0xa0, 0x48, 0xb7}, + .prime1_len = 64, + .prime2 = {0xcb, 0xc4, 0xb2, 0x86, 0x04, 0x76, 0xa2, 0xd3, + 0xe8, 0xa4, 0xda, 0x21, 0x00, 0x16, 0xca, 0xce, + 0xd0, 0xe3, 0x67, 0xcb, 0x86, 0x77, 0x10, 0xa4, + 0xb5, 0xaa, 0x2d, 0xf2, 0xb8, 0xe5, 0xda, 0xf5, + 0xfd, 0xc6, 0x47, 0x80, 0x7d, 0x4d, 0x5e, 0xbb, + 0x6c, 0x56, 0xb9, 0x76, 0x3c, 0xcd, 0xae, 0x4d, + 0xea, 0x33, 0x08, 0xeb, 0x0a, 0xc2, 0xa8, 0x95, + 0x01, 0xcb, 0x20, 0x9d, 0x26, 0x39, 0xfc, 0xff}, + .prime2_len = 64, + .exp1 = {0x6c, 0x76, 0x27, 0xbc, 0xa1, 0x3c, 0xde, 0xa4, + 0x96, 0xa4, 0x77, 0x31, 0x89, 0x90, 0xbb, 0x7a, + 0x5e, 0x40, 0xce, 0x9c, 0x99, 0x24, 0xe4, 0x19, + 0x3d, 0xbb, 0x07, 0x14, 0x3b, 0x34, 0x52, 0x3b, + 0x5f, 0x31, 0xbb, 0x52, 0x55, 0x37, 0x54, 0xf4, + 0x73, 0x05, 0x39, 0xa6, 0xcb, 0x1e, 0x06, 0xf0, + 0x52, 0xb5, 0x12, 0x6f, 0x01, 0x09, 0xda, 0xc7, + 0xb3, 0x09, 0x07, 0xba, 0x80, 0x50, 0xeb, 0xbd}, + .exp1_len = 64, + .exp2 = {0x40, 0x92, 0x74, 0x80, 0x43, 0xa9, 0xd4, 0xaf, + 0x92, 0x69, 0xab, 0x36, 0x09, 0xf1, 0x2f, 0x13, + 0x9a, 0xde, 0x75, 0x65, 0xe9, 0x96, 0x91, 0x8f, + 0xa0, 0x81, 0xed, 0x4d, 0x9d, 0x8a, 0x39, 0x78, + 0xfa, 0x92, 0x7a, 0xd6, 0x1c, 0xdf, 0x07, 0xc6, + 0x1c, 0xee, 0xde, 0x96, 0xb9, 0x6d, 0xf4, 0x6e, + 0x7c, 0x68, 0xef, 0xca, 0x8b, 0xfe, 0x63, 0xad, + 0xd4, 0x83, 0xaa, 0x32, 0x22, 0x8a, 0xfd, 0xc1}, + .exp2_len = 64, + .coef = {0x2a, 0x61, 0x94, 0xca, 0x29, 0x70, 0x72, 0x38, + 0x45, 0xff, 0xf3, 0x8c, 0xa1, 0xa9, 0xa3, 0xb5, + 0x66, 0xb4, 0x24, 0x5d, 0xe2, 0xf9, 0x01, 0x34, + 0xb8, 0xe6, 0xae, 0xc8, 0xae, 0x07, 0xf3, 0xbb, + 0x7c, 0x5e, 0x5a, 0xe6, 0xe1, 0x83, 0x34, 0x85, + 0xe5, 0x5d, 0x8c, 0xa6, 0x0c, 0xe1, 0x64, 0x2f, + 0x72, 0x75, 0x96, 0x8e, 0x66, 0x12, 0x38, 0x35, + 0x52, 0x11, 0xc6, 0x38, 0x48, 0x94, 0x0f, 0x3c}, + .coef_len = 64, + .msg = {0x9d, 0xe5, 0xca, 0x46, 0x74, 0x85, 0x61, 0xa0, + 0xb9, 0x28, 0xb2, 0x60, 0xa9, 0x5a, 0x3e, 0xd9, + 0x20, 0xad, 0xc8, 0xd5, 0xee, 0xb9, 0x27, 0x1d, + 0xc7, 0x1b, 0xc1, 0x4f, 0x69, 0xcc, 0xd6, 0x31, + 0x1d, 0x18, 0x6a, 0x77, 0x9f, 0x5e, 0xb8, 0xdb, + 0x17, 0xc6, 0x90, 0xd6, 0x86, 0x7c, 0xf3, 0x36, + 0x9b, 0xbf, 0xf1, 0x5f, 0xab, 0xb3, 0xcd, 0x2c, + 0xfd, 0xd6, 0xf7, 0xd7, 0x52, 0x86, 0xff, 0x2d, + 0x24, 0x99, 0xc5, 0xab, 0xb4, 0x8e, 0xd5, 0x4f, + 0xd4, 0xd8, 0x49, 0xa9, 0x18, 0x0e, 0x11, 0x0e, + 0x0a, 0x53, 0xa7, 0x21, 0x39, 0x82, 0x92, 0x11, + 0x0f, 0xe8, 0xbe, 0x26}, + .msg_len = 92, + .sig = {0x44, 0x5f, 0xf5, 0xb6, 0x87, 0x9f, 0x8c, 0xe7, + 0x53, 0x95, 0x01, 0x6f, 0x04, 0x95, 0xf1, 0x31, + 0x35, 0xb1, 0x79, 0xe7, 0x3a, 0x3c, 0xae, 0xb3, + 0x30, 0xe3, 0xcd, 0xa7, 0xf3, 0x1f, 0x1d, 0xcb, + 0xa7, 0xaa, 0x82, 0xe2, 0x68, 0xc9, 0x35, 0xe9, + 0xd7, 0x01, 0x4e, 0x0b, 0x0d, 0xce, 0xa6, 0x9c, + 0x7b, 0x96, 0x8a, 0xdb, 0x17, 0x42, 0x4a, 0x64, + 0xdf, 0xd1, 0xe2, 0xbc, 0x57, 0x07, 0xf9, 0x20, + 0xfc, 0x0c, 0x83, 0xcc, 0x63, 0xdf, 0xc7, 0x4b, + 0x96, 0x3e, 0x68, 0x2b, 0x46, 0xa2, 0x2a, 0xc2, + 0x56, 0xac, 0x6b, 0xe5, 0x70, 0x9c, 0x07, 0xcf, + 0xcc, 0x3d, 0x4e, 0xba, 0x3a, 0x1d, 0x61, 0xab, + 0x15, 0xf1, 0xba, 0xdb, 0x0a, 0x49, 0xfb, 0x5c, + 0xf0, 0x9a, 0x1f, 0x74, 0x81, 0xa3, 0xaa, 0xea, + 0xf7, 0xc2, 0x57, 0x54, 0x03, 0x77, 0xae, 0xa7, + 0xb5, 0x44, 0x17, 0xa6, 0x09, 0xc7, 0x6f, 0x4c}, + .sig_len = 128, + .chunks = {92, 0}, + .num_chunks = 2, + }, + { // 14 + .mod = {0xc5, 0x5f, 0xfb, 0xdd, 0x6a, 0x27, 0x53, 0xbc, + 0x02, 0xaf, 0x20, 0xae, 0x18, 0xea, 0x0d, 0xaf, + 0x23, 0x0b, 0xb6, 0xf8, 0x79, 0x5d, 0x05, 0xef, + 0xec, 0xc8, 0x15, 0xba, 0xec, 0xe2, 0x2b, 0x38, + 0x79, 0x99, 0x5f, 0x6d, 0x97, 0x64, 0xc1, 0xdf, + 0x8f, 0x97, 0x85, 0x13, 0x81, 0x68, 0x62, 0x66, + 0xb8, 0x09, 0x2f, 0xb6, 0x01, 0x18, 0x98, 0xa7, + 0x67, 0x07, 0xa4, 0xd1, 0xd5, 0xbd, 0xa0, 0x8d, + 0x24, 0x6c, 0x68, 0x7a, 0x8b, 0xba, 0xfa, 0x63, + 0x98, 0xac, 0x9e, 0xa2, 0x72, 0x68, 0x23, 0x71, + 0x4a, 0x0c, 0x39, 0x34, 0xca, 0x6e, 0x5f, 0x8c, + 0xe3, 0x39, 0x87, 0xb5, 0x34, 0x85, 0x7e, 0xa9, + 0xf8, 0x5c, 0xc4, 0xe1, 0x9a, 0x1d, 0x21, 0x83, + 0xe0, 0xe4, 0xc8, 0xaa, 0x55, 0xcb, 0x22, 0x7b, + 0x0e, 0x56, 0xce, 0xb2, 0xb6, 0x2b, 0x30, 0xef, + 0xc7, 0x88, 0x64, 0xb2, 0xf9, 0xfb, 0x92, 0x49}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x07, 0xe3, 0xfa, 0x71, 0xb3, 0x98, 0xb6, 0xe4, + 0x41, 0x47, 0x37, 0x0b, 0x3e, 0xbb, 0xbc, 0xa8, + 0x4f, 0xc2, 0x5c, 0x22, 0x3a, 0xd7, 0xd9, 0x30, + 0xea, 0x4a, 0x65, 0x73, 0xff, 0x9c, 0x5b, 0x15, + 0xfa, 0xe6, 0x82, 0xc6, 0x22, 0xd3, 0x48, 0x5c, + 0xe3, 0xa4, 0xaf, 0x11, 0x44, 0x8f, 0x23, 0xbf, + 0xef, 0x83, 0x8e, 0x80, 0xbc, 0x32, 0x7b, 0x87, + 0xd5, 0xba, 0x9c, 0x80, 0x37, 0x07, 0x49, 0xaf, + 0xc8, 0xc1, 0xc0, 0x17, 0x54, 0x6f, 0xc6, 0xb6, + 0x59, 0x31, 0xb7, 0x59, 0xca, 0x43, 0x41, 0xfa, + 0x5e, 0x5e, 0x10, 0xb2, 0x40, 0x87, 0xe6, 0xe2, + 0xc0, 0xf4, 0xdb, 0xb7, 0x90, 0x69, 0x52, 0x99, + 0x9c, 0xbd, 0x90, 0xd2, 0x43, 0x5f, 0xca, 0xcc, + 0x9c, 0x82, 0xe4, 0x8f, 0xdf, 0x24, 0xe4, 0x95, + 0xcf, 0xf3, 0x0a, 0xd4, 0x19, 0xe7, 0x12, 0x3e, + 0x3a, 0xc9, 0x42, 0x27, 0x2e, 0x1a, 0xba, 0xb1}, + .privexp_len = 128, + .prime1 = {0xf7, 0xf7, 0xc0, 0x02, 0xf0, 0x19, 0x6e, 0xcd, + 0xd7, 0x1b, 0xa5, 0xad, 0x74, 0x2b, 0x69, 0x48, + 0x27, 0xd2, 0x88, 0xaf, 0x1b, 0x1b, 0xb6, 0x9c, + 0x5e, 0xd7, 0xfb, 0x22, 0x9d, 0xee, 0x4b, 0x7a, + 0x32, 0xf2, 0xf7, 0x56, 0x8a, 0x6f, 0xca, 0xf3, + 0x83, 0xd8, 0x9a, 0xda, 0x9f, 0xc1, 0x4a, 0x7b, + 0xa5, 0xd0, 0xa4, 0xa4, 0x6c, 0x2c, 0x54, 0x3e, + 0xec, 0x17, 0x75, 0x49, 0xc8, 0xa0, 0x48, 0xb7}, + .prime1_len = 64, + .prime2 = {0xcb, 0xc4, 0xb2, 0x86, 0x04, 0x76, 0xa2, 0xd3, + 0xe8, 0xa4, 0xda, 0x21, 0x00, 0x16, 0xca, 0xce, + 0xd0, 0xe3, 0x67, 0xcb, 0x86, 0x77, 0x10, 0xa4, + 0xb5, 0xaa, 0x2d, 0xf2, 0xb8, 0xe5, 0xda, 0xf5, + 0xfd, 0xc6, 0x47, 0x80, 0x7d, 0x4d, 0x5e, 0xbb, + 0x6c, 0x56, 0xb9, 0x76, 0x3c, 0xcd, 0xae, 0x4d, + 0xea, 0x33, 0x08, 0xeb, 0x0a, 0xc2, 0xa8, 0x95, + 0x01, 0xcb, 0x20, 0x9d, 0x26, 0x39, 0xfc, 0xff}, + .prime2_len = 64, + .exp1 = {0x6c, 0x76, 0x27, 0xbc, 0xa1, 0x3c, 0xde, 0xa4, + 0x96, 0xa4, 0x77, 0x31, 0x89, 0x90, 0xbb, 0x7a, + 0x5e, 0x40, 0xce, 0x9c, 0x99, 0x24, 0xe4, 0x19, + 0x3d, 0xbb, 0x07, 0x14, 0x3b, 0x34, 0x52, 0x3b, + 0x5f, 0x31, 0xbb, 0x52, 0x55, 0x37, 0x54, 0xf4, + 0x73, 0x05, 0x39, 0xa6, 0xcb, 0x1e, 0x06, 0xf0, + 0x52, 0xb5, 0x12, 0x6f, 0x01, 0x09, 0xda, 0xc7, + 0xb3, 0x09, 0x07, 0xba, 0x80, 0x50, 0xeb, 0xbd}, + .exp1_len = 64, + .exp2 = {0x40, 0x92, 0x74, 0x80, 0x43, 0xa9, 0xd4, 0xaf, + 0x92, 0x69, 0xab, 0x36, 0x09, 0xf1, 0x2f, 0x13, + 0x9a, 0xde, 0x75, 0x65, 0xe9, 0x96, 0x91, 0x8f, + 0xa0, 0x81, 0xed, 0x4d, 0x9d, 0x8a, 0x39, 0x78, + 0xfa, 0x92, 0x7a, 0xd6, 0x1c, 0xdf, 0x07, 0xc6, + 0x1c, 0xee, 0xde, 0x96, 0xb9, 0x6d, 0xf4, 0x6e, + 0x7c, 0x68, 0xef, 0xca, 0x8b, 0xfe, 0x63, 0xad, + 0xd4, 0x83, 0xaa, 0x32, 0x22, 0x8a, 0xfd, 0xc1}, + .exp2_len = 64, + .coef = {0x2a, 0x61, 0x94, 0xca, 0x29, 0x70, 0x72, 0x38, + 0x45, 0xff, 0xf3, 0x8c, 0xa1, 0xa9, 0xa3, 0xb5, + 0x66, 0xb4, 0x24, 0x5d, 0xe2, 0xf9, 0x01, 0x34, + 0xb8, 0xe6, 0xae, 0xc8, 0xae, 0x07, 0xf3, 0xbb, + 0x7c, 0x5e, 0x5a, 0xe6, 0xe1, 0x83, 0x34, 0x85, + 0xe5, 0x5d, 0x8c, 0xa6, 0x0c, 0xe1, 0x64, 0x2f, + 0x72, 0x75, 0x96, 0x8e, 0x66, 0x12, 0x38, 0x35, + 0x52, 0x11, 0xc6, 0x38, 0x48, 0x94, 0x0f, 0x3c}, + .coef_len = 64, + .msg = {0x18, 0x3b, 0xa1, 0xa3, 0x81, 0x1d, 0x62, 0x5c, + 0xa9, 0xda, 0x1b, 0xba, 0xae, 0xdc, 0x76, 0x19, + 0x20, 0x12, 0xfc, 0xb6, 0x74, 0xbb, 0x9e, 0x77, + 0xd8, 0xf3, 0x77, 0x08, 0xd2, 0x40, 0xd3, 0x49, + 0xe0, 0x57, 0x97, 0x41, 0x6f, 0xeb, 0x24, 0xe3, + 0x01, 0x8c, 0x7a, 0x20, 0x5d, 0x05, 0x9d, 0xe8, + 0xe0, 0xae, 0x05, 0xa8, 0xd7, 0xe0, 0x9e, 0xaf, + 0xee, 0xb9, 0xf0, 0x6d, 0xe5, 0xd4, 0x28, 0x7a, + 0xbb, 0xef, 0x05, 0x9b, 0xc5, 0x86, 0xb2, 0x1c, + 0x82, 0xd6, 0x4a, 0xec, 0xe8, 0xd7, 0x42, 0x8a, + 0xfc, 0xd7, 0xb2, 0x2f, 0xc5, 0xd1, 0x68, 0xbc, + 0x07, 0x6b, 0x61, 0x5f, 0x02, 0x73, 0x3c, 0xb6, + 0x31, 0x25, 0xc8, 0xf3, 0x6d, 0x5c, 0xb8, 0x09, + 0xce, 0x80, 0x65, 0x08, 0x23, 0x98, 0xb3, 0x88, + 0x5a, 0x89, 0x19, 0x57, 0x0c, 0x47, 0x8a, 0x07, + 0x2f, 0x59, 0x66, 0x15, 0xd7, 0x8f, 0x01, 0x36, + 0xd1, 0x1b, 0xe3, 0x2b, 0x3f, 0xe0, 0xf4, 0xfb, + 0xe3, 0xc7, 0xda, 0x5d, 0x81, 0x34, 0x19, 0x10, + 0x17, 0x7e, 0x48, 0xb1, 0xbb, 0xac, 0x27, 0x6c, + 0x12, 0xee, 0x81, 0x54, 0x65, 0xdc, 0x67, 0xd4, + 0x53, 0x24, 0xf9, 0x05, 0xaa, 0xca, 0x48, 0x38, + 0xd8, 0x1f, 0x74, 0x31, 0x46, 0x3e, 0x89, 0xeb, + 0x8b, 0x95, 0x36, 0x58, 0x69, 0x36, 0xaf, 0xb4, + 0x2c, 0xb4, 0x7b, 0xd8, 0xc3, 0x18, 0x29, 0xd3, + 0x1e, 0xc1, 0xee, 0x29, 0xf9, 0x1c, 0xcc, 0x6d, + 0xf9, 0xcd, 0x1b, 0x0b, 0x9b, 0x86, 0x46, 0xb6, + 0x02, 0x67, 0xfd, 0x7e, 0xce, 0xae, 0x92, 0xc0, + 0xae, 0x9e, 0x0c, 0xe5, 0xff, 0x6f, 0x7e, 0x0b, + 0xf7, 0x56, 0xa9, 0xb8, 0xff, 0xc9, 0xc6, 0x16}, + .msg_len = 232, + .sig = {0xab, 0x4b, 0x78, 0x96, 0x4c, 0x2a, 0x35, 0xd3, + 0x28, 0x55, 0xe0, 0xef, 0xce, 0xd3, 0x4b, 0xf8, + 0x02, 0x19, 0xb5, 0x8c, 0x48, 0x8e, 0xa3, 0x75, + 0xb1, 0xf3, 0x27, 0x16, 0x6a, 0x51, 0x35, 0xe5, + 0xda, 0x99, 0x45, 0xc2, 0x87, 0x29, 0x7a, 0x3d, + 0x93, 0x2e, 0x57, 0x27, 0x46, 0xf0, 0x22, 0x74, + 0x8b, 0x85, 0x58, 0x5a, 0x0a, 0xbd, 0x91, 0x86, + 0xf4, 0xac, 0x35, 0xed, 0xc8, 0x50, 0xd2, 0xfd, + 0x88, 0x05, 0xb9, 0xe9, 0xf5, 0x1a, 0x5a, 0xdc, + 0xb9, 0x5e, 0x1a, 0xc1, 0x72, 0x9e, 0x57, 0xb8, + 0x53, 0x31, 0xc1, 0xed, 0x15, 0xc3, 0xd0, 0xcf, + 0xae, 0x33, 0xf6, 0x1c, 0x11, 0x9b, 0x55, 0xc9, + 0x5e, 0x34, 0x4b, 0x72, 0xf2, 0xb4, 0xf8, 0xe7, + 0xe8, 0xfa, 0xc7, 0xa3, 0x3e, 0x5b, 0x8b, 0x27, + 0x6a, 0x60, 0x88, 0xa7, 0xfa, 0xbf, 0x4f, 0xa1, + 0x72, 0x35, 0x7f, 0xb6, 0xe3, 0xf4, 0x4a, 0x94}, + .sig_len = 128, + .chunks = {100, 32, 100}, + .num_chunks = 3, + }, + { // 15 + .mod = {0xd6, 0x31, 0x14, 0x57, 0xe1, 0xca, 0xf1, 0x22, + 0x44, 0x36, 0x69, 0x79, 0x83, 0xc8, 0x6d, 0xd3, + 0x38, 0x20, 0x58, 0x62, 0xd2, 0xa1, 0x05, 0xba, + 0xf7, 0x10, 0x34, 0x28, 0xfd, 0x83, 0x53, 0xa1, + 0x9b, 0x7b, 0xa4, 0x22, 0x8f, 0x78, 0xb4, 0x7f, + 0x79, 0x07, 0x35, 0x70, 0x34, 0xc5, 0x2d, 0x85, + 0x97, 0xda, 0x2b, 0x5d, 0x13, 0xdc, 0x53, 0x5b, + 0x83, 0x6c, 0x74, 0x13, 0x0a, 0x36, 0x48, 0x91, + 0x8d, 0x4a, 0x7a, 0x83, 0x99, 0x0c, 0x2e, 0x28, + 0x81, 0x6a, 0xec, 0x0f, 0xca, 0x01, 0xd1, 0x05, + 0xc6, 0xc6, 0x52, 0xec, 0x57, 0x33, 0xd0, 0x1f, + 0x00, 0x58, 0xb2, 0xdf, 0x5a, 0xe6, 0x73, 0x33, + 0x40, 0x5a, 0x3a, 0x5b, 0x12, 0x20, 0xa2, 0x6a, + 0xc3, 0xd1, 0x42, 0xf2, 0xb4, 0xd8, 0x37, 0xeb, + 0x73, 0x86, 0xa4, 0x0a, 0x74, 0xcc, 0x3d, 0x1e, + 0x4f, 0xbc, 0x64, 0xfd, 0x7d, 0xa6, 0x3c, 0x41}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x5e, 0xa6, 0x11, 0x77, 0x44, 0x2f, 0x89, 0x9e, + 0xba, 0xc5, 0xd0, 0x96, 0x01, 0xc5, 0xef, 0xc2, + 0x06, 0x6b, 0x44, 0xa3, 0x66, 0xb0, 0x00, 0xf8, + 0x3d, 0x74, 0xcb, 0x97, 0xd1, 0x6e, 0xd6, 0xe5, + 0xf2, 0xef, 0x0f, 0xf8, 0xb5, 0xad, 0x81, 0x15, + 0x53, 0x45, 0xfc, 0x37, 0x39, 0x1a, 0x68, 0xa3, + 0x40, 0x17, 0x08, 0x52, 0x79, 0x14, 0x43, 0x41, + 0x8d, 0x31, 0xbf, 0x99, 0x2a, 0x4a, 0x12, 0x86, + 0x6f, 0xe9, 0xff, 0xcc, 0xde, 0xbb, 0xbb, 0xa6, + 0x37, 0xee, 0x88, 0x7b, 0x71, 0x6c, 0xaa, 0x92, + 0xe2, 0x49, 0xce, 0xd6, 0x57, 0xee, 0xd7, 0x1f, + 0x5c, 0xcd, 0xd9, 0x16, 0x3f, 0x32, 0x69, 0x52, + 0x5d, 0x78, 0x9f, 0x4b, 0x33, 0xc4, 0x8a, 0x95, + 0x76, 0x44, 0x36, 0xec, 0x32, 0x5e, 0x86, 0x89, + 0x69, 0x1c, 0x27, 0x2d, 0x90, 0xbd, 0x88, 0x88, + 0x98, 0x51, 0x37, 0x2f, 0xb8, 0xdc, 0xb9}, + .privexp_len = 127, + .prime1 = {0xf3, 0xd4, 0xb8, 0x51, 0xad, 0x7a, 0xc7, 0x78, + 0xbe, 0xcd, 0xdd, 0xae, 0x71, 0xb6, 0x13, 0xf6, + 0x59, 0x7c, 0x70, 0x75, 0xc4, 0xd2, 0x8d, 0xdb, + 0xae, 0x1e, 0xfa, 0xcf, 0x03, 0x59, 0x71, 0xab, + 0x63, 0xee, 0x90, 0xdb, 0xbd, 0xfb, 0xda, 0x43, + 0x25, 0xa1, 0x5f, 0xbf, 0x84, 0x5e, 0xea, 0x54, + 0xbb, 0xcd, 0x05, 0x57, 0x4b, 0x1c, 0xd6, 0x01, + 0xdc, 0xad, 0xba, 0x12, 0x06, 0x28, 0x05, 0xb9}, + .prime1_len = 64, + .prime2 = {0xe0, 0xe1, 0xad, 0x57, 0xd6, 0x8f, 0x30, 0x13, + 0x28, 0x8c, 0x14, 0x83, 0xe8, 0xc5, 0xb1, 0x2e, + 0xfe, 0xb6, 0xec, 0x14, 0x5a, 0xe4, 0x18, 0x8e, + 0x1b, 0x3b, 0x39, 0x04, 0x87, 0x90, 0x0a, 0xd2, + 0xc3, 0x25, 0xd2, 0x32, 0x80, 0x6a, 0x62, 0x17, + 0x34, 0x2a, 0x65, 0x75, 0x95, 0x14, 0xf2, 0x26, + 0x8f, 0xca, 0x72, 0xc4, 0xc5, 0xbb, 0xa0, 0x32, + 0x81, 0x89, 0xdc, 0xfa, 0xe2, 0x06, 0xae, 0xc9}, + .prime2_len = 64, + .exp1 = {0x3b, 0xb6, 0xd2, 0xd5, 0x1d, 0xf9, 0x3d, 0xb4, + 0xb2, 0x75, 0xd4, 0x5e, 0x8e, 0x76, 0x9a, 0xf8, + 0xef, 0xfd, 0x6b, 0xc5, 0x4b, 0xc8, 0x8c, 0xf9, + 0x49, 0xf1, 0x48, 0x57, 0x3e, 0x68, 0xbf, 0x4f, + 0xcc, 0x0f, 0x76, 0xe6, 0x79, 0xe6, 0x9e, 0x13, + 0x67, 0xb9, 0xd7, 0xab, 0x1d, 0x8d, 0xe9, 0x31, + 0x8b, 0x34, 0xb0, 0xa4, 0x2a, 0x3f, 0x0b, 0xa2, + 0x35, 0x1b, 0x4e, 0xc0, 0x6f, 0x45, 0x89, 0xf1}, + .exp1_len = 64, + .exp2 = {0x71, 0xf4, 0xaa, 0x5c, 0x8a, 0x93, 0x80, 0xaf, + 0x14, 0xaa, 0xf7, 0x72, 0x68, 0xb0, 0x55, 0x3b, + 0x15, 0x44, 0x28, 0x99, 0x9f, 0xfd, 0x5a, 0x1c, + 0x18, 0xdc, 0x87, 0xe6, 0x2d, 0xb3, 0xe6, 0x68, + 0x2b, 0x0f, 0xad, 0x56, 0x7e, 0x10, 0x6a, 0xa8, + 0x8b, 0x7c, 0xb8, 0x71, 0x3f, 0x1c, 0xa0, 0x20, + 0xbe, 0x58, 0xbe, 0x93, 0xcc, 0x07, 0x6a, 0x04, + 0x6d, 0xf4, 0x28, 0x90, 0xd1, 0x9c, 0xc5, 0x51}, + .exp2_len = 64, + .coef = {0x23, 0x1a, 0xb8, 0xdd, 0x9a, 0x56, 0x99, 0xd7, + 0x97, 0x59, 0x11, 0xef, 0x0e, 0xf8, 0x7c, 0x28, + 0xdd, 0xb9, 0x2e, 0x24, 0x6e, 0xc3, 0x4c, 0x5f, + 0xac, 0x33, 0x83, 0x22, 0xdd, 0xec, 0x89, 0x8d, + 0x56, 0x68, 0x67, 0x45, 0x3d, 0xe6, 0xd7, 0x8a, + 0x45, 0xc3, 0x16, 0xb1, 0x45, 0xa2, 0x86, 0x18, + 0x94, 0x0e, 0x1a, 0xcd, 0x11, 0x58, 0xc3, 0xaf, + 0x92, 0xfa, 0xab, 0xfd, 0xc3, 0x97, 0x84, 0x32}, + .coef_len = 64, + .msg = {0x8f, 0x75, 0x0e, 0x65, 0x95, 0x1b, 0x5d, 0xe7, + 0x58, 0x14, 0xb0, 0xb7, 0x66, 0x30, 0xdc, 0x9f, + 0x1c, 0x62, 0x53, 0xa0, 0x59, 0x0e, 0xac, 0xb5, + 0x51, 0x2a, 0x8a, 0x4e, 0x1a, 0x8b, 0xe8, 0x52, + 0x5d, 0x36, 0x94, 0x1f, 0xa9, 0xd0, 0x92, 0xf6, + 0xbb, 0x44, 0x22, 0xaa, 0x8c, 0x0a, 0xd6, 0x42, + 0x3e, 0xa2, 0x8c, 0x10, 0xca, 0xa6, 0xe9, 0x54, + 0xb7, 0x95, 0x69, 0xd4, 0x4c, 0x86, 0x0f, 0x1c, + 0x65, 0x81, 0xeb, 0x17, 0xa7, 0x54, 0x3e, 0x7b, + 0xf7, 0xfe}, + .msg_len = 74, + .sig = {0xb1, 0x8b, 0x5e, 0xc8, 0x8d, 0x4e, 0x24, 0xc9, + 0x14, 0xb6, 0x65, 0xff, 0x9a, 0x2c, 0x75, 0xf4, + 0xe9, 0x19, 0x37, 0xdf, 0x8c, 0x19, 0x95, 0x59, + 0x43, 0xe4, 0x51, 0xad, 0xdf, 0x34, 0x84, 0xe4, + 0x97, 0x97, 0x8d, 0x26, 0xda, 0x23, 0x1a, 0xf1, + 0x4d, 0x9c, 0x29, 0x27, 0xed, 0x21, 0x0a, 0xfb, + 0xf9, 0xde, 0xe3, 0x32, 0x67, 0xaa, 0x45, 0x68, + 0x46, 0x49, 0xe8, 0x6f, 0xb2, 0x25, 0xa0, 0x53, + 0xb5, 0x45, 0x52, 0x90, 0xc3, 0x20, 0xe3, 0xf6, + 0x40, 0x62, 0x3c, 0x75, 0xca, 0x42, 0x37, 0x21, + 0xf2, 0x80, 0xb8, 0x87, 0x44, 0x24, 0x97, 0xf3, + 0x2a, 0x90, 0xd7, 0x8f, 0x64, 0x44, 0x04, 0x77, + 0xad, 0x09, 0x27, 0xc7, 0xba, 0x01, 0xc4, 0x4d, + 0xa9, 0xd5, 0xc2, 0x83, 0xa4, 0x38, 0xbe, 0x0d, + 0xc5, 0x80, 0xa0, 0x05, 0x28, 0xfc, 0x65, 0xe2, + 0x04, 0xd4, 0x2a, 0x2d, 0x4e, 0x29, 0x13, 0xc1}, + .sig_len = 128, + .chunks = {20, 20, 20, 14}, + .num_chunks = 4, + }, + { // 16 + .mod = {0xd6, 0x31, 0x14, 0x57, 0xe1, 0xca, 0xf1, 0x22, + 0x44, 0x36, 0x69, 0x79, 0x83, 0xc8, 0x6d, 0xd3, + 0x38, 0x20, 0x58, 0x62, 0xd2, 0xa1, 0x05, 0xba, + 0xf7, 0x10, 0x34, 0x28, 0xfd, 0x83, 0x53, 0xa1, + 0x9b, 0x7b, 0xa4, 0x22, 0x8f, 0x78, 0xb4, 0x7f, + 0x79, 0x07, 0x35, 0x70, 0x34, 0xc5, 0x2d, 0x85, + 0x97, 0xda, 0x2b, 0x5d, 0x13, 0xdc, 0x53, 0x5b, + 0x83, 0x6c, 0x74, 0x13, 0x0a, 0x36, 0x48, 0x91, + 0x8d, 0x4a, 0x7a, 0x83, 0x99, 0x0c, 0x2e, 0x28, + 0x81, 0x6a, 0xec, 0x0f, 0xca, 0x01, 0xd1, 0x05, + 0xc6, 0xc6, 0x52, 0xec, 0x57, 0x33, 0xd0, 0x1f, + 0x00, 0x58, 0xb2, 0xdf, 0x5a, 0xe6, 0x73, 0x33, + 0x40, 0x5a, 0x3a, 0x5b, 0x12, 0x20, 0xa2, 0x6a, + 0xc3, 0xd1, 0x42, 0xf2, 0xb4, 0xd8, 0x37, 0xeb, + 0x73, 0x86, 0xa4, 0x0a, 0x74, 0xcc, 0x3d, 0x1e, + 0x4f, 0xbc, 0x64, 0xfd, 0x7d, 0xa6, 0x3c, 0x41}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x5e, 0xa6, 0x11, 0x77, 0x44, 0x2f, 0x89, 0x9e, + 0xba, 0xc5, 0xd0, 0x96, 0x01, 0xc5, 0xef, 0xc2, + 0x06, 0x6b, 0x44, 0xa3, 0x66, 0xb0, 0x00, 0xf8, + 0x3d, 0x74, 0xcb, 0x97, 0xd1, 0x6e, 0xd6, 0xe5, + 0xf2, 0xef, 0x0f, 0xf8, 0xb5, 0xad, 0x81, 0x15, + 0x53, 0x45, 0xfc, 0x37, 0x39, 0x1a, 0x68, 0xa3, + 0x40, 0x17, 0x08, 0x52, 0x79, 0x14, 0x43, 0x41, + 0x8d, 0x31, 0xbf, 0x99, 0x2a, 0x4a, 0x12, 0x86, + 0x6f, 0xe9, 0xff, 0xcc, 0xde, 0xbb, 0xbb, 0xa6, + 0x37, 0xee, 0x88, 0x7b, 0x71, 0x6c, 0xaa, 0x92, + 0xe2, 0x49, 0xce, 0xd6, 0x57, 0xee, 0xd7, 0x1f, + 0x5c, 0xcd, 0xd9, 0x16, 0x3f, 0x32, 0x69, 0x52, + 0x5d, 0x78, 0x9f, 0x4b, 0x33, 0xc4, 0x8a, 0x95, + 0x76, 0x44, 0x36, 0xec, 0x32, 0x5e, 0x86, 0x89, + 0x69, 0x1c, 0x27, 0x2d, 0x90, 0xbd, 0x88, 0x88, + 0x98, 0x51, 0x37, 0x2f, 0xb8, 0xdc, 0xb9}, + .privexp_len = 127, + .prime1 = {0xf3, 0xd4, 0xb8, 0x51, 0xad, 0x7a, 0xc7, 0x78, + 0xbe, 0xcd, 0xdd, 0xae, 0x71, 0xb6, 0x13, 0xf6, + 0x59, 0x7c, 0x70, 0x75, 0xc4, 0xd2, 0x8d, 0xdb, + 0xae, 0x1e, 0xfa, 0xcf, 0x03, 0x59, 0x71, 0xab, + 0x63, 0xee, 0x90, 0xdb, 0xbd, 0xfb, 0xda, 0x43, + 0x25, 0xa1, 0x5f, 0xbf, 0x84, 0x5e, 0xea, 0x54, + 0xbb, 0xcd, 0x05, 0x57, 0x4b, 0x1c, 0xd6, 0x01, + 0xdc, 0xad, 0xba, 0x12, 0x06, 0x28, 0x05, 0xb9}, + .prime1_len = 64, + .prime2 = {0xe0, 0xe1, 0xad, 0x57, 0xd6, 0x8f, 0x30, 0x13, + 0x28, 0x8c, 0x14, 0x83, 0xe8, 0xc5, 0xb1, 0x2e, + 0xfe, 0xb6, 0xec, 0x14, 0x5a, 0xe4, 0x18, 0x8e, + 0x1b, 0x3b, 0x39, 0x04, 0x87, 0x90, 0x0a, 0xd2, + 0xc3, 0x25, 0xd2, 0x32, 0x80, 0x6a, 0x62, 0x17, + 0x34, 0x2a, 0x65, 0x75, 0x95, 0x14, 0xf2, 0x26, + 0x8f, 0xca, 0x72, 0xc4, 0xc5, 0xbb, 0xa0, 0x32, + 0x81, 0x89, 0xdc, 0xfa, 0xe2, 0x06, 0xae, 0xc9}, + .prime2_len = 64, + .exp1 = {0x3b, 0xb6, 0xd2, 0xd5, 0x1d, 0xf9, 0x3d, 0xb4, + 0xb2, 0x75, 0xd4, 0x5e, 0x8e, 0x76, 0x9a, 0xf8, + 0xef, 0xfd, 0x6b, 0xc5, 0x4b, 0xc8, 0x8c, 0xf9, + 0x49, 0xf1, 0x48, 0x57, 0x3e, 0x68, 0xbf, 0x4f, + 0xcc, 0x0f, 0x76, 0xe6, 0x79, 0xe6, 0x9e, 0x13, + 0x67, 0xb9, 0xd7, 0xab, 0x1d, 0x8d, 0xe9, 0x31, + 0x8b, 0x34, 0xb0, 0xa4, 0x2a, 0x3f, 0x0b, 0xa2, + 0x35, 0x1b, 0x4e, 0xc0, 0x6f, 0x45, 0x89, 0xf1}, + .exp1_len = 64, + .exp2 = {0x71, 0xf4, 0xaa, 0x5c, 0x8a, 0x93, 0x80, 0xaf, + 0x14, 0xaa, 0xf7, 0x72, 0x68, 0xb0, 0x55, 0x3b, + 0x15, 0x44, 0x28, 0x99, 0x9f, 0xfd, 0x5a, 0x1c, + 0x18, 0xdc, 0x87, 0xe6, 0x2d, 0xb3, 0xe6, 0x68, + 0x2b, 0x0f, 0xad, 0x56, 0x7e, 0x10, 0x6a, 0xa8, + 0x8b, 0x7c, 0xb8, 0x71, 0x3f, 0x1c, 0xa0, 0x20, + 0xbe, 0x58, 0xbe, 0x93, 0xcc, 0x07, 0x6a, 0x04, + 0x6d, 0xf4, 0x28, 0x90, 0xd1, 0x9c, 0xc5, 0x51}, + .exp2_len = 64, + .coef = {0x23, 0x1a, 0xb8, 0xdd, 0x9a, 0x56, 0x99, 0xd7, + 0x97, 0x59, 0x11, 0xef, 0x0e, 0xf8, 0x7c, 0x28, + 0xdd, 0xb9, 0x2e, 0x24, 0x6e, 0xc3, 0x4c, 0x5f, + 0xac, 0x33, 0x83, 0x22, 0xdd, 0xec, 0x89, 0x8d, + 0x56, 0x68, 0x67, 0x45, 0x3d, 0xe6, 0xd7, 0x8a, + 0x45, 0xc3, 0x16, 0xb1, 0x45, 0xa2, 0x86, 0x18, + 0x94, 0x0e, 0x1a, 0xcd, 0x11, 0x58, 0xc3, 0xaf, + 0x92, 0xfa, 0xab, 0xfd, 0xc3, 0x97, 0x84, 0x32}, + .coef_len = 64, + .msg = {0xbd, 0xbf, 0x3b, 0x36, 0x40, 0x73, 0xfe, 0x04, + 0x8f, 0xba, 0xe5, 0x5e, 0x3c, 0xde, 0x66, 0x8e, + 0x84, 0xf7, 0x53, 0xab, 0xfc, 0x71, 0x0b, 0x8c, + 0xdb, 0x7b, 0x6c, 0x0c, 0xf8, 0x2d, 0xd5, 0xb6, + 0x74, 0xd2, 0x1e, 0x2b, 0x3e, 0x36, 0xb1, 0xb0, + 0x36, 0x0d, 0xf8, 0xbf, 0x7e, 0x62, 0x27, 0xc9, + 0x2e, 0x15, 0xf3, 0xd7, 0x84}, + .msg_len = 53, + .sig = {0x66, 0xac, 0xf0, 0x43, 0xbc, 0x6a, 0xae, 0x81, + 0xa4, 0xd5, 0x2b, 0x4e, 0x8c, 0x40, 0x12, 0x8b, + 0x25, 0xc6, 0xd1, 0x0a, 0x8c, 0x69, 0x8c, 0x83, + 0xae, 0xd7, 0x1e, 0x8f, 0x35, 0x83, 0x89, 0x8b, + 0xe8, 0xf4, 0xc9, 0xbe, 0xa4, 0xb6, 0x31, 0x90, + 0xe2, 0x15, 0x26, 0xca, 0xf8, 0x3a, 0xb1, 0x4a, + 0x4f, 0x8b, 0xeb, 0xe8, 0x13, 0xa5, 0xab, 0xeb, + 0x95, 0x95, 0x67, 0xbb, 0x2f, 0x06, 0xc5, 0xf1, + 0x1e, 0x46, 0x4b, 0x5c, 0xdf, 0x7b, 0x2a, 0x13, + 0x2d, 0x42, 0x6d, 0xdb, 0xec, 0xf5, 0x85, 0x90, + 0x0a, 0x0d, 0x80, 0x92, 0xca, 0x52, 0xb6, 0xdc, + 0x0a, 0xbc, 0x35, 0xf1, 0x40, 0x94, 0x69, 0x89, + 0x46, 0xe1, 0xcd, 0x0e, 0xcd, 0x6b, 0xd4, 0x1e, + 0x2c, 0x6f, 0x96, 0x3e, 0xe8, 0x9c, 0x82, 0x19, + 0x3e, 0xcc, 0x5f, 0xd4, 0x76, 0x30, 0xd3, 0x4a, + 0xd1, 0x6c, 0xa2, 0x47, 0x9e, 0xaf, 0x06, 0x2d}, + .sig_len = 128, + }, + { // 17 + .mod = {0xd6, 0x31, 0x14, 0x57, 0xe1, 0xca, 0xf1, 0x22, + 0x44, 0x36, 0x69, 0x79, 0x83, 0xc8, 0x6d, 0xd3, + 0x38, 0x20, 0x58, 0x62, 0xd2, 0xa1, 0x05, 0xba, + 0xf7, 0x10, 0x34, 0x28, 0xfd, 0x83, 0x53, 0xa1, + 0x9b, 0x7b, 0xa4, 0x22, 0x8f, 0x78, 0xb4, 0x7f, + 0x79, 0x07, 0x35, 0x70, 0x34, 0xc5, 0x2d, 0x85, + 0x97, 0xda, 0x2b, 0x5d, 0x13, 0xdc, 0x53, 0x5b, + 0x83, 0x6c, 0x74, 0x13, 0x0a, 0x36, 0x48, 0x91, + 0x8d, 0x4a, 0x7a, 0x83, 0x99, 0x0c, 0x2e, 0x28, + 0x81, 0x6a, 0xec, 0x0f, 0xca, 0x01, 0xd1, 0x05, + 0xc6, 0xc6, 0x52, 0xec, 0x57, 0x33, 0xd0, 0x1f, + 0x00, 0x58, 0xb2, 0xdf, 0x5a, 0xe6, 0x73, 0x33, + 0x40, 0x5a, 0x3a, 0x5b, 0x12, 0x20, 0xa2, 0x6a, + 0xc3, 0xd1, 0x42, 0xf2, 0xb4, 0xd8, 0x37, 0xeb, + 0x73, 0x86, 0xa4, 0x0a, 0x74, 0xcc, 0x3d, 0x1e, + 0x4f, 0xbc, 0x64, 0xfd, 0x7d, 0xa6, 0x3c, 0x41}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x5e, 0xa6, 0x11, 0x77, 0x44, 0x2f, 0x89, 0x9e, + 0xba, 0xc5, 0xd0, 0x96, 0x01, 0xc5, 0xef, 0xc2, + 0x06, 0x6b, 0x44, 0xa3, 0x66, 0xb0, 0x00, 0xf8, + 0x3d, 0x74, 0xcb, 0x97, 0xd1, 0x6e, 0xd6, 0xe5, + 0xf2, 0xef, 0x0f, 0xf8, 0xb5, 0xad, 0x81, 0x15, + 0x53, 0x45, 0xfc, 0x37, 0x39, 0x1a, 0x68, 0xa3, + 0x40, 0x17, 0x08, 0x52, 0x79, 0x14, 0x43, 0x41, + 0x8d, 0x31, 0xbf, 0x99, 0x2a, 0x4a, 0x12, 0x86, + 0x6f, 0xe9, 0xff, 0xcc, 0xde, 0xbb, 0xbb, 0xa6, + 0x37, 0xee, 0x88, 0x7b, 0x71, 0x6c, 0xaa, 0x92, + 0xe2, 0x49, 0xce, 0xd6, 0x57, 0xee, 0xd7, 0x1f, + 0x5c, 0xcd, 0xd9, 0x16, 0x3f, 0x32, 0x69, 0x52, + 0x5d, 0x78, 0x9f, 0x4b, 0x33, 0xc4, 0x8a, 0x95, + 0x76, 0x44, 0x36, 0xec, 0x32, 0x5e, 0x86, 0x89, + 0x69, 0x1c, 0x27, 0x2d, 0x90, 0xbd, 0x88, 0x88, + 0x98, 0x51, 0x37, 0x2f, 0xb8, 0xdc, 0xb9}, + .privexp_len = 127, + .prime1 = {0xf3, 0xd4, 0xb8, 0x51, 0xad, 0x7a, 0xc7, 0x78, + 0xbe, 0xcd, 0xdd, 0xae, 0x71, 0xb6, 0x13, 0xf6, + 0x59, 0x7c, 0x70, 0x75, 0xc4, 0xd2, 0x8d, 0xdb, + 0xae, 0x1e, 0xfa, 0xcf, 0x03, 0x59, 0x71, 0xab, + 0x63, 0xee, 0x90, 0xdb, 0xbd, 0xfb, 0xda, 0x43, + 0x25, 0xa1, 0x5f, 0xbf, 0x84, 0x5e, 0xea, 0x54, + 0xbb, 0xcd, 0x05, 0x57, 0x4b, 0x1c, 0xd6, 0x01, + 0xdc, 0xad, 0xba, 0x12, 0x06, 0x28, 0x05, 0xb9}, + .prime1_len = 64, + .prime2 = {0xe0, 0xe1, 0xad, 0x57, 0xd6, 0x8f, 0x30, 0x13, + 0x28, 0x8c, 0x14, 0x83, 0xe8, 0xc5, 0xb1, 0x2e, + 0xfe, 0xb6, 0xec, 0x14, 0x5a, 0xe4, 0x18, 0x8e, + 0x1b, 0x3b, 0x39, 0x04, 0x87, 0x90, 0x0a, 0xd2, + 0xc3, 0x25, 0xd2, 0x32, 0x80, 0x6a, 0x62, 0x17, + 0x34, 0x2a, 0x65, 0x75, 0x95, 0x14, 0xf2, 0x26, + 0x8f, 0xca, 0x72, 0xc4, 0xc5, 0xbb, 0xa0, 0x32, + 0x81, 0x89, 0xdc, 0xfa, 0xe2, 0x06, 0xae, 0xc9}, + .prime2_len = 64, + .exp1 = {0x3b, 0xb6, 0xd2, 0xd5, 0x1d, 0xf9, 0x3d, 0xb4, + 0xb2, 0x75, 0xd4, 0x5e, 0x8e, 0x76, 0x9a, 0xf8, + 0xef, 0xfd, 0x6b, 0xc5, 0x4b, 0xc8, 0x8c, 0xf9, + 0x49, 0xf1, 0x48, 0x57, 0x3e, 0x68, 0xbf, 0x4f, + 0xcc, 0x0f, 0x76, 0xe6, 0x79, 0xe6, 0x9e, 0x13, + 0x67, 0xb9, 0xd7, 0xab, 0x1d, 0x8d, 0xe9, 0x31, + 0x8b, 0x34, 0xb0, 0xa4, 0x2a, 0x3f, 0x0b, 0xa2, + 0x35, 0x1b, 0x4e, 0xc0, 0x6f, 0x45, 0x89, 0xf1}, + .exp1_len = 64, + .exp2 = {0x71, 0xf4, 0xaa, 0x5c, 0x8a, 0x93, 0x80, 0xaf, + 0x14, 0xaa, 0xf7, 0x72, 0x68, 0xb0, 0x55, 0x3b, + 0x15, 0x44, 0x28, 0x99, 0x9f, 0xfd, 0x5a, 0x1c, + 0x18, 0xdc, 0x87, 0xe6, 0x2d, 0xb3, 0xe6, 0x68, + 0x2b, 0x0f, 0xad, 0x56, 0x7e, 0x10, 0x6a, 0xa8, + 0x8b, 0x7c, 0xb8, 0x71, 0x3f, 0x1c, 0xa0, 0x20, + 0xbe, 0x58, 0xbe, 0x93, 0xcc, 0x07, 0x6a, 0x04, + 0x6d, 0xf4, 0x28, 0x90, 0xd1, 0x9c, 0xc5, 0x51}, + .exp2_len = 64, + .coef = {0x23, 0x1a, 0xb8, 0xdd, 0x9a, 0x56, 0x99, 0xd7, + 0x97, 0x59, 0x11, 0xef, 0x0e, 0xf8, 0x7c, 0x28, + 0xdd, 0xb9, 0x2e, 0x24, 0x6e, 0xc3, 0x4c, 0x5f, + 0xac, 0x33, 0x83, 0x22, 0xdd, 0xec, 0x89, 0x8d, + 0x56, 0x68, 0x67, 0x45, 0x3d, 0xe6, 0xd7, 0x8a, + 0x45, 0xc3, 0x16, 0xb1, 0x45, 0xa2, 0x86, 0x18, + 0x94, 0x0e, 0x1a, 0xcd, 0x11, 0x58, 0xc3, 0xaf, + 0x92, 0xfa, 0xab, 0xfd, 0xc3, 0x97, 0x84, 0x32}, + .coef_len = 64, + .msg = {0x3c, 0x5c, 0x74, 0xbc, 0x8f, 0xae, 0x80, 0x7a, + 0xe5, 0x8b, 0xd2, 0x13, 0xe6, 0x27, 0x2a, 0xa3, + 0x85, 0x79, 0x31, 0x57, 0x5c, 0x2a, 0xa2, 0xbe, + 0x4b, 0xca, 0xe4, 0xd7, 0x9a, 0xe0, 0x87, 0xb6, + 0xb8, 0x6f, 0x91, 0x5d, 0xf8, 0xc0, 0x96, 0xc1, + 0x22, 0xed, 0xfb, 0xdc, 0x79, 0x7f, 0x9d, 0x70, + 0xb9, 0x76, 0x13, 0x97, 0xfc, 0xe3, 0xd3, 0xe0, + 0xb8, 0xa6, 0xf2, 0x56, 0xdb, 0xc6, 0x60, 0x5b, + 0xa9, 0x48, 0xd5, 0xfb, 0xe6, 0xf5, 0x24, 0x5c, + 0x02, 0x95, 0xce, 0x5d, 0xd7, 0x3b, 0xf7, 0x43, + 0x65, 0x17, 0xf7, 0xc4, 0x22, 0x2d, 0x2c, 0xfd, + 0x85, 0x42, 0xe7, 0xa1, 0x00, 0xcf, 0x05, 0x13, + 0x04, 0xa1, 0xab, 0x6f, 0xe0, 0x05, 0xda, 0x07, + 0x7b, 0x62, 0x87, 0x8f, 0xd0, 0xb7, 0x41, 0xe6, + 0x27, 0x1e, 0x0d, 0x34, 0x6b, 0x20, 0x72, 0x3b, + 0x7e, 0x00, 0xb3, 0xb8, 0x19, 0x4e, 0x1a, 0x46, + 0x0c, 0x6b, 0xf2, 0x56, 0x00, 0x76, 0x82, 0x90, + 0xc1, 0xdc, 0xaa, 0x2f, 0x41, 0xb9, 0x41, 0xa6, + 0x4f, 0xd9, 0x02, 0x14, 0xd5, 0x16, 0x6d, 0x78, + 0xaa, 0xbb, 0xaf, 0x7e, 0x41, 0xd2, 0x4f, 0xf6, + 0x36, 0xc9, 0x76, 0x2f, 0xd8, 0x92, 0x19, 0x9d, + 0x2c, 0xfd, 0x9d, 0xed, 0xa5, 0x00, 0x51, 0xe0, + 0x01, 0xb9, 0xfd, 0x3e, 0x5e, 0x22, 0x27, 0xae, + 0xcb, 0x15, 0xc1, 0xb3, 0x13, 0x71, 0xb3, 0x5a, + 0x78, 0xb3, 0xb8, 0xb7, 0x63, 0x63, 0x76, 0xf1, + 0x34, 0x56, 0x2b, 0x4e, 0x52, 0xf4, 0x51, 0xb7, + 0x41, 0xa1, 0x9a, 0xc9, 0x32, 0x56, 0x9f, 0xf3, + 0x04, 0x1f, 0xaf, 0x12, 0x27, 0x9f, 0x90}, + .msg_len = 223, + .sig = {0x5e, 0x89, 0x7f, 0x87, 0x9b, 0xa4, 0x6f, 0x67, + 0x11, 0x2c, 0xd7, 0xc7, 0xc6, 0xfb, 0x27, 0x37, + 0xad, 0x79, 0x3a, 0x87, 0x28, 0x79, 0x05, 0x2a, + 0x88, 0x45, 0x7a, 0xf5, 0xe9, 0xd5, 0x99, 0x59, + 0xa8, 0x48, 0x13, 0x4a, 0x68, 0x24, 0xde, 0x3a, + 0x67, 0x4f, 0x72, 0xa9, 0x06, 0x87, 0x9e, 0x95, + 0xbe, 0x0e, 0xd8, 0x7e, 0xa9, 0xf9, 0x74, 0xa7, + 0xa0, 0x7b, 0xa9, 0xad, 0xbe, 0xc2, 0xfb, 0xfa, + 0x02, 0x94, 0x37, 0x8b, 0x14, 0xe7, 0x35, 0xf5, + 0x5f, 0x40, 0x3c, 0xa0, 0x53, 0x08, 0x4f, 0x51, + 0xd3, 0xd3, 0x42, 0xd8, 0xaf, 0x9c, 0x64, 0xb4, + 0xd1, 0x54, 0xad, 0x9a, 0xa3, 0xc6, 0xbc, 0xaa, + 0xce, 0x1f, 0x1b, 0xbe, 0x62, 0xee, 0xb5, 0xd0, + 0xe6, 0xc4, 0xc0, 0x30, 0x93, 0xc2, 0xaf, 0x0f, + 0x07, 0x88, 0x8b, 0x8b, 0xbe, 0xfa, 0x79, 0x40, + 0x03, 0x23, 0x13, 0x3f, 0x77, 0x6a, 0x32, 0x13}, + .sig_len = 128, + .chunks = {75, 100, -1, -1, 48}, + .num_chunks = 5, + }, + { // 18 + .mod = {0x01, 0x69, 0x34, 0xcd, 0xff, 0x48, 0x50, 0xb6, + 0x00, 0x2c, 0xc0, 0xf0, 0xf4, 0x01, 0x0a, 0x32, + 0xc6, 0x55, 0xe5, 0xcf, 0x6e, 0x7c, 0x89, 0x93, + 0x7f, 0xd7, 0x55, 0xef, 0x6a, 0xbe, 0x37, 0x9d, + 0xad, 0xde, 0x70, 0xcc, 0x21, 0x77, 0x51, 0xf1, + 0x4c, 0xba, 0x6d, 0x90, 0xfe, 0x52, 0xdc, 0x0a, + 0xf5, 0x8b, 0x25, 0x2f, 0x26, 0xbf, 0x72, 0xda, + 0x57, 0x9f, 0xda, 0xf5, 0x7d, 0xdd, 0x6c, 0xd6, + 0x02, 0x18, 0x79, 0x94, 0x9a, 0x02, 0x76, 0xb4, + 0x43, 0x3f, 0xf0, 0x1e, 0xfc, 0xcc, 0xf3, 0x5a, + 0x11, 0xe7, 0xc7, 0x7b, 0x38, 0xc1, 0x8c, 0xca, + 0x94, 0xae, 0x01, 0x2d, 0x0f, 0x37, 0x04, 0x21, + 0x49, 0x1c, 0x52, 0xad, 0x15, 0xac, 0x76, 0xb1, + 0x2e, 0xcd, 0x21, 0x8f, 0x52, 0xe7, 0x57, 0x86, + 0x6e, 0x08, 0x9d, 0xd8, 0xad, 0xbb, 0x48, 0xe9, + 0xba, 0x89, 0x43, 0x36, 0xc5, 0x75, 0xc4, 0x06, + 0x55}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x0d, 0x17, 0x19, 0xe5, 0xbd, 0x47, 0x6d, 0x87, + 0xc7, 0xec, 0xc3, 0x1e, 0xb8, 0xab, 0x42, 0x5d, + 0x4f, 0xe4, 0xc8, 0xf5, 0xc7, 0xae, 0x23, 0x0a, + 0x10, 0x47, 0x55, 0x3f, 0xfb, 0x53, 0x9f, 0xd3, + 0x85, 0x5a, 0xf5, 0xa4, 0x3b, 0x2d, 0xdd, 0x4e, + 0x95, 0xa2, 0xb3, 0x0d, 0x40, 0x7a, 0xa8, 0x81, + 0x59, 0xbb, 0xad, 0x2a, 0x87, 0x3d, 0x80, 0x93, + 0xb4, 0x8a, 0x4b, 0xce, 0x20, 0xad, 0x99, 0x26, + 0x25, 0x3e, 0xd3, 0x39, 0xac, 0x3b, 0x54, 0x3f, + 0xc7, 0x42, 0x96, 0x95, 0x33, 0x8d, 0xb0, 0xbc, + 0x1d, 0xc3, 0x68, 0x6c, 0xfd, 0x13, 0x9b, 0xb5, + 0xb2, 0x87, 0x36, 0xbc, 0x16, 0x60, 0xa9, 0x53, + 0x48, 0xfc, 0x91, 0xc3, 0x25, 0xd0, 0x3a, 0x7f, + 0xb2, 0x16, 0xd2, 0xd9, 0xcd, 0x93, 0x64, 0xde, + 0x4e, 0xe7, 0xd2, 0x11, 0x9c, 0x3b, 0x0f, 0xbb, + 0xa8, 0xa7, 0x1f, 0x0d, 0x3f, 0x5a, 0xb9, 0xb9}, + .privexp_len = 128, + .prime1 = {0x01, 0x58, 0xc0, 0x24, 0x6c, 0xd1, 0x69, 0xfc, + 0x59, 0x3b, 0x25, 0x8b, 0xbf, 0x45, 0x23, 0xab, + 0x2b, 0x55, 0xc4, 0x60, 0x73, 0x3a, 0x7f, 0xb4, + 0x69, 0x10, 0x90, 0x77, 0xb3, 0x0e, 0x4d, 0x35, + 0xf2, 0x1a, 0x35, 0xb1, 0xf4, 0x1e, 0x42, 0x04, + 0xe8, 0x1d, 0x2e, 0x4c, 0x46, 0x3c, 0x24, 0x11, + 0x39, 0x34, 0x09, 0x8b, 0x45, 0x2d, 0xab, 0x4b, + 0xe1, 0x59, 0x97, 0x20, 0xef, 0x68, 0x72, 0x83, + 0x3d}, + .prime1_len = 65, + .prime2 = {0x01, 0x0c, 0x38, 0x2d, 0xea, 0x5e, 0x7d, 0x79, + 0x29, 0x8c, 0x64, 0x1f, 0xb2, 0xe4, 0xfa, 0x09, + 0xf2, 0x4f, 0x6a, 0x7a, 0x45, 0x9a, 0x88, 0x2c, + 0x87, 0xa8, 0x03, 0x49, 0x5f, 0x05, 0x6e, 0xcc, + 0x3b, 0x43, 0xc5, 0x37, 0x73, 0x1f, 0x85, 0xef, + 0xc8, 0xfb, 0x53, 0x87, 0xad, 0x67, 0x31, 0xa6, + 0x43, 0x53, 0x32, 0x15, 0xde, 0xcc, 0x38, 0x7d, + 0x96, 0x76, 0x12, 0x2c, 0x17, 0x0e, 0x91, 0xe0, + 0xf9}, + .prime2_len = 65, + .exp1 = {0xd5, 0x78, 0xdc, 0xd5, 0x38, 0xf2, 0xfc, 0xdc, + 0x30, 0x00, 0xb6, 0xc0, 0xf0, 0x49, 0xfe, 0xe2, + 0xad, 0x90, 0x14, 0xfd, 0x24, 0xfb, 0x10, 0xb6, + 0x82, 0x18, 0x42, 0xd6, 0x70, 0x03, 0xa5, 0x64, + 0xcd, 0x8f, 0xf4, 0x2a, 0x2a, 0x56, 0x4c, 0xfd, + 0x81, 0x9c, 0x3a, 0x84, 0xbf, 0x16, 0xc2, 0x47, + 0x7e, 0x8e, 0x6e, 0x5b, 0x9e, 0xc4, 0xd4, 0x0e, + 0xad, 0x50, 0x24, 0x87, 0xba, 0x50, 0x36, 0x2d}, + .exp1_len = 64, + .exp2 = {0x88, 0x88, 0xdc, 0x8e, 0xae, 0x94, 0xee, 0xa5, + 0x80, 0xca, 0xc2, 0xfc, 0x1c, 0xe5, 0x4f, 0x44, + 0xe2, 0xba, 0x50, 0x0d, 0xb8, 0x71, 0x53, 0x41, + 0xa6, 0xfc, 0x2d, 0x50, 0x4a, 0x82, 0xb1, 0x42, + 0x05, 0xe8, 0x91, 0xa6, 0x6f, 0xc8, 0x8d, 0x5c, + 0x60, 0xdb, 0x8f, 0x78, 0x6c, 0xcc, 0x70, 0x57, + 0x5b, 0x35, 0x66, 0xbe, 0xa8, 0x74, 0xa5, 0x31, + 0x7f, 0x5f, 0x16, 0xc4, 0x91, 0xed, 0x1e, 0x79}, + .exp2_len = 64, + .coef = {0x17, 0xb0, 0xd6, 0x23, 0x36, 0x19, 0x1e, 0x63, + 0xbc, 0xa1, 0x59, 0x93, 0x4d, 0x06, 0x16, 0xcb, + 0x89, 0x97, 0x40, 0x9c, 0xbf, 0xca, 0x37, 0x05, + 0x69, 0x5b, 0x14, 0xfb, 0x64, 0xa0, 0x81, 0xc1, + 0xc9, 0xf5, 0x86, 0x19, 0x3e, 0x52, 0x3a, 0xbd, + 0x0b, 0xeb, 0x8d, 0x72, 0x0c, 0xfe, 0x53, 0x7d, + 0xfa, 0x1e, 0xde, 0xc4, 0xa6, 0x64, 0x37, 0xd2, + 0x41, 0x19, 0x6b, 0x7a, 0x2c, 0xe5, 0x56, 0xc4}, + .coef_len = 64, + .msg = {0x35, 0x39, 0x99, 0x7a, 0xe7, 0x09, 0xfe, 0x32, + 0xc1, 0x03, 0x6a, 0x13, 0x27, 0x57, 0xf2, 0xa1, + 0x66, 0x7a, 0x91, 0xcc, 0x83, 0xbe, 0x73, 0x3a, + 0xad, 0xa1, 0xbd, 0xd2, 0x17, 0x92, 0x4c, 0x9a, + 0x2c, 0x9f, 0xed, 0x1f, 0xec, 0xf6, 0x1d, 0x1c, + 0xf7, 0x9d, 0xae, 0x9a, 0x83, 0xf8, 0xae, 0x3f, + 0x4d, 0x05, 0x1b, 0x34, 0xfb, 0xb5, 0x59, 0xcb, + 0xfd, 0xa4, 0x92, 0xf1, 0xd8, 0x3b, 0x8b, 0xeb, + 0xa0, 0x45, 0xd4, 0xae, 0x1c, 0x8f, 0xea, 0x15, + 0xb7, 0x57, 0x7a, 0x1b, 0x8a, 0x3f, 0x55, 0xba, + 0xc1, 0x72, 0x7e, 0xdc, 0xa7, 0xf8, 0xf5, 0x2c, + 0xb4, 0xba, 0x61, 0xca, 0xf1, 0xfa, 0x8f, 0x8f, + 0xd9, 0xaa, 0xc7, 0x79, 0x09, 0x5c, 0xa8, 0x4c, + 0x79, 0x91, 0x52, 0x9f, 0xb8, 0x06, 0x99, 0xd0, + 0xd4, 0x68, 0x8d, 0xfd, 0xb1, 0x42, 0xed, 0x61, + 0xa9, 0x5b, 0x89, 0xce, 0x33, 0x06, 0xbf, 0x97, + 0x80, 0xe1, 0xb9, 0x1b, 0x84, 0x8c, 0x8d, 0x20, + 0x03, 0x97, 0x0e, 0x52, 0x70, 0x2a, 0x1f, 0x61, + 0x2e, 0x2f, 0x40, 0x17, 0xcf, 0xe0, 0xa9, 0x1d, + 0xb9, 0xe4, 0x6d, 0xb9, 0xdc}, + .msg_len = 157, + .sig = {0x00, 0x08, 0x0f, 0x77, 0x0a, 0x2d, 0x1f, 0x6a, + 0xbf, 0x5f, 0x22, 0x1f, 0x62, 0xe1, 0x66, 0xab, + 0xd7, 0x9d, 0x06, 0xc7, 0xb9, 0xa8, 0x78, 0xd6, + 0x1b, 0x80, 0xfc, 0x4d, 0x5b, 0xa2, 0x90, 0xb2, + 0x3a, 0xba, 0xab, 0x51, 0x8f, 0x09, 0x44, 0x7e, + 0x45, 0xae, 0xe6, 0xf3, 0xbd, 0x06, 0x10, 0x24, + 0x44, 0x36, 0xa4, 0x73, 0x01, 0x60, 0xe6, 0xa6, + 0x72, 0x11, 0x0c, 0x01, 0xae, 0xb5, 0x62, 0x4b, + 0x71, 0x8d, 0xc7, 0xc0, 0x86, 0x1e, 0x58, 0x6b, + 0xa8, 0xb6, 0x0a, 0x29, 0xd6, 0xa5, 0x75, 0x5c, + 0xd2, 0xcc, 0x50, 0x85, 0x99, 0xc6, 0xe2, 0x8d, + 0x73, 0x55, 0xb2, 0x7e, 0x40, 0xb7, 0x40, 0xc6, + 0xfb, 0xbb, 0xb1, 0xa9, 0x18, 0x23, 0xb1, 0xc1, + 0x24, 0x2b, 0xa6, 0x93, 0xd4, 0x52, 0x69, 0x51, + 0x47, 0xdb, 0xb2, 0x3e, 0xa8, 0x9c, 0xbf, 0x11, + 0xeb, 0x8b, 0x07, 0xec, 0x3a, 0x02, 0x7b, 0x0f, + 0x17}, + .sig_len = 129, + .chunks = {28, -1, 65, 64}, + .num_chunks = 4 + }, + { // 19 + .mod = {0x01, 0x69, 0x34, 0xcd, 0xff, 0x48, 0x50, 0xb6, + 0x00, 0x2c, 0xc0, 0xf0, 0xf4, 0x01, 0x0a, 0x32, + 0xc6, 0x55, 0xe5, 0xcf, 0x6e, 0x7c, 0x89, 0x93, + 0x7f, 0xd7, 0x55, 0xef, 0x6a, 0xbe, 0x37, 0x9d, + 0xad, 0xde, 0x70, 0xcc, 0x21, 0x77, 0x51, 0xf1, + 0x4c, 0xba, 0x6d, 0x90, 0xfe, 0x52, 0xdc, 0x0a, + 0xf5, 0x8b, 0x25, 0x2f, 0x26, 0xbf, 0x72, 0xda, + 0x57, 0x9f, 0xda, 0xf5, 0x7d, 0xdd, 0x6c, 0xd6, + 0x02, 0x18, 0x79, 0x94, 0x9a, 0x02, 0x76, 0xb4, + 0x43, 0x3f, 0xf0, 0x1e, 0xfc, 0xcc, 0xf3, 0x5a, + 0x11, 0xe7, 0xc7, 0x7b, 0x38, 0xc1, 0x8c, 0xca, + 0x94, 0xae, 0x01, 0x2d, 0x0f, 0x37, 0x04, 0x21, + 0x49, 0x1c, 0x52, 0xad, 0x15, 0xac, 0x76, 0xb1, + 0x2e, 0xcd, 0x21, 0x8f, 0x52, 0xe7, 0x57, 0x86, + 0x6e, 0x08, 0x9d, 0xd8, 0xad, 0xbb, 0x48, 0xe9, + 0xba, 0x89, 0x43, 0x36, 0xc5, 0x75, 0xc4, 0x06, + 0x55}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x0d, 0x17, 0x19, 0xe5, 0xbd, 0x47, 0x6d, 0x87, + 0xc7, 0xec, 0xc3, 0x1e, 0xb8, 0xab, 0x42, 0x5d, + 0x4f, 0xe4, 0xc8, 0xf5, 0xc7, 0xae, 0x23, 0x0a, + 0x10, 0x47, 0x55, 0x3f, 0xfb, 0x53, 0x9f, 0xd3, + 0x85, 0x5a, 0xf5, 0xa4, 0x3b, 0x2d, 0xdd, 0x4e, + 0x95, 0xa2, 0xb3, 0x0d, 0x40, 0x7a, 0xa8, 0x81, + 0x59, 0xbb, 0xad, 0x2a, 0x87, 0x3d, 0x80, 0x93, + 0xb4, 0x8a, 0x4b, 0xce, 0x20, 0xad, 0x99, 0x26, + 0x25, 0x3e, 0xd3, 0x39, 0xac, 0x3b, 0x54, 0x3f, + 0xc7, 0x42, 0x96, 0x95, 0x33, 0x8d, 0xb0, 0xbc, + 0x1d, 0xc3, 0x68, 0x6c, 0xfd, 0x13, 0x9b, 0xb5, + 0xb2, 0x87, 0x36, 0xbc, 0x16, 0x60, 0xa9, 0x53, + 0x48, 0xfc, 0x91, 0xc3, 0x25, 0xd0, 0x3a, 0x7f, + 0xb2, 0x16, 0xd2, 0xd9, 0xcd, 0x93, 0x64, 0xde, + 0x4e, 0xe7, 0xd2, 0x11, 0x9c, 0x3b, 0x0f, 0xbb, + 0xa8, 0xa7, 0x1f, 0x0d, 0x3f, 0x5a, 0xb9, 0xb9}, + .privexp_len = 128, + .prime1 = {0x01, 0x58, 0xc0, 0x24, 0x6c, 0xd1, 0x69, 0xfc, + 0x59, 0x3b, 0x25, 0x8b, 0xbf, 0x45, 0x23, 0xab, + 0x2b, 0x55, 0xc4, 0x60, 0x73, 0x3a, 0x7f, 0xb4, + 0x69, 0x10, 0x90, 0x77, 0xb3, 0x0e, 0x4d, 0x35, + 0xf2, 0x1a, 0x35, 0xb1, 0xf4, 0x1e, 0x42, 0x04, + 0xe8, 0x1d, 0x2e, 0x4c, 0x46, 0x3c, 0x24, 0x11, + 0x39, 0x34, 0x09, 0x8b, 0x45, 0x2d, 0xab, 0x4b, + 0xe1, 0x59, 0x97, 0x20, 0xef, 0x68, 0x72, 0x83, + 0x3d}, + .prime1_len = 65, + .prime2 = {0x01, 0x0c, 0x38, 0x2d, 0xea, 0x5e, 0x7d, 0x79, + 0x29, 0x8c, 0x64, 0x1f, 0xb2, 0xe4, 0xfa, 0x09, + 0xf2, 0x4f, 0x6a, 0x7a, 0x45, 0x9a, 0x88, 0x2c, + 0x87, 0xa8, 0x03, 0x49, 0x5f, 0x05, 0x6e, 0xcc, + 0x3b, 0x43, 0xc5, 0x37, 0x73, 0x1f, 0x85, 0xef, + 0xc8, 0xfb, 0x53, 0x87, 0xad, 0x67, 0x31, 0xa6, + 0x43, 0x53, 0x32, 0x15, 0xde, 0xcc, 0x38, 0x7d, + 0x96, 0x76, 0x12, 0x2c, 0x17, 0x0e, 0x91, 0xe0, + 0xf9}, + .prime2_len = 65, + .exp1 = {0xd5, 0x78, 0xdc, 0xd5, 0x38, 0xf2, 0xfc, 0xdc, + 0x30, 0x00, 0xb6, 0xc0, 0xf0, 0x49, 0xfe, 0xe2, + 0xad, 0x90, 0x14, 0xfd, 0x24, 0xfb, 0x10, 0xb6, + 0x82, 0x18, 0x42, 0xd6, 0x70, 0x03, 0xa5, 0x64, + 0xcd, 0x8f, 0xf4, 0x2a, 0x2a, 0x56, 0x4c, 0xfd, + 0x81, 0x9c, 0x3a, 0x84, 0xbf, 0x16, 0xc2, 0x47, + 0x7e, 0x8e, 0x6e, 0x5b, 0x9e, 0xc4, 0xd4, 0x0e, + 0xad, 0x50, 0x24, 0x87, 0xba, 0x50, 0x36, 0x2d}, + .exp1_len = 64, + .exp2 = {0x88, 0x88, 0xdc, 0x8e, 0xae, 0x94, 0xee, 0xa5, + 0x80, 0xca, 0xc2, 0xfc, 0x1c, 0xe5, 0x4f, 0x44, + 0xe2, 0xba, 0x50, 0x0d, 0xb8, 0x71, 0x53, 0x41, + 0xa6, 0xfc, 0x2d, 0x50, 0x4a, 0x82, 0xb1, 0x42, + 0x05, 0xe8, 0x91, 0xa6, 0x6f, 0xc8, 0x8d, 0x5c, + 0x60, 0xdb, 0x8f, 0x78, 0x6c, 0xcc, 0x70, 0x57, + 0x5b, 0x35, 0x66, 0xbe, 0xa8, 0x74, 0xa5, 0x31, + 0x7f, 0x5f, 0x16, 0xc4, 0x91, 0xed, 0x1e, 0x79}, + .exp2_len = 64, + .coef = {0x17, 0xb0, 0xd6, 0x23, 0x36, 0x19, 0x1e, 0x63, + 0xbc, 0xa1, 0x59, 0x93, 0x4d, 0x06, 0x16, 0xcb, + 0x89, 0x97, 0x40, 0x9c, 0xbf, 0xca, 0x37, 0x05, + 0x69, 0x5b, 0x14, 0xfb, 0x64, 0xa0, 0x81, 0xc1, + 0xc9, 0xf5, 0x86, 0x19, 0x3e, 0x52, 0x3a, 0xbd, + 0x0b, 0xeb, 0x8d, 0x72, 0x0c, 0xfe, 0x53, 0x7d, + 0xfa, 0x1e, 0xde, 0xc4, 0xa6, 0x64, 0x37, 0xd2, + 0x41, 0x19, 0x6b, 0x7a, 0x2c, 0xe5, 0x56, 0xc4}, + .coef_len = 64, + .msg = {0x31, 0x80, 0x08, 0x87, 0x3c, 0x4c, 0xfe, 0xa7, + 0x12, 0x5e, 0xa6, 0xfd, 0x52, 0x15, 0xdf, 0xd9, + 0x8d, 0x5c, 0x5e, 0x73, 0x32, 0x3f, 0x03, 0xf2, + 0x15, 0xc6, 0x9c, 0x8f, 0x2b, 0xb1, 0x98, 0x3b, + 0x59, 0xdf, 0xa6, 0xe9, 0x9a, 0xdd, 0x30, 0x69, + 0x66, 0xf3, 0x11, 0x0c, 0x16, 0x1c, 0xa2, 0x26, + 0x24, 0xb8, 0x80, 0x70, 0x26, 0x5b, 0x8f, 0x3f, + 0x9d, 0x5d, 0xf7, 0x29, 0x91, 0xe7, 0x9e, 0x5b, + 0x18, 0x9a, 0xa3, 0xd9, 0xcd, 0x9b, 0x20, 0x47, + 0xcf, 0xa6, 0x1d, 0x01, 0x23, 0x4b, 0x23, 0x3d, + 0x36, 0xac, 0x4b, 0x96, 0xed, 0x08, 0x16, 0x48, + 0x87, 0x74, 0x90, 0xfa, 0x4a, 0x80, 0xec, 0x4c, + 0xbb, 0xd9, 0xd2, 0xe0, 0x06, 0x2c, 0x39, 0xe1, + 0x85, 0x3a, 0x0c, 0x38, 0x34, 0x4b, 0xa8, 0x58, + 0xbd, 0x1d, 0x99, 0x5f, 0x6c, 0xaa, 0x28, 0xbf, + 0x90, 0x40, 0x26, 0x26, 0x8a, 0x99, 0x72, 0x11, + 0x43, 0xc8, 0x6a, 0x43, 0x43, 0xba, 0xf8, 0x9b, + 0x6d, 0x55, 0x07, 0x64, 0x25, 0x1f, 0xb0, 0x7d, + 0x16, 0x7b, 0x4c, 0x4b, 0x1b, 0x70, 0xf9, 0x9e, + 0xf5, 0xfe, 0x50, 0xe6, 0x2e, 0x54, 0x13, 0xfc, + 0xce, 0x0f, 0x99, 0x59, 0xc2, 0xa3, 0x78, 0xc4, + 0x1d, 0x6f, 0x42, 0x36, 0x17, 0x8b, 0x14, 0xb8, + 0x91, 0x9d, 0xb1, 0xd0}, + .msg_len = 180, + .sig = {0x00, 0x6d, 0x54, 0x7d, 0xa4, 0xed, 0xcb, 0x10, + 0x33, 0x15, 0xcb, 0x8e, 0x4b, 0x66, 0x9b, 0xee, + 0x96, 0xaa, 0x21, 0x56, 0x23, 0x5c, 0xa5, 0xc3, + 0xe3, 0x1b, 0x24, 0xa1, 0x5a, 0x13, 0x92, 0xe4, + 0x94, 0x04, 0x7f, 0xed, 0xcb, 0x70, 0x81, 0x90, + 0x7c, 0x56, 0x17, 0xa8, 0xaa, 0x18, 0xd1, 0x01, + 0xb0, 0x53, 0x2a, 0x36, 0x32, 0x45, 0x19, 0x23, + 0xc4, 0x8a, 0x75, 0xb0, 0xec, 0x21, 0x76, 0xcb, + 0x98, 0xe5, 0xce, 0x51, 0x58, 0x8b, 0xcf, 0x86, + 0x8e, 0x29, 0xd5, 0xd9, 0x69, 0x4f, 0x00, 0xae, + 0x2c, 0x92, 0x4e, 0x73, 0xd2, 0xe6, 0xdd, 0x14, + 0x4d, 0x24, 0xfa, 0x45, 0xd0, 0x12, 0x06, 0xa3, + 0xf5, 0xd9, 0x36, 0x41, 0x3c, 0xcb, 0xb7, 0x4b, + 0x0e, 0x2d, 0x04, 0x7d, 0x82, 0xb6, 0x00, 0xb8, + 0x9d, 0x51, 0x59, 0x4f, 0xce, 0x7d, 0xe6, 0xbb, + 0xd9, 0x5b, 0x97, 0xfc, 0xfe, 0xc5, 0x98, 0xc4, + 0xeb}, + .sig_len = 129, + }, + { // 20 + .mod = {0x01, 0x69, 0x34, 0xcd, 0xff, 0x48, 0x50, 0xb6, + 0x00, 0x2c, 0xc0, 0xf0, 0xf4, 0x01, 0x0a, 0x32, + 0xc6, 0x55, 0xe5, 0xcf, 0x6e, 0x7c, 0x89, 0x93, + 0x7f, 0xd7, 0x55, 0xef, 0x6a, 0xbe, 0x37, 0x9d, + 0xad, 0xde, 0x70, 0xcc, 0x21, 0x77, 0x51, 0xf1, + 0x4c, 0xba, 0x6d, 0x90, 0xfe, 0x52, 0xdc, 0x0a, + 0xf5, 0x8b, 0x25, 0x2f, 0x26, 0xbf, 0x72, 0xda, + 0x57, 0x9f, 0xda, 0xf5, 0x7d, 0xdd, 0x6c, 0xd6, + 0x02, 0x18, 0x79, 0x94, 0x9a, 0x02, 0x76, 0xb4, + 0x43, 0x3f, 0xf0, 0x1e, 0xfc, 0xcc, 0xf3, 0x5a, + 0x11, 0xe7, 0xc7, 0x7b, 0x38, 0xc1, 0x8c, 0xca, + 0x94, 0xae, 0x01, 0x2d, 0x0f, 0x37, 0x04, 0x21, + 0x49, 0x1c, 0x52, 0xad, 0x15, 0xac, 0x76, 0xb1, + 0x2e, 0xcd, 0x21, 0x8f, 0x52, 0xe7, 0x57, 0x86, + 0x6e, 0x08, 0x9d, 0xd8, 0xad, 0xbb, 0x48, 0xe9, + 0xba, 0x89, 0x43, 0x36, 0xc5, 0x75, 0xc4, 0x06, + 0x55}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x0d, 0x17, 0x19, 0xe5, 0xbd, 0x47, 0x6d, 0x87, + 0xc7, 0xec, 0xc3, 0x1e, 0xb8, 0xab, 0x42, 0x5d, + 0x4f, 0xe4, 0xc8, 0xf5, 0xc7, 0xae, 0x23, 0x0a, + 0x10, 0x47, 0x55, 0x3f, 0xfb, 0x53, 0x9f, 0xd3, + 0x85, 0x5a, 0xf5, 0xa4, 0x3b, 0x2d, 0xdd, 0x4e, + 0x95, 0xa2, 0xb3, 0x0d, 0x40, 0x7a, 0xa8, 0x81, + 0x59, 0xbb, 0xad, 0x2a, 0x87, 0x3d, 0x80, 0x93, + 0xb4, 0x8a, 0x4b, 0xce, 0x20, 0xad, 0x99, 0x26, + 0x25, 0x3e, 0xd3, 0x39, 0xac, 0x3b, 0x54, 0x3f, + 0xc7, 0x42, 0x96, 0x95, 0x33, 0x8d, 0xb0, 0xbc, + 0x1d, 0xc3, 0x68, 0x6c, 0xfd, 0x13, 0x9b, 0xb5, + 0xb2, 0x87, 0x36, 0xbc, 0x16, 0x60, 0xa9, 0x53, + 0x48, 0xfc, 0x91, 0xc3, 0x25, 0xd0, 0x3a, 0x7f, + 0xb2, 0x16, 0xd2, 0xd9, 0xcd, 0x93, 0x64, 0xde, + 0x4e, 0xe7, 0xd2, 0x11, 0x9c, 0x3b, 0x0f, 0xbb, + 0xa8, 0xa7, 0x1f, 0x0d, 0x3f, 0x5a, 0xb9, 0xb9}, + .privexp_len = 128, + .prime1 = {0x01, 0x58, 0xc0, 0x24, 0x6c, 0xd1, 0x69, 0xfc, + 0x59, 0x3b, 0x25, 0x8b, 0xbf, 0x45, 0x23, 0xab, + 0x2b, 0x55, 0xc4, 0x60, 0x73, 0x3a, 0x7f, 0xb4, + 0x69, 0x10, 0x90, 0x77, 0xb3, 0x0e, 0x4d, 0x35, + 0xf2, 0x1a, 0x35, 0xb1, 0xf4, 0x1e, 0x42, 0x04, + 0xe8, 0x1d, 0x2e, 0x4c, 0x46, 0x3c, 0x24, 0x11, + 0x39, 0x34, 0x09, 0x8b, 0x45, 0x2d, 0xab, 0x4b, + 0xe1, 0x59, 0x97, 0x20, 0xef, 0x68, 0x72, 0x83, + 0x3d}, + .prime1_len = 65, + .prime2 = {0x01, 0x0c, 0x38, 0x2d, 0xea, 0x5e, 0x7d, 0x79, + 0x29, 0x8c, 0x64, 0x1f, 0xb2, 0xe4, 0xfa, 0x09, + 0xf2, 0x4f, 0x6a, 0x7a, 0x45, 0x9a, 0x88, 0x2c, + 0x87, 0xa8, 0x03, 0x49, 0x5f, 0x05, 0x6e, 0xcc, + 0x3b, 0x43, 0xc5, 0x37, 0x73, 0x1f, 0x85, 0xef, + 0xc8, 0xfb, 0x53, 0x87, 0xad, 0x67, 0x31, 0xa6, + 0x43, 0x53, 0x32, 0x15, 0xde, 0xcc, 0x38, 0x7d, + 0x96, 0x76, 0x12, 0x2c, 0x17, 0x0e, 0x91, 0xe0, + 0xf9}, + .prime2_len = 65, + .exp1 = {0xd5, 0x78, 0xdc, 0xd5, 0x38, 0xf2, 0xfc, 0xdc, + 0x30, 0x00, 0xb6, 0xc0, 0xf0, 0x49, 0xfe, 0xe2, + 0xad, 0x90, 0x14, 0xfd, 0x24, 0xfb, 0x10, 0xb6, + 0x82, 0x18, 0x42, 0xd6, 0x70, 0x03, 0xa5, 0x64, + 0xcd, 0x8f, 0xf4, 0x2a, 0x2a, 0x56, 0x4c, 0xfd, + 0x81, 0x9c, 0x3a, 0x84, 0xbf, 0x16, 0xc2, 0x47, + 0x7e, 0x8e, 0x6e, 0x5b, 0x9e, 0xc4, 0xd4, 0x0e, + 0xad, 0x50, 0x24, 0x87, 0xba, 0x50, 0x36, 0x2d}, + .exp1_len = 64, + .exp2 = {0x88, 0x88, 0xdc, 0x8e, 0xae, 0x94, 0xee, 0xa5, + 0x80, 0xca, 0xc2, 0xfc, 0x1c, 0xe5, 0x4f, 0x44, + 0xe2, 0xba, 0x50, 0x0d, 0xb8, 0x71, 0x53, 0x41, + 0xa6, 0xfc, 0x2d, 0x50, 0x4a, 0x82, 0xb1, 0x42, + 0x05, 0xe8, 0x91, 0xa6, 0x6f, 0xc8, 0x8d, 0x5c, + 0x60, 0xdb, 0x8f, 0x78, 0x6c, 0xcc, 0x70, 0x57, + 0x5b, 0x35, 0x66, 0xbe, 0xa8, 0x74, 0xa5, 0x31, + 0x7f, 0x5f, 0x16, 0xc4, 0x91, 0xed, 0x1e, 0x79}, + .exp2_len = 64, + .coef = {0x17, 0xb0, 0xd6, 0x23, 0x36, 0x19, 0x1e, 0x63, + 0xbc, 0xa1, 0x59, 0x93, 0x4d, 0x06, 0x16, 0xcb, + 0x89, 0x97, 0x40, 0x9c, 0xbf, 0xca, 0x37, 0x05, + 0x69, 0x5b, 0x14, 0xfb, 0x64, 0xa0, 0x81, 0xc1, + 0xc9, 0xf5, 0x86, 0x19, 0x3e, 0x52, 0x3a, 0xbd, + 0x0b, 0xeb, 0x8d, 0x72, 0x0c, 0xfe, 0x53, 0x7d, + 0xfa, 0x1e, 0xde, 0xc4, 0xa6, 0x64, 0x37, 0xd2, + 0x41, 0x19, 0x6b, 0x7a, 0x2c, 0xe5, 0x56, 0xc4}, + .coef_len = 64, + .msg = {0x7f, 0x83, 0xb3, 0xe0, 0x54, 0xc0, 0x24, 0x82, + 0x50, 0x78, 0xdd, 0x9f, 0x04, 0x0e, 0x1d, 0x09, + 0x05, 0x82, 0x00, 0xc9, 0x75, 0x7b, 0x76, 0xfb, + 0x37, 0x2b, 0x8b, 0x52, 0x66, 0xb9, 0xdc, 0x26, + 0x9e, 0xc7, 0x56, 0x9d, 0x00}, + .msg_len = 37, + .sig = {0x01, 0x34, 0xee, 0x21, 0x51, 0x51, 0xe5, 0x32, + 0x50, 0xf5, 0xa0, 0x01, 0x6a, 0xcc, 0xe3, 0x70, + 0x1e, 0x2a, 0x58, 0xdd, 0xaa, 0xd6, 0xcc, 0x36, + 0x9d, 0xf0, 0xdc, 0xd9, 0x34, 0x6a, 0x2b, 0x53, + 0x0f, 0xe3, 0x71, 0x5a, 0xfe, 0xff, 0x1e, 0x9b, + 0xcb, 0x72, 0x08, 0x31, 0xc1, 0x25, 0x58, 0x97, + 0x0a, 0x9e, 0x03, 0x89, 0x60, 0x04, 0xf2, 0x87, + 0xad, 0xb8, 0x21, 0xf3, 0x17, 0xcf, 0x63, 0x93, + 0x00, 0xca, 0xe6, 0xe9, 0x09, 0xe9, 0x1e, 0xd2, + 0xa3, 0xea, 0xcb, 0x99, 0x52, 0xa7, 0xcc, 0x54, + 0x94, 0x76, 0x52, 0x64, 0x24, 0x79, 0x51, 0xd2, + 0x8c, 0x16, 0xaf, 0x03, 0xe2, 0x4b, 0x80, 0xee, + 0x32, 0xb0, 0xb6, 0x2e, 0xdf, 0x10, 0xd7, 0x00, + 0x91, 0x92, 0x71, 0x35, 0xf0, 0x5a, 0x88, 0x9f, + 0x2f, 0x60, 0x56, 0xb9, 0x5c, 0xdd, 0xac, 0xe4, + 0x7c, 0x69, 0xf9, 0x73, 0x08, 0xc0, 0xdf, 0x2e, + 0xba}, + .sig_len = 129, + }, + { // 21 + .mod = {0x03, 0x33, 0x12, 0x64, 0x88, 0xf7, 0xa2, 0x91, + 0x51, 0x32, 0xe3, 0x0d, 0x5e, 0x97, 0xf6, 0xed, + 0x7b, 0xbb, 0x67, 0xb6, 0x19, 0x85, 0x00, 0x8e, + 0xae, 0xa2, 0xa5, 0xda, 0xfb, 0x96, 0xa4, 0x48, + 0xab, 0x75, 0xce, 0x3d, 0x6e, 0x68, 0xa6, 0x26, + 0x5e, 0x7c, 0x24, 0x56, 0x84, 0x99, 0x93, 0x24, + 0xc8, 0x1e, 0x0b, 0xa6, 0x38, 0x98, 0x63, 0xfe, + 0xb4, 0x88, 0xb3, 0xf2, 0x55, 0xd0, 0xd6, 0x19, + 0xc1, 0x90, 0x40, 0xb7, 0x4c, 0x18, 0x9f, 0x0c, + 0x9a, 0xf4, 0xb0, 0xd5, 0xa5, 0x5a, 0x54, 0x4c, + 0x09, 0x0c, 0xd6, 0x15, 0x2c, 0x90, 0xa6, 0xf2, + 0x55, 0x0d, 0x7d, 0x2a, 0x6b, 0x6d, 0x34, 0x7d, + 0x5b, 0x1b, 0x9d, 0xfb, 0x1d, 0xe4, 0x40, 0x3c, + 0x79, 0x66, 0x23, 0xd7, 0x03, 0xbf, 0x9d, 0xb4, + 0x43, 0xbf, 0x67, 0x02, 0x68, 0x3b, 0x8d, 0x2a, + 0x9c, 0x61, 0xe9, 0x36, 0x8a, 0xc4, 0x25, 0xa5, + 0x81}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x01, 0x4a, 0x2b, 0x15, 0xdf, 0xa8, 0x83, 0x1d, + 0xb4, 0xef, 0xa0, 0x5b, 0x19, 0x50, 0x84, 0xb7, + 0x42, 0x73, 0x4e, 0xe1, 0x36, 0xf4, 0x48, 0x3f, + 0x3b, 0xe2, 0x50, 0x9d, 0x2f, 0x61, 0x90, 0x23, + 0xc3, 0x0a, 0x1f, 0xf2, 0xdf, 0x78, 0xcb, 0xd1, + 0x17, 0xb1, 0x4f, 0x2c, 0x99, 0x13, 0x17, 0x1f, + 0x72, 0x93, 0xb9, 0xfa, 0x6d, 0x41, 0xf0, 0xbd, + 0x11, 0xa5, 0x31, 0x74, 0x74, 0x67, 0x54, 0x86, + 0xd7, 0xf0, 0xae, 0xc0, 0xa7, 0x78, 0xba, 0x92, + 0x0e, 0x81, 0xf5, 0x64, 0xd1, 0x59, 0x30, 0xcd, + 0xde, 0xe7, 0xe2, 0xb0, 0x6a, 0xd8, 0xad, 0xb6, + 0x12, 0x75, 0x1f, 0x4e, 0x38, 0x4d, 0x6f, 0x3f, + 0xa0, 0xa6, 0x63, 0x9f, 0xd6, 0x2e, 0xdf, 0x86, + 0xf5, 0x2c, 0x9f, 0xe0, 0x77, 0x62, 0x91, 0x83, + 0x21, 0x83, 0xd3, 0x59, 0xb7, 0x34, 0x32, 0x60, + 0xc9, 0x4e, 0x12, 0x5f, 0x4a, 0xb8, 0xbf, 0x43, + 0x69}, + .privexp_len = 129, + .prime1 = {0x01, 0xd6, 0xe7, 0xbd, 0x8e, 0x39, 0x5b, 0xbe, + 0xf2, 0x10, 0x46, 0x49, 0xc0, 0x12, 0x78, 0xcc, + 0x1c, 0x51, 0xc9, 0x68, 0x7d, 0xef, 0xb4, 0x59, + 0x1f, 0x03, 0xb6, 0x78, 0x52, 0xa4, 0xbc, 0xb5, + 0x30, 0x75, 0x0c, 0xf9, 0xbf, 0xca, 0xd0, 0x72, + 0x8c, 0x53, 0x99, 0xd8, 0x70, 0x35, 0x01, 0x06, + 0xcb, 0xa3, 0xec, 0x41, 0x6a, 0x31, 0xe4, 0x2d, + 0x0b, 0x59, 0x75, 0x10, 0xff, 0x1c, 0x9d, 0x53, + 0xbb}, + .prime1_len = 65, + .prime2 = {0x01, 0xbd, 0x46, 0x6f, 0x43, 0xa4, 0xd4, 0x61, + 0x3e, 0x42, 0x64, 0xf0, 0x1b, 0x2d, 0xac, 0x2e, + 0x5a, 0xa4, 0x20, 0x43, 0xf8, 0xfb, 0x5f, 0x69, + 0xfa, 0x87, 0x1d, 0x14, 0xfb, 0x27, 0x3e, 0x76, + 0x7a, 0x53, 0x1c, 0x40, 0xf0, 0x2f, 0x34, 0x3b, + 0xc2, 0xfb, 0x45, 0xa0, 0xc7, 0xe0, 0xf6, 0xbe, + 0x25, 0x61, 0x92, 0x3a, 0x77, 0x21, 0x1d, 0x66, + 0xa6, 0xe2, 0xdb, 0xb4, 0x3c, 0x36, 0x63, 0x51, + 0xf3}, + .prime2_len = 65, + .exp1 = {0xfb, 0x66, 0x85, 0x00, 0x65, 0x06, 0xe2, 0x0e, + 0x01, 0x3a, 0x45, 0x2d, 0x51, 0xaf, 0x43, 0xe8, + 0xea, 0x91, 0x08, 0x44, 0x13, 0xb0, 0xc8, 0xd3, + 0x91, 0xfb, 0xdc, 0x88, 0xe2, 0x82, 0x0c, 0x89, + 0x6e, 0x34, 0x1b, 0x31, 0x95, 0x69, 0x6b, 0x7e, + 0x17, 0x33, 0xcf, 0x25, 0x38, 0x66, 0xef, 0xe5, + 0xd0, 0x01, 0xd5, 0x7a, 0x88, 0x60, 0x34, 0xdc, + 0x16, 0x4a, 0x35, 0x64, 0xbd, 0x36, 0x10, 0xf9}, + .exp1_len = 64, + .exp2 = {0xbe, 0x4e, 0x9e, 0x3b, 0x40, 0xf5, 0x6c, 0x62, + 0x59, 0xaa, 0x1e, 0x5c, 0xdf, 0x56, 0x59, 0xb1, + 0x6f, 0xb8, 0x42, 0x94, 0xe5, 0x8a, 0xd0, 0x16, + 0xbd, 0x2c, 0x96, 0xcd, 0x08, 0xe6, 0xcf, 0x68, + 0x54, 0xa1, 0x1c, 0xb8, 0x0a, 0xd4, 0xbe, 0x3e, + 0x05, 0x7a, 0xaa, 0xcf, 0x02, 0xbd, 0x32, 0x63, + 0x73, 0xa2, 0x35, 0xce, 0xb8, 0x9e, 0x82, 0x43, + 0x0d, 0x6e, 0x6d, 0x47, 0xd6, 0xce, 0xf8, 0x35}, + .exp2_len = 64, + .coef = {0xc0, 0x23, 0x5c, 0x89, 0x73, 0xcf, 0xbf, 0x30, + 0xbf, 0x1d, 0xd3, 0xc8, 0x39, 0xf0, 0x2c, 0x94, + 0xc6, 0x9d, 0xc5, 0x34, 0xcb, 0xfc, 0x98, 0x88, + 0x05, 0xd6, 0xfc, 0x46, 0x2a, 0xdb, 0xd3, 0x77, + 0xd1, 0x75, 0xb9, 0xa9, 0x64, 0x60, 0x18, 0xd7, + 0xfa, 0xb7, 0x5c, 0x1d, 0x1f, 0x7d, 0x61, 0xb7, + 0x7f, 0xa7, 0x95, 0x59, 0xb8, 0x6f, 0xfa, 0x9e, + 0xc6, 0xe2, 0x11, 0x33, 0xfa, 0x7f, 0x1a, 0x45}, + .coef_len = 64, + .msg = {0x9a, 0x28, 0x20, 0xf3, 0xb9, 0x02, 0x9a, 0xbc, + 0x18, 0x65, 0xeb, 0x06, 0xfe, 0x61, 0xb8, 0xd3, + 0x97, 0xb6, 0x55, 0x72, 0xd6, 0x00, 0x61, 0xca, + 0xa7, 0x4e, 0x63, 0x56, 0x93, 0x1e, 0x25, 0x6b, + 0x89, 0x71, 0x2d, 0x18, 0x66, 0x84, 0xb4, 0xde, + 0x1e, 0x14, 0xc9, 0xeb, 0xfe, 0xf1, 0x6e, 0x40, + 0xd9, 0x9d, 0x10, 0x94, 0x39, 0x6c, 0x56, 0x1c, + 0x88, 0x31, 0x77, 0xe5, 0x12, 0x6b, 0x9b, 0xe2, + 0xd9, 0xa9, 0x68, 0x03, 0x27, 0xd5, 0x37, 0x0c, + 0x6f, 0x26, 0x86, 0x1f, 0x58, 0x20, 0xc4, 0x3d, + 0xa6, 0x7a, 0x3a, 0xd6, 0x09, 0x04, 0xe2, 0x15, + 0xee, 0x6f, 0xf9, 0x34, 0xb9, 0xda, 0x70, 0xd7, + 0x73, 0x0c, 0x87, 0x34, 0xab, 0xfc, 0xec, 0xde, + 0x89, 0x7f, 0xdd, 0x67, 0x0a, 0x01, 0x46, 0x58, + 0x68, 0xad, 0xc9, 0x3f, 0x26, 0x13, 0x19, 0x57, + 0xa5, 0x0c, 0x52, 0xfb, 0x77, 0x7c, 0xdb, 0xaa, + 0x30, 0x89, 0x2c, 0x9e, 0x12, 0x36, 0x11, 0x64, + 0xec, 0x13, 0x97, 0x9d, 0x43, 0x04, 0x81, 0x18, + 0xe4, 0x44, 0x5d, 0xb8, 0x7b, 0xee, 0x58, 0xdd, + 0x98, 0x7b, 0x34, 0x25, 0xd0, 0x20, 0x71, 0xd8, + 0xdb, 0xae, 0x80, 0x70, 0x8b, 0x03, 0x9d, 0xbb, + 0x64, 0xdb, 0xd1, 0xde, 0x56, 0x57, 0xd9, 0xfe, + 0xd0, 0xc1, 0x18, 0xa5, 0x41}, + .msg_len = 181, + .sig = {0x03, 0x22, 0xd0, 0x0f, 0xc1, 0xd9, 0x66, 0x94, + 0xf3, 0x6e, 0xae, 0xd2, 0x30, 0x90, 0x56, 0xf3, + 0xea, 0x1c, 0x1c, 0xc2, 0x2b, 0x13, 0xb6, 0x5e, + 0x79, 0x11, 0x8d, 0x20, 0x2c, 0x42, 0xd1, 0x61, + 0x30, 0x99, 0x38, 0x05, 0x09, 0xda, 0x74, 0x35, + 0xbb, 0x57, 0x92, 0x16, 0xfd, 0x57, 0x65, 0x06, + 0x68, 0x42, 0xe3, 0x56, 0xa6, 0x41, 0x6f, 0xc8, + 0x42, 0xa2, 0x4a, 0x9e, 0xa1, 0xbc, 0x6a, 0x90, + 0x98, 0x05, 0x23, 0xb4, 0x28, 0xe3, 0x99, 0xbb, + 0xd6, 0xfc, 0xdc, 0x2c, 0xb7, 0x71, 0xda, 0xf0, + 0x03, 0x7a, 0x2d, 0xe8, 0xc7, 0x64, 0x9b, 0xd5, + 0x33, 0x17, 0xde, 0x0e, 0x37, 0xc3, 0x14, 0xba, + 0xb0, 0xc4, 0x37, 0xbb, 0xd7, 0x98, 0xdf, 0xb9, + 0x65, 0x50, 0x6c, 0x34, 0x8b, 0x74, 0x2f, 0x13, + 0x8e, 0xf1, 0xd1, 0xa2, 0x03, 0xe0, 0x51, 0xe3, + 0x4b, 0xdd, 0x3a, 0x30, 0xe0, 0xfc, 0xe1, 0xac, + 0x43}, + .sig_len = 129, + .chunks = {46, 23, 81, 31}, + .num_chunks = 4, + }, + { // 22 + .mod = {0x03, 0x33, 0x12, 0x64, 0x88, 0xf7, 0xa2, 0x91, + 0x51, 0x32, 0xe3, 0x0d, 0x5e, 0x97, 0xf6, 0xed, + 0x7b, 0xbb, 0x67, 0xb6, 0x19, 0x85, 0x00, 0x8e, + 0xae, 0xa2, 0xa5, 0xda, 0xfb, 0x96, 0xa4, 0x48, + 0xab, 0x75, 0xce, 0x3d, 0x6e, 0x68, 0xa6, 0x26, + 0x5e, 0x7c, 0x24, 0x56, 0x84, 0x99, 0x93, 0x24, + 0xc8, 0x1e, 0x0b, 0xa6, 0x38, 0x98, 0x63, 0xfe, + 0xb4, 0x88, 0xb3, 0xf2, 0x55, 0xd0, 0xd6, 0x19, + 0xc1, 0x90, 0x40, 0xb7, 0x4c, 0x18, 0x9f, 0x0c, + 0x9a, 0xf4, 0xb0, 0xd5, 0xa5, 0x5a, 0x54, 0x4c, + 0x09, 0x0c, 0xd6, 0x15, 0x2c, 0x90, 0xa6, 0xf2, + 0x55, 0x0d, 0x7d, 0x2a, 0x6b, 0x6d, 0x34, 0x7d, + 0x5b, 0x1b, 0x9d, 0xfb, 0x1d, 0xe4, 0x40, 0x3c, + 0x79, 0x66, 0x23, 0xd7, 0x03, 0xbf, 0x9d, 0xb4, + 0x43, 0xbf, 0x67, 0x02, 0x68, 0x3b, 0x8d, 0x2a, + 0x9c, 0x61, 0xe9, 0x36, 0x8a, 0xc4, 0x25, 0xa5, + 0x81}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x01, 0x4a, 0x2b, 0x15, 0xdf, 0xa8, 0x83, 0x1d, + 0xb4, 0xef, 0xa0, 0x5b, 0x19, 0x50, 0x84, 0xb7, + 0x42, 0x73, 0x4e, 0xe1, 0x36, 0xf4, 0x48, 0x3f, + 0x3b, 0xe2, 0x50, 0x9d, 0x2f, 0x61, 0x90, 0x23, + 0xc3, 0x0a, 0x1f, 0xf2, 0xdf, 0x78, 0xcb, 0xd1, + 0x17, 0xb1, 0x4f, 0x2c, 0x99, 0x13, 0x17, 0x1f, + 0x72, 0x93, 0xb9, 0xfa, 0x6d, 0x41, 0xf0, 0xbd, + 0x11, 0xa5, 0x31, 0x74, 0x74, 0x67, 0x54, 0x86, + 0xd7, 0xf0, 0xae, 0xc0, 0xa7, 0x78, 0xba, 0x92, + 0x0e, 0x81, 0xf5, 0x64, 0xd1, 0x59, 0x30, 0xcd, + 0xde, 0xe7, 0xe2, 0xb0, 0x6a, 0xd8, 0xad, 0xb6, + 0x12, 0x75, 0x1f, 0x4e, 0x38, 0x4d, 0x6f, 0x3f, + 0xa0, 0xa6, 0x63, 0x9f, 0xd6, 0x2e, 0xdf, 0x86, + 0xf5, 0x2c, 0x9f, 0xe0, 0x77, 0x62, 0x91, 0x83, + 0x21, 0x83, 0xd3, 0x59, 0xb7, 0x34, 0x32, 0x60, + 0xc9, 0x4e, 0x12, 0x5f, 0x4a, 0xb8, 0xbf, 0x43, + 0x69}, + .privexp_len = 129, + .prime1 = {0x01, 0xd6, 0xe7, 0xbd, 0x8e, 0x39, 0x5b, 0xbe, + 0xf2, 0x10, 0x46, 0x49, 0xc0, 0x12, 0x78, 0xcc, + 0x1c, 0x51, 0xc9, 0x68, 0x7d, 0xef, 0xb4, 0x59, + 0x1f, 0x03, 0xb6, 0x78, 0x52, 0xa4, 0xbc, 0xb5, + 0x30, 0x75, 0x0c, 0xf9, 0xbf, 0xca, 0xd0, 0x72, + 0x8c, 0x53, 0x99, 0xd8, 0x70, 0x35, 0x01, 0x06, + 0xcb, 0xa3, 0xec, 0x41, 0x6a, 0x31, 0xe4, 0x2d, + 0x0b, 0x59, 0x75, 0x10, 0xff, 0x1c, 0x9d, 0x53, + 0xbb}, + .prime1_len = 65, + .prime2 = {0x01, 0xbd, 0x46, 0x6f, 0x43, 0xa4, 0xd4, 0x61, + 0x3e, 0x42, 0x64, 0xf0, 0x1b, 0x2d, 0xac, 0x2e, + 0x5a, 0xa4, 0x20, 0x43, 0xf8, 0xfb, 0x5f, 0x69, + 0xfa, 0x87, 0x1d, 0x14, 0xfb, 0x27, 0x3e, 0x76, + 0x7a, 0x53, 0x1c, 0x40, 0xf0, 0x2f, 0x34, 0x3b, + 0xc2, 0xfb, 0x45, 0xa0, 0xc7, 0xe0, 0xf6, 0xbe, + 0x25, 0x61, 0x92, 0x3a, 0x77, 0x21, 0x1d, 0x66, + 0xa6, 0xe2, 0xdb, 0xb4, 0x3c, 0x36, 0x63, 0x51, + 0xf3}, + .prime2_len = 65, + .exp1 = {0xfb, 0x66, 0x85, 0x00, 0x65, 0x06, 0xe2, 0x0e, + 0x01, 0x3a, 0x45, 0x2d, 0x51, 0xaf, 0x43, 0xe8, + 0xea, 0x91, 0x08, 0x44, 0x13, 0xb0, 0xc8, 0xd3, + 0x91, 0xfb, 0xdc, 0x88, 0xe2, 0x82, 0x0c, 0x89, + 0x6e, 0x34, 0x1b, 0x31, 0x95, 0x69, 0x6b, 0x7e, + 0x17, 0x33, 0xcf, 0x25, 0x38, 0x66, 0xef, 0xe5, + 0xd0, 0x01, 0xd5, 0x7a, 0x88, 0x60, 0x34, 0xdc, + 0x16, 0x4a, 0x35, 0x64, 0xbd, 0x36, 0x10, 0xf9}, + .exp1_len = 64, + .exp2 = {0xbe, 0x4e, 0x9e, 0x3b, 0x40, 0xf5, 0x6c, 0x62, + 0x59, 0xaa, 0x1e, 0x5c, 0xdf, 0x56, 0x59, 0xb1, + 0x6f, 0xb8, 0x42, 0x94, 0xe5, 0x8a, 0xd0, 0x16, + 0xbd, 0x2c, 0x96, 0xcd, 0x08, 0xe6, 0xcf, 0x68, + 0x54, 0xa1, 0x1c, 0xb8, 0x0a, 0xd4, 0xbe, 0x3e, + 0x05, 0x7a, 0xaa, 0xcf, 0x02, 0xbd, 0x32, 0x63, + 0x73, 0xa2, 0x35, 0xce, 0xb8, 0x9e, 0x82, 0x43, + 0x0d, 0x6e, 0x6d, 0x47, 0xd6, 0xce, 0xf8, 0x35}, + .exp2_len = 64, + .coef = {0xc0, 0x23, 0x5c, 0x89, 0x73, 0xcf, 0xbf, 0x30, + 0xbf, 0x1d, 0xd3, 0xc8, 0x39, 0xf0, 0x2c, 0x94, + 0xc6, 0x9d, 0xc5, 0x34, 0xcb, 0xfc, 0x98, 0x88, + 0x05, 0xd6, 0xfc, 0x46, 0x2a, 0xdb, 0xd3, 0x77, + 0xd1, 0x75, 0xb9, 0xa9, 0x64, 0x60, 0x18, 0xd7, + 0xfa, 0xb7, 0x5c, 0x1d, 0x1f, 0x7d, 0x61, 0xb7, + 0x7f, 0xa7, 0x95, 0x59, 0xb8, 0x6f, 0xfa, 0x9e, + 0xc6, 0xe2, 0x11, 0x33, 0xfa, 0x7f, 0x1a, 0x45}, + .coef_len = 64, + .msg = {0xea, 0x9a, 0x1a, 0x04, 0xb7, 0xcf, 0x47, 0x8a, + 0x89, 0x7a, 0x70, 0x8f, 0xd9, 0x88, 0xf4, 0x8e, + 0x80, 0x1e, 0xdb, 0x0b, 0x70, 0x39, 0xdf, 0x8c, + 0x23, 0xbb, 0x3c, 0x56, 0xf4, 0xe8, 0x21, 0xac, + 0x8b, 0x2b, 0xdd, 0x4b, 0x40, 0xfa, 0xf5, 0x45, + 0xc7, 0x78, 0xdd, 0xf9, 0xbc, 0x1a, 0x49, 0xcb, + 0x57, 0xf9, 0xb7, 0x1b, 0x6d, 0x48, 0xb2, 0xb6, + 0xa5, 0x7a, 0x63, 0xc8, 0x4c, 0xea, 0x85, 0x9d, + 0x65, 0xc6, 0x68, 0x28, 0x4b, 0x08, 0xd9, 0x6b, + 0xdc, 0xaa, 0xbe, 0x25, 0x2d, 0xb0, 0xe4, 0xa9, + 0x6c, 0xb1, 0xba, 0xc6, 0x01, 0x93, 0x41, 0xdb, + 0x6f, 0xbe, 0xfb, 0x8d, 0x10, 0x6b, 0x0e, 0x90, + 0xed, 0xa6, 0xbc, 0xc6, 0xc6, 0x26, 0x2f, 0x37, + 0xe7, 0xea, 0x9c, 0x7e, 0x5d, 0x22, 0x6b, 0xd7, + 0xdf, 0x85, 0xec, 0x5e, 0x71, 0xef}, + .msg_len = 118, + .sig = {0x02, 0x68, 0x44, 0x09, 0x39, 0x99, 0x6a, 0xe5, + 0xcb, 0xda, 0xfd, 0xbc, 0xa8, 0x6a, 0x7c, 0x42, + 0x8a, 0x04, 0xb5, 0x78, 0xfe, 0x2d, 0xbe, 0x51, + 0x26, 0xa8, 0x2f, 0xaf, 0x2b, 0xec, 0xff, 0x09, + 0x9a, 0xc6, 0x0c, 0xb8, 0x1b, 0x11, 0x7f, 0x1e, + 0xbf, 0x42, 0x04, 0xfe, 0x43, 0x70, 0x54, 0x8d, + 0x5d, 0x2c, 0x46, 0x80, 0x63, 0x68, 0x2d, 0xa8, + 0x7d, 0xc8, 0x01, 0x79, 0xbb, 0x3b, 0xba, 0x85, + 0xa1, 0x48, 0xae, 0x2d, 0xe7, 0xdc, 0xb4, 0x94, + 0xf4, 0x76, 0x22, 0x1d, 0xf8, 0x21, 0x9d, 0x4a, + 0xae, 0x1e, 0x45, 0xaf, 0x65, 0xde, 0x33, 0x4a, + 0x1a, 0x6d, 0xc1, 0x45, 0x52, 0x86, 0xae, 0x09, + 0xcf, 0x26, 0x72, 0x58, 0x85, 0xe7, 0x74, 0x80, + 0x99, 0x72, 0xd7, 0x81, 0x98, 0x05, 0xff, 0xf5, + 0xa8, 0xc8, 0x9d, 0x37, 0x37, 0x64, 0x50, 0x73, + 0x92, 0x49, 0xf5, 0x7e, 0xb1, 0x51, 0xb7, 0x1d, + 0xc0}, + .sig_len = 129, + .chunks = {20, 20, 20, 20, 20, 9, 9}, + .num_chunks = 7, + }, + { // 23 + .mod = {0x03, 0x33, 0x12, 0x64, 0x88, 0xf7, 0xa2, 0x91, + 0x51, 0x32, 0xe3, 0x0d, 0x5e, 0x97, 0xf6, 0xed, + 0x7b, 0xbb, 0x67, 0xb6, 0x19, 0x85, 0x00, 0x8e, + 0xae, 0xa2, 0xa5, 0xda, 0xfb, 0x96, 0xa4, 0x48, + 0xab, 0x75, 0xce, 0x3d, 0x6e, 0x68, 0xa6, 0x26, + 0x5e, 0x7c, 0x24, 0x56, 0x84, 0x99, 0x93, 0x24, + 0xc8, 0x1e, 0x0b, 0xa6, 0x38, 0x98, 0x63, 0xfe, + 0xb4, 0x88, 0xb3, 0xf2, 0x55, 0xd0, 0xd6, 0x19, + 0xc1, 0x90, 0x40, 0xb7, 0x4c, 0x18, 0x9f, 0x0c, + 0x9a, 0xf4, 0xb0, 0xd5, 0xa5, 0x5a, 0x54, 0x4c, + 0x09, 0x0c, 0xd6, 0x15, 0x2c, 0x90, 0xa6, 0xf2, + 0x55, 0x0d, 0x7d, 0x2a, 0x6b, 0x6d, 0x34, 0x7d, + 0x5b, 0x1b, 0x9d, 0xfb, 0x1d, 0xe4, 0x40, 0x3c, + 0x79, 0x66, 0x23, 0xd7, 0x03, 0xbf, 0x9d, 0xb4, + 0x43, 0xbf, 0x67, 0x02, 0x68, 0x3b, 0x8d, 0x2a, + 0x9c, 0x61, 0xe9, 0x36, 0x8a, 0xc4, 0x25, 0xa5, + 0x81}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x01, 0x4a, 0x2b, 0x15, 0xdf, 0xa8, 0x83, 0x1d, + 0xb4, 0xef, 0xa0, 0x5b, 0x19, 0x50, 0x84, 0xb7, + 0x42, 0x73, 0x4e, 0xe1, 0x36, 0xf4, 0x48, 0x3f, + 0x3b, 0xe2, 0x50, 0x9d, 0x2f, 0x61, 0x90, 0x23, + 0xc3, 0x0a, 0x1f, 0xf2, 0xdf, 0x78, 0xcb, 0xd1, + 0x17, 0xb1, 0x4f, 0x2c, 0x99, 0x13, 0x17, 0x1f, + 0x72, 0x93, 0xb9, 0xfa, 0x6d, 0x41, 0xf0, 0xbd, + 0x11, 0xa5, 0x31, 0x74, 0x74, 0x67, 0x54, 0x86, + 0xd7, 0xf0, 0xae, 0xc0, 0xa7, 0x78, 0xba, 0x92, + 0x0e, 0x81, 0xf5, 0x64, 0xd1, 0x59, 0x30, 0xcd, + 0xde, 0xe7, 0xe2, 0xb0, 0x6a, 0xd8, 0xad, 0xb6, + 0x12, 0x75, 0x1f, 0x4e, 0x38, 0x4d, 0x6f, 0x3f, + 0xa0, 0xa6, 0x63, 0x9f, 0xd6, 0x2e, 0xdf, 0x86, + 0xf5, 0x2c, 0x9f, 0xe0, 0x77, 0x62, 0x91, 0x83, + 0x21, 0x83, 0xd3, 0x59, 0xb7, 0x34, 0x32, 0x60, + 0xc9, 0x4e, 0x12, 0x5f, 0x4a, 0xb8, 0xbf, 0x43, + 0x69}, + .privexp_len = 129, + .prime1 = {0x01, 0xd6, 0xe7, 0xbd, 0x8e, 0x39, 0x5b, 0xbe, + 0xf2, 0x10, 0x46, 0x49, 0xc0, 0x12, 0x78, 0xcc, + 0x1c, 0x51, 0xc9, 0x68, 0x7d, 0xef, 0xb4, 0x59, + 0x1f, 0x03, 0xb6, 0x78, 0x52, 0xa4, 0xbc, 0xb5, + 0x30, 0x75, 0x0c, 0xf9, 0xbf, 0xca, 0xd0, 0x72, + 0x8c, 0x53, 0x99, 0xd8, 0x70, 0x35, 0x01, 0x06, + 0xcb, 0xa3, 0xec, 0x41, 0x6a, 0x31, 0xe4, 0x2d, + 0x0b, 0x59, 0x75, 0x10, 0xff, 0x1c, 0x9d, 0x53, + 0xbb}, + .prime1_len = 65, + .prime2 = {0x01, 0xbd, 0x46, 0x6f, 0x43, 0xa4, 0xd4, 0x61, + 0x3e, 0x42, 0x64, 0xf0, 0x1b, 0x2d, 0xac, 0x2e, + 0x5a, 0xa4, 0x20, 0x43, 0xf8, 0xfb, 0x5f, 0x69, + 0xfa, 0x87, 0x1d, 0x14, 0xfb, 0x27, 0x3e, 0x76, + 0x7a, 0x53, 0x1c, 0x40, 0xf0, 0x2f, 0x34, 0x3b, + 0xc2, 0xfb, 0x45, 0xa0, 0xc7, 0xe0, 0xf6, 0xbe, + 0x25, 0x61, 0x92, 0x3a, 0x77, 0x21, 0x1d, 0x66, + 0xa6, 0xe2, 0xdb, 0xb4, 0x3c, 0x36, 0x63, 0x51, + 0xf3}, + .prime2_len = 65, + .exp1 = {0xfb, 0x66, 0x85, 0x00, 0x65, 0x06, 0xe2, 0x0e, + 0x01, 0x3a, 0x45, 0x2d, 0x51, 0xaf, 0x43, 0xe8, + 0xea, 0x91, 0x08, 0x44, 0x13, 0xb0, 0xc8, 0xd3, + 0x91, 0xfb, 0xdc, 0x88, 0xe2, 0x82, 0x0c, 0x89, + 0x6e, 0x34, 0x1b, 0x31, 0x95, 0x69, 0x6b, 0x7e, + 0x17, 0x33, 0xcf, 0x25, 0x38, 0x66, 0xef, 0xe5, + 0xd0, 0x01, 0xd5, 0x7a, 0x88, 0x60, 0x34, 0xdc, + 0x16, 0x4a, 0x35, 0x64, 0xbd, 0x36, 0x10, 0xf9}, + .exp1_len = 64, + .exp2 = {0xbe, 0x4e, 0x9e, 0x3b, 0x40, 0xf5, 0x6c, 0x62, + 0x59, 0xaa, 0x1e, 0x5c, 0xdf, 0x56, 0x59, 0xb1, + 0x6f, 0xb8, 0x42, 0x94, 0xe5, 0x8a, 0xd0, 0x16, + 0xbd, 0x2c, 0x96, 0xcd, 0x08, 0xe6, 0xcf, 0x68, + 0x54, 0xa1, 0x1c, 0xb8, 0x0a, 0xd4, 0xbe, 0x3e, + 0x05, 0x7a, 0xaa, 0xcf, 0x02, 0xbd, 0x32, 0x63, + 0x73, 0xa2, 0x35, 0xce, 0xb8, 0x9e, 0x82, 0x43, + 0x0d, 0x6e, 0x6d, 0x47, 0xd6, 0xce, 0xf8, 0x35}, + .exp2_len = 64, + .coef = {0xc0, 0x23, 0x5c, 0x89, 0x73, 0xcf, 0xbf, 0x30, + 0xbf, 0x1d, 0xd3, 0xc8, 0x39, 0xf0, 0x2c, 0x94, + 0xc6, 0x9d, 0xc5, 0x34, 0xcb, 0xfc, 0x98, 0x88, + 0x05, 0xd6, 0xfc, 0x46, 0x2a, 0xdb, 0xd3, 0x77, + 0xd1, 0x75, 0xb9, 0xa9, 0x64, 0x60, 0x18, 0xd7, + 0xfa, 0xb7, 0x5c, 0x1d, 0x1f, 0x7d, 0x61, 0xb7, + 0x7f, 0xa7, 0x95, 0x59, 0xb8, 0x6f, 0xfa, 0x9e, + 0xc6, 0xe2, 0x11, 0x33, 0xfa, 0x7f, 0x1a, 0x45}, + .coef_len = 64, + .msg = {0x07, 0xdf, 0x58, 0x6b, 0x90, 0x5b, 0x23, 0xb9, + 0x1a, 0xf1, 0x3d, 0xa1, 0x23, 0x04, 0xbf, 0x83, + 0xec, 0xa8, 0xa7, 0x3e, 0x87, 0x1f, 0xf9}, + .msg_len = 23, + .sig = {0x01, 0xbf, 0xd9, 0x15, 0xff, 0x77, 0x80, 0xf1, + 0x4c, 0xcc, 0x55, 0xbd, 0x03, 0x06, 0xb3, 0xae, + 0xda, 0x5b, 0x5b, 0x59, 0x55, 0xa8, 0x26, 0xd4, + 0x52, 0x6b, 0x0b, 0xc7, 0x66, 0x15, 0x4f, 0xa8, + 0xda, 0x59, 0x56, 0x05, 0x78, 0xcc, 0xd4, 0x88, + 0x2f, 0xe9, 0x70, 0x92, 0xfb, 0xc7, 0x36, 0xfd, + 0xa7, 0x3c, 0xee, 0xfd, 0x10, 0x38, 0x94, 0x06, + 0x3e, 0x93, 0xe2, 0x2a, 0x7b, 0x5c, 0x44, 0xf7, + 0xa8, 0x5e, 0x3b, 0xdb, 0x96, 0x71, 0x9a, 0x09, + 0x37, 0x43, 0x03, 0xc9, 0x1e, 0xd7, 0xe2, 0x27, + 0x49, 0xfe, 0x3c, 0x4d, 0x6b, 0x96, 0x69, 0x9d, + 0x50, 0x7c, 0x50, 0xad, 0xcf, 0xbd, 0xfc, 0x13, + 0x1d, 0x6b, 0x5f, 0x2c, 0xf1, 0x83, 0x0e, 0x31, + 0xea, 0xbe, 0x39, 0xae, 0xb5, 0x17, 0x96, 0x9c, + 0x94, 0xa8, 0x1c, 0xfe, 0xfe, 0x67, 0x31, 0xaa, + 0x2c, 0xdf, 0xfe, 0x28, 0xc8, 0xaf, 0x71, 0x40, + 0xf4}, + .sig_len = 129, + .chunks = {23, 0}, + .num_chunks = 2, + }, + { // 24 + .mod = {0x05, 0xf3, 0x74, 0x34, 0x88, 0x26, 0x1c, 0x6f, + 0x06, 0x25, 0xe4, 0x32, 0xfa, 0x6e, 0xb8, 0x7f, + 0xb1, 0x2b, 0x26, 0x21, 0x82, 0x90, 0xbf, 0xe3, + 0x96, 0xba, 0x76, 0xea, 0x42, 0x61, 0x32, 0x2f, + 0x81, 0x43, 0xe4, 0xb4, 0xeb, 0xcd, 0x5d, 0x2a, + 0xe1, 0x9b, 0x0f, 0x9d, 0x8d, 0xcd, 0x2f, 0xc7, + 0xe6, 0x82, 0x32, 0x08, 0xa7, 0x51, 0x83, 0x3d, + 0x3b, 0x4e, 0x8e, 0x38, 0x7c, 0x39, 0xf8, 0xed, + 0x6b, 0xbc, 0x9f, 0xda, 0xec, 0x32, 0xd3, 0xea, + 0x9a, 0xbb, 0xff, 0x57, 0x47, 0x23, 0xf3, 0xf1, + 0x22, 0x99, 0x90, 0x96, 0x3e, 0xa4, 0xfd, 0x9f, + 0xb5, 0x44, 0xf6, 0x42, 0x90, 0xaa, 0x2e, 0xa7, + 0xda, 0x63, 0x11, 0x91, 0xa2, 0x0d, 0xbc, 0x94, + 0x23, 0xb4, 0x61, 0x23, 0x3b, 0x93, 0x72, 0x49, + 0xf2, 0xf4, 0xea, 0x10, 0x92, 0x8f, 0xae, 0x2a, + 0x6f, 0xe6, 0x64, 0xf1, 0x2c, 0x09, 0x23, 0xed, + 0x11}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x01, 0x4c, 0xc3, 0x26, 0x32, 0x52, 0xf8, 0xc4, + 0xfb, 0x77, 0xcd, 0x57, 0xa1, 0x42, 0x0c, 0x04, + 0xc0, 0x43, 0x27, 0x8a, 0x0c, 0x45, 0xe7, 0xd4, + 0x23, 0x79, 0x49, 0x3e, 0x34, 0x0f, 0x9c, 0xf1, + 0xa9, 0x6f, 0x96, 0x06, 0x3a, 0xb7, 0x59, 0xd1, + 0x63, 0x04, 0x06, 0xae, 0x28, 0x6a, 0x18, 0x34, + 0xb6, 0xd1, 0xdb, 0x71, 0xee, 0x72, 0x2c, 0x93, + 0x74, 0x5f, 0xdd, 0x4a, 0xd3, 0x3f, 0xaa, 0x72, + 0xd8, 0x93, 0x51, 0xda, 0x69, 0x1a, 0x7d, 0x0a, + 0x71, 0xd2, 0xc5, 0x5c, 0x57, 0x97, 0xd2, 0xcc, + 0xb3, 0xb4, 0x62, 0x62, 0x08, 0xbc, 0x5f, 0x5c, + 0x84, 0xfe, 0x43, 0x2f, 0x66, 0x4d, 0xc3, 0x0e, + 0xde, 0x09, 0x63, 0xe6, 0x58, 0x45, 0x2b, 0x2a, + 0xd5, 0xef, 0xa4, 0x93, 0x5a, 0x12, 0x2f, 0x46, + 0x1d, 0x1e, 0xab, 0x84, 0x1c, 0x8a, 0xe0, 0xe6, + 0xe8, 0x2f, 0xc1, 0xfe, 0xe8, 0x5d, 0x18, 0x1c, + 0xbd}, + .privexp_len = 129, + .prime1 = {0x02, 0x94, 0xea, 0x0f, 0xa3, 0x4e, 0xc3, 0x13, + 0x72, 0x33, 0x44, 0x20, 0x2e, 0x85, 0xec, 0xa2, + 0x4b, 0x5d, 0xf6, 0x46, 0x1a, 0x1c, 0x30, 0x08, + 0x7d, 0xca, 0xb5, 0xd2, 0x53, 0x39, 0x4a, 0xf5, + 0x66, 0x6f, 0x03, 0x5c, 0x33, 0x35, 0x41, 0x0d, + 0x8b, 0xb9, 0x86, 0x62, 0xc9, 0x78, 0xf6, 0x1d, + 0x37, 0xdb, 0x4d, 0x83, 0xf0, 0xb2, 0x4c, 0xdc, + 0xb6, 0x3f, 0xca, 0xdb, 0x79, 0xc5, 0x27, 0xf5, + 0xab}, + .prime1_len = 65, + .prime2 = {0x02, 0x4e, 0x19, 0x16, 0x52, 0xf1, 0x70, 0x9f, + 0xf4, 0x74, 0x37, 0x40, 0x85, 0x81, 0x88, 0x8a, + 0x9d, 0xa1, 0x09, 0x17, 0xc5, 0xb5, 0xab, 0xaf, + 0x91, 0x46, 0x10, 0x9f, 0xda, 0xc6, 0x94, 0x76, + 0x6f, 0x4c, 0x8f, 0xb0, 0x57, 0x96, 0x8e, 0x84, + 0x8d, 0x99, 0x58, 0x6b, 0x05, 0xf8, 0xa0, 0x2f, + 0xba, 0x6c, 0xa1, 0xeb, 0x12, 0xba, 0x08, 0xdf, + 0xd4, 0x9b, 0x62, 0xc2, 0x7a, 0x8f, 0x15, 0xf4, + 0x33}, + .prime2_len = 65, + .exp1 = {0x01, 0x22, 0x7f, 0x36, 0xdc, 0x6b, 0x14, 0x27, + 0x89, 0xfc, 0xaa, 0xa7, 0x12, 0x8b, 0xdf, 0x14, + 0xfe, 0xd7, 0x90, 0x16, 0x04, 0x07, 0xfb, 0xbc, + 0xdf, 0xbd, 0xa7, 0xe9, 0x88, 0x97, 0x18, 0x31, + 0x81, 0x12, 0xae, 0x81, 0x6a, 0x28, 0xb0, 0x2d, + 0x4a, 0x0b, 0x03, 0xdc, 0x8b, 0xfd, 0xd4, 0xff, + 0xc6, 0xbb, 0x67, 0xf8, 0xe4, 0x65, 0x1a, 0x8f, + 0xb0, 0xb3, 0x9d, 0x70, 0x96, 0xb7, 0x67, 0xf6, + 0xfd}, + .exp1_len = 65, + .exp2 = {0x02, 0x25, 0xec, 0x05, 0x3c, 0xe8, 0xda, 0x6f, + 0x86, 0xad, 0xe3, 0x6b, 0xd2, 0xbf, 0x43, 0x93, + 0x02, 0x91, 0x37, 0x5b, 0x1b, 0x1a, 0x51, 0xd4, + 0x7d, 0x0b, 0x11, 0xa5, 0x17, 0x8a, 0x26, 0x83, + 0x34, 0xf7, 0xe1, 0x94, 0x92, 0x1b, 0xb1, 0xd7, + 0x5f, 0xea, 0x7f, 0x56, 0xc5, 0xaa, 0xcd, 0x05, + 0x8d, 0xb3, 0x7d, 0x36, 0x08, 0x2e, 0xac, 0xe4, + 0x83, 0x4b, 0x07, 0xbf, 0x7b, 0xdd, 0xea, 0xb4, + 0xb7}, + .exp2_len = 65, + .coef = {0x02, 0x0b, 0xd0, 0xf5, 0x15, 0x80, 0x87, 0xed, + 0xe3, 0x8c, 0xb5, 0xdc, 0x66, 0xe4, 0x01, 0x0a, + 0xe4, 0xe4, 0x8c, 0xc0, 0x04, 0x2e, 0x15, 0x2c, + 0xd5, 0xee, 0xb0, 0x51, 0xc9, 0xec, 0x45, 0xad, + 0x23, 0x40, 0x24, 0x53, 0x52, 0xc0, 0x1d, 0x94, + 0xc6, 0xa5, 0x26, 0xaa, 0x5a, 0x45, 0x4c, 0xdb, + 0xae, 0xac, 0x85, 0x95, 0x34, 0x9b, 0xbe, 0x6a, + 0x8d, 0x55, 0x19, 0xa3, 0xc9, 0xb7, 0xd0, 0x7c, + 0x3a}, + .coef_len = 65, + .msg = {0x82, 0xe5, 0xc5, 0xaa, 0xe6, 0x4e, 0x60, 0x8b, + 0x27, 0x50, 0x4b, 0x91, 0xdb}, + .msg_len = 13, + .sig = {0x01, 0x45, 0x82, 0xda, 0xe9, 0x35, 0xe6, 0xb2, + 0xae, 0xff, 0x7d, 0x72, 0x50, 0x89, 0xda, 0xb0, + 0x58, 0xc6, 0x78, 0xb2, 0xee, 0x28, 0xbc, 0xd4, + 0x44, 0xa7, 0x2b, 0xdf, 0xac, 0x31, 0x46, 0x3e, + 0x18, 0xe9, 0x4d, 0x7b, 0x5e, 0xcc, 0x84, 0xa4, + 0x31, 0x69, 0x6a, 0x1c, 0xdd, 0x79, 0xf9, 0xc0, + 0x8c, 0x33, 0xe1, 0xd4, 0xb3, 0x22, 0xdd, 0x27, + 0x7b, 0x50, 0x3a, 0xe6, 0xe4, 0xf9, 0xc3, 0x15, + 0x30, 0x5b, 0x43, 0x72, 0xfe, 0x45, 0xfe, 0x4a, + 0x7e, 0xbb, 0xfc, 0x4a, 0xe5, 0x90, 0xfa, 0x3c, + 0x52, 0x0b, 0xf8, 0x28, 0x15, 0x8f, 0x78, 0x20, + 0x29, 0x9f, 0x09, 0xb1, 0x34, 0xed, 0xe1, 0x17, + 0xb6, 0x72, 0xa1, 0xea, 0xc2, 0xf0, 0x50, 0xc0, + 0x44, 0xb2, 0x55, 0xca, 0x8d, 0x45, 0x52, 0xd4, + 0xb5, 0xf3, 0xf5, 0x7b, 0x87, 0x34, 0xdb, 0x24, + 0x74, 0x50, 0x07, 0x44, 0xa5, 0x33, 0x75, 0x00, + 0x5e}, + .sig_len = 129, + .chunks = {13, -1}, + .num_chunks = 2, + }, + { // 25 + .mod = {0x05, 0xf3, 0x74, 0x34, 0x88, 0x26, 0x1c, 0x6f, + 0x06, 0x25, 0xe4, 0x32, 0xfa, 0x6e, 0xb8, 0x7f, + 0xb1, 0x2b, 0x26, 0x21, 0x82, 0x90, 0xbf, 0xe3, + 0x96, 0xba, 0x76, 0xea, 0x42, 0x61, 0x32, 0x2f, + 0x81, 0x43, 0xe4, 0xb4, 0xeb, 0xcd, 0x5d, 0x2a, + 0xe1, 0x9b, 0x0f, 0x9d, 0x8d, 0xcd, 0x2f, 0xc7, + 0xe6, 0x82, 0x32, 0x08, 0xa7, 0x51, 0x83, 0x3d, + 0x3b, 0x4e, 0x8e, 0x38, 0x7c, 0x39, 0xf8, 0xed, + 0x6b, 0xbc, 0x9f, 0xda, 0xec, 0x32, 0xd3, 0xea, + 0x9a, 0xbb, 0xff, 0x57, 0x47, 0x23, 0xf3, 0xf1, + 0x22, 0x99, 0x90, 0x96, 0x3e, 0xa4, 0xfd, 0x9f, + 0xb5, 0x44, 0xf6, 0x42, 0x90, 0xaa, 0x2e, 0xa7, + 0xda, 0x63, 0x11, 0x91, 0xa2, 0x0d, 0xbc, 0x94, + 0x23, 0xb4, 0x61, 0x23, 0x3b, 0x93, 0x72, 0x49, + 0xf2, 0xf4, 0xea, 0x10, 0x92, 0x8f, 0xae, 0x2a, + 0x6f, 0xe6, 0x64, 0xf1, 0x2c, 0x09, 0x23, 0xed, + 0x11}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x01, 0x4c, 0xc3, 0x26, 0x32, 0x52, 0xf8, 0xc4, + 0xfb, 0x77, 0xcd, 0x57, 0xa1, 0x42, 0x0c, 0x04, + 0xc0, 0x43, 0x27, 0x8a, 0x0c, 0x45, 0xe7, 0xd4, + 0x23, 0x79, 0x49, 0x3e, 0x34, 0x0f, 0x9c, 0xf1, + 0xa9, 0x6f, 0x96, 0x06, 0x3a, 0xb7, 0x59, 0xd1, + 0x63, 0x04, 0x06, 0xae, 0x28, 0x6a, 0x18, 0x34, + 0xb6, 0xd1, 0xdb, 0x71, 0xee, 0x72, 0x2c, 0x93, + 0x74, 0x5f, 0xdd, 0x4a, 0xd3, 0x3f, 0xaa, 0x72, + 0xd8, 0x93, 0x51, 0xda, 0x69, 0x1a, 0x7d, 0x0a, + 0x71, 0xd2, 0xc5, 0x5c, 0x57, 0x97, 0xd2, 0xcc, + 0xb3, 0xb4, 0x62, 0x62, 0x08, 0xbc, 0x5f, 0x5c, + 0x84, 0xfe, 0x43, 0x2f, 0x66, 0x4d, 0xc3, 0x0e, + 0xde, 0x09, 0x63, 0xe6, 0x58, 0x45, 0x2b, 0x2a, + 0xd5, 0xef, 0xa4, 0x93, 0x5a, 0x12, 0x2f, 0x46, + 0x1d, 0x1e, 0xab, 0x84, 0x1c, 0x8a, 0xe0, 0xe6, + 0xe8, 0x2f, 0xc1, 0xfe, 0xe8, 0x5d, 0x18, 0x1c, + 0xbd}, + .privexp_len = 129, + .prime1 = {0x02, 0x94, 0xea, 0x0f, 0xa3, 0x4e, 0xc3, 0x13, + 0x72, 0x33, 0x44, 0x20, 0x2e, 0x85, 0xec, 0xa2, + 0x4b, 0x5d, 0xf6, 0x46, 0x1a, 0x1c, 0x30, 0x08, + 0x7d, 0xca, 0xb5, 0xd2, 0x53, 0x39, 0x4a, 0xf5, + 0x66, 0x6f, 0x03, 0x5c, 0x33, 0x35, 0x41, 0x0d, + 0x8b, 0xb9, 0x86, 0x62, 0xc9, 0x78, 0xf6, 0x1d, + 0x37, 0xdb, 0x4d, 0x83, 0xf0, 0xb2, 0x4c, 0xdc, + 0xb6, 0x3f, 0xca, 0xdb, 0x79, 0xc5, 0x27, 0xf5, + 0xab}, + .prime1_len = 65, + .prime2 = {0x02, 0x4e, 0x19, 0x16, 0x52, 0xf1, 0x70, 0x9f, + 0xf4, 0x74, 0x37, 0x40, 0x85, 0x81, 0x88, 0x8a, + 0x9d, 0xa1, 0x09, 0x17, 0xc5, 0xb5, 0xab, 0xaf, + 0x91, 0x46, 0x10, 0x9f, 0xda, 0xc6, 0x94, 0x76, + 0x6f, 0x4c, 0x8f, 0xb0, 0x57, 0x96, 0x8e, 0x84, + 0x8d, 0x99, 0x58, 0x6b, 0x05, 0xf8, 0xa0, 0x2f, + 0xba, 0x6c, 0xa1, 0xeb, 0x12, 0xba, 0x08, 0xdf, + 0xd4, 0x9b, 0x62, 0xc2, 0x7a, 0x8f, 0x15, 0xf4, + 0x33}, + .prime2_len = 65, + .exp1 = {0x01, 0x22, 0x7f, 0x36, 0xdc, 0x6b, 0x14, 0x27, + 0x89, 0xfc, 0xaa, 0xa7, 0x12, 0x8b, 0xdf, 0x14, + 0xfe, 0xd7, 0x90, 0x16, 0x04, 0x07, 0xfb, 0xbc, + 0xdf, 0xbd, 0xa7, 0xe9, 0x88, 0x97, 0x18, 0x31, + 0x81, 0x12, 0xae, 0x81, 0x6a, 0x28, 0xb0, 0x2d, + 0x4a, 0x0b, 0x03, 0xdc, 0x8b, 0xfd, 0xd4, 0xff, + 0xc6, 0xbb, 0x67, 0xf8, 0xe4, 0x65, 0x1a, 0x8f, + 0xb0, 0xb3, 0x9d, 0x70, 0x96, 0xb7, 0x67, 0xf6, + 0xfd}, + .exp1_len = 65, + .exp2 = {0x02, 0x25, 0xec, 0x05, 0x3c, 0xe8, 0xda, 0x6f, + 0x86, 0xad, 0xe3, 0x6b, 0xd2, 0xbf, 0x43, 0x93, + 0x02, 0x91, 0x37, 0x5b, 0x1b, 0x1a, 0x51, 0xd4, + 0x7d, 0x0b, 0x11, 0xa5, 0x17, 0x8a, 0x26, 0x83, + 0x34, 0xf7, 0xe1, 0x94, 0x92, 0x1b, 0xb1, 0xd7, + 0x5f, 0xea, 0x7f, 0x56, 0xc5, 0xaa, 0xcd, 0x05, + 0x8d, 0xb3, 0x7d, 0x36, 0x08, 0x2e, 0xac, 0xe4, + 0x83, 0x4b, 0x07, 0xbf, 0x7b, 0xdd, 0xea, 0xb4, + 0xb7}, + .exp2_len = 65, + .coef = {0x02, 0x0b, 0xd0, 0xf5, 0x15, 0x80, 0x87, 0xed, + 0xe3, 0x8c, 0xb5, 0xdc, 0x66, 0xe4, 0x01, 0x0a, + 0xe4, 0xe4, 0x8c, 0xc0, 0x04, 0x2e, 0x15, 0x2c, + 0xd5, 0xee, 0xb0, 0x51, 0xc9, 0xec, 0x45, 0xad, + 0x23, 0x40, 0x24, 0x53, 0x52, 0xc0, 0x1d, 0x94, + 0xc6, 0xa5, 0x26, 0xaa, 0x5a, 0x45, 0x4c, 0xdb, + 0xae, 0xac, 0x85, 0x95, 0x34, 0x9b, 0xbe, 0x6a, + 0x8d, 0x55, 0x19, 0xa3, 0xc9, 0xb7, 0xd0, 0x7c, + 0x3a}, + .coef_len = 65, + .msg = {0x77, 0xe0, 0xfb, 0xdc, 0xd6, 0xe0, 0x49, 0x8f, + 0xc5, 0x68, 0x4f, 0xf1, 0x3d, 0x4c, 0x9f, 0x5b, + 0x78, 0x0e, 0x77, 0xe2, 0x46, 0x46, 0x37, 0xff, + 0x66, 0xea, 0xa2, 0xd7, 0xd9, 0xc3, 0xde, 0xfb, + 0x9b, 0x0e, 0x3a, 0x38, 0x37, 0x73, 0xdb, 0x97, + 0xa4, 0xfb, 0x49, 0x1b, 0xeb, 0x21, 0x14, 0xfd, + 0xea, 0x2c, 0x2a, 0x48, 0x0f, 0xfc, 0x21, 0x9b, + 0x79, 0x6a, 0xd8, 0x05, 0xd5, 0x4f, 0xbe, 0xc1, + 0x7d, 0xcb, 0x34, 0xb1, 0xda, 0x17, 0x96, 0xcb, + 0x9c, 0xd5, 0xf2, 0x41, 0x6a, 0xb5, 0xe7, 0x66, + 0xf8, 0xe0, 0x06, 0x91, 0x8e, 0xbe, 0xc1, 0x82, + 0x29, 0x98, 0xa2, 0x8f, 0xff, 0xa6, 0x23, 0x0c, + 0x07, 0x87, 0x26, 0xfb, 0xa2, 0xe4, 0xa7, 0xb0}, + .msg_len = 104, + .sig = {0x05, 0x93, 0x27, 0xce, 0xe7, 0x26, 0xff, 0xb6, + 0x03, 0xe8, 0xa9, 0xfc, 0xd5, 0x74, 0xab, 0xa9, + 0xcb, 0xdf, 0xc3, 0x6c, 0x0a, 0xa6, 0x6f, 0xcf, + 0xe3, 0x55, 0x5c, 0xf2, 0xef, 0x35, 0x82, 0xd3, + 0x22, 0x0d, 0xf9, 0xd6, 0xbf, 0x8a, 0x78, 0xe3, + 0xff, 0xf0, 0xc1, 0x29, 0xb3, 0xab, 0xb3, 0xdc, + 0x71, 0x21, 0x12, 0xa2, 0x05, 0x6b, 0xca, 0x08, + 0x63, 0x65, 0x54, 0xc1, 0xac, 0x57, 0xdf, 0x87, + 0xf3, 0x66, 0x41, 0x52, 0x68, 0x8c, 0x6a, 0xc7, + 0x2e, 0x6b, 0x88, 0xf5, 0x63, 0x7c, 0xd7, 0x3f, + 0x16, 0x69, 0x89, 0xc8, 0x29, 0x09, 0xfb, 0x67, + 0xbc, 0x1f, 0xa2, 0xe2, 0xd5, 0x23, 0xe5, 0x1c, + 0x91, 0x8f, 0x2b, 0xbe, 0xc1, 0xd7, 0x52, 0x02, + 0xaf, 0x24, 0x0a, 0x61, 0xcd, 0x2d, 0xcc, 0x55, + 0x5c, 0xae, 0xae, 0x9a, 0x68, 0x57, 0x0d, 0x77, + 0x81, 0x0c, 0xf1, 0xdf, 0x81, 0x23, 0xff, 0x41, + 0xc0}, + .sig_len = 129, + .chunks = {10, 50, 40, 4}, + .num_chunks = 4, + }, + { // 26 + .mod = {0x05, 0xf3, 0x74, 0x34, 0x88, 0x26, 0x1c, 0x6f, + 0x06, 0x25, 0xe4, 0x32, 0xfa, 0x6e, 0xb8, 0x7f, + 0xb1, 0x2b, 0x26, 0x21, 0x82, 0x90, 0xbf, 0xe3, + 0x96, 0xba, 0x76, 0xea, 0x42, 0x61, 0x32, 0x2f, + 0x81, 0x43, 0xe4, 0xb4, 0xeb, 0xcd, 0x5d, 0x2a, + 0xe1, 0x9b, 0x0f, 0x9d, 0x8d, 0xcd, 0x2f, 0xc7, + 0xe6, 0x82, 0x32, 0x08, 0xa7, 0x51, 0x83, 0x3d, + 0x3b, 0x4e, 0x8e, 0x38, 0x7c, 0x39, 0xf8, 0xed, + 0x6b, 0xbc, 0x9f, 0xda, 0xec, 0x32, 0xd3, 0xea, + 0x9a, 0xbb, 0xff, 0x57, 0x47, 0x23, 0xf3, 0xf1, + 0x22, 0x99, 0x90, 0x96, 0x3e, 0xa4, 0xfd, 0x9f, + 0xb5, 0x44, 0xf6, 0x42, 0x90, 0xaa, 0x2e, 0xa7, + 0xda, 0x63, 0x11, 0x91, 0xa2, 0x0d, 0xbc, 0x94, + 0x23, 0xb4, 0x61, 0x23, 0x3b, 0x93, 0x72, 0x49, + 0xf2, 0xf4, 0xea, 0x10, 0x92, 0x8f, 0xae, 0x2a, + 0x6f, 0xe6, 0x64, 0xf1, 0x2c, 0x09, 0x23, 0xed, + 0x11}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x01, 0x4c, 0xc3, 0x26, 0x32, 0x52, 0xf8, 0xc4, + 0xfb, 0x77, 0xcd, 0x57, 0xa1, 0x42, 0x0c, 0x04, + 0xc0, 0x43, 0x27, 0x8a, 0x0c, 0x45, 0xe7, 0xd4, + 0x23, 0x79, 0x49, 0x3e, 0x34, 0x0f, 0x9c, 0xf1, + 0xa9, 0x6f, 0x96, 0x06, 0x3a, 0xb7, 0x59, 0xd1, + 0x63, 0x04, 0x06, 0xae, 0x28, 0x6a, 0x18, 0x34, + 0xb6, 0xd1, 0xdb, 0x71, 0xee, 0x72, 0x2c, 0x93, + 0x74, 0x5f, 0xdd, 0x4a, 0xd3, 0x3f, 0xaa, 0x72, + 0xd8, 0x93, 0x51, 0xda, 0x69, 0x1a, 0x7d, 0x0a, + 0x71, 0xd2, 0xc5, 0x5c, 0x57, 0x97, 0xd2, 0xcc, + 0xb3, 0xb4, 0x62, 0x62, 0x08, 0xbc, 0x5f, 0x5c, + 0x84, 0xfe, 0x43, 0x2f, 0x66, 0x4d, 0xc3, 0x0e, + 0xde, 0x09, 0x63, 0xe6, 0x58, 0x45, 0x2b, 0x2a, + 0xd5, 0xef, 0xa4, 0x93, 0x5a, 0x12, 0x2f, 0x46, + 0x1d, 0x1e, 0xab, 0x84, 0x1c, 0x8a, 0xe0, 0xe6, + 0xe8, 0x2f, 0xc1, 0xfe, 0xe8, 0x5d, 0x18, 0x1c, + 0xbd}, + .privexp_len = 129, + .prime1 = {0x02, 0x94, 0xea, 0x0f, 0xa3, 0x4e, 0xc3, 0x13, + 0x72, 0x33, 0x44, 0x20, 0x2e, 0x85, 0xec, 0xa2, + 0x4b, 0x5d, 0xf6, 0x46, 0x1a, 0x1c, 0x30, 0x08, + 0x7d, 0xca, 0xb5, 0xd2, 0x53, 0x39, 0x4a, 0xf5, + 0x66, 0x6f, 0x03, 0x5c, 0x33, 0x35, 0x41, 0x0d, + 0x8b, 0xb9, 0x86, 0x62, 0xc9, 0x78, 0xf6, 0x1d, + 0x37, 0xdb, 0x4d, 0x83, 0xf0, 0xb2, 0x4c, 0xdc, + 0xb6, 0x3f, 0xca, 0xdb, 0x79, 0xc5, 0x27, 0xf5, + 0xab}, + .prime1_len = 65, + .prime2 = {0x02, 0x4e, 0x19, 0x16, 0x52, 0xf1, 0x70, 0x9f, + 0xf4, 0x74, 0x37, 0x40, 0x85, 0x81, 0x88, 0x8a, + 0x9d, 0xa1, 0x09, 0x17, 0xc5, 0xb5, 0xab, 0xaf, + 0x91, 0x46, 0x10, 0x9f, 0xda, 0xc6, 0x94, 0x76, + 0x6f, 0x4c, 0x8f, 0xb0, 0x57, 0x96, 0x8e, 0x84, + 0x8d, 0x99, 0x58, 0x6b, 0x05, 0xf8, 0xa0, 0x2f, + 0xba, 0x6c, 0xa1, 0xeb, 0x12, 0xba, 0x08, 0xdf, + 0xd4, 0x9b, 0x62, 0xc2, 0x7a, 0x8f, 0x15, 0xf4, + 0x33}, + .prime2_len = 65, + .exp1 = {0x01, 0x22, 0x7f, 0x36, 0xdc, 0x6b, 0x14, 0x27, + 0x89, 0xfc, 0xaa, 0xa7, 0x12, 0x8b, 0xdf, 0x14, + 0xfe, 0xd7, 0x90, 0x16, 0x04, 0x07, 0xfb, 0xbc, + 0xdf, 0xbd, 0xa7, 0xe9, 0x88, 0x97, 0x18, 0x31, + 0x81, 0x12, 0xae, 0x81, 0x6a, 0x28, 0xb0, 0x2d, + 0x4a, 0x0b, 0x03, 0xdc, 0x8b, 0xfd, 0xd4, 0xff, + 0xc6, 0xbb, 0x67, 0xf8, 0xe4, 0x65, 0x1a, 0x8f, + 0xb0, 0xb3, 0x9d, 0x70, 0x96, 0xb7, 0x67, 0xf6, + 0xfd}, + .exp1_len = 65, + .exp2 = {0x02, 0x25, 0xec, 0x05, 0x3c, 0xe8, 0xda, 0x6f, + 0x86, 0xad, 0xe3, 0x6b, 0xd2, 0xbf, 0x43, 0x93, + 0x02, 0x91, 0x37, 0x5b, 0x1b, 0x1a, 0x51, 0xd4, + 0x7d, 0x0b, 0x11, 0xa5, 0x17, 0x8a, 0x26, 0x83, + 0x34, 0xf7, 0xe1, 0x94, 0x92, 0x1b, 0xb1, 0xd7, + 0x5f, 0xea, 0x7f, 0x56, 0xc5, 0xaa, 0xcd, 0x05, + 0x8d, 0xb3, 0x7d, 0x36, 0x08, 0x2e, 0xac, 0xe4, + 0x83, 0x4b, 0x07, 0xbf, 0x7b, 0xdd, 0xea, 0xb4, + 0xb7}, + .exp2_len = 65, + .coef = {0x02, 0x0b, 0xd0, 0xf5, 0x15, 0x80, 0x87, 0xed, + 0xe3, 0x8c, 0xb5, 0xdc, 0x66, 0xe4, 0x01, 0x0a, + 0xe4, 0xe4, 0x8c, 0xc0, 0x04, 0x2e, 0x15, 0x2c, + 0xd5, 0xee, 0xb0, 0x51, 0xc9, 0xec, 0x45, 0xad, + 0x23, 0x40, 0x24, 0x53, 0x52, 0xc0, 0x1d, 0x94, + 0xc6, 0xa5, 0x26, 0xaa, 0x5a, 0x45, 0x4c, 0xdb, + 0xae, 0xac, 0x85, 0x95, 0x34, 0x9b, 0xbe, 0x6a, + 0x8d, 0x55, 0x19, 0xa3, 0xc9, 0xb7, 0xd0, 0x7c, + 0x3a}, + .coef_len = 65, + .msg = {0x0d, 0xfa, 0x5b, 0xaa, 0x1c, 0xdd, 0xb8, 0x34, + 0x70, 0x7a, 0x5f, 0x8c, 0xc6, 0xec, 0xe5, 0x71, + 0xa7, 0xa7, 0xfc, 0xa5, 0x67, 0x63, 0x62, 0xd2, + 0xb2, 0x37, 0x41, 0xa9, 0x57, 0x0a, 0xe2, 0x63, + 0x8f, 0x6b, 0x1c, 0x23, 0x89, 0x85, 0x36, 0x75, + 0xcc, 0xc6, 0xcc, 0x1b, 0x4c, 0x6d, 0xae, 0x23, + 0xcd, 0xa7, 0x1a, 0xb9, 0x6b, 0x5a, 0x2f, 0x22, + 0x14, 0x57, 0x50, 0x43, 0x3e, 0x2d, 0x6b, 0xa4, + 0x27, 0x6a, 0xc1, 0xff, 0x9a, 0x48, 0xaf, 0xc9, + 0xf3, 0x12, 0xf4, 0x13, 0x37, 0x85, 0xca, 0x5a, + 0xf3, 0x74, 0x66, 0x74, 0x31, 0x9a, 0x67, 0x57, + 0xa1, 0x64, 0xe3, 0x4d, 0x14, 0x98, 0xbd, 0x55, + 0x30, 0x90, 0x2e, 0x32, 0x18, 0x55, 0xe3, 0xbe, + 0xd4, 0x08, 0x81, 0xf0, 0x05, 0x42, 0x25, 0x6a, + 0xa2, 0x1a, 0x42, 0xfc}, + .msg_len = 116, + .sig = {0x01, 0xd1, 0x95, 0x41, 0x69, 0xaf, 0x58, 0x99, + 0x3e, 0x14, 0x77, 0x2a, 0x94, 0xf1, 0x9b, 0xc4, + 0x79, 0x24, 0xcc, 0xdb, 0x2e, 0x90, 0xee, 0x43, + 0x36, 0xfb, 0x6e, 0x08, 0x49, 0x8a, 0xf4, 0xda, + 0x26, 0x51, 0xa2, 0xb7, 0x83, 0x6c, 0x31, 0x3a, + 0x57, 0xc8, 0x61, 0xb5, 0x51, 0x84, 0xec, 0x3b, + 0x15, 0xfa, 0xc8, 0x14, 0x53, 0x51, 0xbe, 0xc5, + 0xa7, 0x27, 0x0a, 0x3a, 0xa8, 0x69, 0x4d, 0xb4, + 0xe9, 0xa9, 0x2c, 0xb9, 0x32, 0x7b, 0xb7, 0xa4, + 0xf7, 0xb7, 0x0d, 0x24, 0x4e, 0xaf, 0x9e, 0xbf, + 0xa9, 0xed, 0xfd, 0x4d, 0x54, 0x78, 0x2f, 0x3f, + 0x97, 0x26, 0x26, 0x95, 0xb9, 0x7d, 0x41, 0x6e, + 0x52, 0x7b, 0xe4, 0xea, 0x2d, 0xef, 0xfe, 0x6e, + 0xb5, 0xe0, 0x6c, 0xda, 0x6f, 0x0a, 0x7e, 0x41, + 0x66, 0x77, 0xac, 0x0f, 0xd6, 0xf8, 0x19, 0x5d, + 0x4c, 0xe2, 0x89, 0x70, 0xd2, 0xca, 0x41, 0x1a, + 0x2b}, + .sig_len = 129, + }, + { // 27 + .mod = {0x0d, 0x5f, 0xb9, 0x9f, 0xde, 0xdf, 0x42, 0x56, + 0xe2, 0x8d, 0x4b, 0x41, 0xd7, 0x07, 0xfc, 0x27, + 0x63, 0x3e, 0x89, 0x95, 0x15, 0xf4, 0xda, 0xbf, + 0x6b, 0x46, 0x27, 0x10, 0xac, 0x11, 0x25, 0x81, + 0xfa, 0x73, 0xfa, 0x83, 0x69, 0x58, 0x2c, 0x9f, + 0xd4, 0x52, 0x5a, 0x70, 0x16, 0x18, 0x99, 0xdf, + 0x63, 0x25, 0x84, 0x9e, 0x5c, 0x43, 0x49, 0x3e, + 0x13, 0x35, 0x4e, 0x27, 0x09, 0x55, 0xa4, 0x3e, + 0x38, 0x35, 0xb5, 0x99, 0x8e, 0xd4, 0x2a, 0x57, + 0x5b, 0xbf, 0x68, 0x8d, 0x69, 0xec, 0x36, 0x6d, + 0x2b, 0xa6, 0xf0, 0x50, 0x4c, 0x1e, 0xe1, 0x7d, + 0xc5, 0x9b, 0x7e, 0xa0, 0xb4, 0x64, 0x0c, 0xbe, + 0xcd, 0x8b, 0xd7, 0x96, 0x2b, 0xe8, 0x56, 0x6f, + 0x0e, 0xbd, 0x65, 0x57, 0x43, 0x65, 0x6a, 0x29, + 0x12, 0x85, 0xe0, 0x37, 0xbb, 0xfa, 0x86, 0x55, + 0x80, 0x1b, 0xd0, 0x31, 0x4f, 0x46, 0x4c, 0x56, + 0x91}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0xe7, 0x6f, 0x42, 0xb4, 0x74, 0x02, 0xd5, 0xe0, + 0xf9, 0x64, 0x64, 0x92, 0x5a, 0xb4, 0xb3, 0xbc, + 0x68, 0x94, 0x30, 0x0e, 0xe4, 0x86, 0xfb, 0x70, + 0xce, 0xd4, 0x91, 0xf2, 0xd1, 0xb3, 0x67, 0x80, + 0x84, 0xc1, 0xc2, 0xcb, 0x96, 0x95, 0x68, 0xa5, + 0xf7, 0x7d, 0xab, 0xcd, 0x40, 0x93, 0x39, 0x37, + 0xa8, 0x67, 0xf9, 0x34, 0xfb, 0x2a, 0xea, 0xae, + 0x6d, 0x78, 0x67, 0x98, 0xe0, 0xd0, 0x4a, 0x10, + 0x6f, 0x54, 0x5e, 0x41, 0xa9, 0xc9, 0x38, 0x33, + 0xd8, 0x1f, 0xd4, 0xd7, 0x53, 0x53, 0x17, 0x9c, + 0xb0, 0xbc, 0xa4, 0x5e, 0x79, 0xaa, 0xc9, 0x41, + 0x34, 0x64, 0xb0, 0x36, 0x7f, 0x31, 0xac, 0x5a, + 0xca, 0x56, 0x6f, 0x22, 0x14, 0xbf, 0x51, 0x46, + 0xa9, 0x48, 0x4b, 0x87, 0xe4, 0x2b, 0xda, 0xc2, + 0xb0, 0x1a, 0x99, 0x67, 0x03, 0x50, 0x6b, 0xe0, + 0x77, 0x49, 0xaa, 0x0f, 0xbe, 0xb3, 0xb2, 0x29}, + .privexp_len = 128, + .prime1 = {0x03, 0xff, 0xaf, 0x4a, 0x61, 0x21, 0xd7, 0x42, + 0x0c, 0xfd, 0xa6, 0x4c, 0x41, 0x71, 0x2f, 0x47, + 0xc8, 0xf2, 0xd0, 0xd2, 0x5b, 0x17, 0xe9, 0x5b, + 0x35, 0x41, 0x42, 0x84, 0x69, 0x10, 0xaf, 0xef, + 0xbd, 0xf2, 0x1e, 0x74, 0x23, 0xe8, 0xb3, 0xbe, + 0x44, 0xae, 0xd9, 0xaf, 0x5e, 0x49, 0x81, 0x68, + 0x5d, 0x3b, 0x9a, 0x1d, 0x59, 0xc9, 0xb9, 0x47, + 0xfb, 0x9c, 0x33, 0x9c, 0x9a, 0x31, 0xe5, 0x7b, + 0xd9}, + .prime1_len = 65, + .prime2 = {0x03, 0x58, 0x31, 0xe3, 0xb9, 0x29, 0x3b, 0xcd, + 0xa4, 0x51, 0xbe, 0x9d, 0xb1, 0x91, 0x97, 0x48, + 0x6a, 0xa2, 0xe2, 0x2e, 0x92, 0x98, 0x65, 0x0f, + 0x2b, 0x7f, 0xf4, 0x25, 0x69, 0xeb, 0xec, 0x33, + 0xd2, 0x0a, 0x34, 0x98, 0x44, 0xa3, 0x3b, 0xea, + 0xa0, 0x93, 0xd1, 0x43, 0x4a, 0xfb, 0x4a, 0x04, + 0xa0, 0x4a, 0xed, 0xd3, 0xbb, 0xc4, 0xb3, 0x87, + 0x77, 0xa5, 0x5f, 0xe6, 0x50, 0x5b, 0x8c, 0x15, + 0x79}, + .prime2_len = 65, + .exp1 = {0x02, 0x8e, 0x91, 0xd5, 0xab, 0xba, 0x69, 0xdc, + 0x50, 0x56, 0x38, 0xe9, 0xf5, 0xc6, 0x9c, 0x06, + 0xf8, 0xd5, 0x5a, 0xf5, 0xc7, 0x4d, 0xc8, 0xe7, + 0x8b, 0x6c, 0x09, 0x4e, 0x85, 0xa8, 0x27, 0xf7, + 0xd2, 0xab, 0x69, 0x11, 0xb6, 0x8c, 0x6b, 0xb2, + 0xb4, 0x54, 0x61, 0xd9, 0xa3, 0x1e, 0xb9, 0x62, + 0xb4, 0x8b, 0x12, 0x06, 0xc6, 0x8d, 0x18, 0xae, + 0x90, 0x92, 0xd6, 0xe5, 0xc2, 0x2b, 0x39, 0xa4, + 0x31}, + .exp1_len = 65, + .exp2 = {0x02, 0x98, 0x04, 0xe1, 0x32, 0xfa, 0x3a, 0xaa, + 0x4b, 0x15, 0x26, 0xbb, 0x50, 0x3a, 0xb4, 0xd4, + 0x71, 0xf7, 0x6f, 0x69, 0x65, 0x42, 0x11, 0xa6, + 0x89, 0x3b, 0x0c, 0x13, 0x74, 0x29, 0x87, 0x9f, + 0xcc, 0xf7, 0x23, 0x41, 0x30, 0x82, 0x54, 0x76, + 0xac, 0x20, 0xd7, 0xfb, 0xd3, 0x8c, 0x3e, 0x24, + 0x86, 0x58, 0x76, 0x48, 0x6e, 0xe8, 0xa7, 0xbf, + 0x99, 0x58, 0x45, 0x9e, 0xee, 0x95, 0x81, 0x78, + 0x29}, + .exp2_len = 65, + .coef = {0x02, 0x11, 0x97, 0x5e, 0x88, 0x56, 0xd4, 0xea, + 0x9d, 0x1d, 0xdf, 0x87, 0xb8, 0x7d, 0x39, 0x79, + 0x2f, 0x1c, 0xf7, 0xe2, 0xf1, 0x82, 0xf4, 0xa4, + 0xe6, 0x91, 0xe5, 0x00, 0x2b, 0x10, 0xa0, 0x8a, + 0x46, 0xdc, 0xa1, 0xa4, 0xf4, 0x83, 0x00, 0x85, + 0xd8, 0xd4, 0x0b, 0xea, 0x1d, 0xff, 0x11, 0xb0, + 0xc0, 0xdf, 0x20, 0x22, 0x43, 0xeb, 0x99, 0x3e, + 0x58, 0x0a, 0x94, 0x49, 0x9b, 0x9c, 0xed, 0xd2, + 0xbe}, + .coef_len = 65, + .msg = {0xb2, 0xd5, 0x88, 0x50, 0x9c, 0x2e, 0xac, 0xda, + 0x28, 0x1e, 0x76, 0x71, 0xcb, 0xa2, 0xfc, 0xa9, + 0x14, 0xef, 0x73, 0xa3, 0xae, 0xa9, 0x20, 0x20, + 0x43, 0xea, 0xd6, 0xb7, 0x21, 0x25, 0xc1, 0xb0, + 0xd5, 0xcc, 0x15, 0x41, 0x46, 0x20, 0xd5, 0x73, + 0xd7, 0xab, 0x0b, 0x3a, 0x8a, 0xb6, 0x6a, 0x92, + 0xdf, 0x87, 0x0b, 0x75, 0xb1, 0xc4, 0xd6, 0x8e, + 0xa7, 0x05, 0x6b, 0xe0, 0x41, 0x9e, 0xa2, 0x53, + 0xe6, 0xb0, 0x8b, 0x12, 0x9e, 0x0f, 0x64, 0xf1, + 0x0a, 0xbf, 0x82, 0xe1, 0x67, 0xf8, 0xe3, 0xe9, + 0x28, 0x2e, 0x7b, 0xf7, 0x1b, 0x04, 0x3b, 0xaa, + 0x2b, 0xa2, 0xd8, 0x75, 0x6d, 0x46, 0xb6, 0xd3, + 0x6e, 0x97, 0x34, 0x15, 0xf4, 0xf8, 0xc0, 0xeb, + 0x43, 0xfc, 0x60, 0x4c, 0xed, 0x49, 0x3d, 0xc0, + 0x46, 0xa2, 0x5a, 0x11, 0x9b, 0xd1, 0x58, 0x1d, + 0xbb, 0x59, 0x7c, 0x3e, 0x67, 0xc2, 0xfd, 0xdc, + 0x39, 0x6d, 0xf5, 0xd2, 0x3b, 0x7b, 0xa8, 0x0b, + 0xd2, 0xe3, 0x12, 0x90, 0xbf, 0xc2, 0x62, 0x25, + 0xe0, 0x09, 0x55, 0xa9, 0x8d, 0x91, 0x19, 0x11, + 0xa3, 0x99, 0x67, 0x6f, 0xbb}, + .msg_len = 157, + .sig = {0x07, 0x9a, 0x7b, 0x91, 0x6f, 0x67, 0x41, 0x17, + 0xf1, 0xd8, 0x77, 0xf4, 0x93, 0x43, 0x25, 0x68, + 0x41, 0x48, 0xd5, 0xd0, 0xb0, 0xd5, 0xc2, 0xc6, + 0x15, 0x6a, 0x11, 0x15, 0x9b, 0xc0, 0xbd, 0x30, + 0xd0, 0xa7, 0x35, 0x34, 0xdc, 0x94, 0x45, 0xeb, + 0xe2, 0x06, 0xd6, 0x07, 0x5e, 0xb4, 0xea, 0x7a, + 0x7c, 0x04, 0x32, 0xbd, 0x44, 0xb8, 0x3c, 0xfa, + 0xe4, 0x68, 0x5a, 0x9e, 0xb9, 0xa9, 0x7c, 0xbb, + 0xfa, 0x4e, 0x82, 0xf7, 0x1d, 0xb5, 0x1a, 0xfa, + 0x0d, 0x27, 0xcf, 0x27, 0xf0, 0x60, 0x9b, 0xb3, + 0xf8, 0x80, 0x64, 0x13, 0x24, 0x7d, 0x5d, 0x49, + 0x54, 0xf7, 0x89, 0xa1, 0x01, 0xbf, 0x39, 0x21, + 0x72, 0x8b, 0x48, 0x7e, 0x85, 0xfa, 0x3f, 0xd4, + 0xdc, 0xd7, 0x2d, 0x04, 0x44, 0x8e, 0x42, 0xd3, + 0xec, 0x05, 0xcc, 0x47, 0x5d, 0x74, 0xcb, 0xf7, + 0x65, 0xc3, 0x4e, 0x3e, 0xc1, 0x4c, 0xca, 0x50, + 0x40}, + .sig_len = 129, + .chunks = {50, 50, 50, 7}, + .num_chunks = 4, + }, + { // 28 + .mod = {0x0d, 0x5f, 0xb9, 0x9f, 0xde, 0xdf, 0x42, 0x56, + 0xe2, 0x8d, 0x4b, 0x41, 0xd7, 0x07, 0xfc, 0x27, + 0x63, 0x3e, 0x89, 0x95, 0x15, 0xf4, 0xda, 0xbf, + 0x6b, 0x46, 0x27, 0x10, 0xac, 0x11, 0x25, 0x81, + 0xfa, 0x73, 0xfa, 0x83, 0x69, 0x58, 0x2c, 0x9f, + 0xd4, 0x52, 0x5a, 0x70, 0x16, 0x18, 0x99, 0xdf, + 0x63, 0x25, 0x84, 0x9e, 0x5c, 0x43, 0x49, 0x3e, + 0x13, 0x35, 0x4e, 0x27, 0x09, 0x55, 0xa4, 0x3e, + 0x38, 0x35, 0xb5, 0x99, 0x8e, 0xd4, 0x2a, 0x57, + 0x5b, 0xbf, 0x68, 0x8d, 0x69, 0xec, 0x36, 0x6d, + 0x2b, 0xa6, 0xf0, 0x50, 0x4c, 0x1e, 0xe1, 0x7d, + 0xc5, 0x9b, 0x7e, 0xa0, 0xb4, 0x64, 0x0c, 0xbe, + 0xcd, 0x8b, 0xd7, 0x96, 0x2b, 0xe8, 0x56, 0x6f, + 0x0e, 0xbd, 0x65, 0x57, 0x43, 0x65, 0x6a, 0x29, + 0x12, 0x85, 0xe0, 0x37, 0xbb, 0xfa, 0x86, 0x55, + 0x80, 0x1b, 0xd0, 0x31, 0x4f, 0x46, 0x4c, 0x56, + 0x91}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0xe7, 0x6f, 0x42, 0xb4, 0x74, 0x02, 0xd5, 0xe0, + 0xf9, 0x64, 0x64, 0x92, 0x5a, 0xb4, 0xb3, 0xbc, + 0x68, 0x94, 0x30, 0x0e, 0xe4, 0x86, 0xfb, 0x70, + 0xce, 0xd4, 0x91, 0xf2, 0xd1, 0xb3, 0x67, 0x80, + 0x84, 0xc1, 0xc2, 0xcb, 0x96, 0x95, 0x68, 0xa5, + 0xf7, 0x7d, 0xab, 0xcd, 0x40, 0x93, 0x39, 0x37, + 0xa8, 0x67, 0xf9, 0x34, 0xfb, 0x2a, 0xea, 0xae, + 0x6d, 0x78, 0x67, 0x98, 0xe0, 0xd0, 0x4a, 0x10, + 0x6f, 0x54, 0x5e, 0x41, 0xa9, 0xc9, 0x38, 0x33, + 0xd8, 0x1f, 0xd4, 0xd7, 0x53, 0x53, 0x17, 0x9c, + 0xb0, 0xbc, 0xa4, 0x5e, 0x79, 0xaa, 0xc9, 0x41, + 0x34, 0x64, 0xb0, 0x36, 0x7f, 0x31, 0xac, 0x5a, + 0xca, 0x56, 0x6f, 0x22, 0x14, 0xbf, 0x51, 0x46, + 0xa9, 0x48, 0x4b, 0x87, 0xe4, 0x2b, 0xda, 0xc2, + 0xb0, 0x1a, 0x99, 0x67, 0x03, 0x50, 0x6b, 0xe0, + 0x77, 0x49, 0xaa, 0x0f, 0xbe, 0xb3, 0xb2, 0x29}, + .privexp_len = 128, + .prime1 = {0x03, 0xff, 0xaf, 0x4a, 0x61, 0x21, 0xd7, 0x42, + 0x0c, 0xfd, 0xa6, 0x4c, 0x41, 0x71, 0x2f, 0x47, + 0xc8, 0xf2, 0xd0, 0xd2, 0x5b, 0x17, 0xe9, 0x5b, + 0x35, 0x41, 0x42, 0x84, 0x69, 0x10, 0xaf, 0xef, + 0xbd, 0xf2, 0x1e, 0x74, 0x23, 0xe8, 0xb3, 0xbe, + 0x44, 0xae, 0xd9, 0xaf, 0x5e, 0x49, 0x81, 0x68, + 0x5d, 0x3b, 0x9a, 0x1d, 0x59, 0xc9, 0xb9, 0x47, + 0xfb, 0x9c, 0x33, 0x9c, 0x9a, 0x31, 0xe5, 0x7b, + 0xd9}, + .prime1_len = 65, + .prime2 = {0x03, 0x58, 0x31, 0xe3, 0xb9, 0x29, 0x3b, 0xcd, + 0xa4, 0x51, 0xbe, 0x9d, 0xb1, 0x91, 0x97, 0x48, + 0x6a, 0xa2, 0xe2, 0x2e, 0x92, 0x98, 0x65, 0x0f, + 0x2b, 0x7f, 0xf4, 0x25, 0x69, 0xeb, 0xec, 0x33, + 0xd2, 0x0a, 0x34, 0x98, 0x44, 0xa3, 0x3b, 0xea, + 0xa0, 0x93, 0xd1, 0x43, 0x4a, 0xfb, 0x4a, 0x04, + 0xa0, 0x4a, 0xed, 0xd3, 0xbb, 0xc4, 0xb3, 0x87, + 0x77, 0xa5, 0x5f, 0xe6, 0x50, 0x5b, 0x8c, 0x15, + 0x79}, + .prime2_len = 65, + .exp1 = {0x02, 0x8e, 0x91, 0xd5, 0xab, 0xba, 0x69, 0xdc, + 0x50, 0x56, 0x38, 0xe9, 0xf5, 0xc6, 0x9c, 0x06, + 0xf8, 0xd5, 0x5a, 0xf5, 0xc7, 0x4d, 0xc8, 0xe7, + 0x8b, 0x6c, 0x09, 0x4e, 0x85, 0xa8, 0x27, 0xf7, + 0xd2, 0xab, 0x69, 0x11, 0xb6, 0x8c, 0x6b, 0xb2, + 0xb4, 0x54, 0x61, 0xd9, 0xa3, 0x1e, 0xb9, 0x62, + 0xb4, 0x8b, 0x12, 0x06, 0xc6, 0x8d, 0x18, 0xae, + 0x90, 0x92, 0xd6, 0xe5, 0xc2, 0x2b, 0x39, 0xa4, + 0x31}, + .exp1_len = 65, + .exp2 = {0x02, 0x98, 0x04, 0xe1, 0x32, 0xfa, 0x3a, 0xaa, + 0x4b, 0x15, 0x26, 0xbb, 0x50, 0x3a, 0xb4, 0xd4, + 0x71, 0xf7, 0x6f, 0x69, 0x65, 0x42, 0x11, 0xa6, + 0x89, 0x3b, 0x0c, 0x13, 0x74, 0x29, 0x87, 0x9f, + 0xcc, 0xf7, 0x23, 0x41, 0x30, 0x82, 0x54, 0x76, + 0xac, 0x20, 0xd7, 0xfb, 0xd3, 0x8c, 0x3e, 0x24, + 0x86, 0x58, 0x76, 0x48, 0x6e, 0xe8, 0xa7, 0xbf, + 0x99, 0x58, 0x45, 0x9e, 0xee, 0x95, 0x81, 0x78, + 0x29}, + .exp2_len = 65, + .coef = {0x02, 0x11, 0x97, 0x5e, 0x88, 0x56, 0xd4, 0xea, + 0x9d, 0x1d, 0xdf, 0x87, 0xb8, 0x7d, 0x39, 0x79, + 0x2f, 0x1c, 0xf7, 0xe2, 0xf1, 0x82, 0xf4, 0xa4, + 0xe6, 0x91, 0xe5, 0x00, 0x2b, 0x10, 0xa0, 0x8a, + 0x46, 0xdc, 0xa1, 0xa4, 0xf4, 0x83, 0x00, 0x85, + 0xd8, 0xd4, 0x0b, 0xea, 0x1d, 0xff, 0x11, 0xb0, + 0xc0, 0xdf, 0x20, 0x22, 0x43, 0xeb, 0x99, 0x3e, + 0x58, 0x0a, 0x94, 0x49, 0x9b, 0x9c, 0xed, 0xd2, + 0xbe}, + .coef_len = 65, + .msg = {0xca, 0x25, 0x18, 0xa5, 0xa2, 0x24, 0xb2, 0x3d, + 0x42, 0x05, 0xd8, 0xdd, 0x7e, 0xb0, 0x4c, 0xbd, + 0xcd, 0x0c, 0xcb, 0x82, 0xbc, 0x87, 0x96, 0x1d, + 0x85, 0x9d, 0x66, 0x00, 0xb1, 0xac, 0x3e, 0x25, + 0xa9, 0x40, 0x7b, 0x6c, 0x06, 0x50, 0x27, 0xc0, + 0x40, 0x81, 0xf4, 0x45, 0xa2, 0x30, 0xab, 0x93, + 0x08, 0xe7, 0x55, 0xf3, 0x3a, 0x75, 0x97, 0x73, + 0xbe, 0x6b, 0x96, 0x9e, 0x0e, 0xa7, 0x74, 0xaa, + 0x6e, 0x33, 0x4f, 0xb6, 0x04, 0x18, 0x42, 0x75, + 0xf3, 0x6a, 0x03, 0x1d, 0xae, 0xa6, 0x51, 0x86, + 0x97, 0x79, 0x5b, 0xd6, 0xa7, 0xd6, 0x69, 0x7b, + 0x40, 0x6d, 0xa2, 0xce, 0xce, 0x15, 0xdc, 0x11, + 0x3d, 0x85, 0x44, 0x98, 0x85, 0x61, 0x13, 0x1d, + 0x4f, 0xc6, 0xf6, 0xe3, 0xc5, 0x80, 0xd8, 0x06, + 0x80, 0x7d, 0xf2, 0xc6, 0x85, 0x65, 0x09, 0x54, + 0x2e, 0x4e, 0xd3, 0x9d, 0x34, 0x6e, 0xba, 0x15, + 0x97, 0x6a, 0x8f, 0xd0, 0x1d, 0x79, 0x41, 0xb0, + 0x16, 0x56, 0x06, 0xc7, 0x61, 0x76, 0x64, 0x9a, + 0x16, 0x10, 0x05, 0xa0}, + .msg_len = 148, + .sig = {0x00, 0xbe, 0xb9, 0x21, 0xce, 0x74, 0x89, 0x81, + 0x9d, 0x2f, 0x85, 0xc7, 0x88, 0x39, 0xa2, 0x7d, + 0x7e, 0x19, 0xea, 0x0a, 0x76, 0x4a, 0xc5, 0x31, + 0x01, 0xe8, 0x6f, 0x31, 0x70, 0xa7, 0x6e, 0x31, + 0x8a, 0x7e, 0xe8, 0x9b, 0x1f, 0x5e, 0x23, 0xe7, + 0xe2, 0xdb, 0x96, 0x66, 0xeb, 0x43, 0x91, 0xb2, + 0x79, 0x2a, 0x57, 0x67, 0xee, 0x35, 0x9b, 0x5c, + 0x71, 0xe2, 0x74, 0x79, 0x10, 0xc8, 0x2c, 0x60, + 0x83, 0xd6, 0xd3, 0x48, 0x29, 0xb9, 0x6f, 0xa5, + 0xa2, 0xec, 0x0f, 0x62, 0xf1, 0xbc, 0xda, 0x5d, + 0x78, 0xf8, 0xdc, 0x3c, 0x65, 0x0b, 0x94, 0xe3, + 0x2b, 0x38, 0x60, 0xda, 0x5f, 0xc5, 0xb1, 0x7f, + 0xbf, 0x68, 0x7e, 0xc0, 0x07, 0x5a, 0x9c, 0x73, + 0xdc, 0x1e, 0x98, 0xd1, 0xf3, 0x6a, 0xae, 0xc4, + 0x49, 0x3f, 0x78, 0x91, 0xe3, 0xab, 0x08, 0xe2, + 0x04, 0x2d, 0x8b, 0x1e, 0x46, 0x2e, 0x8c, 0x4c, + 0x33}, + .sig_len = 129, + .chunks = {100, 48}, + .num_chunks = 2, + }, + { // 29 + .mod = {0x0d, 0x5f, 0xb9, 0x9f, 0xde, 0xdf, 0x42, 0x56, + 0xe2, 0x8d, 0x4b, 0x41, 0xd7, 0x07, 0xfc, 0x27, + 0x63, 0x3e, 0x89, 0x95, 0x15, 0xf4, 0xda, 0xbf, + 0x6b, 0x46, 0x27, 0x10, 0xac, 0x11, 0x25, 0x81, + 0xfa, 0x73, 0xfa, 0x83, 0x69, 0x58, 0x2c, 0x9f, + 0xd4, 0x52, 0x5a, 0x70, 0x16, 0x18, 0x99, 0xdf, + 0x63, 0x25, 0x84, 0x9e, 0x5c, 0x43, 0x49, 0x3e, + 0x13, 0x35, 0x4e, 0x27, 0x09, 0x55, 0xa4, 0x3e, + 0x38, 0x35, 0xb5, 0x99, 0x8e, 0xd4, 0x2a, 0x57, + 0x5b, 0xbf, 0x68, 0x8d, 0x69, 0xec, 0x36, 0x6d, + 0x2b, 0xa6, 0xf0, 0x50, 0x4c, 0x1e, 0xe1, 0x7d, + 0xc5, 0x9b, 0x7e, 0xa0, 0xb4, 0x64, 0x0c, 0xbe, + 0xcd, 0x8b, 0xd7, 0x96, 0x2b, 0xe8, 0x56, 0x6f, + 0x0e, 0xbd, 0x65, 0x57, 0x43, 0x65, 0x6a, 0x29, + 0x12, 0x85, 0xe0, 0x37, 0xbb, 0xfa, 0x86, 0x55, + 0x80, 0x1b, 0xd0, 0x31, 0x4f, 0x46, 0x4c, 0x56, + 0x91}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0xe7, 0x6f, 0x42, 0xb4, 0x74, 0x02, 0xd5, 0xe0, + 0xf9, 0x64, 0x64, 0x92, 0x5a, 0xb4, 0xb3, 0xbc, + 0x68, 0x94, 0x30, 0x0e, 0xe4, 0x86, 0xfb, 0x70, + 0xce, 0xd4, 0x91, 0xf2, 0xd1, 0xb3, 0x67, 0x80, + 0x84, 0xc1, 0xc2, 0xcb, 0x96, 0x95, 0x68, 0xa5, + 0xf7, 0x7d, 0xab, 0xcd, 0x40, 0x93, 0x39, 0x37, + 0xa8, 0x67, 0xf9, 0x34, 0xfb, 0x2a, 0xea, 0xae, + 0x6d, 0x78, 0x67, 0x98, 0xe0, 0xd0, 0x4a, 0x10, + 0x6f, 0x54, 0x5e, 0x41, 0xa9, 0xc9, 0x38, 0x33, + 0xd8, 0x1f, 0xd4, 0xd7, 0x53, 0x53, 0x17, 0x9c, + 0xb0, 0xbc, 0xa4, 0x5e, 0x79, 0xaa, 0xc9, 0x41, + 0x34, 0x64, 0xb0, 0x36, 0x7f, 0x31, 0xac, 0x5a, + 0xca, 0x56, 0x6f, 0x22, 0x14, 0xbf, 0x51, 0x46, + 0xa9, 0x48, 0x4b, 0x87, 0xe4, 0x2b, 0xda, 0xc2, + 0xb0, 0x1a, 0x99, 0x67, 0x03, 0x50, 0x6b, 0xe0, + 0x77, 0x49, 0xaa, 0x0f, 0xbe, 0xb3, 0xb2, 0x29}, + .privexp_len = 128, + .prime1 = {0x03, 0xff, 0xaf, 0x4a, 0x61, 0x21, 0xd7, 0x42, + 0x0c, 0xfd, 0xa6, 0x4c, 0x41, 0x71, 0x2f, 0x47, + 0xc8, 0xf2, 0xd0, 0xd2, 0x5b, 0x17, 0xe9, 0x5b, + 0x35, 0x41, 0x42, 0x84, 0x69, 0x10, 0xaf, 0xef, + 0xbd, 0xf2, 0x1e, 0x74, 0x23, 0xe8, 0xb3, 0xbe, + 0x44, 0xae, 0xd9, 0xaf, 0x5e, 0x49, 0x81, 0x68, + 0x5d, 0x3b, 0x9a, 0x1d, 0x59, 0xc9, 0xb9, 0x47, + 0xfb, 0x9c, 0x33, 0x9c, 0x9a, 0x31, 0xe5, 0x7b, + 0xd9}, + .prime1_len = 65, + .prime2 = {0x03, 0x58, 0x31, 0xe3, 0xb9, 0x29, 0x3b, 0xcd, + 0xa4, 0x51, 0xbe, 0x9d, 0xb1, 0x91, 0x97, 0x48, + 0x6a, 0xa2, 0xe2, 0x2e, 0x92, 0x98, 0x65, 0x0f, + 0x2b, 0x7f, 0xf4, 0x25, 0x69, 0xeb, 0xec, 0x33, + 0xd2, 0x0a, 0x34, 0x98, 0x44, 0xa3, 0x3b, 0xea, + 0xa0, 0x93, 0xd1, 0x43, 0x4a, 0xfb, 0x4a, 0x04, + 0xa0, 0x4a, 0xed, 0xd3, 0xbb, 0xc4, 0xb3, 0x87, + 0x77, 0xa5, 0x5f, 0xe6, 0x50, 0x5b, 0x8c, 0x15, + 0x79}, + .prime2_len = 65, + .exp1 = {0x02, 0x8e, 0x91, 0xd5, 0xab, 0xba, 0x69, 0xdc, + 0x50, 0x56, 0x38, 0xe9, 0xf5, 0xc6, 0x9c, 0x06, + 0xf8, 0xd5, 0x5a, 0xf5, 0xc7, 0x4d, 0xc8, 0xe7, + 0x8b, 0x6c, 0x09, 0x4e, 0x85, 0xa8, 0x27, 0xf7, + 0xd2, 0xab, 0x69, 0x11, 0xb6, 0x8c, 0x6b, 0xb2, + 0xb4, 0x54, 0x61, 0xd9, 0xa3, 0x1e, 0xb9, 0x62, + 0xb4, 0x8b, 0x12, 0x06, 0xc6, 0x8d, 0x18, 0xae, + 0x90, 0x92, 0xd6, 0xe5, 0xc2, 0x2b, 0x39, 0xa4, + 0x31}, + .exp1_len = 65, + .exp2 = {0x02, 0x98, 0x04, 0xe1, 0x32, 0xfa, 0x3a, 0xaa, + 0x4b, 0x15, 0x26, 0xbb, 0x50, 0x3a, 0xb4, 0xd4, + 0x71, 0xf7, 0x6f, 0x69, 0x65, 0x42, 0x11, 0xa6, + 0x89, 0x3b, 0x0c, 0x13, 0x74, 0x29, 0x87, 0x9f, + 0xcc, 0xf7, 0x23, 0x41, 0x30, 0x82, 0x54, 0x76, + 0xac, 0x20, 0xd7, 0xfb, 0xd3, 0x8c, 0x3e, 0x24, + 0x86, 0x58, 0x76, 0x48, 0x6e, 0xe8, 0xa7, 0xbf, + 0x99, 0x58, 0x45, 0x9e, 0xee, 0x95, 0x81, 0x78, + 0x29}, + .exp2_len = 65, + .coef = {0x02, 0x11, 0x97, 0x5e, 0x88, 0x56, 0xd4, 0xea, + 0x9d, 0x1d, 0xdf, 0x87, 0xb8, 0x7d, 0x39, 0x79, + 0x2f, 0x1c, 0xf7, 0xe2, 0xf1, 0x82, 0xf4, 0xa4, + 0xe6, 0x91, 0xe5, 0x00, 0x2b, 0x10, 0xa0, 0x8a, + 0x46, 0xdc, 0xa1, 0xa4, 0xf4, 0x83, 0x00, 0x85, + 0xd8, 0xd4, 0x0b, 0xea, 0x1d, 0xff, 0x11, 0xb0, + 0xc0, 0xdf, 0x20, 0x22, 0x43, 0xeb, 0x99, 0x3e, + 0x58, 0x0a, 0x94, 0x49, 0x9b, 0x9c, 0xed, 0xd2, + 0xbe}, + .coef_len = 65, + .msg = {0xd4, 0x33, 0xd1, 0x5b, 0x2d, 0x61, 0xb8, 0x6a, + 0xc8, 0xec, 0x0d, 0xae, 0xba, 0x65, 0xe1, 0x1d, + 0xed, 0x3c, 0x38, 0x84, 0x25, 0x25, 0xe4, 0xb7, + 0xc8, 0xe4, 0x53, 0xb0, 0xf5, 0x53, 0xcb, 0x4e, + 0xb8, 0x75, 0xa6, 0x9d, 0x78, 0x16, 0xf5, 0x4c, + 0x87, 0x79, 0x3e, 0x3a, 0xbb, 0x79, 0xfc, 0x55, + 0x11, 0x35, 0x37, 0xb4, 0x76, 0x29, 0x65, 0xcf, + 0xee, 0x58, 0x6e, 0x0a, 0x17, 0x99, 0x78, 0x51, + 0xe3, 0xdc, 0x9e, 0xaf, 0x6f, 0x1c, 0x9c, 0x2e, + 0x98, 0xc9, 0x61, 0x3e, 0x3b, 0xbe, 0xa0, 0x13, + 0xff, 0x58, 0x61, 0x6b, 0x2a, 0xb0, 0x5a, 0xb3, + 0x24, 0xa9, 0xc5, 0xff, 0x4c, 0x5e, 0xfd, 0xd9, + 0x90, 0xdd, 0x97, 0xd9, 0x16, 0x93, 0xc1, 0xeb, + 0xd4, 0xc0, 0x9c, 0x73, 0x21, 0x16, 0xc8, 0xdf, + 0xc3, 0xec, 0x51, 0x5c, 0x20, 0x53, 0x2c, 0xba, + 0x7e, 0x47, 0x58, 0xc6, 0x8a, 0x69, 0xcf, 0xa0, + 0xac, 0x31, 0x86}, + .msg_len = 131, + .sig = {0x03, 0xae, 0x3b, 0xe1, 0xc7, 0x44, 0x6a, 0xd3, + 0xef, 0xd8, 0xba, 0xe6, 0x1b, 0x3d, 0x32, 0xd3, + 0xef, 0x15, 0x24, 0x82, 0xb1, 0xbf, 0xee, 0x31, + 0x2f, 0xe9, 0xe6, 0xbe, 0xee, 0xab, 0x8c, 0xbd, + 0x08, 0xf4, 0xc8, 0xf9, 0xcf, 0x06, 0x7d, 0xea, + 0xb6, 0xba, 0xc7, 0xc0, 0xfe, 0xcd, 0x87, 0xbb, + 0xab, 0xc7, 0xf6, 0x79, 0x8c, 0x77, 0xef, 0x1c, + 0x3f, 0xd8, 0xbc, 0xa2, 0x8c, 0xf9, 0xec, 0xe6, + 0x56, 0x79, 0x5f, 0x60, 0xb3, 0x78, 0x75, 0xea, + 0xbe, 0xf8, 0x21, 0x53, 0xa1, 0x2b, 0xc7, 0xfd, + 0xe3, 0xfb, 0xc9, 0xe5, 0xe1, 0x48, 0xf4, 0xe1, + 0x6c, 0xb7, 0x2a, 0x77, 0x3d, 0x9d, 0xd0, 0x23, + 0x17, 0xf7, 0x0b, 0x33, 0x91, 0x40, 0x08, 0x05, + 0xe8, 0x5e, 0x7a, 0x23, 0x56, 0x7b, 0x34, 0xaa, + 0x65, 0xa3, 0x5f, 0x74, 0x41, 0x70, 0xaf, 0xfc, + 0xb3, 0x23, 0x37, 0x1a, 0xd2, 0xab, 0x9f, 0x1e, + 0x4d}, + .sig_len = 129, + .chunks = {45, 20, 33, 33}, + .num_chunks = 4, + }, + { // 30 + .mod = {0x1e, 0xd7, 0xee, 0xa9, 0x40, 0x5f, 0x50, 0x7f, + 0x94, 0x16, 0x23, 0xa1, 0x7b, 0xea, 0x71, 0x7b, + 0x86, 0x0d, 0xe4, 0x4c, 0xb7, 0x76, 0x87, 0xb8, + 0xb8, 0x5a, 0x6d, 0x7d, 0x1e, 0xf4, 0xf8, 0x62, + 0x8d, 0x25, 0x7c, 0xb9, 0x42, 0x38, 0xc6, 0x25, + 0xba, 0x25, 0xd4, 0x6a, 0xae, 0x59, 0x39, 0x60, + 0xaf, 0x79, 0xf7, 0x5e, 0x28, 0xab, 0x63, 0xac, + 0x3c, 0xac, 0x48, 0x20, 0xb8, 0x2d, 0xa1, 0xcf, + 0x75, 0x0d, 0x6c, 0x93, 0x0d, 0x6b, 0x82, 0x78, + 0x54, 0xaa, 0xf6, 0xca, 0xc0, 0xc1, 0x7b, 0x80, + 0xb0, 0x29, 0xf5, 0xd3, 0x19, 0xcc, 0xca, 0x66, + 0x5c, 0x56, 0x94, 0xf5, 0x4b, 0xa5, 0xf0, 0x96, + 0xf4, 0x54, 0x34, 0x13, 0xec, 0x4c, 0x5e, 0x97, + 0xcc, 0x1d, 0xda, 0x89, 0xd2, 0xaf, 0xd4, 0x28, + 0x57, 0x87, 0x59, 0x03, 0x2a, 0xdf, 0x92, 0x89, + 0x50, 0x65, 0xba, 0xaf, 0xe8, 0x8d, 0x2d, 0x8b, + 0x61}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x0d, 0x93, 0x80, 0x72, 0xb1, 0x6a, 0x02, 0xf5, + 0xd5, 0x0a, 0x15, 0xae, 0xeb, 0xeb, 0x5a, 0xfe, + 0x43, 0x18, 0x74, 0x48, 0x2c, 0x6d, 0x18, 0xfa, + 0x7e, 0xf3, 0x16, 0xc4, 0x7f, 0x4e, 0xd6, 0xd2, + 0x12, 0x4c, 0xd0, 0xe4, 0x7e, 0xb8, 0x9c, 0xc7, + 0x58, 0x73, 0x74, 0x57, 0x6c, 0xdc, 0xcb, 0x3b, + 0xba, 0xa1, 0x95, 0xf7, 0xb5, 0x31, 0x13, 0x93, + 0x69, 0xb5, 0x6f, 0x9e, 0x2f, 0x53, 0xae, 0xa8, + 0xac, 0x7a, 0x97, 0xe1, 0xd7, 0x45, 0x8f, 0x52, + 0x6c, 0xf7, 0xd7, 0x10, 0xc4, 0x90, 0x2a, 0xae, + 0xdf, 0x99, 0x7c, 0x11, 0x94, 0xb8, 0x7b, 0x62, + 0xcc, 0xd8, 0xda, 0xb8, 0xff, 0x5b, 0x67, 0xd4, + 0x0f, 0xe8, 0x3d, 0xe1, 0xb8, 0x2b, 0x91, 0x60, + 0x9a, 0x7c, 0x5c, 0xf3, 0x92, 0x29, 0xeb, 0x3a, + 0x1b, 0x2f, 0x0e, 0xbf, 0x0b, 0x12, 0x5c, 0xb8, + 0x00, 0x91, 0xa0, 0x7e, 0xbc, 0x77, 0x9c, 0xe7, + 0xfd}, + .privexp_len = 129, + .prime1 = {0x05, 0x90, 0xa1, 0xe5, 0x18, 0x71, 0x07, 0xfa, + 0xef, 0x1e, 0x0c, 0xd5, 0x2f, 0xa2, 0xdc, 0xad, + 0xa2, 0xd5, 0x8a, 0xbc, 0xc9, 0xe0, 0x73, 0x8f, + 0xf4, 0x85, 0x0f, 0x7d, 0x2d, 0xee, 0x19, 0x82, + 0x3f, 0x6e, 0x3e, 0x2c, 0xa9, 0x11, 0xb7, 0x17, + 0x4b, 0xe7, 0x0b, 0x15, 0xc1, 0xb8, 0x87, 0xe0, + 0xae, 0x15, 0x10, 0x21, 0x22, 0x42, 0x2f, 0xa1, + 0x58, 0xb9, 0x8b, 0x0d, 0x38, 0x21, 0x15, 0x24, + 0x5f}, + .prime1_len = 65, + .prime2 = {0x05, 0x8a, 0xdd, 0x02, 0x9b, 0xc9, 0x7e, 0xcf, + 0xd1, 0xd0, 0xdb, 0x26, 0xbe, 0x45, 0xee, 0x8d, + 0x3e, 0x54, 0xbf, 0xe6, 0x36, 0xfc, 0x4d, 0xa6, + 0x66, 0xdc, 0xf2, 0x50, 0xab, 0x2c, 0x2e, 0x96, + 0x56, 0x62, 0x16, 0xb8, 0xa5, 0x17, 0xf1, 0x0f, + 0x75, 0xb9, 0x8f, 0xde, 0x6c, 0xcd, 0x8a, 0x58, + 0xe8, 0xfc, 0x58, 0x2e, 0x78, 0x74, 0x90, 0xe1, + 0x95, 0x8f, 0x7a, 0x0f, 0xda, 0x82, 0xad, 0x68, + 0x3f}, + .prime2_len = 65, + .exp1 = {0x01, 0x80, 0xee, 0xfd, 0xa3, 0xf9, 0x06, 0x9a, + 0xfa, 0xf9, 0x37, 0xa6, 0x72, 0xd4, 0xa2, 0xa4, + 0x18, 0x17, 0x73, 0x01, 0x47, 0xda, 0xe9, 0xde, + 0xbf, 0xc7, 0x24, 0x44, 0x42, 0xa0, 0xcf, 0x2b, + 0xae, 0x4f, 0xef, 0x64, 0xc9, 0xda, 0x0b, 0x8a, + 0xb3, 0xeb, 0x9d, 0xc7, 0x27, 0x2c, 0xe1, 0x2a, + 0x08, 0x5f, 0x90, 0x98, 0x23, 0x55, 0x96, 0xe1, + 0x15, 0xc4, 0x2c, 0x9a, 0x49, 0xcc, 0x46, 0x96, + 0x29}, + .exp1_len = 65, + .exp2 = {0x05, 0x12, 0xe1, 0x4e, 0x11, 0x05, 0x7d, 0x84, + 0x8c, 0x23, 0xf1, 0x6b, 0x5f, 0x46, 0x2f, 0xa2, + 0xb7, 0x8b, 0xe7, 0xfc, 0xbd, 0x1b, 0x6d, 0x8e, + 0x46, 0x9e, 0x3f, 0x69, 0x9f, 0xb9, 0x9b, 0x90, + 0x5e, 0xd5, 0xfe, 0xcc, 0xdb, 0xbd, 0xb6, 0x1d, + 0x1b, 0xfd, 0x5a, 0x7a, 0x19, 0x0a, 0x74, 0x7a, + 0xfe, 0x16, 0x7c, 0x37, 0x56, 0x68, 0x07, 0x75, + 0xab, 0x6f, 0xa4, 0x23, 0x3d, 0x3a, 0xe1, 0xba, + 0x0b}, + .exp2_len = 65, + .coef = {0x26, 0x2e, 0x28, 0x23, 0x16, 0x98, 0xbe, 0x32, + 0x87, 0xa9, 0xc7, 0x06, 0xf3, 0x94, 0x7b, 0x7d, + 0x5c, 0x2f, 0x5f, 0xd2, 0xb9, 0x14, 0x46, 0xf5, + 0xe9, 0xa3, 0x15, 0x44, 0xd9, 0xaf, 0xf4, 0x55, + 0xa3, 0xec, 0xc6, 0xb5, 0x43, 0x14, 0x82, 0x0c, + 0x2a, 0x48, 0x82, 0x61, 0xd9, 0xf9, 0x8d, 0x34, + 0x8d, 0x9c, 0x3d, 0x10, 0x02, 0xe4, 0xe8, 0x28, + 0x7a, 0x15, 0x2c, 0x12, 0x87, 0x09, 0x65, 0x60}, + .coef_len = 64, + .msg = {0x84, 0x55, 0x19, 0xdd, 0x45, 0xd2, 0xdd, 0xcb, + 0xc8, 0xdb, 0xe0, 0xb8, 0x29, 0x54, 0xc4, 0x58, + 0xc3, 0x66, 0x4d, 0x88, 0x27, 0x4e, 0x50, 0x2d, + 0x27, 0x91, 0x46, 0xb1, 0x8f, 0x6a, 0x81, 0x67, + 0x50, 0xe9, 0x4b, 0x4e, 0xcd, 0xee, 0x68, 0x32, + 0xcb, 0x35, 0xdf, 0xcb, 0xdb, 0xdd, 0x3e, 0x5d, + 0xc0, 0x64, 0x04, 0xd5, 0xf0, 0xc7, 0x0e, 0x7c, + 0x7c, 0xd0, 0xe1, 0x9f, 0x38, 0xbc, 0x5a, 0xe3, + 0x2c, 0x7c, 0xd9, 0x1f, 0x94, 0xd8, 0xf5, 0x67, + 0x82, 0x39, 0x7b, 0xc7, 0x4e, 0x6b, 0x06, 0x98, + 0x27, 0xec, 0x27, 0x30, 0x17, 0x37, 0x40, 0xce, + 0x4a, 0x10, 0xe6, 0x48, 0xc7, 0x88, 0x97, 0xaf, + 0x1a, 0x89, 0xe8, 0x33, 0x31, 0xd0, 0xf4, 0x61, + 0x37, 0x8d, 0x06, 0x05, 0x28, 0x73, 0xf1, 0x7d, + 0x9f, 0xfc, 0xe4, 0x6a, 0x32, 0x47, 0x26, 0x07, + 0xfe, 0x73, 0xe4, 0xa5, 0x61, 0x87, 0x9e, 0x61, + 0x9e, 0x7c, 0x1a, 0xe8, 0x14, 0xe4, 0x5e, 0x1d, + 0x2b, 0xdb, 0x12, 0x19, 0x46, 0xb2, 0xae, 0xb8, + 0x56, 0x39, 0x16, 0xc5, 0x43, 0xeb, 0xfd, 0xc2, + 0xc0, 0x90, 0xfe, 0xb5, 0x56, 0x65, 0x00, 0xa8, + 0xce, 0x74, 0xaf, 0xa4, 0x53, 0x72, 0xbd, 0xe0, + 0xc6, 0x67, 0x3a, 0x7f, 0x6a, 0xcc, 0xb0, 0xee, + 0x9d, 0x57, 0xbd, 0xe9, 0x3c, 0x36, 0xdd, 0xc5, + 0x7b, 0x84, 0x90, 0xaa, 0x2d, 0x68, 0x58, 0x5a, + 0x3d, 0xb7, 0x29, 0x7a, 0xda, 0x6d, 0x9b, 0x3f, + 0x35, 0x6d, 0xbc, 0x74, 0xd3, 0x15, 0xc5, 0xfa, + 0x1a, 0xbf, 0x7d, 0xe6, 0xce, 0xbc, 0xa8, 0x3c, + 0x9d, 0xf7}, + .msg_len = 218, + .sig = {0x08, 0x63, 0xa6, 0x26, 0xdc, 0x42, 0xba, 0xf3, + 0xe1, 0x61, 0xc3, 0x5b, 0x3d, 0xe3, 0xb1, 0xab, + 0xc1, 0xaa, 0x5a, 0xdf, 0x54, 0x16, 0x46, 0x5d, + 0x4c, 0x7b, 0x6b, 0x01, 0xae, 0x2d, 0xad, 0x73, + 0xf9, 0xf1, 0x58, 0xeb, 0x21, 0x3d, 0xbc, 0x36, + 0x0b, 0xe4, 0xd4, 0x7e, 0x57, 0x07, 0x87, 0x1c, + 0x39, 0xc3, 0x8d, 0xbb, 0xc9, 0x6b, 0x46, 0xc8, + 0xf9, 0xaf, 0xeb, 0xd3, 0xdd, 0xac, 0x87, 0x16, + 0x90, 0x98, 0xe1, 0xa7, 0x67, 0x18, 0xd3, 0x54, + 0xcd, 0x09, 0x1c, 0xa3, 0x52, 0x96, 0xa7, 0x7c, + 0x21, 0xd2, 0x51, 0x2f, 0xfe, 0x65, 0xe3, 0xb7, + 0x1b, 0x90, 0x22, 0xe9, 0xcd, 0x1f, 0x7c, 0x35, + 0xce, 0x13, 0x65, 0xfd, 0x1f, 0x2c, 0x2c, 0xb9, + 0x67, 0xff, 0x4c, 0x8f, 0x90, 0xf0, 0xc8, 0xea, + 0xef, 0x0d, 0xb7, 0x3f, 0xed, 0x00, 0xe9, 0x8c, + 0xfc, 0x83, 0xf8, 0x0c, 0x67, 0xb3, 0xbe, 0x1d, + 0x33}, + .sig_len = 129, + }, + { // 31 + .mod = {0x1e, 0xd7, 0xee, 0xa9, 0x40, 0x5f, 0x50, 0x7f, + 0x94, 0x16, 0x23, 0xa1, 0x7b, 0xea, 0x71, 0x7b, + 0x86, 0x0d, 0xe4, 0x4c, 0xb7, 0x76, 0x87, 0xb8, + 0xb8, 0x5a, 0x6d, 0x7d, 0x1e, 0xf4, 0xf8, 0x62, + 0x8d, 0x25, 0x7c, 0xb9, 0x42, 0x38, 0xc6, 0x25, + 0xba, 0x25, 0xd4, 0x6a, 0xae, 0x59, 0x39, 0x60, + 0xaf, 0x79, 0xf7, 0x5e, 0x28, 0xab, 0x63, 0xac, + 0x3c, 0xac, 0x48, 0x20, 0xb8, 0x2d, 0xa1, 0xcf, + 0x75, 0x0d, 0x6c, 0x93, 0x0d, 0x6b, 0x82, 0x78, + 0x54, 0xaa, 0xf6, 0xca, 0xc0, 0xc1, 0x7b, 0x80, + 0xb0, 0x29, 0xf5, 0xd3, 0x19, 0xcc, 0xca, 0x66, + 0x5c, 0x56, 0x94, 0xf5, 0x4b, 0xa5, 0xf0, 0x96, + 0xf4, 0x54, 0x34, 0x13, 0xec, 0x4c, 0x5e, 0x97, + 0xcc, 0x1d, 0xda, 0x89, 0xd2, 0xaf, 0xd4, 0x28, + 0x57, 0x87, 0x59, 0x03, 0x2a, 0xdf, 0x92, 0x89, + 0x50, 0x65, 0xba, 0xaf, 0xe8, 0x8d, 0x2d, 0x8b, + 0x61}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x0d, 0x93, 0x80, 0x72, 0xb1, 0x6a, 0x02, 0xf5, + 0xd5, 0x0a, 0x15, 0xae, 0xeb, 0xeb, 0x5a, 0xfe, + 0x43, 0x18, 0x74, 0x48, 0x2c, 0x6d, 0x18, 0xfa, + 0x7e, 0xf3, 0x16, 0xc4, 0x7f, 0x4e, 0xd6, 0xd2, + 0x12, 0x4c, 0xd0, 0xe4, 0x7e, 0xb8, 0x9c, 0xc7, + 0x58, 0x73, 0x74, 0x57, 0x6c, 0xdc, 0xcb, 0x3b, + 0xba, 0xa1, 0x95, 0xf7, 0xb5, 0x31, 0x13, 0x93, + 0x69, 0xb5, 0x6f, 0x9e, 0x2f, 0x53, 0xae, 0xa8, + 0xac, 0x7a, 0x97, 0xe1, 0xd7, 0x45, 0x8f, 0x52, + 0x6c, 0xf7, 0xd7, 0x10, 0xc4, 0x90, 0x2a, 0xae, + 0xdf, 0x99, 0x7c, 0x11, 0x94, 0xb8, 0x7b, 0x62, + 0xcc, 0xd8, 0xda, 0xb8, 0xff, 0x5b, 0x67, 0xd4, + 0x0f, 0xe8, 0x3d, 0xe1, 0xb8, 0x2b, 0x91, 0x60, + 0x9a, 0x7c, 0x5c, 0xf3, 0x92, 0x29, 0xeb, 0x3a, + 0x1b, 0x2f, 0x0e, 0xbf, 0x0b, 0x12, 0x5c, 0xb8, + 0x00, 0x91, 0xa0, 0x7e, 0xbc, 0x77, 0x9c, 0xe7, + 0xfd}, + .privexp_len = 129, + .prime1 = {0x05, 0x90, 0xa1, 0xe5, 0x18, 0x71, 0x07, 0xfa, + 0xef, 0x1e, 0x0c, 0xd5, 0x2f, 0xa2, 0xdc, 0xad, + 0xa2, 0xd5, 0x8a, 0xbc, 0xc9, 0xe0, 0x73, 0x8f, + 0xf4, 0x85, 0x0f, 0x7d, 0x2d, 0xee, 0x19, 0x82, + 0x3f, 0x6e, 0x3e, 0x2c, 0xa9, 0x11, 0xb7, 0x17, + 0x4b, 0xe7, 0x0b, 0x15, 0xc1, 0xb8, 0x87, 0xe0, + 0xae, 0x15, 0x10, 0x21, 0x22, 0x42, 0x2f, 0xa1, + 0x58, 0xb9, 0x8b, 0x0d, 0x38, 0x21, 0x15, 0x24, + 0x5f}, + .prime1_len = 65, + .prime2 = {0x05, 0x8a, 0xdd, 0x02, 0x9b, 0xc9, 0x7e, 0xcf, + 0xd1, 0xd0, 0xdb, 0x26, 0xbe, 0x45, 0xee, 0x8d, + 0x3e, 0x54, 0xbf, 0xe6, 0x36, 0xfc, 0x4d, 0xa6, + 0x66, 0xdc, 0xf2, 0x50, 0xab, 0x2c, 0x2e, 0x96, + 0x56, 0x62, 0x16, 0xb8, 0xa5, 0x17, 0xf1, 0x0f, + 0x75, 0xb9, 0x8f, 0xde, 0x6c, 0xcd, 0x8a, 0x58, + 0xe8, 0xfc, 0x58, 0x2e, 0x78, 0x74, 0x90, 0xe1, + 0x95, 0x8f, 0x7a, 0x0f, 0xda, 0x82, 0xad, 0x68, + 0x3f}, + .prime2_len = 65, + .exp1 = {0x01, 0x80, 0xee, 0xfd, 0xa3, 0xf9, 0x06, 0x9a, + 0xfa, 0xf9, 0x37, 0xa6, 0x72, 0xd4, 0xa2, 0xa4, + 0x18, 0x17, 0x73, 0x01, 0x47, 0xda, 0xe9, 0xde, + 0xbf, 0xc7, 0x24, 0x44, 0x42, 0xa0, 0xcf, 0x2b, + 0xae, 0x4f, 0xef, 0x64, 0xc9, 0xda, 0x0b, 0x8a, + 0xb3, 0xeb, 0x9d, 0xc7, 0x27, 0x2c, 0xe1, 0x2a, + 0x08, 0x5f, 0x90, 0x98, 0x23, 0x55, 0x96, 0xe1, + 0x15, 0xc4, 0x2c, 0x9a, 0x49, 0xcc, 0x46, 0x96, + 0x29}, + .exp1_len = 65, + .exp2 = {0x05, 0x12, 0xe1, 0x4e, 0x11, 0x05, 0x7d, 0x84, + 0x8c, 0x23, 0xf1, 0x6b, 0x5f, 0x46, 0x2f, 0xa2, + 0xb7, 0x8b, 0xe7, 0xfc, 0xbd, 0x1b, 0x6d, 0x8e, + 0x46, 0x9e, 0x3f, 0x69, 0x9f, 0xb9, 0x9b, 0x90, + 0x5e, 0xd5, 0xfe, 0xcc, 0xdb, 0xbd, 0xb6, 0x1d, + 0x1b, 0xfd, 0x5a, 0x7a, 0x19, 0x0a, 0x74, 0x7a, + 0xfe, 0x16, 0x7c, 0x37, 0x56, 0x68, 0x07, 0x75, + 0xab, 0x6f, 0xa4, 0x23, 0x3d, 0x3a, 0xe1, 0xba, + 0x0b}, + .exp2_len = 65, + .coef = {0x26, 0x2e, 0x28, 0x23, 0x16, 0x98, 0xbe, 0x32, + 0x87, 0xa9, 0xc7, 0x06, 0xf3, 0x94, 0x7b, 0x7d, + 0x5c, 0x2f, 0x5f, 0xd2, 0xb9, 0x14, 0x46, 0xf5, + 0xe9, 0xa3, 0x15, 0x44, 0xd9, 0xaf, 0xf4, 0x55, + 0xa3, 0xec, 0xc6, 0xb5, 0x43, 0x14, 0x82, 0x0c, + 0x2a, 0x48, 0x82, 0x61, 0xd9, 0xf9, 0x8d, 0x34, + 0x8d, 0x9c, 0x3d, 0x10, 0x02, 0xe4, 0xe8, 0x28, + 0x7a, 0x15, 0x2c, 0x12, 0x87, 0x09, 0x65, 0x60}, + .coef_len = 64, + .msg = {0x86, 0x8e, 0x7c, 0x4f, 0xc6, 0x34, 0x0b, 0x6b, + 0xbe, 0xb7, 0xb8, 0x6e, 0xa8, 0x9e, 0xe7, 0x26, + 0x5f, 0x32, 0x31, 0xf4, 0x8b, 0xaa, 0x92, 0xe4, + 0xa2, 0xe8, 0xce, 0x0f, 0xa1, 0xc1, 0xa8, 0xc0, + 0xfb, 0x0a, 0xca, 0x94, 0x4c, 0x74, 0xbc, 0xcd}, + .msg_len = 40, + .sig = {0x10, 0xcb, 0xf8, 0x71, 0x7f, 0x76, 0x27, 0x8f, + 0xcc, 0x8f, 0xc0, 0xaa, 0xb4, 0x6e, 0x90, 0xa3, + 0xd1, 0x80, 0xc3, 0xc9, 0x2a, 0x4a, 0x83, 0xeb, + 0x93, 0xc8, 0x92, 0x0a, 0xf8, 0x8b, 0xd6, 0x50, + 0x6b, 0x40, 0x73, 0x45, 0x3f, 0x0b, 0xef, 0xf3, + 0xe6, 0x1e, 0xdb, 0xb4, 0xdb, 0xc9, 0xc9, 0x47, + 0xc6, 0x9d, 0xeb, 0x69, 0xa1, 0xac, 0x92, 0x9e, + 0xfc, 0x15, 0x62, 0x5b, 0x9e, 0xd7, 0xcf, 0x1b, + 0xc4, 0x23, 0xa8, 0x87, 0x5f, 0x37, 0x80, 0xdd, + 0xda, 0x9e, 0xb2, 0xfc, 0xcd, 0x9f, 0xa0, 0x14, + 0x62, 0x6a, 0x7f, 0xcf, 0x99, 0x86, 0x49, 0xbc, + 0xfa, 0x59, 0x53, 0xa3, 0xc4, 0x3e, 0xfb, 0xcc, + 0x38, 0x70, 0x4d, 0x02, 0x49, 0x19, 0xdf, 0x2f, + 0xc4, 0xad, 0xea, 0x39, 0xe3, 0x4c, 0xd1, 0x5c, + 0xd4, 0xf8, 0x6a, 0xd3, 0xf5, 0x01, 0x01, 0x2f, + 0x6b, 0xd2, 0x8a, 0xa5, 0x00, 0x2c, 0x3b, 0x41, + 0xba}, + .sig_len = 129, + .chunks = {20, -1, 20}, + .num_chunks = 3, + }, + { // 32 + .mod = {0x1e, 0xd7, 0xee, 0xa9, 0x40, 0x5f, 0x50, 0x7f, + 0x94, 0x16, 0x23, 0xa1, 0x7b, 0xea, 0x71, 0x7b, + 0x86, 0x0d, 0xe4, 0x4c, 0xb7, 0x76, 0x87, 0xb8, + 0xb8, 0x5a, 0x6d, 0x7d, 0x1e, 0xf4, 0xf8, 0x62, + 0x8d, 0x25, 0x7c, 0xb9, 0x42, 0x38, 0xc6, 0x25, + 0xba, 0x25, 0xd4, 0x6a, 0xae, 0x59, 0x39, 0x60, + 0xaf, 0x79, 0xf7, 0x5e, 0x28, 0xab, 0x63, 0xac, + 0x3c, 0xac, 0x48, 0x20, 0xb8, 0x2d, 0xa1, 0xcf, + 0x75, 0x0d, 0x6c, 0x93, 0x0d, 0x6b, 0x82, 0x78, + 0x54, 0xaa, 0xf6, 0xca, 0xc0, 0xc1, 0x7b, 0x80, + 0xb0, 0x29, 0xf5, 0xd3, 0x19, 0xcc, 0xca, 0x66, + 0x5c, 0x56, 0x94, 0xf5, 0x4b, 0xa5, 0xf0, 0x96, + 0xf4, 0x54, 0x34, 0x13, 0xec, 0x4c, 0x5e, 0x97, + 0xcc, 0x1d, 0xda, 0x89, 0xd2, 0xaf, 0xd4, 0x28, + 0x57, 0x87, 0x59, 0x03, 0x2a, 0xdf, 0x92, 0x89, + 0x50, 0x65, 0xba, 0xaf, 0xe8, 0x8d, 0x2d, 0x8b, + 0x61}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x0d, 0x93, 0x80, 0x72, 0xb1, 0x6a, 0x02, 0xf5, + 0xd5, 0x0a, 0x15, 0xae, 0xeb, 0xeb, 0x5a, 0xfe, + 0x43, 0x18, 0x74, 0x48, 0x2c, 0x6d, 0x18, 0xfa, + 0x7e, 0xf3, 0x16, 0xc4, 0x7f, 0x4e, 0xd6, 0xd2, + 0x12, 0x4c, 0xd0, 0xe4, 0x7e, 0xb8, 0x9c, 0xc7, + 0x58, 0x73, 0x74, 0x57, 0x6c, 0xdc, 0xcb, 0x3b, + 0xba, 0xa1, 0x95, 0xf7, 0xb5, 0x31, 0x13, 0x93, + 0x69, 0xb5, 0x6f, 0x9e, 0x2f, 0x53, 0xae, 0xa8, + 0xac, 0x7a, 0x97, 0xe1, 0xd7, 0x45, 0x8f, 0x52, + 0x6c, 0xf7, 0xd7, 0x10, 0xc4, 0x90, 0x2a, 0xae, + 0xdf, 0x99, 0x7c, 0x11, 0x94, 0xb8, 0x7b, 0x62, + 0xcc, 0xd8, 0xda, 0xb8, 0xff, 0x5b, 0x67, 0xd4, + 0x0f, 0xe8, 0x3d, 0xe1, 0xb8, 0x2b, 0x91, 0x60, + 0x9a, 0x7c, 0x5c, 0xf3, 0x92, 0x29, 0xeb, 0x3a, + 0x1b, 0x2f, 0x0e, 0xbf, 0x0b, 0x12, 0x5c, 0xb8, + 0x00, 0x91, 0xa0, 0x7e, 0xbc, 0x77, 0x9c, 0xe7, + 0xfd}, + .privexp_len = 129, + .prime1 = {0x05, 0x90, 0xa1, 0xe5, 0x18, 0x71, 0x07, 0xfa, + 0xef, 0x1e, 0x0c, 0xd5, 0x2f, 0xa2, 0xdc, 0xad, + 0xa2, 0xd5, 0x8a, 0xbc, 0xc9, 0xe0, 0x73, 0x8f, + 0xf4, 0x85, 0x0f, 0x7d, 0x2d, 0xee, 0x19, 0x82, + 0x3f, 0x6e, 0x3e, 0x2c, 0xa9, 0x11, 0xb7, 0x17, + 0x4b, 0xe7, 0x0b, 0x15, 0xc1, 0xb8, 0x87, 0xe0, + 0xae, 0x15, 0x10, 0x21, 0x22, 0x42, 0x2f, 0xa1, + 0x58, 0xb9, 0x8b, 0x0d, 0x38, 0x21, 0x15, 0x24, + 0x5f}, + .prime1_len = 65, + .prime2 = {0x05, 0x8a, 0xdd, 0x02, 0x9b, 0xc9, 0x7e, 0xcf, + 0xd1, 0xd0, 0xdb, 0x26, 0xbe, 0x45, 0xee, 0x8d, + 0x3e, 0x54, 0xbf, 0xe6, 0x36, 0xfc, 0x4d, 0xa6, + 0x66, 0xdc, 0xf2, 0x50, 0xab, 0x2c, 0x2e, 0x96, + 0x56, 0x62, 0x16, 0xb8, 0xa5, 0x17, 0xf1, 0x0f, + 0x75, 0xb9, 0x8f, 0xde, 0x6c, 0xcd, 0x8a, 0x58, + 0xe8, 0xfc, 0x58, 0x2e, 0x78, 0x74, 0x90, 0xe1, + 0x95, 0x8f, 0x7a, 0x0f, 0xda, 0x82, 0xad, 0x68, + 0x3f}, + .prime2_len = 65, + .exp1 = {0x01, 0x80, 0xee, 0xfd, 0xa3, 0xf9, 0x06, 0x9a, + 0xfa, 0xf9, 0x37, 0xa6, 0x72, 0xd4, 0xa2, 0xa4, + 0x18, 0x17, 0x73, 0x01, 0x47, 0xda, 0xe9, 0xde, + 0xbf, 0xc7, 0x24, 0x44, 0x42, 0xa0, 0xcf, 0x2b, + 0xae, 0x4f, 0xef, 0x64, 0xc9, 0xda, 0x0b, 0x8a, + 0xb3, 0xeb, 0x9d, 0xc7, 0x27, 0x2c, 0xe1, 0x2a, + 0x08, 0x5f, 0x90, 0x98, 0x23, 0x55, 0x96, 0xe1, + 0x15, 0xc4, 0x2c, 0x9a, 0x49, 0xcc, 0x46, 0x96, + 0x29}, + .exp1_len = 65, + .exp2 = {0x05, 0x12, 0xe1, 0x4e, 0x11, 0x05, 0x7d, 0x84, + 0x8c, 0x23, 0xf1, 0x6b, 0x5f, 0x46, 0x2f, 0xa2, + 0xb7, 0x8b, 0xe7, 0xfc, 0xbd, 0x1b, 0x6d, 0x8e, + 0x46, 0x9e, 0x3f, 0x69, 0x9f, 0xb9, 0x9b, 0x90, + 0x5e, 0xd5, 0xfe, 0xcc, 0xdb, 0xbd, 0xb6, 0x1d, + 0x1b, 0xfd, 0x5a, 0x7a, 0x19, 0x0a, 0x74, 0x7a, + 0xfe, 0x16, 0x7c, 0x37, 0x56, 0x68, 0x07, 0x75, + 0xab, 0x6f, 0xa4, 0x23, 0x3d, 0x3a, 0xe1, 0xba, + 0x0b}, + .exp2_len = 65, + .coef = {0x26, 0x2e, 0x28, 0x23, 0x16, 0x98, 0xbe, 0x32, + 0x87, 0xa9, 0xc7, 0x06, 0xf3, 0x94, 0x7b, 0x7d, + 0x5c, 0x2f, 0x5f, 0xd2, 0xb9, 0x14, 0x46, 0xf5, + 0xe9, 0xa3, 0x15, 0x44, 0xd9, 0xaf, 0xf4, 0x55, + 0xa3, 0xec, 0xc6, 0xb5, 0x43, 0x14, 0x82, 0x0c, + 0x2a, 0x48, 0x82, 0x61, 0xd9, 0xf9, 0x8d, 0x34, + 0x8d, 0x9c, 0x3d, 0x10, 0x02, 0xe4, 0xe8, 0x28, + 0x7a, 0x15, 0x2c, 0x12, 0x87, 0x09, 0x65, 0x60}, + .coef_len = 64, + .msg = {0x92, 0xcf, 0x88, 0x0d, 0xa5, 0x89, 0x15, 0xe3, + 0xaa, 0x95, 0x08, 0x93, 0x53, 0xe4, 0x61, 0x84, + 0xc9, 0x15, 0x94, 0x5c, 0x57, 0x67, 0x9c, 0x1e, + 0x4b, 0xd3, 0x82, 0x5e, 0xd9, 0x19, 0xa3, 0x20, + 0x52, 0xe9, 0x78, 0x6e, 0x23, 0xb9, 0x42, 0x53, + 0x9b, 0x93, 0x15, 0xf5, 0x81, 0xda, 0xf0, 0xb4, + 0x1f, 0xa3, 0x26, 0x1b, 0x96, 0x7d, 0xe4, 0x0c, + 0xd5, 0xd9, 0x2a, 0x48, 0x24, 0xf3, 0x64, 0xbd, + 0x1e, 0x1f, 0x51, 0x84, 0x4b, 0x10, 0x9b, 0x14, + 0x54, 0x13, 0x4a, 0xdf, 0x23, 0x4e}, + .msg_len = 78, + .sig = {0x08, 0x82, 0x89, 0x66, 0xac, 0x58, 0x36, 0xc5, + 0x13, 0xda, 0x4f, 0xfb, 0x87, 0x61, 0x87, 0x97, + 0x94, 0x3c, 0x61, 0x2e, 0xde, 0x7e, 0x12, 0xb3, + 0x10, 0x03, 0xef, 0x17, 0x10, 0x65, 0xb4, 0xce, + 0xdc, 0x6a, 0x80, 0xb1, 0x45, 0x6c, 0x21, 0xb6, + 0x74, 0xb3, 0x77, 0x9a, 0xd3, 0x5f, 0x70, 0x17, + 0x7a, 0xa9, 0x2c, 0x6e, 0xac, 0x0b, 0x83, 0x3a, + 0x96, 0x7d, 0x7e, 0x98, 0x99, 0x0b, 0x48, 0x24, + 0x42, 0x05, 0xdb, 0xf2, 0x6f, 0x5c, 0xd5, 0x7e, + 0xf8, 0x7d, 0xc6, 0xfe, 0x5e, 0xd9, 0x99, 0xcf, + 0x8c, 0xa7, 0x5d, 0xc8, 0xe6, 0x26, 0xfd, 0x6e, + 0xb2, 0x81, 0xc4, 0x99, 0xaf, 0xf7, 0x29, 0x89, + 0xed, 0xf5, 0x2e, 0xc6, 0xf3, 0xbc, 0xaf, 0x81, + 0xec, 0x5f, 0x8e, 0x82, 0x30, 0xb8, 0x7e, 0xde, + 0xdc, 0xf7, 0xb7, 0x78, 0x14, 0x3e, 0xd6, 0xc8, + 0xce, 0xbb, 0xac, 0x9d, 0xe5, 0x41, 0x09, 0xdc, + 0xf7}, + .sig_len = 129, + .chunks = {78, 0}, + .num_chunks = 2, + }, + { // 33 + .mod = {0x36, 0x98, 0x1a, 0x95, 0xae, 0x24, 0x18, 0x14, + 0x52, 0xda, 0x25, 0x7c, 0x03, 0x8f, 0x05, 0x82, + 0x14, 0x12, 0xd8, 0x4e, 0xb4, 0x7a, 0x43, 0xfc, + 0xc7, 0xef, 0x12, 0x17, 0x95, 0x9b, 0xa6, 0x77, + 0x02, 0x7f, 0x70, 0x86, 0xd3, 0xa8, 0x5c, 0xdd, + 0x34, 0x9f, 0x92, 0x0f, 0x03, 0x4c, 0x02, 0x78, + 0x79, 0x2d, 0xc8, 0xa8, 0xcf, 0x0c, 0x00, 0x80, + 0xe5, 0xc6, 0x1f, 0x47, 0x48, 0x83, 0xc6, 0x87, + 0x9f, 0x4d, 0xee, 0x0a, 0xe9, 0x52, 0x47, 0x8a, + 0x5e, 0xe2, 0xce, 0x4e, 0x39, 0x18, 0x64, 0x1e, + 0x81, 0x3c, 0xb3, 0x74, 0xf7, 0xb2, 0x83, 0x2b, + 0xcd, 0x6a, 0xea, 0x80, 0x9d, 0x25, 0x4f, 0xc2, + 0xca, 0x9a, 0xc5, 0xa3, 0x32, 0x42, 0x4a, 0xb6, + 0x5c, 0x2a, 0x26, 0x12, 0x75, 0xd1, 0x9a, 0x41, + 0x4b, 0x61, 0x65, 0x00, 0xd5, 0xe3, 0x73, 0x70, + 0x63, 0x15, 0xf0, 0x63, 0xdc, 0x88, 0x5d, 0x7f, + 0xb9}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x09, 0xad, 0x03, 0x17, 0x30, 0xb6, 0x32, 0x73, + 0x55, 0xac, 0xd6, 0x94, 0x68, 0x70, 0x0e, 0x7e, + 0x9b, 0xae, 0xac, 0x5a, 0x24, 0xa7, 0xff, 0xc9, + 0x3b, 0x29, 0x2e, 0xb8, 0x71, 0xda, 0x54, 0x92, + 0x46, 0xa5, 0xce, 0x0c, 0x83, 0x52, 0x55, 0x65, + 0x1a, 0x28, 0xc6, 0xe2, 0xf4, 0xc7, 0x61, 0xaf, + 0xb6, 0xf0, 0x6b, 0x9e, 0x29, 0x95, 0xfb, 0xb7, + 0xdc, 0xa1, 0x74, 0xd5, 0x36, 0x2f, 0xae, 0xbd, + 0xc3, 0x9a, 0x72, 0xc5, 0x79, 0x5d, 0x1f, 0x33, + 0x92, 0xec, 0x08, 0x8b, 0x5d, 0xc2, 0xa7, 0x85, + 0xb2, 0xc9, 0xc4, 0xc6, 0xe6, 0x69, 0xe7, 0x23, + 0xb5, 0xdd, 0x0c, 0xe4, 0x43, 0x25, 0x55, 0x12, + 0x67, 0xdd, 0x62, 0xe0, 0xf7, 0x8d, 0x24, 0x24, + 0xad, 0xae, 0x48, 0xe2, 0x49, 0x44, 0x3a, 0xef, + 0x4a, 0x37, 0x04, 0x10, 0xdb, 0x9e, 0x70, 0x93, + 0x99, 0xac, 0x37, 0xcc, 0x48, 0x1b, 0x59, 0x00, + 0xc5}, + .privexp_len = 129, + .prime1 = {0x07, 0x72, 0x0f, 0x21, 0xcd, 0xdb, 0x92, 0x27, + 0x45, 0xb7, 0x1c, 0xf8, 0x11, 0x6a, 0x83, 0x66, + 0x9a, 0x0d, 0xdb, 0x89, 0xe8, 0xf3, 0xf0, 0x6c, + 0x34, 0x7c, 0xa7, 0x87, 0xcf, 0x10, 0xef, 0x16, + 0x93, 0xbd, 0xfe, 0x3a, 0x0c, 0x36, 0x4c, 0x7a, + 0x7e, 0x89, 0x04, 0x17, 0xf2, 0xaf, 0x49, 0x47, + 0x5c, 0x7d, 0x07, 0x6f, 0x9c, 0xee, 0xaa, 0xe7, + 0x6d, 0xbd, 0x4e, 0x92, 0x15, 0xaf, 0x45, 0x69, + 0x4d}, + .prime1_len = 65, + .prime2 = {0x07, 0x55, 0x1c, 0x27, 0xe9, 0xaa, 0xf1, 0x1f, + 0x47, 0x4f, 0x1c, 0x9a, 0x14, 0xbf, 0x14, 0x4c, + 0xfa, 0xef, 0xe2, 0x7f, 0xca, 0x4f, 0x20, 0x79, + 0x5d, 0xec, 0x85, 0x34, 0xc9, 0x37, 0xbb, 0x00, + 0xfe, 0x16, 0x23, 0x5e, 0xcd, 0x69, 0x1f, 0xd2, + 0x3e, 0x32, 0xcd, 0xfb, 0x8b, 0x78, 0x66, 0x6b, + 0xb7, 0x82, 0x84, 0xae, 0x15, 0xd5, 0x9b, 0xe5, + 0xca, 0x74, 0x73, 0xe6, 0x2d, 0x46, 0xa9, 0xda, + 0x1d}, + .prime2_len = 65, + .exp1 = {0x02, 0xe2, 0x2c, 0x74, 0x16, 0x0a, 0x94, 0x36, + 0xbb, 0x6c, 0x28, 0x3e, 0xf6, 0x57, 0xbe, 0xdd, + 0xec, 0x89, 0xb3, 0x5d, 0x5c, 0xa7, 0xa4, 0x93, + 0xf3, 0x5b, 0xd7, 0x71, 0xe4, 0x42, 0x95, 0xa5, + 0xb3, 0xc0, 0x20, 0x06, 0x11, 0x16, 0xb2, 0x55, + 0xba, 0x4d, 0x8c, 0x15, 0x4e, 0x3a, 0x8e, 0x71, + 0xa1, 0xa3, 0x16, 0x4f, 0x26, 0x82, 0xd4, 0x13, + 0x5e, 0xcf, 0xb2, 0xef, 0x26, 0x90, 0xc3, 0x9b, + 0xfd}, + .exp1_len = 65, + .exp2 = {0x01, 0xd2, 0xbf, 0xf5, 0x8c, 0xbc, 0xdc, 0xc8, + 0x12, 0x4b, 0x31, 0xa9, 0x7e, 0x8f, 0x24, 0xd5, + 0x1f, 0x70, 0x96, 0xb9, 0x7f, 0xec, 0xbc, 0xfe, + 0x70, 0xc4, 0x67, 0x3b, 0x00, 0xed, 0xc2, 0xaa, + 0x34, 0x83, 0xfc, 0xb7, 0x8e, 0x0c, 0x1d, 0xc5, + 0x81, 0x81, 0xd0, 0x86, 0x43, 0xdf, 0xe4, 0x57, + 0xd4, 0x81, 0xb7, 0xcc, 0x31, 0xd1, 0xb3, 0xba, + 0x27, 0xe5, 0x5d, 0x0c, 0x57, 0x25, 0xc3, 0x06, + 0x61}, + .exp2_len = 65, + .coef = {0x06, 0xd2, 0x27, 0x72, 0x57, 0x42, 0xef, 0x03, + 0x46, 0x2d, 0x1c, 0xf6, 0x12, 0x67, 0x4a, 0x78, + 0x83, 0x1d, 0x61, 0x9d, 0xa3, 0xd6, 0x40, 0xeb, + 0x7c, 0x71, 0xc8, 0x7b, 0x53, 0x28, 0x69, 0x72, + 0x73, 0xc5, 0xf7, 0x51, 0xe1, 0x4d, 0x7b, 0x81, + 0xc1, 0x2b, 0x6d, 0xeb, 0x44, 0x75, 0x1a, 0x92, + 0x95, 0xcb, 0x67, 0x1e, 0x81, 0x48, 0x4d, 0xea, + 0xa8, 0x3b, 0x4d, 0xf1, 0xfd, 0x37, 0xe2, 0xff, + 0x3c}, + .coef_len = 65, + .msg = {0xe4, 0xb2, 0xd6, 0x0e, 0x3b, 0xdd, 0x27, 0x81, + 0x6f}, + .msg_len = 9, + .sig = {0x13, 0xfd, 0x4a, 0xc1, 0xac, 0x68, 0x48, 0x17, + 0x37, 0x80, 0x96, 0x5a, 0xff, 0x5e, 0x61, 0xc5, + 0x96, 0x89, 0x2b, 0xc1, 0x47, 0x76, 0x0d, 0x43, + 0x07, 0x9b, 0x5d, 0x71, 0x77, 0xe4, 0x23, 0xd4, + 0x86, 0xf5, 0xa7, 0x3e, 0x1a, 0x16, 0xb3, 0xce, + 0x9b, 0x5e, 0xda, 0xc1, 0x61, 0xea, 0x6d, 0x4f, + 0x6c, 0x23, 0xfc, 0xfc, 0x3e, 0x62, 0x19, 0xca, + 0xc5, 0x56, 0x06, 0x7f, 0xfa, 0xed, 0x4a, 0xda, + 0xc0, 0xa9, 0x50, 0x05, 0x09, 0x0b, 0x89, 0x84, + 0x4c, 0x54, 0x35, 0x4d, 0xb2, 0x2a, 0xaf, 0xf9, + 0xee, 0xff, 0x9d, 0xa5, 0xaa, 0xa5, 0x49, 0x04, + 0x25, 0xe1, 0x35, 0xcc, 0x0f, 0x64, 0x58, 0x4c, + 0x7f, 0x05, 0xfe, 0x33, 0x6e, 0x44, 0x40, 0xbb, + 0x86, 0x92, 0x86, 0xd4, 0x4a, 0xf1, 0x57, 0x88, + 0x0e, 0x3a, 0x40, 0xfb, 0x06, 0x72, 0x5d, 0x09, + 0xde, 0xb3, 0x7f, 0x1e, 0xbb, 0x18, 0x1c, 0x8f, + 0x5c}, + .sig_len = 129, + }, + { // 34 + .mod = {0x36, 0x98, 0x1a, 0x95, 0xae, 0x24, 0x18, 0x14, + 0x52, 0xda, 0x25, 0x7c, 0x03, 0x8f, 0x05, 0x82, + 0x14, 0x12, 0xd8, 0x4e, 0xb4, 0x7a, 0x43, 0xfc, + 0xc7, 0xef, 0x12, 0x17, 0x95, 0x9b, 0xa6, 0x77, + 0x02, 0x7f, 0x70, 0x86, 0xd3, 0xa8, 0x5c, 0xdd, + 0x34, 0x9f, 0x92, 0x0f, 0x03, 0x4c, 0x02, 0x78, + 0x79, 0x2d, 0xc8, 0xa8, 0xcf, 0x0c, 0x00, 0x80, + 0xe5, 0xc6, 0x1f, 0x47, 0x48, 0x83, 0xc6, 0x87, + 0x9f, 0x4d, 0xee, 0x0a, 0xe9, 0x52, 0x47, 0x8a, + 0x5e, 0xe2, 0xce, 0x4e, 0x39, 0x18, 0x64, 0x1e, + 0x81, 0x3c, 0xb3, 0x74, 0xf7, 0xb2, 0x83, 0x2b, + 0xcd, 0x6a, 0xea, 0x80, 0x9d, 0x25, 0x4f, 0xc2, + 0xca, 0x9a, 0xc5, 0xa3, 0x32, 0x42, 0x4a, 0xb6, + 0x5c, 0x2a, 0x26, 0x12, 0x75, 0xd1, 0x9a, 0x41, + 0x4b, 0x61, 0x65, 0x00, 0xd5, 0xe3, 0x73, 0x70, + 0x63, 0x15, 0xf0, 0x63, 0xdc, 0x88, 0x5d, 0x7f, + 0xb9}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x09, 0xad, 0x03, 0x17, 0x30, 0xb6, 0x32, 0x73, + 0x55, 0xac, 0xd6, 0x94, 0x68, 0x70, 0x0e, 0x7e, + 0x9b, 0xae, 0xac, 0x5a, 0x24, 0xa7, 0xff, 0xc9, + 0x3b, 0x29, 0x2e, 0xb8, 0x71, 0xda, 0x54, 0x92, + 0x46, 0xa5, 0xce, 0x0c, 0x83, 0x52, 0x55, 0x65, + 0x1a, 0x28, 0xc6, 0xe2, 0xf4, 0xc7, 0x61, 0xaf, + 0xb6, 0xf0, 0x6b, 0x9e, 0x29, 0x95, 0xfb, 0xb7, + 0xdc, 0xa1, 0x74, 0xd5, 0x36, 0x2f, 0xae, 0xbd, + 0xc3, 0x9a, 0x72, 0xc5, 0x79, 0x5d, 0x1f, 0x33, + 0x92, 0xec, 0x08, 0x8b, 0x5d, 0xc2, 0xa7, 0x85, + 0xb2, 0xc9, 0xc4, 0xc6, 0xe6, 0x69, 0xe7, 0x23, + 0xb5, 0xdd, 0x0c, 0xe4, 0x43, 0x25, 0x55, 0x12, + 0x67, 0xdd, 0x62, 0xe0, 0xf7, 0x8d, 0x24, 0x24, + 0xad, 0xae, 0x48, 0xe2, 0x49, 0x44, 0x3a, 0xef, + 0x4a, 0x37, 0x04, 0x10, 0xdb, 0x9e, 0x70, 0x93, + 0x99, 0xac, 0x37, 0xcc, 0x48, 0x1b, 0x59, 0x00, + 0xc5}, + .privexp_len = 129, + .prime1 = {0x07, 0x72, 0x0f, 0x21, 0xcd, 0xdb, 0x92, 0x27, + 0x45, 0xb7, 0x1c, 0xf8, 0x11, 0x6a, 0x83, 0x66, + 0x9a, 0x0d, 0xdb, 0x89, 0xe8, 0xf3, 0xf0, 0x6c, + 0x34, 0x7c, 0xa7, 0x87, 0xcf, 0x10, 0xef, 0x16, + 0x93, 0xbd, 0xfe, 0x3a, 0x0c, 0x36, 0x4c, 0x7a, + 0x7e, 0x89, 0x04, 0x17, 0xf2, 0xaf, 0x49, 0x47, + 0x5c, 0x7d, 0x07, 0x6f, 0x9c, 0xee, 0xaa, 0xe7, + 0x6d, 0xbd, 0x4e, 0x92, 0x15, 0xaf, 0x45, 0x69, + 0x4d}, + .prime1_len = 65, + .prime2 = {0x07, 0x55, 0x1c, 0x27, 0xe9, 0xaa, 0xf1, 0x1f, + 0x47, 0x4f, 0x1c, 0x9a, 0x14, 0xbf, 0x14, 0x4c, + 0xfa, 0xef, 0xe2, 0x7f, 0xca, 0x4f, 0x20, 0x79, + 0x5d, 0xec, 0x85, 0x34, 0xc9, 0x37, 0xbb, 0x00, + 0xfe, 0x16, 0x23, 0x5e, 0xcd, 0x69, 0x1f, 0xd2, + 0x3e, 0x32, 0xcd, 0xfb, 0x8b, 0x78, 0x66, 0x6b, + 0xb7, 0x82, 0x84, 0xae, 0x15, 0xd5, 0x9b, 0xe5, + 0xca, 0x74, 0x73, 0xe6, 0x2d, 0x46, 0xa9, 0xda, + 0x1d}, + .prime2_len = 65, + .exp1 = {0x02, 0xe2, 0x2c, 0x74, 0x16, 0x0a, 0x94, 0x36, + 0xbb, 0x6c, 0x28, 0x3e, 0xf6, 0x57, 0xbe, 0xdd, + 0xec, 0x89, 0xb3, 0x5d, 0x5c, 0xa7, 0xa4, 0x93, + 0xf3, 0x5b, 0xd7, 0x71, 0xe4, 0x42, 0x95, 0xa5, + 0xb3, 0xc0, 0x20, 0x06, 0x11, 0x16, 0xb2, 0x55, + 0xba, 0x4d, 0x8c, 0x15, 0x4e, 0x3a, 0x8e, 0x71, + 0xa1, 0xa3, 0x16, 0x4f, 0x26, 0x82, 0xd4, 0x13, + 0x5e, 0xcf, 0xb2, 0xef, 0x26, 0x90, 0xc3, 0x9b, + 0xfd}, + .exp1_len = 65, + .exp2 = {0x01, 0xd2, 0xbf, 0xf5, 0x8c, 0xbc, 0xdc, 0xc8, + 0x12, 0x4b, 0x31, 0xa9, 0x7e, 0x8f, 0x24, 0xd5, + 0x1f, 0x70, 0x96, 0xb9, 0x7f, 0xec, 0xbc, 0xfe, + 0x70, 0xc4, 0x67, 0x3b, 0x00, 0xed, 0xc2, 0xaa, + 0x34, 0x83, 0xfc, 0xb7, 0x8e, 0x0c, 0x1d, 0xc5, + 0x81, 0x81, 0xd0, 0x86, 0x43, 0xdf, 0xe4, 0x57, + 0xd4, 0x81, 0xb7, 0xcc, 0x31, 0xd1, 0xb3, 0xba, + 0x27, 0xe5, 0x5d, 0x0c, 0x57, 0x25, 0xc3, 0x06, + 0x61}, + .exp2_len = 65, + .coef = {0x06, 0xd2, 0x27, 0x72, 0x57, 0x42, 0xef, 0x03, + 0x46, 0x2d, 0x1c, 0xf6, 0x12, 0x67, 0x4a, 0x78, + 0x83, 0x1d, 0x61, 0x9d, 0xa3, 0xd6, 0x40, 0xeb, + 0x7c, 0x71, 0xc8, 0x7b, 0x53, 0x28, 0x69, 0x72, + 0x73, 0xc5, 0xf7, 0x51, 0xe1, 0x4d, 0x7b, 0x81, + 0xc1, 0x2b, 0x6d, 0xeb, 0x44, 0x75, 0x1a, 0x92, + 0x95, 0xcb, 0x67, 0x1e, 0x81, 0x48, 0x4d, 0xea, + 0xa8, 0x3b, 0x4d, 0xf1, 0xfd, 0x37, 0xe2, 0xff, + 0x3c}, + .coef_len = 65, + .msg = {0x78, 0x86, 0x85, 0xfc, 0x58, 0x05, 0xd6, 0x27, + 0xb1, 0x3f, 0x2f, 0xe7, 0xfe, 0x6f, 0x7c, 0x9a, + 0xb2, 0xca, 0x49, 0x44, 0xab, 0xf3, 0x08, 0xb8, + 0x6d, 0x1a, 0x0f, 0x58, 0x3d, 0x17, 0xb5, 0x76, + 0x02, 0x43, 0x9e, 0x1f, 0x2c, 0x6e, 0x0c, 0x5b, + 0xf7, 0x81, 0x70, 0x50, 0x13, 0x38, 0xb4, 0xc4, + 0x47, 0xe9, 0x19, 0x7b, 0x65, 0x03, 0xfb, 0x73, + 0xeb, 0xab, 0xf7, 0x76, 0xde, 0xfa, 0xe3, 0x3b, + 0xdc, 0xdc, 0xe7, 0x7d, 0xe7, 0x9b, 0x82, 0xbe, + 0x14, 0x85, 0xa8, 0xaa, 0x9b, 0x82, 0x09, 0x37, + 0xdb, 0xf4, 0x28, 0xa2, 0x05, 0x50, 0x96, 0x6a, + 0x86, 0xb6, 0x2a, 0x17, 0x2e, 0x6c, 0xfb, 0xdc, + 0xfe, 0x0d, 0x6f, 0xc6, 0x7a, 0x4d, 0xb6, 0x22, + 0x52, 0xfd, 0xaf, 0x85, 0xf1, 0xe6, 0xbc, 0x14, + 0xf8, 0xab, 0x1c, 0x53, 0x32, 0x6a, 0xa6, 0xa7, + 0xbc, 0x5e, 0xec, 0x88, 0xe0, 0xb1, 0x1d, 0x48, + 0xd2, 0xb5, 0x61, 0xf2, 0x26, 0x06, 0x50, 0x10, + 0x2f, 0xf2, 0x7b, 0x57, 0xb7, 0x00, 0x72, 0xbc, + 0xc1, 0x21, 0xe3, 0x5e, 0x70, 0xf3, 0x78, 0x0c, + 0x83, 0x33, 0xb5, 0xbf, 0x6b, 0x08, 0xfa, 0x12, + 0x08, 0x26, 0x0f, 0x33}, + .msg_len = 164, + .sig = {0x09, 0x04, 0xcc, 0x11, 0xac, 0x66, 0xa9, 0x83, + 0x7b, 0x74, 0x56, 0x8b, 0xe2, 0x50, 0xe5, 0x3a, + 0xe4, 0xbe, 0xf7, 0x8d, 0xc6, 0x7f, 0xfe, 0xe5, + 0x09, 0xe5, 0xd9, 0xb4, 0x72, 0x58, 0x3e, 0xaa, + 0xa5, 0x6d, 0x4c, 0x9e, 0xe7, 0x0f, 0x6e, 0x82, + 0xdc, 0x99, 0x8b, 0x53, 0xef, 0xf1, 0x27, 0x2b, + 0xf0, 0x1f, 0x09, 0xe5, 0x26, 0x2b, 0x15, 0x5a, + 0x6e, 0x56, 0xd1, 0x50, 0x40, 0x03, 0xe4, 0xc8, + 0xa4, 0x6e, 0x65, 0x02, 0x55, 0x32, 0x78, 0x23, + 0x0d, 0x6e, 0x81, 0xb7, 0x29, 0x18, 0x43, 0xab, + 0x97, 0x69, 0x73, 0x7f, 0x3c, 0x69, 0x31, 0x52, + 0xf1, 0x7b, 0xf2, 0xd8, 0xbf, 0xc7, 0x82, 0xbd, + 0xb3, 0xfa, 0x0a, 0xea, 0xdf, 0x0d, 0x44, 0x1e, + 0x1e, 0x52, 0xde, 0xa5, 0x4b, 0x75, 0xcf, 0x16, + 0x5e, 0x35, 0xc3, 0x82, 0xd3, 0x11, 0x74, 0xf6, + 0x67, 0x9d, 0x2f, 0x21, 0xb9, 0x81, 0xf4, 0x13, + 0x58}, + .sig_len = 129, + }, + { // 35 + .mod = {0x36, 0x98, 0x1a, 0x95, 0xae, 0x24, 0x18, 0x14, + 0x52, 0xda, 0x25, 0x7c, 0x03, 0x8f, 0x05, 0x82, + 0x14, 0x12, 0xd8, 0x4e, 0xb4, 0x7a, 0x43, 0xfc, + 0xc7, 0xef, 0x12, 0x17, 0x95, 0x9b, 0xa6, 0x77, + 0x02, 0x7f, 0x70, 0x86, 0xd3, 0xa8, 0x5c, 0xdd, + 0x34, 0x9f, 0x92, 0x0f, 0x03, 0x4c, 0x02, 0x78, + 0x79, 0x2d, 0xc8, 0xa8, 0xcf, 0x0c, 0x00, 0x80, + 0xe5, 0xc6, 0x1f, 0x47, 0x48, 0x83, 0xc6, 0x87, + 0x9f, 0x4d, 0xee, 0x0a, 0xe9, 0x52, 0x47, 0x8a, + 0x5e, 0xe2, 0xce, 0x4e, 0x39, 0x18, 0x64, 0x1e, + 0x81, 0x3c, 0xb3, 0x74, 0xf7, 0xb2, 0x83, 0x2b, + 0xcd, 0x6a, 0xea, 0x80, 0x9d, 0x25, 0x4f, 0xc2, + 0xca, 0x9a, 0xc5, 0xa3, 0x32, 0x42, 0x4a, 0xb6, + 0x5c, 0x2a, 0x26, 0x12, 0x75, 0xd1, 0x9a, 0x41, + 0x4b, 0x61, 0x65, 0x00, 0xd5, 0xe3, 0x73, 0x70, + 0x63, 0x15, 0xf0, 0x63, 0xdc, 0x88, 0x5d, 0x7f, + 0xb9}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x09, 0xad, 0x03, 0x17, 0x30, 0xb6, 0x32, 0x73, + 0x55, 0xac, 0xd6, 0x94, 0x68, 0x70, 0x0e, 0x7e, + 0x9b, 0xae, 0xac, 0x5a, 0x24, 0xa7, 0xff, 0xc9, + 0x3b, 0x29, 0x2e, 0xb8, 0x71, 0xda, 0x54, 0x92, + 0x46, 0xa5, 0xce, 0x0c, 0x83, 0x52, 0x55, 0x65, + 0x1a, 0x28, 0xc6, 0xe2, 0xf4, 0xc7, 0x61, 0xaf, + 0xb6, 0xf0, 0x6b, 0x9e, 0x29, 0x95, 0xfb, 0xb7, + 0xdc, 0xa1, 0x74, 0xd5, 0x36, 0x2f, 0xae, 0xbd, + 0xc3, 0x9a, 0x72, 0xc5, 0x79, 0x5d, 0x1f, 0x33, + 0x92, 0xec, 0x08, 0x8b, 0x5d, 0xc2, 0xa7, 0x85, + 0xb2, 0xc9, 0xc4, 0xc6, 0xe6, 0x69, 0xe7, 0x23, + 0xb5, 0xdd, 0x0c, 0xe4, 0x43, 0x25, 0x55, 0x12, + 0x67, 0xdd, 0x62, 0xe0, 0xf7, 0x8d, 0x24, 0x24, + 0xad, 0xae, 0x48, 0xe2, 0x49, 0x44, 0x3a, 0xef, + 0x4a, 0x37, 0x04, 0x10, 0xdb, 0x9e, 0x70, 0x93, + 0x99, 0xac, 0x37, 0xcc, 0x48, 0x1b, 0x59, 0x00, + 0xc5}, + .privexp_len = 129, + .prime1 = {0x07, 0x72, 0x0f, 0x21, 0xcd, 0xdb, 0x92, 0x27, + 0x45, 0xb7, 0x1c, 0xf8, 0x11, 0x6a, 0x83, 0x66, + 0x9a, 0x0d, 0xdb, 0x89, 0xe8, 0xf3, 0xf0, 0x6c, + 0x34, 0x7c, 0xa7, 0x87, 0xcf, 0x10, 0xef, 0x16, + 0x93, 0xbd, 0xfe, 0x3a, 0x0c, 0x36, 0x4c, 0x7a, + 0x7e, 0x89, 0x04, 0x17, 0xf2, 0xaf, 0x49, 0x47, + 0x5c, 0x7d, 0x07, 0x6f, 0x9c, 0xee, 0xaa, 0xe7, + 0x6d, 0xbd, 0x4e, 0x92, 0x15, 0xaf, 0x45, 0x69, + 0x4d}, + .prime1_len = 65, + .prime2 = {0x07, 0x55, 0x1c, 0x27, 0xe9, 0xaa, 0xf1, 0x1f, + 0x47, 0x4f, 0x1c, 0x9a, 0x14, 0xbf, 0x14, 0x4c, + 0xfa, 0xef, 0xe2, 0x7f, 0xca, 0x4f, 0x20, 0x79, + 0x5d, 0xec, 0x85, 0x34, 0xc9, 0x37, 0xbb, 0x00, + 0xfe, 0x16, 0x23, 0x5e, 0xcd, 0x69, 0x1f, 0xd2, + 0x3e, 0x32, 0xcd, 0xfb, 0x8b, 0x78, 0x66, 0x6b, + 0xb7, 0x82, 0x84, 0xae, 0x15, 0xd5, 0x9b, 0xe5, + 0xca, 0x74, 0x73, 0xe6, 0x2d, 0x46, 0xa9, 0xda, + 0x1d}, + .prime2_len = 65, + .exp1 = {0x02, 0xe2, 0x2c, 0x74, 0x16, 0x0a, 0x94, 0x36, + 0xbb, 0x6c, 0x28, 0x3e, 0xf6, 0x57, 0xbe, 0xdd, + 0xec, 0x89, 0xb3, 0x5d, 0x5c, 0xa7, 0xa4, 0x93, + 0xf3, 0x5b, 0xd7, 0x71, 0xe4, 0x42, 0x95, 0xa5, + 0xb3, 0xc0, 0x20, 0x06, 0x11, 0x16, 0xb2, 0x55, + 0xba, 0x4d, 0x8c, 0x15, 0x4e, 0x3a, 0x8e, 0x71, + 0xa1, 0xa3, 0x16, 0x4f, 0x26, 0x82, 0xd4, 0x13, + 0x5e, 0xcf, 0xb2, 0xef, 0x26, 0x90, 0xc3, 0x9b, + 0xfd}, + .exp1_len = 65, + .exp2 = {0x01, 0xd2, 0xbf, 0xf5, 0x8c, 0xbc, 0xdc, 0xc8, + 0x12, 0x4b, 0x31, 0xa9, 0x7e, 0x8f, 0x24, 0xd5, + 0x1f, 0x70, 0x96, 0xb9, 0x7f, 0xec, 0xbc, 0xfe, + 0x70, 0xc4, 0x67, 0x3b, 0x00, 0xed, 0xc2, 0xaa, + 0x34, 0x83, 0xfc, 0xb7, 0x8e, 0x0c, 0x1d, 0xc5, + 0x81, 0x81, 0xd0, 0x86, 0x43, 0xdf, 0xe4, 0x57, + 0xd4, 0x81, 0xb7, 0xcc, 0x31, 0xd1, 0xb3, 0xba, + 0x27, 0xe5, 0x5d, 0x0c, 0x57, 0x25, 0xc3, 0x06, + 0x61}, + .exp2_len = 65, + .coef = {0x06, 0xd2, 0x27, 0x72, 0x57, 0x42, 0xef, 0x03, + 0x46, 0x2d, 0x1c, 0xf6, 0x12, 0x67, 0x4a, 0x78, + 0x83, 0x1d, 0x61, 0x9d, 0xa3, 0xd6, 0x40, 0xeb, + 0x7c, 0x71, 0xc8, 0x7b, 0x53, 0x28, 0x69, 0x72, + 0x73, 0xc5, 0xf7, 0x51, 0xe1, 0x4d, 0x7b, 0x81, + 0xc1, 0x2b, 0x6d, 0xeb, 0x44, 0x75, 0x1a, 0x92, + 0x95, 0xcb, 0x67, 0x1e, 0x81, 0x48, 0x4d, 0xea, + 0xa8, 0x3b, 0x4d, 0xf1, 0xfd, 0x37, 0xe2, 0xff, + 0x3c}, + .coef_len = 65, + .msg = {0x4e, 0xc7, 0x39, 0x3f, 0xdc, 0x4b, 0x90, 0xaf, + 0x8f, 0xff, 0xca, 0xf3, 0x4e, 0x84, 0x5a, 0x09, + 0x65, 0x6a, 0xef, 0x9d, 0xda, 0x12, 0xb0, 0x34, + 0x2c, 0x46, 0xeb, 0x04, 0x91, 0x74, 0xaa, 0x51, + 0x1b, 0x43, 0xc9, 0x4d, 0x75, 0xc0, 0xe2, 0x90, + 0x70, 0xaf, 0xf5, 0xb4, 0x14, 0x23, 0xa1, 0x70, + 0xd9, 0xb3, 0xe8, 0xb2, 0x12, 0x24, 0xaa, 0xbc, + 0x53, 0x1d, 0x88, 0x88, 0x6e, 0x26, 0x46, 0xd6, + 0x78, 0x8f, 0x1b, 0xaa, 0xd4, 0xef, 0x4b, 0x0b, + 0x4b, 0xde, 0x4b, 0x12, 0xce, 0x90, 0x52, 0x08, + 0x2e, 0x2d, 0xdd, 0x0e, 0x3e, 0x6c, 0xaa, 0xbb, + 0x0a, 0x14, 0x34, 0x4b, 0x0a, 0x58, 0x3f, 0x40, + 0x4c, 0x1b, 0x6a, 0x3c, 0x7b, 0xca, 0x8a, 0x58, + 0x85, 0xd5, 0xf2, 0x24, 0xaf, 0x1f, 0xca, 0xc3, + 0xfa, 0xd9, 0x37, 0x0e, 0x9b, 0x29, 0x74, 0xe8, + 0xca, 0x62, 0xe2, 0x2a, 0xce, 0xb9}, + .msg_len = 126, + .sig = {0x21, 0xa6, 0x6a, 0xf6, 0x27, 0xee, 0x0d, 0xd0, + 0x5f, 0xe7, 0x56, 0x3c, 0xc1, 0xd2, 0x9c, 0xcf, + 0x6f, 0x87, 0x31, 0xb4, 0x1e, 0x3d, 0xb3, 0x95, + 0x97, 0x89, 0x3b, 0xa1, 0xcf, 0x37, 0x5f, 0x78, + 0x17, 0x88, 0xfd, 0xf0, 0x73, 0xb0, 0xb5, 0x93, + 0xc7, 0x6d, 0xf2, 0x81, 0x6e, 0xc6, 0xde, 0xfc, + 0x22, 0x42, 0x21, 0xac, 0x19, 0xf5, 0xbe, 0xe4, + 0x4f, 0xc0, 0xe5, 0xd4, 0x09, 0x3d, 0x34, 0x68, + 0x27, 0x8f, 0xb4, 0x2d, 0x40, 0x5a, 0x07, 0x04, + 0x46, 0x53, 0x22, 0xda, 0x4d, 0x3a, 0x7c, 0xa9, + 0xc3, 0xda, 0x73, 0xc3, 0xd0, 0x82, 0xae, 0xe5, + 0x67, 0xb7, 0x70, 0x83, 0x32, 0x3e, 0x75, 0xbb, + 0x35, 0xed, 0x77, 0xe8, 0xdb, 0x9c, 0x01, 0xb4, + 0x96, 0xa0, 0x4c, 0xc4, 0xa8, 0x99, 0xdf, 0x35, + 0x9d, 0xa4, 0xa2, 0x28, 0x7c, 0xaf, 0xff, 0xe1, + 0xed, 0x63, 0xcd, 0xde, 0xad, 0x87, 0x6c, 0x94, + 0x07}, + .sig_len = 129, + .chunks = {25, 25, 25, 25, 25, 1}, + .num_chunks = 6, + }, + { // 36 + .mod = {0x70, 0xe9, 0x23, 0xa5, 0xa0, 0xcd, 0x8e, 0xcd, + 0xf9, 0x9b, 0xbe, 0x93, 0xd7, 0xd0, 0x28, 0x82, + 0x95, 0x5d, 0x91, 0xb6, 0xef, 0xe3, 0xce, 0xc8, + 0x6c, 0x93, 0xd2, 0x1c, 0x0a, 0xc3, 0x01, 0xb8, + 0x29, 0x3e, 0x51, 0x43, 0x5b, 0x87, 0x8b, 0xc6, + 0xb3, 0x4b, 0xed, 0x41, 0x11, 0x59, 0x0e, 0x76, + 0x46, 0x76, 0x58, 0x8b, 0x11, 0x6c, 0x2a, 0x36, + 0xa4, 0xc7, 0x7e, 0xd9, 0xc9, 0x0a, 0x13, 0xc1, + 0x4d, 0x23, 0xe1, 0x99, 0x47, 0x87, 0xfc, 0xdb, + 0x8f, 0x5c, 0x97, 0x41, 0x0f, 0xca, 0xd4, 0x04, + 0x5b, 0x85, 0x85, 0x70, 0x2c, 0xce, 0x29, 0xda, + 0x11, 0xf9, 0x7e, 0x79, 0xa9, 0x7c, 0x2e, 0x5f, + 0x6a, 0x5f, 0xc0, 0xbb, 0x8c, 0xe7, 0x6d, 0x15, + 0x54, 0xa8, 0xbc, 0x47, 0x96, 0x17, 0x20, 0xd3, + 0x64, 0x05, 0x0b, 0xf2, 0x74, 0x19, 0xbf, 0xf1, + 0x68, 0xc0, 0xa7, 0xec, 0xc8, 0x73, 0x4c, 0xb5, + 0xa5}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x02, 0x9e, 0x10, 0xf6, 0xbb, 0xb7, 0xd0, 0x2d, + 0xeb, 0xb1, 0xa5, 0xd5, 0x19, 0x0d, 0x69, 0x06, + 0xff, 0xed, 0xeb, 0x9d, 0x15, 0x4a, 0x0f, 0x66, + 0xdb, 0x87, 0x80, 0xb9, 0x28, 0x31, 0xb5, 0x96, + 0x3e, 0x94, 0x84, 0x7f, 0x3e, 0x7d, 0xb1, 0xaa, + 0x91, 0x48, 0xfb, 0x0e, 0xc5, 0x57, 0x6e, 0x6b, + 0xa4, 0xfe, 0x04, 0xd6, 0xf2, 0x78, 0x32, 0xb1, + 0x52, 0x18, 0x12, 0xd3, 0x7b, 0x22, 0xd9, 0xea, + 0xe2, 0x80, 0x08, 0xe0, 0x92, 0xc6, 0x7e, 0x72, + 0x32, 0x42, 0x67, 0xe1, 0xb1, 0xee, 0x45, 0x43, + 0x55, 0x74, 0x1d, 0x8d, 0xe1, 0xd2, 0xa6, 0xa0, + 0x50, 0x74, 0xbb, 0x1c, 0xe5, 0x81, 0x8b, 0x41, + 0xbd, 0x19, 0xdc, 0x6b, 0x58, 0xc8, 0x93, 0x7d, + 0x8a, 0xd6, 0x40, 0xd7, 0x04, 0x3f, 0xa1, 0x1f, + 0x46, 0x8d, 0x6c, 0xcb, 0xec, 0x4a, 0xde, 0x52, + 0x0a, 0x9e, 0x15, 0x9d, 0x60, 0x5d, 0x09, 0x28, + 0x29}, + .privexp_len = 129, + .prime1 = {0x0a, 0xb4, 0x64, 0xfd, 0x6f, 0xe3, 0x3c, 0x45, + 0x9a, 0xb2, 0xdc, 0xce, 0x5f, 0x78, 0xa4, 0xd7, + 0x4f, 0x92, 0xb9, 0x97, 0xd4, 0xbf, 0x54, 0x2e, + 0x2d, 0x85, 0x4e, 0x76, 0x2c, 0x85, 0x86, 0xfc, + 0x43, 0x57, 0xcc, 0x58, 0xcb, 0x33, 0x36, 0x33, + 0xb0, 0x95, 0xa5, 0xee, 0x04, 0xa0, 0x32, 0x48, + 0x53, 0x64, 0xd7, 0x0f, 0x67, 0xa3, 0xaa, 0x04, + 0x85, 0x4c, 0x7a, 0x87, 0xa6, 0x9c, 0xf4, 0xc2, + 0xad}, + .prime1_len = 65, + .prime2 = {0x0a, 0x8c, 0x3c, 0xc5, 0x04, 0x13, 0x40, 0xf4, + 0x32, 0xfe, 0x0a, 0x78, 0x73, 0x13, 0x57, 0x79, + 0x16, 0xfe, 0x76, 0xc0, 0x39, 0xf9, 0x71, 0x75, + 0x9e, 0xc5, 0x0e, 0xd6, 0xc5, 0xb9, 0xa7, 0x36, + 0x9b, 0x68, 0x96, 0x9e, 0xcb, 0x52, 0x59, 0xfe, + 0x9c, 0x50, 0xd0, 0x75, 0x9b, 0xf8, 0xb3, 0xaa, + 0xc1, 0xa5, 0xd5, 0xb5, 0x28, 0x8d, 0x67, 0x89, + 0xe7, 0x18, 0xfa, 0x37, 0xef, 0x42, 0x39, 0x95, + 0xd9}, + .prime2_len = 65, + .exp1 = {0xbb, 0x29, 0x5a, 0x95, 0xd5, 0xb3, 0x3c, 0x1d, + 0xc0, 0xb1, 0x8b, 0xf6, 0xc1, 0x4a, 0xa0, 0xd9, + 0xf2, 0x6f, 0x72, 0x8b, 0x39, 0x36, 0x0a, 0xa1, + 0x59, 0x45, 0x6e, 0x94, 0xc3, 0xd9, 0xe0, 0x48, + 0xc9, 0x2a, 0x4f, 0xb6, 0x31, 0x1d, 0x36, 0x92, + 0x8c, 0xe5, 0xf4, 0x47, 0xa4, 0x99, 0x4a, 0x8f, + 0x47, 0x87, 0xd8, 0xa9, 0x7f, 0x68, 0x11, 0x3e, + 0xf9, 0x66, 0x34, 0xf5, 0x90, 0x2a, 0xb7, 0x51}, + .exp1_len = 64, + .exp2 = {0x02, 0xfa, 0x11, 0x2c, 0x89, 0x39, 0xe5, 0xdb, + 0x05, 0x89, 0x2c, 0xeb, 0x51, 0x8e, 0xe3, 0xe1, + 0x08, 0xdc, 0x48, 0x27, 0x78, 0x35, 0x2e, 0x10, + 0x43, 0xfe, 0xd9, 0x71, 0x43, 0xdc, 0x61, 0x94, + 0xc7, 0xc7, 0x7c, 0xba, 0xd4, 0x27, 0x29, 0xbe, + 0xf1, 0xde, 0xdc, 0xf6, 0x54, 0x4e, 0x9c, 0x66, + 0x54, 0xc0, 0xb8, 0xcf, 0xa7, 0xe2, 0x40, 0x96, + 0x6a, 0xe2, 0x61, 0xbb, 0xe7, 0x8a, 0x89, 0x36, + 0x01}, + .exp2_len = 65, + .coef = {0xa8, 0x8b, 0xf3, 0xff, 0xe9, 0x3f, 0x40, 0x4e, + 0x06, 0x82, 0x1c, 0x97, 0x71, 0xea, 0xe6, 0x08, + 0x15, 0x71, 0x2d, 0x6f, 0x94, 0x52, 0x71, 0xf6, + 0xf3, 0x6f, 0x03, 0x69, 0xd9, 0x66, 0xc9, 0x20, + 0xc7, 0xf8, 0xcb, 0xc7, 0x84, 0x25, 0xac, 0xbb, + 0x9c, 0xe0, 0xfa, 0x1a, 0x03, 0x22, 0xf5, 0x0c, + 0x97, 0xb8, 0x11, 0x5b, 0xd1, 0x51, 0x91, 0xf2, + 0x24, 0xb5, 0x68, 0xd1, 0xd6, 0xec, 0xa6, 0xdb}, + .coef_len = 64, + .msg = {0xb5, 0xe8, 0x6c, 0x8b, 0xa3, 0x98, 0x5a, 0xa5, + 0x54, 0x1d, 0xf9, 0x5e, 0x51, 0x3c, 0xff, 0x67, + 0x61, 0x2e, 0xaf, 0x2e, 0x16, 0x68, 0x85, 0x76, + 0xf7, 0xd6, 0x73, 0xf6, 0xf1, 0x89, 0x1f, 0xb7, + 0x5c, 0x9d, 0xd2, 0xcd}, + .msg_len = 36, + .sig = {0x6b, 0x42, 0xfd, 0x51, 0x63, 0x09, 0x19, 0x7f, + 0x8a, 0xf3, 0xc7, 0x3e, 0x39, 0x62, 0x4d, 0x8e, + 0xba, 0xbe, 0xcd, 0xa3, 0xec, 0x3c, 0xe6, 0x57, + 0xb1, 0x11, 0x7f, 0x43, 0xe9, 0x83, 0x87, 0x7a, + 0x1b, 0xa1, 0xaa, 0xf8, 0xe9, 0x5c, 0xc3, 0x99, + 0x91, 0xd9, 0x2e, 0x35, 0xe2, 0xdb, 0x1e, 0x41, + 0x30, 0x90, 0x14, 0x3d, 0x16, 0x46, 0x71, 0x98, + 0xb9, 0xb9, 0xa9, 0x90, 0xd7, 0x74, 0xc2, 0x7a, + 0xd3, 0xbb, 0xb4, 0x35, 0x2d, 0x3f, 0x07, 0x5d, + 0x61, 0x73, 0x2c, 0x6b, 0x58, 0xec, 0x0f, 0x66, + 0xe4, 0x92, 0xa3, 0xf7, 0xac, 0x4b, 0xbc, 0xf0, + 0x12, 0xed, 0x6b, 0x40, 0x1f, 0xeb, 0x4f, 0xf3, + 0x95, 0xcb, 0x8b, 0x21, 0x8a, 0x81, 0xd6, 0x17, + 0x31, 0xee, 0xce, 0x37, 0x6f, 0x68, 0x8e, 0x66, + 0xae, 0xa6, 0x98, 0xb4, 0xa8, 0x86, 0x2f, 0x58, + 0xc9, 0x1d, 0x87, 0x60, 0x85, 0x49, 0x6f, 0xd0, + 0x14}, + .sig_len = 129, + }, + { // 37 + .mod = {0x70, 0xe9, 0x23, 0xa5, 0xa0, 0xcd, 0x8e, 0xcd, + 0xf9, 0x9b, 0xbe, 0x93, 0xd7, 0xd0, 0x28, 0x82, + 0x95, 0x5d, 0x91, 0xb6, 0xef, 0xe3, 0xce, 0xc8, + 0x6c, 0x93, 0xd2, 0x1c, 0x0a, 0xc3, 0x01, 0xb8, + 0x29, 0x3e, 0x51, 0x43, 0x5b, 0x87, 0x8b, 0xc6, + 0xb3, 0x4b, 0xed, 0x41, 0x11, 0x59, 0x0e, 0x76, + 0x46, 0x76, 0x58, 0x8b, 0x11, 0x6c, 0x2a, 0x36, + 0xa4, 0xc7, 0x7e, 0xd9, 0xc9, 0x0a, 0x13, 0xc1, + 0x4d, 0x23, 0xe1, 0x99, 0x47, 0x87, 0xfc, 0xdb, + 0x8f, 0x5c, 0x97, 0x41, 0x0f, 0xca, 0xd4, 0x04, + 0x5b, 0x85, 0x85, 0x70, 0x2c, 0xce, 0x29, 0xda, + 0x11, 0xf9, 0x7e, 0x79, 0xa9, 0x7c, 0x2e, 0x5f, + 0x6a, 0x5f, 0xc0, 0xbb, 0x8c, 0xe7, 0x6d, 0x15, + 0x54, 0xa8, 0xbc, 0x47, 0x96, 0x17, 0x20, 0xd3, + 0x64, 0x05, 0x0b, 0xf2, 0x74, 0x19, 0xbf, 0xf1, + 0x68, 0xc0, 0xa7, 0xec, 0xc8, 0x73, 0x4c, 0xb5, + 0xa5}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x02, 0x9e, 0x10, 0xf6, 0xbb, 0xb7, 0xd0, 0x2d, + 0xeb, 0xb1, 0xa5, 0xd5, 0x19, 0x0d, 0x69, 0x06, + 0xff, 0xed, 0xeb, 0x9d, 0x15, 0x4a, 0x0f, 0x66, + 0xdb, 0x87, 0x80, 0xb9, 0x28, 0x31, 0xb5, 0x96, + 0x3e, 0x94, 0x84, 0x7f, 0x3e, 0x7d, 0xb1, 0xaa, + 0x91, 0x48, 0xfb, 0x0e, 0xc5, 0x57, 0x6e, 0x6b, + 0xa4, 0xfe, 0x04, 0xd6, 0xf2, 0x78, 0x32, 0xb1, + 0x52, 0x18, 0x12, 0xd3, 0x7b, 0x22, 0xd9, 0xea, + 0xe2, 0x80, 0x08, 0xe0, 0x92, 0xc6, 0x7e, 0x72, + 0x32, 0x42, 0x67, 0xe1, 0xb1, 0xee, 0x45, 0x43, + 0x55, 0x74, 0x1d, 0x8d, 0xe1, 0xd2, 0xa6, 0xa0, + 0x50, 0x74, 0xbb, 0x1c, 0xe5, 0x81, 0x8b, 0x41, + 0xbd, 0x19, 0xdc, 0x6b, 0x58, 0xc8, 0x93, 0x7d, + 0x8a, 0xd6, 0x40, 0xd7, 0x04, 0x3f, 0xa1, 0x1f, + 0x46, 0x8d, 0x6c, 0xcb, 0xec, 0x4a, 0xde, 0x52, + 0x0a, 0x9e, 0x15, 0x9d, 0x60, 0x5d, 0x09, 0x28, + 0x29}, + .privexp_len = 129, + .prime1 = {0x0a, 0xb4, 0x64, 0xfd, 0x6f, 0xe3, 0x3c, 0x45, + 0x9a, 0xb2, 0xdc, 0xce, 0x5f, 0x78, 0xa4, 0xd7, + 0x4f, 0x92, 0xb9, 0x97, 0xd4, 0xbf, 0x54, 0x2e, + 0x2d, 0x85, 0x4e, 0x76, 0x2c, 0x85, 0x86, 0xfc, + 0x43, 0x57, 0xcc, 0x58, 0xcb, 0x33, 0x36, 0x33, + 0xb0, 0x95, 0xa5, 0xee, 0x04, 0xa0, 0x32, 0x48, + 0x53, 0x64, 0xd7, 0x0f, 0x67, 0xa3, 0xaa, 0x04, + 0x85, 0x4c, 0x7a, 0x87, 0xa6, 0x9c, 0xf4, 0xc2, + 0xad}, + .prime1_len = 65, + .prime2 = {0x0a, 0x8c, 0x3c, 0xc5, 0x04, 0x13, 0x40, 0xf4, + 0x32, 0xfe, 0x0a, 0x78, 0x73, 0x13, 0x57, 0x79, + 0x16, 0xfe, 0x76, 0xc0, 0x39, 0xf9, 0x71, 0x75, + 0x9e, 0xc5, 0x0e, 0xd6, 0xc5, 0xb9, 0xa7, 0x36, + 0x9b, 0x68, 0x96, 0x9e, 0xcb, 0x52, 0x59, 0xfe, + 0x9c, 0x50, 0xd0, 0x75, 0x9b, 0xf8, 0xb3, 0xaa, + 0xc1, 0xa5, 0xd5, 0xb5, 0x28, 0x8d, 0x67, 0x89, + 0xe7, 0x18, 0xfa, 0x37, 0xef, 0x42, 0x39, 0x95, + 0xd9}, + .prime2_len = 65, + .exp1 = {0xbb, 0x29, 0x5a, 0x95, 0xd5, 0xb3, 0x3c, 0x1d, + 0xc0, 0xb1, 0x8b, 0xf6, 0xc1, 0x4a, 0xa0, 0xd9, + 0xf2, 0x6f, 0x72, 0x8b, 0x39, 0x36, 0x0a, 0xa1, + 0x59, 0x45, 0x6e, 0x94, 0xc3, 0xd9, 0xe0, 0x48, + 0xc9, 0x2a, 0x4f, 0xb6, 0x31, 0x1d, 0x36, 0x92, + 0x8c, 0xe5, 0xf4, 0x47, 0xa4, 0x99, 0x4a, 0x8f, + 0x47, 0x87, 0xd8, 0xa9, 0x7f, 0x68, 0x11, 0x3e, + 0xf9, 0x66, 0x34, 0xf5, 0x90, 0x2a, 0xb7, 0x51}, + .exp1_len = 64, + .exp2 = {0x02, 0xfa, 0x11, 0x2c, 0x89, 0x39, 0xe5, 0xdb, + 0x05, 0x89, 0x2c, 0xeb, 0x51, 0x8e, 0xe3, 0xe1, + 0x08, 0xdc, 0x48, 0x27, 0x78, 0x35, 0x2e, 0x10, + 0x43, 0xfe, 0xd9, 0x71, 0x43, 0xdc, 0x61, 0x94, + 0xc7, 0xc7, 0x7c, 0xba, 0xd4, 0x27, 0x29, 0xbe, + 0xf1, 0xde, 0xdc, 0xf6, 0x54, 0x4e, 0x9c, 0x66, + 0x54, 0xc0, 0xb8, 0xcf, 0xa7, 0xe2, 0x40, 0x96, + 0x6a, 0xe2, 0x61, 0xbb, 0xe7, 0x8a, 0x89, 0x36, + 0x01}, + .exp2_len = 65, + .coef = {0xa8, 0x8b, 0xf3, 0xff, 0xe9, 0x3f, 0x40, 0x4e, + 0x06, 0x82, 0x1c, 0x97, 0x71, 0xea, 0xe6, 0x08, + 0x15, 0x71, 0x2d, 0x6f, 0x94, 0x52, 0x71, 0xf6, + 0xf3, 0x6f, 0x03, 0x69, 0xd9, 0x66, 0xc9, 0x20, + 0xc7, 0xf8, 0xcb, 0xc7, 0x84, 0x25, 0xac, 0xbb, + 0x9c, 0xe0, 0xfa, 0x1a, 0x03, 0x22, 0xf5, 0x0c, + 0x97, 0xb8, 0x11, 0x5b, 0xd1, 0x51, 0x91, 0xf2, + 0x24, 0xb5, 0x68, 0xd1, 0xd6, 0xec, 0xa6, 0xdb}, + .coef_len = 64, + .msg = {0x95, 0x46, 0x34, 0x6c, 0xf2, 0x21, 0x94, 0xc7, + 0x87, 0x88, 0x81, 0x70, 0xa4, 0x82, 0xf7, 0xf4, + 0x92, 0x17, 0xc3, 0x94, 0x0d, 0xc6, 0x21, 0x0c, + 0xe3, 0x9e, 0x45, 0x50, 0xa3, 0x9b, 0x45, 0x28, + 0x22, 0x41, 0x9a, 0xea, 0xc2, 0x4b, 0xec, 0x19, + 0x8b, 0xb3, 0x59, 0xd0, 0x8b, 0xe8, 0x19, 0x6d, + 0xf2, 0xe7, 0x57, 0x76, 0x61, 0x96, 0xc9, 0x58, + 0xe2, 0xb1, 0x59, 0xc7, 0x4c, 0x1c, 0x30, 0x23, + 0xc2, 0xdb, 0xcc, 0xe9, 0xed, 0x5d, 0x0e, 0xf3, + 0xfb, 0x51, 0x45, 0x0b, 0xff, 0x64, 0x45, 0xdb, + 0x26, 0x5e, 0x60, 0x6e, 0x19, 0x4b, 0xee, 0x06, + 0x4c, 0xa5, 0xb3, 0x21, 0xd7, 0xe1, 0x55, 0x14, + 0x23, 0x0c, 0x2b, 0x3b, 0x55, 0xd5, 0xda, 0x4c, + 0xd0, 0x40, 0x52, 0x2f, 0x7b, 0xb8, 0x6a, 0x96, + 0x2b, 0x81, 0x3f, 0x9d, 0xa3, 0x9e, 0x51, 0x38, + 0x9b, 0xc6, 0x4f, 0x56, 0xe4, 0x47, 0xb2, 0xa2, + 0xbf, 0x81, 0x9d, 0x7a, 0x80, 0x09, 0x4e, 0x2b, + 0x8d, 0xe2, 0x7f, 0x10, 0x4b, 0xb6, 0xeb, 0x2f, + 0x2f, 0xb4, 0x3a, 0xf1, 0xd0, 0x1e, 0xad, 0xca, + 0x23, 0xa1, 0x96, 0xba, 0x12, 0x5b, 0x6a, 0x78, + 0x57, 0x99, 0x74, 0xc0, 0xee, 0xc8, 0xa5, 0x49, + 0x67, 0x71, 0xf6, 0x7d, 0xbd, 0x50, 0x69, 0xf3, + 0x36, 0xe4, 0xef, 0x1f, 0x40, 0x47, 0x42, 0xdf, + 0xc6, 0x9c, 0xe3, 0x25, 0xaa, 0x64, 0x9f, 0x8a, + 0x63, 0x31, 0xcf, 0x40, 0x35, 0x55, 0xe1, 0x3f, + 0x08, 0x10, 0xa7, 0x63, 0x50, 0xa7, 0xe1, 0x8d, + 0x29, 0x92, 0xfa, 0xb4, 0x8f, 0x39, 0x7f, 0x3b, + 0x93, 0xc5, 0xbd, 0x5a, 0x6f, 0xe1, 0xd2, 0xc4, + 0x61, 0x8b, 0xa1, 0xf5, 0x9f, 0x00, 0x2d, 0xc2, + 0x57, 0xec, 0x39, 0xee, 0x2f, 0x87, 0x62, 0x98, + 0xda, 0x90, 0xf7, 0x44, 0x0a, 0xd4, 0xc6, 0xc9, + 0x3f, 0xc1, 0x14, 0xdf, 0x05}, + .msg_len = 253, + .sig = {0x67, 0xe4, 0x14, 0x99, 0x3f, 0x98, 0x7a, 0x22, + 0x64, 0x3d, 0xd0, 0x39, 0xe7, 0xf9, 0xfe, 0x1c, + 0xae, 0x74, 0x4a, 0x7a, 0xe4, 0x1d, 0x4c, 0x04, + 0x4f, 0xa4, 0xed, 0x8d, 0xc9, 0xe3, 0x40, 0xce, + 0xbb, 0x1e, 0x2a, 0xfb, 0x19, 0x8e, 0x84, 0x7a, + 0xef, 0x4b, 0xc0, 0x61, 0xfd, 0x80, 0x0d, 0x81, + 0xd4, 0xd3, 0x67, 0xb0, 0xfc, 0x2f, 0x73, 0x09, + 0x33, 0xc1, 0x9b, 0x88, 0xd4, 0xdd, 0xf0, 0x5e, + 0xd9, 0x8a, 0x58, 0x56, 0xde, 0x5e, 0xb4, 0x5b, + 0x11, 0x6b, 0x7d, 0x24, 0xfe, 0xb4, 0x56, 0x77, + 0x84, 0x9d, 0xab, 0x76, 0xe9, 0xe0, 0xcc, 0xb4, + 0x5b, 0xa6, 0xb6, 0xf6, 0x14, 0x1f, 0x37, 0xbb, + 0xad, 0x7c, 0x19, 0x1c, 0x37, 0x77, 0x11, 0x3b, + 0xc7, 0x38, 0x8e, 0x4e, 0x46, 0x44, 0xec, 0xa9, + 0x47, 0x03, 0xa7, 0x2b, 0xdd, 0xcc, 0x6f, 0x50, + 0xcf, 0x98, 0x0e, 0x3f, 0x6d, 0xe3, 0x9d, 0x73, + 0x12}, + .sig_len = 129, + .chunks = {90, -1, 75, 0, 0, 88}, + .num_chunks = 6, + }, + { // 38 + .mod = {0x70, 0xe9, 0x23, 0xa5, 0xa0, 0xcd, 0x8e, 0xcd, + 0xf9, 0x9b, 0xbe, 0x93, 0xd7, 0xd0, 0x28, 0x82, + 0x95, 0x5d, 0x91, 0xb6, 0xef, 0xe3, 0xce, 0xc8, + 0x6c, 0x93, 0xd2, 0x1c, 0x0a, 0xc3, 0x01, 0xb8, + 0x29, 0x3e, 0x51, 0x43, 0x5b, 0x87, 0x8b, 0xc6, + 0xb3, 0x4b, 0xed, 0x41, 0x11, 0x59, 0x0e, 0x76, + 0x46, 0x76, 0x58, 0x8b, 0x11, 0x6c, 0x2a, 0x36, + 0xa4, 0xc7, 0x7e, 0xd9, 0xc9, 0x0a, 0x13, 0xc1, + 0x4d, 0x23, 0xe1, 0x99, 0x47, 0x87, 0xfc, 0xdb, + 0x8f, 0x5c, 0x97, 0x41, 0x0f, 0xca, 0xd4, 0x04, + 0x5b, 0x85, 0x85, 0x70, 0x2c, 0xce, 0x29, 0xda, + 0x11, 0xf9, 0x7e, 0x79, 0xa9, 0x7c, 0x2e, 0x5f, + 0x6a, 0x5f, 0xc0, 0xbb, 0x8c, 0xe7, 0x6d, 0x15, + 0x54, 0xa8, 0xbc, 0x47, 0x96, 0x17, 0x20, 0xd3, + 0x64, 0x05, 0x0b, 0xf2, 0x74, 0x19, 0xbf, 0xf1, + 0x68, 0xc0, 0xa7, 0xec, 0xc8, 0x73, 0x4c, 0xb5, + 0xa5}, + .mod_len = 129, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x02, 0x9e, 0x10, 0xf6, 0xbb, 0xb7, 0xd0, 0x2d, + 0xeb, 0xb1, 0xa5, 0xd5, 0x19, 0x0d, 0x69, 0x06, + 0xff, 0xed, 0xeb, 0x9d, 0x15, 0x4a, 0x0f, 0x66, + 0xdb, 0x87, 0x80, 0xb9, 0x28, 0x31, 0xb5, 0x96, + 0x3e, 0x94, 0x84, 0x7f, 0x3e, 0x7d, 0xb1, 0xaa, + 0x91, 0x48, 0xfb, 0x0e, 0xc5, 0x57, 0x6e, 0x6b, + 0xa4, 0xfe, 0x04, 0xd6, 0xf2, 0x78, 0x32, 0xb1, + 0x52, 0x18, 0x12, 0xd3, 0x7b, 0x22, 0xd9, 0xea, + 0xe2, 0x80, 0x08, 0xe0, 0x92, 0xc6, 0x7e, 0x72, + 0x32, 0x42, 0x67, 0xe1, 0xb1, 0xee, 0x45, 0x43, + 0x55, 0x74, 0x1d, 0x8d, 0xe1, 0xd2, 0xa6, 0xa0, + 0x50, 0x74, 0xbb, 0x1c, 0xe5, 0x81, 0x8b, 0x41, + 0xbd, 0x19, 0xdc, 0x6b, 0x58, 0xc8, 0x93, 0x7d, + 0x8a, 0xd6, 0x40, 0xd7, 0x04, 0x3f, 0xa1, 0x1f, + 0x46, 0x8d, 0x6c, 0xcb, 0xec, 0x4a, 0xde, 0x52, + 0x0a, 0x9e, 0x15, 0x9d, 0x60, 0x5d, 0x09, 0x28, + 0x29}, + .privexp_len = 129, + .prime1 = {0x0a, 0xb4, 0x64, 0xfd, 0x6f, 0xe3, 0x3c, 0x45, + 0x9a, 0xb2, 0xdc, 0xce, 0x5f, 0x78, 0xa4, 0xd7, + 0x4f, 0x92, 0xb9, 0x97, 0xd4, 0xbf, 0x54, 0x2e, + 0x2d, 0x85, 0x4e, 0x76, 0x2c, 0x85, 0x86, 0xfc, + 0x43, 0x57, 0xcc, 0x58, 0xcb, 0x33, 0x36, 0x33, + 0xb0, 0x95, 0xa5, 0xee, 0x04, 0xa0, 0x32, 0x48, + 0x53, 0x64, 0xd7, 0x0f, 0x67, 0xa3, 0xaa, 0x04, + 0x85, 0x4c, 0x7a, 0x87, 0xa6, 0x9c, 0xf4, 0xc2, + 0xad}, + .prime1_len = 65, + .prime2 = {0x0a, 0x8c, 0x3c, 0xc5, 0x04, 0x13, 0x40, 0xf4, + 0x32, 0xfe, 0x0a, 0x78, 0x73, 0x13, 0x57, 0x79, + 0x16, 0xfe, 0x76, 0xc0, 0x39, 0xf9, 0x71, 0x75, + 0x9e, 0xc5, 0x0e, 0xd6, 0xc5, 0xb9, 0xa7, 0x36, + 0x9b, 0x68, 0x96, 0x9e, 0xcb, 0x52, 0x59, 0xfe, + 0x9c, 0x50, 0xd0, 0x75, 0x9b, 0xf8, 0xb3, 0xaa, + 0xc1, 0xa5, 0xd5, 0xb5, 0x28, 0x8d, 0x67, 0x89, + 0xe7, 0x18, 0xfa, 0x37, 0xef, 0x42, 0x39, 0x95, + 0xd9}, + .prime2_len = 65, + .exp1 = {0xbb, 0x29, 0x5a, 0x95, 0xd5, 0xb3, 0x3c, 0x1d, + 0xc0, 0xb1, 0x8b, 0xf6, 0xc1, 0x4a, 0xa0, 0xd9, + 0xf2, 0x6f, 0x72, 0x8b, 0x39, 0x36, 0x0a, 0xa1, + 0x59, 0x45, 0x6e, 0x94, 0xc3, 0xd9, 0xe0, 0x48, + 0xc9, 0x2a, 0x4f, 0xb6, 0x31, 0x1d, 0x36, 0x92, + 0x8c, 0xe5, 0xf4, 0x47, 0xa4, 0x99, 0x4a, 0x8f, + 0x47, 0x87, 0xd8, 0xa9, 0x7f, 0x68, 0x11, 0x3e, + 0xf9, 0x66, 0x34, 0xf5, 0x90, 0x2a, 0xb7, 0x51}, + .exp1_len = 64, + .exp2 = {0x02, 0xfa, 0x11, 0x2c, 0x89, 0x39, 0xe5, 0xdb, + 0x05, 0x89, 0x2c, 0xeb, 0x51, 0x8e, 0xe3, 0xe1, + 0x08, 0xdc, 0x48, 0x27, 0x78, 0x35, 0x2e, 0x10, + 0x43, 0xfe, 0xd9, 0x71, 0x43, 0xdc, 0x61, 0x94, + 0xc7, 0xc7, 0x7c, 0xba, 0xd4, 0x27, 0x29, 0xbe, + 0xf1, 0xde, 0xdc, 0xf6, 0x54, 0x4e, 0x9c, 0x66, + 0x54, 0xc0, 0xb8, 0xcf, 0xa7, 0xe2, 0x40, 0x96, + 0x6a, 0xe2, 0x61, 0xbb, 0xe7, 0x8a, 0x89, 0x36, + 0x01}, + .exp2_len = 65, + .coef = {0xa8, 0x8b, 0xf3, 0xff, 0xe9, 0x3f, 0x40, 0x4e, + 0x06, 0x82, 0x1c, 0x97, 0x71, 0xea, 0xe6, 0x08, + 0x15, 0x71, 0x2d, 0x6f, 0x94, 0x52, 0x71, 0xf6, + 0xf3, 0x6f, 0x03, 0x69, 0xd9, 0x66, 0xc9, 0x20, + 0xc7, 0xf8, 0xcb, 0xc7, 0x84, 0x25, 0xac, 0xbb, + 0x9c, 0xe0, 0xfa, 0x1a, 0x03, 0x22, 0xf5, 0x0c, + 0x97, 0xb8, 0x11, 0x5b, 0xd1, 0x51, 0x91, 0xf2, + 0x24, 0xb5, 0x68, 0xd1, 0xd6, 0xec, 0xa6, 0xdb}, + .coef_len = 64, + .msg = {0x56, 0x52, 0xb4, 0xc5, 0x75, 0x20, 0xb2, 0x55, + 0xfb, 0x96, 0xf7, 0x0a, 0x30, 0xab, 0x92, 0xee, + 0xc1, 0x93, 0x99, 0x56, 0xb6, 0xa9, 0x43, 0xc8, + 0x3e, 0xd0, 0x98, 0x6e, 0x2e, 0x6e, 0xe4, 0xef, + 0xbf, 0x8a, 0x52, 0x28, 0x78, 0x67, 0x28, 0x12, + 0x03, 0xa7, 0xa6, 0xd1, 0xd8, 0x86, 0xb7, 0x00, + 0x59, 0x52, 0xb4, 0x3b, 0x77, 0x85, 0x44, 0xed, + 0xa8, 0x98, 0xe0, 0xdf, 0x2f, 0xa0, 0x6f, 0x68, + 0x38, 0x03, 0x18, 0xf1, 0x4a, 0x53, 0xfe, 0x55, + 0xd7, 0x2f, 0x8c, 0xfa, 0x6a, 0xf2, 0x1d, 0x93, + 0xbb, 0xfc, 0x20, 0xd3, 0x58, 0xc2, 0x08, 0xc5, + 0x62, 0xd7, 0x39, 0xbe, 0x00, 0x01, 0xce, 0x07, + 0xfd, 0x8c, 0xd2, 0xf4, 0x6c, 0x3b, 0x44, 0xc8, + 0x36, 0x51, 0x88, 0x09, 0xb7, 0x6f, 0x3a, 0x70, + 0xcf, 0x69, 0x26, 0xbe, 0x06, 0x9c, 0x35, 0x75, + 0xd5}, + .msg_len = 121, + .sig = {0x01, 0x64, 0x11, 0xa2, 0x31, 0xa7, 0x38, 0x94, + 0x4b, 0x3e, 0x44, 0xf7, 0x88, 0x5c, 0xf8, 0x1a, + 0xca, 0xb7, 0x32, 0xd1, 0x73, 0x6d, 0xe3, 0x4c, + 0x56, 0xcf, 0x40, 0xf9, 0x9a, 0x6c, 0xe4, 0x00, + 0x70, 0xa2, 0x0a, 0xa9, 0x4c, 0x48, 0x78, 0x44, + 0xa9, 0x3c, 0xef, 0x28, 0x7a, 0x58, 0xbc, 0x0e, + 0xa1, 0x81, 0xb2, 0xcf, 0x27, 0xd9, 0x14, 0xf2, + 0x93, 0xb9, 0x29, 0x77, 0x9d, 0x39, 0x03, 0x6c, + 0x4e, 0x5a, 0xae, 0xd3, 0x5e, 0xee, 0x8a, 0x7f, + 0xd5, 0x0e, 0xfd, 0x09, 0x6c, 0x91, 0xa8, 0xf7, + 0x2c, 0x3c, 0x14, 0x1c, 0x57, 0x6c, 0x8d, 0x10, + 0xb6, 0x36, 0xfc, 0x4d, 0xdc, 0x1e, 0x67, 0x14, + 0xf1, 0x7f, 0xfc, 0xce, 0x10, 0x6d, 0x22, 0x1b, + 0x4f, 0xd7, 0xd6, 0xfe, 0x1e, 0x7c, 0xbd, 0x3f, + 0x3b, 0x08, 0xf5, 0x54, 0x6b, 0x44, 0xd1, 0xfe, + 0xb7, 0x18, 0xfb, 0xc1, 0x33, 0x70, 0xc7, 0xfa, + 0x2c}, + .sig_len = 129, + }, + { // 39 + .mod = {0xd8, 0x70, 0xa7, 0x76, 0xcd, 0x13, 0xed, 0x44, + 0x3d, 0xf3, 0x99, 0x08, 0xbe, 0xe2, 0xca, 0xd7, + 0x3c, 0x48, 0x5f, 0xd9, 0xbf, 0x06, 0x32, 0x13, + 0x22, 0x88, 0x7f, 0xbe, 0x65, 0x5c, 0x08, 0xcb, + 0xe4, 0xc8, 0xf6, 0x3e, 0x25, 0x4f, 0xc9, 0x1c, + 0x75, 0xf0, 0x55, 0x7d, 0x90, 0x1d, 0x43, 0x5b, + 0x0e, 0x8d, 0xed, 0x82, 0xd4, 0x91, 0x73, 0x41, + 0x4d, 0x29, 0x86, 0x03, 0x24, 0xe4, 0x6c, 0x1b, + 0x03, 0x0d, 0xfe, 0xaa, 0x29, 0xd8, 0x0f, 0x98, + 0x98, 0xc2, 0xc5, 0xe1, 0x01, 0xcb, 0xf6, 0xda, + 0xa0, 0x62, 0x89, 0x78, 0xd4, 0x15, 0xb5, 0x02, + 0xde, 0xa2, 0x6d, 0xe6, 0x56, 0x1c, 0x79, 0xab, + 0x06, 0x5c, 0x6d, 0xca, 0x6a, 0xbc, 0x4d, 0x4d, + 0x4d, 0x5e, 0x9f, 0x5c, 0x74, 0xcb, 0x3e, 0x6a, + 0x5a, 0xf7, 0x1d, 0x1f, 0x90, 0xfa, 0x5e, 0xaa, + 0x1b, 0xe0, 0xca, 0x94, 0x7a, 0x70, 0xa3, 0x9e, + 0xfd, 0x31, 0x5c, 0x4d, 0xf2, 0x1a, 0x1a, 0x82, + 0x1c, 0xaa, 0xff, 0x8d, 0xcb, 0xad, 0x13, 0xb2, + 0x9c, 0x7e, 0x82, 0xaa, 0xd5, 0x3c, 0x64, 0xf5, + 0x82, 0xec, 0x9e, 0xc3, 0x1e, 0x6b, 0xde, 0x82, + 0xea, 0x5a, 0x5f, 0x4c, 0xcc, 0xf0, 0xc4, 0x57, + 0xb8, 0x88, 0xf1, 0x55, 0x0c, 0x4f, 0xf8, 0xe1, + 0xc1, 0x78, 0xa7, 0x6a, 0x46, 0xc1, 0x96, 0xf4, + 0xbe, 0xf5, 0x9e, 0x61, 0xdd, 0x94, 0x4e, 0x47}, + .mod_len = 192, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x05, 0x88, 0x8f, 0xc7, 0x7a, 0x43, 0xbd, 0xa7, + 0xa6, 0x7b, 0xd1, 0x58, 0x47, 0x65, 0x0d, 0xf1, + 0x85, 0xc1, 0x85, 0xed, 0xcf, 0xb3, 0xed, 0x58, + 0xce, 0xe3, 0xb5, 0x7c, 0x5d, 0x24, 0x06, 0xb7, + 0x8b, 0xc0, 0x55, 0x87, 0x4e, 0x35, 0xe5, 0x7a, + 0xdc, 0x4b, 0x0a, 0x2c, 0x7d, 0x20, 0x3a, 0x66, + 0x1c, 0x0f, 0xa5, 0xd8, 0x57, 0xed, 0xe6, 0x07, + 0xef, 0xdc, 0x95, 0x68, 0x04, 0x2b, 0xf0, 0xd5, + 0x99, 0xf4, 0xe4, 0x23, 0x5e, 0x91, 0x7f, 0x08, + 0x94, 0x33, 0x3a, 0x92, 0xdf, 0x94, 0x62, 0xd9, + 0xc1, 0x0a, 0xf3, 0xdf, 0xca, 0x70, 0x49, 0xa1, + 0xea, 0xa6, 0x35, 0x70, 0x13, 0x98, 0x83, 0xc5, + 0xbe, 0xfe, 0xbe, 0xe4, 0xe2, 0x21, 0x89, 0x43, + 0xd3, 0x0f, 0xc6, 0x45, 0xff, 0xe8, 0xb9, 0x14, + 0xd2, 0x18, 0xdd, 0x58, 0x96, 0x0a, 0xad, 0xc1, + 0x21, 0x71, 0x5b, 0xce, 0x5c, 0xcd, 0xde, 0x4a, + 0x2c, 0x73, 0xa8, 0xd9, 0xd8, 0x6a, 0x4e, 0xb6, + 0xe4, 0x55, 0xdc, 0x92, 0x4f, 0xd7, 0x4a, 0x0b, + 0x1f, 0x75, 0x69, 0x1c, 0x28, 0x1b, 0xae, 0x91, + 0x4d, 0x69, 0x9e, 0xe2, 0x59, 0xd8, 0x5c, 0x5f, + 0xb5, 0xdd, 0x99, 0x9e, 0xbe, 0xf9, 0xb7, 0x0a, + 0x4b, 0xd9, 0x4a, 0xa4, 0xfa, 0xfa, 0xe2, 0x6c, + 0xa7, 0x84, 0xd3, 0x2f, 0xd4, 0xe0, 0x77, 0xdb, + 0xb6, 0xea, 0x69, 0x3b, 0xcd, 0x6d, 0x27, 0xd5}, + .privexp_len = 192, + .prime1 = {0xff, 0x8e, 0xf1, 0xe7, 0x4c, 0x44, 0x5a, 0x5c, + 0xc8, 0x97, 0x3a, 0x81, 0x9c, 0x75, 0x45, 0x49, + 0x12, 0x35, 0x72, 0x0c, 0xf9, 0xeb, 0x83, 0xf1, + 0x81, 0x13, 0x3c, 0x78, 0xa1, 0x4d, 0xcc, 0x4c, + 0xe5, 0xe7, 0x75, 0xbe, 0x3e, 0x0c, 0x46, 0xed, + 0x2f, 0x21, 0x9a, 0xb8, 0x8d, 0x87, 0x77, 0xad, + 0x6e, 0xcb, 0xe4, 0x0c, 0xf9, 0x18, 0x76, 0x4d, + 0x7e, 0x37, 0xc6, 0x68, 0x35, 0x91, 0xe7, 0xaa, + 0xa1, 0x3b, 0x24, 0x4b, 0x7f, 0xcc, 0x0e, 0xb6, + 0xdf, 0xd7, 0x6a, 0x11, 0x5f, 0x30, 0xed, 0x2d, + 0x63, 0x68, 0xc8, 0xea, 0x78, 0x0a, 0x21, 0x1c, + 0x0a, 0xc9, 0xc0, 0x72, 0x5d, 0xfa, 0xb0, 0x8d}, + .prime1_len = 96, + .prime2 = {0xd8, 0xd0, 0x67, 0x64, 0xc1, 0xf7, 0x64, 0x54, + 0xc6, 0x8a, 0x3a, 0x08, 0x1e, 0x95, 0xd7, 0x47, + 0xc2, 0x94, 0x11, 0xad, 0xc4, 0x03, 0xa7, 0xcb, + 0x71, 0xb4, 0x3a, 0xf5, 0x05, 0xca, 0xbe, 0x41, + 0xb4, 0x9c, 0x97, 0x1c, 0x13, 0xad, 0x65, 0x63, + 0xb8, 0xc9, 0x0b, 0x93, 0xb5, 0x89, 0x79, 0xbb, + 0x74, 0xf8, 0x20, 0xef, 0xb8, 0xde, 0xd8, 0x1f, + 0x46, 0x30, 0x54, 0xa7, 0x7f, 0xb3, 0x0b, 0xb0, + 0x99, 0x98, 0x51, 0xa4, 0x3c, 0xcd, 0x01, 0x69, + 0x18, 0x51, 0x31, 0xf7, 0x43, 0x1b, 0x02, 0xe9, + 0xc6, 0xb9, 0xf8, 0x38, 0x71, 0xd9, 0xcd, 0x5e, + 0x0c, 0x3c, 0x58, 0x70, 0xcf, 0x97, 0x97, 0x23}, + .prime2_len = 96, + .exp1 = {0xe8, 0xd6, 0x15, 0xf4, 0x04, 0x7a, 0xaa, 0x51, + 0xaa, 0xb8, 0x8e, 0x27, 0x94, 0xa3, 0x0b, 0xd3, + 0x3d, 0x71, 0xd0, 0x4d, 0x9e, 0x4e, 0x43, 0xd2, + 0x7f, 0x25, 0x45, 0x8d, 0x2a, 0x79, 0xb5, 0x4f, + 0xc2, 0x8f, 0x95, 0xa9, 0x14, 0xe3, 0x1e, 0xa3, + 0xee, 0xb3, 0x11, 0x42, 0x60, 0x40, 0x32, 0x7b, + 0xa3, 0x5c, 0xc4, 0x94, 0x45, 0x47, 0x52, 0x51, + 0xdc, 0x53, 0x78, 0xc3, 0x6d, 0x3b, 0x57, 0xf5, + 0x10, 0x1c, 0xd0, 0x3e, 0xb1, 0x5a, 0xfb, 0x75, + 0x06, 0x90, 0x3f, 0x25, 0x40, 0xb3, 0x55, 0x04, + 0x6b, 0x74, 0x06, 0xca, 0x09, 0x40, 0x41, 0x56, + 0x49, 0x45, 0xf3, 0xbe, 0xbf, 0x7d, 0x2d, 0xe9}, + .exp1_len = 96, + .exp2 = {0x73, 0x5d, 0xb1, 0x26, 0x73, 0xef, 0x67, 0x7b, + 0x94, 0x89, 0x48, 0x87, 0xb9, 0x7e, 0x91, 0xa6, + 0xa5, 0x6a, 0x94, 0x5d, 0x99, 0xc7, 0x38, 0x29, + 0x90, 0xbf, 0x0e, 0x00, 0x02, 0xac, 0xf6, 0xbf, + 0x8f, 0x93, 0x22, 0xf4, 0xd5, 0xa3, 0x96, 0x27, + 0x91, 0xd3, 0xa8, 0x4d, 0x58, 0x73, 0x66, 0x4a, + 0xd0, 0xda, 0x96, 0xeb, 0xf7, 0xba, 0xdb, 0xd5, + 0x08, 0x4b, 0xff, 0x3f, 0x81, 0x3b, 0x8c, 0x24, + 0xd4, 0x15, 0xb0, 0x9b, 0x6b, 0x9e, 0xc9, 0xf9, + 0x59, 0xef, 0x1a, 0x5f, 0x2f, 0x5d, 0xd8, 0x16, + 0xfc, 0x9f, 0x47, 0xed, 0x00, 0xe7, 0x9b, 0xd7, + 0x47, 0x3b, 0x74, 0xf3, 0xd2, 0x02, 0x1f, 0x71}, + .exp2_len = 96, + .coef = {0x10, 0x62, 0x18, 0xaf, 0x97, 0x1d, 0x92, 0x95, + 0x91, 0x59, 0x90, 0xa4, 0xed, 0x3e, 0x09, 0xd3, + 0x63, 0xdb, 0x33, 0x06, 0xb0, 0x90, 0xa1, 0x33, + 0xeb, 0xd7, 0x54, 0xe2, 0xbd, 0x77, 0x6b, 0x25, + 0x85, 0x99, 0x9d, 0x4f, 0x88, 0x43, 0x03, 0x0a, + 0xc7, 0x0c, 0x0f, 0xf5, 0xde, 0x52, 0x12, 0x67, + 0x22, 0x34, 0xc0, 0x07, 0xce, 0x74, 0x56, 0x4c, + 0x79, 0x1e, 0xdc, 0xd5, 0x76, 0xf9, 0x68, 0x44, + 0x04, 0x8c, 0xfa, 0x66, 0x36, 0x46, 0xb8, 0xfd, + 0x80, 0xc7, 0x51, 0x26, 0xb2, 0x26, 0x6e, 0x48, + 0xf1, 0xfa, 0xa7, 0x05, 0x44, 0xad, 0x42, 0x04, + 0xfd, 0x61, 0x56, 0x29, 0x2e, 0x51, 0x6e, 0x13}, + .coef_len = 96, + .msg = {0xf7, 0xa3, 0xc6, 0x7e, 0x92, 0xa7, 0x87, 0xf3, + 0x5d, 0xcc, 0x47, 0xae, 0xd7, 0xd6, 0xb6, 0x19, + 0x29, 0x67, 0xbd, 0xfd, 0x00, 0xa6, 0xac, 0xbf, + 0x6f, 0x7e, 0xfe, 0x46, 0xd3, 0xac, 0xae, 0xd9, + 0x78, 0x8a, 0xa4, 0xf1, 0xdb, 0x18, 0x44, 0x02, + 0x24, 0x9f, 0x9a, 0xce, 0xfc, 0x1c, 0x7d, 0xfb, + 0x1e, 0x69, 0x0d, 0x24, 0x73, 0x8d, 0xe8, 0x6f, + 0xa5, 0xb5, 0x25, 0x0f, 0x97, 0x9e, 0xbd, 0x8f, + 0x77, 0x8e, 0xec, 0x0d, 0x7f, 0xcf, 0x73, 0x1f, + 0xa2, 0x25, 0x08, 0x6c, 0x86, 0x65, 0x64, 0xed, + 0x3e, 0xb1, 0x54, 0xdd, 0x45, 0x8d, 0x05, 0x00, + 0x28, 0x2f, 0x86, 0x80, 0x48, 0x87, 0xd4, 0x43, + 0x5e, 0xda, 0x9a, 0x44, 0x36, 0xa8, 0xe9, 0x23, + 0xa2, 0x0c, 0xb4, 0xb4, 0xd0, 0xe8, 0x1c, 0x91, + 0x11, 0x4b, 0xdc, 0x06, 0x82, 0x27, 0x8e, 0xc2, + 0x58, 0x86, 0x07, 0x99, 0xb5, 0x9c, 0x94, 0x36, + 0xf4, 0x3a, 0x53, 0xca, 0xb4, 0xc4, 0xcd}, + .msg_len = 135, + .sig = {0x09, 0xd1, 0x43, 0x5b, 0xf5, 0xa9, 0xc1, 0x72, + 0x03, 0xd5, 0x37, 0xfe, 0x57, 0xdf, 0x98, 0x7b, + 0x7a, 0x51, 0xf3, 0x4b, 0x2a, 0x14, 0x09, 0x7e, + 0x06, 0xa0, 0xde, 0x56, 0x3b, 0xe7, 0xd6, 0x4b, + 0x4e, 0xa3, 0x79, 0x73, 0xb4, 0xfe, 0x99, 0x73, + 0xa6, 0x6a, 0x3f, 0x31, 0xba, 0x8e, 0x07, 0xe9, + 0x11, 0x7b, 0x6a, 0x1e, 0xe7, 0x09, 0x61, 0x33, + 0x7b, 0x4d, 0x2b, 0x0d, 0xf5, 0x98, 0x10, 0xb6, + 0x24, 0x08, 0x51, 0x18, 0xbd, 0xa7, 0x0a, 0xc7, + 0x4a, 0xe4, 0x3e, 0x2f, 0xbc, 0xf8, 0x92, 0x27, + 0x63, 0x03, 0x23, 0xda, 0x68, 0x30, 0xf5, 0xb1, + 0xa2, 0xb9, 0x54, 0xf1, 0xb1, 0x5a, 0xea, 0x07, + 0x54, 0xdf, 0x2c, 0x51, 0x18, 0x57, 0x95, 0x16, + 0xe8, 0x77, 0xcc, 0xb0, 0xb1, 0x28, 0x6c, 0x57, + 0x24, 0x65, 0x5e, 0xf8, 0xd2, 0x91, 0x85, 0x66, + 0x6f, 0x6e, 0x9b, 0xd3, 0x2a, 0x6b, 0xd9, 0xce, + 0x9e, 0x1e, 0xf9, 0x47, 0x29, 0xfc, 0x67, 0xd6, + 0xa3, 0x0e, 0x64, 0x56, 0x0e, 0xcf, 0x78, 0xbf, + 0x8e, 0x1b, 0x2b, 0x40, 0xe5, 0x06, 0x05, 0xe2, + 0x5a, 0xe8, 0x0c, 0x38, 0x67, 0x64, 0xae, 0xd1, + 0x1a, 0x0e, 0x71, 0x44, 0x90, 0x49, 0xc9, 0x39, + 0xb2, 0x96, 0x2f, 0x6c, 0x24, 0x17, 0xa3, 0x58, + 0xcd, 0xc8, 0x10, 0x6b, 0x12, 0xb1, 0xa5, 0x58, + 0x76, 0x39, 0x43, 0x8a, 0xf1, 0xa6, 0x8d, 0x32}, + .sig_len = 192, + .chunks = {25, 110}, + .num_chunks = 2, + }, + { // 40 + .mod = {0xd8, 0x70, 0xa7, 0x76, 0xcd, 0x13, 0xed, 0x44, + 0x3d, 0xf3, 0x99, 0x08, 0xbe, 0xe2, 0xca, 0xd7, + 0x3c, 0x48, 0x5f, 0xd9, 0xbf, 0x06, 0x32, 0x13, + 0x22, 0x88, 0x7f, 0xbe, 0x65, 0x5c, 0x08, 0xcb, + 0xe4, 0xc8, 0xf6, 0x3e, 0x25, 0x4f, 0xc9, 0x1c, + 0x75, 0xf0, 0x55, 0x7d, 0x90, 0x1d, 0x43, 0x5b, + 0x0e, 0x8d, 0xed, 0x82, 0xd4, 0x91, 0x73, 0x41, + 0x4d, 0x29, 0x86, 0x03, 0x24, 0xe4, 0x6c, 0x1b, + 0x03, 0x0d, 0xfe, 0xaa, 0x29, 0xd8, 0x0f, 0x98, + 0x98, 0xc2, 0xc5, 0xe1, 0x01, 0xcb, 0xf6, 0xda, + 0xa0, 0x62, 0x89, 0x78, 0xd4, 0x15, 0xb5, 0x02, + 0xde, 0xa2, 0x6d, 0xe6, 0x56, 0x1c, 0x79, 0xab, + 0x06, 0x5c, 0x6d, 0xca, 0x6a, 0xbc, 0x4d, 0x4d, + 0x4d, 0x5e, 0x9f, 0x5c, 0x74, 0xcb, 0x3e, 0x6a, + 0x5a, 0xf7, 0x1d, 0x1f, 0x90, 0xfa, 0x5e, 0xaa, + 0x1b, 0xe0, 0xca, 0x94, 0x7a, 0x70, 0xa3, 0x9e, + 0xfd, 0x31, 0x5c, 0x4d, 0xf2, 0x1a, 0x1a, 0x82, + 0x1c, 0xaa, 0xff, 0x8d, 0xcb, 0xad, 0x13, 0xb2, + 0x9c, 0x7e, 0x82, 0xaa, 0xd5, 0x3c, 0x64, 0xf5, + 0x82, 0xec, 0x9e, 0xc3, 0x1e, 0x6b, 0xde, 0x82, + 0xea, 0x5a, 0x5f, 0x4c, 0xcc, 0xf0, 0xc4, 0x57, + 0xb8, 0x88, 0xf1, 0x55, 0x0c, 0x4f, 0xf8, 0xe1, + 0xc1, 0x78, 0xa7, 0x6a, 0x46, 0xc1, 0x96, 0xf4, + 0xbe, 0xf5, 0x9e, 0x61, 0xdd, 0x94, 0x4e, 0x47}, + .mod_len = 192, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x05, 0x88, 0x8f, 0xc7, 0x7a, 0x43, 0xbd, 0xa7, + 0xa6, 0x7b, 0xd1, 0x58, 0x47, 0x65, 0x0d, 0xf1, + 0x85, 0xc1, 0x85, 0xed, 0xcf, 0xb3, 0xed, 0x58, + 0xce, 0xe3, 0xb5, 0x7c, 0x5d, 0x24, 0x06, 0xb7, + 0x8b, 0xc0, 0x55, 0x87, 0x4e, 0x35, 0xe5, 0x7a, + 0xdc, 0x4b, 0x0a, 0x2c, 0x7d, 0x20, 0x3a, 0x66, + 0x1c, 0x0f, 0xa5, 0xd8, 0x57, 0xed, 0xe6, 0x07, + 0xef, 0xdc, 0x95, 0x68, 0x04, 0x2b, 0xf0, 0xd5, + 0x99, 0xf4, 0xe4, 0x23, 0x5e, 0x91, 0x7f, 0x08, + 0x94, 0x33, 0x3a, 0x92, 0xdf, 0x94, 0x62, 0xd9, + 0xc1, 0x0a, 0xf3, 0xdf, 0xca, 0x70, 0x49, 0xa1, + 0xea, 0xa6, 0x35, 0x70, 0x13, 0x98, 0x83, 0xc5, + 0xbe, 0xfe, 0xbe, 0xe4, 0xe2, 0x21, 0x89, 0x43, + 0xd3, 0x0f, 0xc6, 0x45, 0xff, 0xe8, 0xb9, 0x14, + 0xd2, 0x18, 0xdd, 0x58, 0x96, 0x0a, 0xad, 0xc1, + 0x21, 0x71, 0x5b, 0xce, 0x5c, 0xcd, 0xde, 0x4a, + 0x2c, 0x73, 0xa8, 0xd9, 0xd8, 0x6a, 0x4e, 0xb6, + 0xe4, 0x55, 0xdc, 0x92, 0x4f, 0xd7, 0x4a, 0x0b, + 0x1f, 0x75, 0x69, 0x1c, 0x28, 0x1b, 0xae, 0x91, + 0x4d, 0x69, 0x9e, 0xe2, 0x59, 0xd8, 0x5c, 0x5f, + 0xb5, 0xdd, 0x99, 0x9e, 0xbe, 0xf9, 0xb7, 0x0a, + 0x4b, 0xd9, 0x4a, 0xa4, 0xfa, 0xfa, 0xe2, 0x6c, + 0xa7, 0x84, 0xd3, 0x2f, 0xd4, 0xe0, 0x77, 0xdb, + 0xb6, 0xea, 0x69, 0x3b, 0xcd, 0x6d, 0x27, 0xd5}, + .privexp_len = 192, + .prime1 = {0xff, 0x8e, 0xf1, 0xe7, 0x4c, 0x44, 0x5a, 0x5c, + 0xc8, 0x97, 0x3a, 0x81, 0x9c, 0x75, 0x45, 0x49, + 0x12, 0x35, 0x72, 0x0c, 0xf9, 0xeb, 0x83, 0xf1, + 0x81, 0x13, 0x3c, 0x78, 0xa1, 0x4d, 0xcc, 0x4c, + 0xe5, 0xe7, 0x75, 0xbe, 0x3e, 0x0c, 0x46, 0xed, + 0x2f, 0x21, 0x9a, 0xb8, 0x8d, 0x87, 0x77, 0xad, + 0x6e, 0xcb, 0xe4, 0x0c, 0xf9, 0x18, 0x76, 0x4d, + 0x7e, 0x37, 0xc6, 0x68, 0x35, 0x91, 0xe7, 0xaa, + 0xa1, 0x3b, 0x24, 0x4b, 0x7f, 0xcc, 0x0e, 0xb6, + 0xdf, 0xd7, 0x6a, 0x11, 0x5f, 0x30, 0xed, 0x2d, + 0x63, 0x68, 0xc8, 0xea, 0x78, 0x0a, 0x21, 0x1c, + 0x0a, 0xc9, 0xc0, 0x72, 0x5d, 0xfa, 0xb0, 0x8d}, + .prime1_len = 96, + .prime2 = {0xd8, 0xd0, 0x67, 0x64, 0xc1, 0xf7, 0x64, 0x54, + 0xc6, 0x8a, 0x3a, 0x08, 0x1e, 0x95, 0xd7, 0x47, + 0xc2, 0x94, 0x11, 0xad, 0xc4, 0x03, 0xa7, 0xcb, + 0x71, 0xb4, 0x3a, 0xf5, 0x05, 0xca, 0xbe, 0x41, + 0xb4, 0x9c, 0x97, 0x1c, 0x13, 0xad, 0x65, 0x63, + 0xb8, 0xc9, 0x0b, 0x93, 0xb5, 0x89, 0x79, 0xbb, + 0x74, 0xf8, 0x20, 0xef, 0xb8, 0xde, 0xd8, 0x1f, + 0x46, 0x30, 0x54, 0xa7, 0x7f, 0xb3, 0x0b, 0xb0, + 0x99, 0x98, 0x51, 0xa4, 0x3c, 0xcd, 0x01, 0x69, + 0x18, 0x51, 0x31, 0xf7, 0x43, 0x1b, 0x02, 0xe9, + 0xc6, 0xb9, 0xf8, 0x38, 0x71, 0xd9, 0xcd, 0x5e, + 0x0c, 0x3c, 0x58, 0x70, 0xcf, 0x97, 0x97, 0x23}, + .prime2_len = 96, + .exp1 = {0xe8, 0xd6, 0x15, 0xf4, 0x04, 0x7a, 0xaa, 0x51, + 0xaa, 0xb8, 0x8e, 0x27, 0x94, 0xa3, 0x0b, 0xd3, + 0x3d, 0x71, 0xd0, 0x4d, 0x9e, 0x4e, 0x43, 0xd2, + 0x7f, 0x25, 0x45, 0x8d, 0x2a, 0x79, 0xb5, 0x4f, + 0xc2, 0x8f, 0x95, 0xa9, 0x14, 0xe3, 0x1e, 0xa3, + 0xee, 0xb3, 0x11, 0x42, 0x60, 0x40, 0x32, 0x7b, + 0xa3, 0x5c, 0xc4, 0x94, 0x45, 0x47, 0x52, 0x51, + 0xdc, 0x53, 0x78, 0xc3, 0x6d, 0x3b, 0x57, 0xf5, + 0x10, 0x1c, 0xd0, 0x3e, 0xb1, 0x5a, 0xfb, 0x75, + 0x06, 0x90, 0x3f, 0x25, 0x40, 0xb3, 0x55, 0x04, + 0x6b, 0x74, 0x06, 0xca, 0x09, 0x40, 0x41, 0x56, + 0x49, 0x45, 0xf3, 0xbe, 0xbf, 0x7d, 0x2d, 0xe9}, + .exp1_len = 96, + .exp2 = {0x73, 0x5d, 0xb1, 0x26, 0x73, 0xef, 0x67, 0x7b, + 0x94, 0x89, 0x48, 0x87, 0xb9, 0x7e, 0x91, 0xa6, + 0xa5, 0x6a, 0x94, 0x5d, 0x99, 0xc7, 0x38, 0x29, + 0x90, 0xbf, 0x0e, 0x00, 0x02, 0xac, 0xf6, 0xbf, + 0x8f, 0x93, 0x22, 0xf4, 0xd5, 0xa3, 0x96, 0x27, + 0x91, 0xd3, 0xa8, 0x4d, 0x58, 0x73, 0x66, 0x4a, + 0xd0, 0xda, 0x96, 0xeb, 0xf7, 0xba, 0xdb, 0xd5, + 0x08, 0x4b, 0xff, 0x3f, 0x81, 0x3b, 0x8c, 0x24, + 0xd4, 0x15, 0xb0, 0x9b, 0x6b, 0x9e, 0xc9, 0xf9, + 0x59, 0xef, 0x1a, 0x5f, 0x2f, 0x5d, 0xd8, 0x16, + 0xfc, 0x9f, 0x47, 0xed, 0x00, 0xe7, 0x9b, 0xd7, + 0x47, 0x3b, 0x74, 0xf3, 0xd2, 0x02, 0x1f, 0x71}, + .exp2_len = 96, + .coef = {0x10, 0x62, 0x18, 0xaf, 0x97, 0x1d, 0x92, 0x95, + 0x91, 0x59, 0x90, 0xa4, 0xed, 0x3e, 0x09, 0xd3, + 0x63, 0xdb, 0x33, 0x06, 0xb0, 0x90, 0xa1, 0x33, + 0xeb, 0xd7, 0x54, 0xe2, 0xbd, 0x77, 0x6b, 0x25, + 0x85, 0x99, 0x9d, 0x4f, 0x88, 0x43, 0x03, 0x0a, + 0xc7, 0x0c, 0x0f, 0xf5, 0xde, 0x52, 0x12, 0x67, + 0x22, 0x34, 0xc0, 0x07, 0xce, 0x74, 0x56, 0x4c, + 0x79, 0x1e, 0xdc, 0xd5, 0x76, 0xf9, 0x68, 0x44, + 0x04, 0x8c, 0xfa, 0x66, 0x36, 0x46, 0xb8, 0xfd, + 0x80, 0xc7, 0x51, 0x26, 0xb2, 0x26, 0x6e, 0x48, + 0xf1, 0xfa, 0xa7, 0x05, 0x44, 0xad, 0x42, 0x04, + 0xfd, 0x61, 0x56, 0x29, 0x2e, 0x51, 0x6e, 0x13}, + .coef_len = 96, + .msg = {0x2a, 0x13, 0x30, 0x03, 0xab, 0x67, 0xcd, 0xd2, + 0xe8, 0x3b, 0x44, 0xe9, 0xe9, 0xdc, 0x77, 0x7d, + 0xe0, 0x1f, 0x4d, 0x23, 0x3d, 0x22, 0xe7, 0xd2, + 0xb4, 0x46, 0x7f, 0x04, 0x81, 0x2a, 0x3a, 0xeb, + 0xff, 0xb1, 0x0a, 0x09, 0x24, 0x54, 0xe3, 0x3b, + 0x9e, 0x70, 0x28, 0x24, 0x93, 0x28, 0x74, 0x7e, + 0xa1, 0x4a, 0x11, 0xc7, 0x98, 0xac, 0x2e, 0x14, + 0x6e, 0x4e, 0x49, 0x65, 0x9b, 0xa8, 0x60, 0x67, + 0xdb, 0x64, 0xe9, 0xbd, 0x80, 0xa7, 0x02, 0x1a, + 0xab, 0xcc, 0x22, 0x85, 0x6e, 0x81, 0x01, 0x40, + 0xc2, 0x0f, 0xd8, 0xc6, 0x52, 0x7b, 0xad, 0xbb, + 0xd9, 0xfa, 0x59, 0x53, 0xfa, 0x77, 0xe6, 0x85, + 0x87, 0x00, 0xbe, 0xb6, 0xc7, 0x4d, 0x5a, 0x46, + 0x3c, 0x9d, 0xa8, 0x61, 0x13, 0x3b, 0xaa, 0x5b, + 0xd6, 0xa5, 0x99, 0x80, 0x7a, 0xe9, 0x16, 0x2e, + 0x3a, 0xf3, 0xa3, 0x48, 0xd0, 0x4a, 0x4e, 0xdd, + 0x2f, 0xfb, 0xab}, + .msg_len = 131, + .sig = {0x35, 0xe6, 0x66, 0xcf, 0xb8, 0x7c, 0x04, 0x88, + 0xa8, 0x6f, 0xdf, 0xed, 0x5f, 0x9d, 0xea, 0xed, + 0xbc, 0x46, 0x74, 0x17, 0x1c, 0x31, 0x84, 0x59, + 0xac, 0xaa, 0xaa, 0x20, 0xe1, 0xca, 0xd7, 0xc5, + 0x86, 0x04, 0x14, 0x0a, 0x80, 0xff, 0x7f, 0x56, + 0x5b, 0xfb, 0xc8, 0x6e, 0x90, 0x32, 0x8d, 0x4c, + 0x72, 0x9b, 0x91, 0xbf, 0x72, 0xa9, 0x8d, 0xb7, + 0x01, 0xc1, 0xbe, 0x63, 0x8a, 0x6e, 0x8f, 0x2e, + 0x46, 0x8f, 0x20, 0x39, 0x24, 0x70, 0xc7, 0xc5, + 0xc3, 0x44, 0x42, 0xd5, 0x1b, 0x1b, 0x15, 0x5f, + 0xb4, 0x64, 0xb8, 0xa5, 0x56, 0xf4, 0xa1, 0x70, + 0xc0, 0x23, 0x01, 0xfe, 0xd0, 0xd1, 0xaa, 0x92, + 0xaa, 0xfd, 0xeb, 0xc3, 0xf1, 0x8e, 0xa8, 0xb4, + 0xd7, 0x1e, 0x24, 0x5c, 0x25, 0x26, 0xf6, 0xfe, + 0x66, 0x5d, 0xe4, 0x83, 0x85, 0xf4, 0x6c, 0xe1, + 0xbf, 0x33, 0x12, 0xfa, 0x89, 0x28, 0x09, 0x8e, + 0xd3, 0x31, 0x2b, 0x61, 0x11, 0x6c, 0xa7, 0xe4, + 0x23, 0x20, 0x4e, 0xf0, 0x8b, 0xd2, 0xdf, 0x3a, + 0xd7, 0xbb, 0xc8, 0x50, 0x09, 0x8c, 0xb0, 0x26, + 0x83, 0x26, 0x66, 0x25, 0xbb, 0xd9, 0x59, 0x82, + 0x51, 0x35, 0xa4, 0x5f, 0x03, 0x82, 0x9d, 0x09, + 0x6f, 0xed, 0x18, 0xb2, 0x0b, 0xaa, 0x3f, 0x9d, + 0x44, 0xb0, 0x07, 0xaa, 0x24, 0x1f, 0x92, 0xf8, + 0x88, 0x60, 0x55, 0xd9, 0x8e, 0x0e, 0x07, 0x04}, + .sig_len = 192, + .chunks = {10, 100, 21}, + .num_chunks = 3, + }, + { // 41 + .mod = {0xd8, 0x70, 0xa7, 0x76, 0xcd, 0x13, 0xed, 0x44, + 0x3d, 0xf3, 0x99, 0x08, 0xbe, 0xe2, 0xca, 0xd7, + 0x3c, 0x48, 0x5f, 0xd9, 0xbf, 0x06, 0x32, 0x13, + 0x22, 0x88, 0x7f, 0xbe, 0x65, 0x5c, 0x08, 0xcb, + 0xe4, 0xc8, 0xf6, 0x3e, 0x25, 0x4f, 0xc9, 0x1c, + 0x75, 0xf0, 0x55, 0x7d, 0x90, 0x1d, 0x43, 0x5b, + 0x0e, 0x8d, 0xed, 0x82, 0xd4, 0x91, 0x73, 0x41, + 0x4d, 0x29, 0x86, 0x03, 0x24, 0xe4, 0x6c, 0x1b, + 0x03, 0x0d, 0xfe, 0xaa, 0x29, 0xd8, 0x0f, 0x98, + 0x98, 0xc2, 0xc5, 0xe1, 0x01, 0xcb, 0xf6, 0xda, + 0xa0, 0x62, 0x89, 0x78, 0xd4, 0x15, 0xb5, 0x02, + 0xde, 0xa2, 0x6d, 0xe6, 0x56, 0x1c, 0x79, 0xab, + 0x06, 0x5c, 0x6d, 0xca, 0x6a, 0xbc, 0x4d, 0x4d, + 0x4d, 0x5e, 0x9f, 0x5c, 0x74, 0xcb, 0x3e, 0x6a, + 0x5a, 0xf7, 0x1d, 0x1f, 0x90, 0xfa, 0x5e, 0xaa, + 0x1b, 0xe0, 0xca, 0x94, 0x7a, 0x70, 0xa3, 0x9e, + 0xfd, 0x31, 0x5c, 0x4d, 0xf2, 0x1a, 0x1a, 0x82, + 0x1c, 0xaa, 0xff, 0x8d, 0xcb, 0xad, 0x13, 0xb2, + 0x9c, 0x7e, 0x82, 0xaa, 0xd5, 0x3c, 0x64, 0xf5, + 0x82, 0xec, 0x9e, 0xc3, 0x1e, 0x6b, 0xde, 0x82, + 0xea, 0x5a, 0x5f, 0x4c, 0xcc, 0xf0, 0xc4, 0x57, + 0xb8, 0x88, 0xf1, 0x55, 0x0c, 0x4f, 0xf8, 0xe1, + 0xc1, 0x78, 0xa7, 0x6a, 0x46, 0xc1, 0x96, 0xf4, + 0xbe, 0xf5, 0x9e, 0x61, 0xdd, 0x94, 0x4e, 0x47}, + .mod_len = 192, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x05, 0x88, 0x8f, 0xc7, 0x7a, 0x43, 0xbd, 0xa7, + 0xa6, 0x7b, 0xd1, 0x58, 0x47, 0x65, 0x0d, 0xf1, + 0x85, 0xc1, 0x85, 0xed, 0xcf, 0xb3, 0xed, 0x58, + 0xce, 0xe3, 0xb5, 0x7c, 0x5d, 0x24, 0x06, 0xb7, + 0x8b, 0xc0, 0x55, 0x87, 0x4e, 0x35, 0xe5, 0x7a, + 0xdc, 0x4b, 0x0a, 0x2c, 0x7d, 0x20, 0x3a, 0x66, + 0x1c, 0x0f, 0xa5, 0xd8, 0x57, 0xed, 0xe6, 0x07, + 0xef, 0xdc, 0x95, 0x68, 0x04, 0x2b, 0xf0, 0xd5, + 0x99, 0xf4, 0xe4, 0x23, 0x5e, 0x91, 0x7f, 0x08, + 0x94, 0x33, 0x3a, 0x92, 0xdf, 0x94, 0x62, 0xd9, + 0xc1, 0x0a, 0xf3, 0xdf, 0xca, 0x70, 0x49, 0xa1, + 0xea, 0xa6, 0x35, 0x70, 0x13, 0x98, 0x83, 0xc5, + 0xbe, 0xfe, 0xbe, 0xe4, 0xe2, 0x21, 0x89, 0x43, + 0xd3, 0x0f, 0xc6, 0x45, 0xff, 0xe8, 0xb9, 0x14, + 0xd2, 0x18, 0xdd, 0x58, 0x96, 0x0a, 0xad, 0xc1, + 0x21, 0x71, 0x5b, 0xce, 0x5c, 0xcd, 0xde, 0x4a, + 0x2c, 0x73, 0xa8, 0xd9, 0xd8, 0x6a, 0x4e, 0xb6, + 0xe4, 0x55, 0xdc, 0x92, 0x4f, 0xd7, 0x4a, 0x0b, + 0x1f, 0x75, 0x69, 0x1c, 0x28, 0x1b, 0xae, 0x91, + 0x4d, 0x69, 0x9e, 0xe2, 0x59, 0xd8, 0x5c, 0x5f, + 0xb5, 0xdd, 0x99, 0x9e, 0xbe, 0xf9, 0xb7, 0x0a, + 0x4b, 0xd9, 0x4a, 0xa4, 0xfa, 0xfa, 0xe2, 0x6c, + 0xa7, 0x84, 0xd3, 0x2f, 0xd4, 0xe0, 0x77, 0xdb, + 0xb6, 0xea, 0x69, 0x3b, 0xcd, 0x6d, 0x27, 0xd5}, + .privexp_len = 192, + .prime1 = {0xff, 0x8e, 0xf1, 0xe7, 0x4c, 0x44, 0x5a, 0x5c, + 0xc8, 0x97, 0x3a, 0x81, 0x9c, 0x75, 0x45, 0x49, + 0x12, 0x35, 0x72, 0x0c, 0xf9, 0xeb, 0x83, 0xf1, + 0x81, 0x13, 0x3c, 0x78, 0xa1, 0x4d, 0xcc, 0x4c, + 0xe5, 0xe7, 0x75, 0xbe, 0x3e, 0x0c, 0x46, 0xed, + 0x2f, 0x21, 0x9a, 0xb8, 0x8d, 0x87, 0x77, 0xad, + 0x6e, 0xcb, 0xe4, 0x0c, 0xf9, 0x18, 0x76, 0x4d, + 0x7e, 0x37, 0xc6, 0x68, 0x35, 0x91, 0xe7, 0xaa, + 0xa1, 0x3b, 0x24, 0x4b, 0x7f, 0xcc, 0x0e, 0xb6, + 0xdf, 0xd7, 0x6a, 0x11, 0x5f, 0x30, 0xed, 0x2d, + 0x63, 0x68, 0xc8, 0xea, 0x78, 0x0a, 0x21, 0x1c, + 0x0a, 0xc9, 0xc0, 0x72, 0x5d, 0xfa, 0xb0, 0x8d}, + .prime1_len = 96, + .prime2 = {0xd8, 0xd0, 0x67, 0x64, 0xc1, 0xf7, 0x64, 0x54, + 0xc6, 0x8a, 0x3a, 0x08, 0x1e, 0x95, 0xd7, 0x47, + 0xc2, 0x94, 0x11, 0xad, 0xc4, 0x03, 0xa7, 0xcb, + 0x71, 0xb4, 0x3a, 0xf5, 0x05, 0xca, 0xbe, 0x41, + 0xb4, 0x9c, 0x97, 0x1c, 0x13, 0xad, 0x65, 0x63, + 0xb8, 0xc9, 0x0b, 0x93, 0xb5, 0x89, 0x79, 0xbb, + 0x74, 0xf8, 0x20, 0xef, 0xb8, 0xde, 0xd8, 0x1f, + 0x46, 0x30, 0x54, 0xa7, 0x7f, 0xb3, 0x0b, 0xb0, + 0x99, 0x98, 0x51, 0xa4, 0x3c, 0xcd, 0x01, 0x69, + 0x18, 0x51, 0x31, 0xf7, 0x43, 0x1b, 0x02, 0xe9, + 0xc6, 0xb9, 0xf8, 0x38, 0x71, 0xd9, 0xcd, 0x5e, + 0x0c, 0x3c, 0x58, 0x70, 0xcf, 0x97, 0x97, 0x23}, + .prime2_len = 96, + .exp1 = {0xe8, 0xd6, 0x15, 0xf4, 0x04, 0x7a, 0xaa, 0x51, + 0xaa, 0xb8, 0x8e, 0x27, 0x94, 0xa3, 0x0b, 0xd3, + 0x3d, 0x71, 0xd0, 0x4d, 0x9e, 0x4e, 0x43, 0xd2, + 0x7f, 0x25, 0x45, 0x8d, 0x2a, 0x79, 0xb5, 0x4f, + 0xc2, 0x8f, 0x95, 0xa9, 0x14, 0xe3, 0x1e, 0xa3, + 0xee, 0xb3, 0x11, 0x42, 0x60, 0x40, 0x32, 0x7b, + 0xa3, 0x5c, 0xc4, 0x94, 0x45, 0x47, 0x52, 0x51, + 0xdc, 0x53, 0x78, 0xc3, 0x6d, 0x3b, 0x57, 0xf5, + 0x10, 0x1c, 0xd0, 0x3e, 0xb1, 0x5a, 0xfb, 0x75, + 0x06, 0x90, 0x3f, 0x25, 0x40, 0xb3, 0x55, 0x04, + 0x6b, 0x74, 0x06, 0xca, 0x09, 0x40, 0x41, 0x56, + 0x49, 0x45, 0xf3, 0xbe, 0xbf, 0x7d, 0x2d, 0xe9}, + .exp1_len = 96, + .exp2 = {0x73, 0x5d, 0xb1, 0x26, 0x73, 0xef, 0x67, 0x7b, + 0x94, 0x89, 0x48, 0x87, 0xb9, 0x7e, 0x91, 0xa6, + 0xa5, 0x6a, 0x94, 0x5d, 0x99, 0xc7, 0x38, 0x29, + 0x90, 0xbf, 0x0e, 0x00, 0x02, 0xac, 0xf6, 0xbf, + 0x8f, 0x93, 0x22, 0xf4, 0xd5, 0xa3, 0x96, 0x27, + 0x91, 0xd3, 0xa8, 0x4d, 0x58, 0x73, 0x66, 0x4a, + 0xd0, 0xda, 0x96, 0xeb, 0xf7, 0xba, 0xdb, 0xd5, + 0x08, 0x4b, 0xff, 0x3f, 0x81, 0x3b, 0x8c, 0x24, + 0xd4, 0x15, 0xb0, 0x9b, 0x6b, 0x9e, 0xc9, 0xf9, + 0x59, 0xef, 0x1a, 0x5f, 0x2f, 0x5d, 0xd8, 0x16, + 0xfc, 0x9f, 0x47, 0xed, 0x00, 0xe7, 0x9b, 0xd7, + 0x47, 0x3b, 0x74, 0xf3, 0xd2, 0x02, 0x1f, 0x71}, + .exp2_len = 96, + .coef = {0x10, 0x62, 0x18, 0xaf, 0x97, 0x1d, 0x92, 0x95, + 0x91, 0x59, 0x90, 0xa4, 0xed, 0x3e, 0x09, 0xd3, + 0x63, 0xdb, 0x33, 0x06, 0xb0, 0x90, 0xa1, 0x33, + 0xeb, 0xd7, 0x54, 0xe2, 0xbd, 0x77, 0x6b, 0x25, + 0x85, 0x99, 0x9d, 0x4f, 0x88, 0x43, 0x03, 0x0a, + 0xc7, 0x0c, 0x0f, 0xf5, 0xde, 0x52, 0x12, 0x67, + 0x22, 0x34, 0xc0, 0x07, 0xce, 0x74, 0x56, 0x4c, + 0x79, 0x1e, 0xdc, 0xd5, 0x76, 0xf9, 0x68, 0x44, + 0x04, 0x8c, 0xfa, 0x66, 0x36, 0x46, 0xb8, 0xfd, + 0x80, 0xc7, 0x51, 0x26, 0xb2, 0x26, 0x6e, 0x48, + 0xf1, 0xfa, 0xa7, 0x05, 0x44, 0xad, 0x42, 0x04, + 0xfd, 0x61, 0x56, 0x29, 0x2e, 0x51, 0x6e, 0x13}, + .coef_len = 96, + .msg = {0x58, 0x62, 0x7f, 0xfa, 0xaa, 0x8e, 0x80, 0x0a, + 0x8b, 0xe9, 0x8e, 0x42, 0xf5, 0x1a, 0x83, 0x61, + 0x1c, 0xfa, 0xb7, 0xee, 0x37, 0x6b, 0x34, 0x73, + 0x7b, 0x3e, 0x48, 0xe1, 0xbc, 0x17, 0x42, 0xda, + 0xa7, 0x7d, 0xe4, 0x7e, 0x1a, 0x9b, 0x29, 0x33, + 0x77, 0xaa}, + .msg_len = 42, + .sig = {0x3d, 0x17, 0xcb, 0x38, 0x6c, 0x88, 0x78, 0x4d, + 0x35, 0x9a, 0xd3, 0xc3, 0x8d, 0xbe, 0x88, 0x8b, + 0xfa, 0xe8, 0x31, 0xbf, 0xb8, 0xed, 0xc9, 0xd0, + 0xe8, 0x01, 0xe7, 0xd6, 0x9e, 0x1d, 0xd4, 0xc2, + 0x44, 0x1d, 0x68, 0xfd, 0xbb, 0x35, 0x12, 0x6c, + 0x73, 0xa4, 0xed, 0xab, 0xbf, 0xf5, 0x4e, 0x74, + 0xfa, 0x51, 0x09, 0xda, 0xd8, 0xb5, 0xc3, 0x13, + 0xd8, 0x6a, 0x79, 0xe4, 0xd4, 0x12, 0x76, 0x60, + 0xfc, 0x2a, 0x8e, 0x1c, 0x93, 0xfa, 0x8d, 0x09, + 0x2a, 0xcc, 0xf0, 0x1c, 0xc1, 0x8a, 0x60, 0x6c, + 0xf0, 0x7d, 0xe2, 0xdc, 0x3e, 0x7b, 0x55, 0x33, + 0x11, 0x52, 0xdb, 0x01, 0xb6, 0xca, 0xea, 0x1e, + 0xce, 0xc9, 0x09, 0x31, 0x99, 0xbe, 0x62, 0xc3, + 0xe1, 0x23, 0xe2, 0x87, 0x31, 0x13, 0x50, 0x3b, + 0x22, 0x03, 0x0f, 0x16, 0x8d, 0xaf, 0xc4, 0xe6, + 0xbd, 0x06, 0x5a, 0xd2, 0xf6, 0xb1, 0xde, 0xd0, + 0x5b, 0xe0, 0xc2, 0xf9, 0xb6, 0x7b, 0xdc, 0x1a, + 0x3b, 0xb1, 0x8d, 0xa9, 0x59, 0x4c, 0x95, 0x7d, + 0xa4, 0xe4, 0x9f, 0xac, 0x3f, 0xe7, 0x6e, 0x07, + 0x66, 0xf7, 0x4e, 0xb0, 0xd5, 0x23, 0xe4, 0xdd, + 0x1a, 0xe7, 0x59, 0xda, 0xd6, 0xb9, 0xb9, 0x08, + 0xb7, 0xfc, 0x8b, 0x97, 0xef, 0x5f, 0x4c, 0x82, + 0x92, 0x32, 0x0a, 0xc3, 0x87, 0xc3, 0x50, 0x8b, + 0x54, 0xcf, 0xb8, 0x5d, 0x34, 0xf6, 0xad, 0x39}, + .sig_len = 192, + }, + { // 42 + .mod = {0xdf, 0x27, 0x1f, 0xd2, 0x5f, 0x86, 0x44, 0x49, + 0x6b, 0x0c, 0x81, 0xbe, 0x4b, 0xd5, 0x02, 0x97, + 0xef, 0x09, 0x9b, 0x00, 0x2a, 0x6f, 0xd6, 0x77, + 0x27, 0xeb, 0x44, 0x9c, 0xea, 0x56, 0x6e, 0xd6, + 0xa3, 0x98, 0x1a, 0x71, 0x31, 0x2a, 0x14, 0x1c, + 0xab, 0xc9, 0x81, 0x5c, 0x12, 0x09, 0xe3, 0x20, + 0xa2, 0x5b, 0x32, 0x46, 0x4e, 0x99, 0x99, 0xf1, + 0x8c, 0xa1, 0x3a, 0x9f, 0xd3, 0x89, 0x25, 0x58, + 0xf9, 0xe0, 0xad, 0xef, 0xdd, 0x36, 0x50, 0xdd, + 0x23, 0xa3, 0xf0, 0x36, 0xd6, 0x0f, 0xe3, 0x98, + 0x84, 0x37, 0x06, 0xa4, 0x0b, 0x0b, 0x84, 0x62, + 0xc8, 0xbe, 0xe3, 0xbc, 0xe1, 0x2f, 0x1f, 0x28, + 0x60, 0xc2, 0x44, 0x4c, 0xdc, 0x6a, 0x44, 0x47, + 0x6a, 0x75, 0xff, 0x4a, 0xa2, 0x42, 0x73, 0xcc, + 0xbe, 0x3b, 0xf8, 0x02, 0x48, 0x46, 0x5f, 0x8f, + 0xf8, 0xc3, 0xa7, 0xf3, 0x36, 0x7d, 0xfc, 0x0d, + 0xf5, 0xb6, 0x50, 0x9a, 0x4f, 0x82, 0x81, 0x1c, + 0xed, 0xd8, 0x1c, 0xda, 0xaa, 0x73, 0xc4, 0x91, + 0xda, 0x41, 0x21, 0x70, 0xd5, 0x44, 0xd4, 0xba, + 0x96, 0xb9, 0x7f, 0x0a, 0xfc, 0x80, 0x65, 0x49, + 0x8d, 0x3a, 0x49, 0xfd, 0x91, 0x09, 0x92, 0xa1, + 0xf0, 0x72, 0x5b, 0xe2, 0x4f, 0x46, 0x5c, 0xfe, + 0x7e, 0x0e, 0xab, 0xf6, 0x78, 0x99, 0x6c, 0x50, + 0xbc, 0x5e, 0x75, 0x24, 0xab, 0xf7, 0x3f, 0x15, + 0xe5, 0xbe, 0xf7, 0xd5, 0x18, 0x39, 0x4e, 0x31, + 0x38, 0xce, 0x49, 0x44, 0x50, 0x6a, 0xaa, 0xaf, + 0x3f, 0x9b, 0x23, 0x6d, 0xca, 0xb8, 0xfc, 0x00, + 0xf8, 0x7a, 0xf5, 0x96, 0xfd, 0xc3, 0xd9, 0xd6, + 0xc7, 0x5c, 0xd5, 0x08, 0x36, 0x2f, 0xae, 0x2c, + 0xbe, 0xdd, 0xcc, 0x4c, 0x74, 0x50, 0xb1, 0x7b, + 0x77, 0x6c, 0x07, 0x9e, 0xcc, 0xa1, 0xf2, 0x56, + 0x35, 0x1a, 0x43, 0xb9, 0x7d, 0xbe, 0x21, 0x53}, + .mod_len = 256, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x5b, 0xd9, 0x10, 0x25, 0x78, 0x30, 0xdc, 0xe1, + 0x75, 0x20, 0xb0, 0x34, 0x41, 0xa5, 0x1a, 0x8c, + 0xab, 0x94, 0x02, 0x0a, 0xc6, 0xec, 0xc2, 0x52, + 0xc8, 0x08, 0xf3, 0x74, 0x3c, 0x95, 0xb7, 0xc8, + 0x3b, 0x8c, 0x8a, 0xf1, 0xa5, 0x01, 0x43, 0x46, + 0xeb, 0xc4, 0x24, 0x2c, 0xdf, 0xb5, 0xd7, 0x18, + 0xe3, 0x0a, 0x73, 0x3e, 0x71, 0xf2, 0x91, 0xe4, + 0xd4, 0x73, 0xb6, 0x1b, 0xfb, 0xa6, 0xda, 0xca, + 0xed, 0x0a, 0x77, 0xbd, 0x1f, 0x09, 0x50, 0xae, + 0x3c, 0x91, 0xa8, 0xf9, 0x01, 0x11, 0x88, 0x25, + 0x89, 0xe1, 0xd6, 0x27, 0x65, 0xee, 0x67, 0x1e, + 0x7b, 0xae, 0xea, 0x30, 0x9f, 0x64, 0xd4, 0x47, + 0xbb, 0xcf, 0xa9, 0xea, 0x12, 0xdc, 0xe0, 0x5e, + 0x9e, 0xa8, 0x93, 0x9b, 0xc5, 0xfe, 0x61, 0x08, + 0x58, 0x12, 0x79, 0xc9, 0x82, 0xb3, 0x08, 0x79, + 0x4b, 0x34, 0x48, 0xe7, 0xf7, 0xb9, 0x52, 0x29, + 0x2d, 0xf8, 0x8c, 0x80, 0xcb, 0x40, 0x14, 0x2c, + 0x4b, 0x5c, 0xf5, 0xf8, 0xdd, 0xaa, 0x08, 0x91, + 0x67, 0x8d, 0x61, 0x0e, 0x58, 0x2f, 0xcb, 0x88, + 0x0f, 0x0d, 0x70, 0x7c, 0xaf, 0x47, 0xd0, 0x9a, + 0x84, 0xe1, 0x4c, 0xa6, 0x58, 0x41, 0xe5, 0xa3, + 0xab, 0xc5, 0xe9, 0xdb, 0xa9, 0x40, 0x75, 0xa9, + 0x08, 0x43, 0x41, 0xf0, 0xed, 0xad, 0x9b, 0x68, + 0xe3, 0xb8, 0xe0, 0x82, 0xb8, 0x0b, 0x6e, 0x6e, + 0x8a, 0x05, 0x47, 0xb4, 0x4f, 0xb5, 0x06, 0x1b, + 0x6a, 0x91, 0x31, 0x60, 0x3a, 0x55, 0x37, 0xdd, + 0xab, 0xd0, 0x1d, 0x8e, 0x86, 0x3d, 0x89, 0x22, + 0xe9, 0xaa, 0x3e, 0x4b, 0xfa, 0xea, 0x0b, 0x39, + 0xd7, 0x92, 0x83, 0xad, 0x2c, 0xbc, 0x8a, 0x59, + 0xcc, 0xe7, 0xa6, 0xec, 0xf4, 0xe4, 0xc8, 0x1e, + 0xd4, 0xc6, 0x59, 0x1c, 0x80, 0x7d, 0xef, 0xd7, + 0x1a, 0xb0, 0x68, 0x66, 0xbb, 0x5e, 0x77, 0x45}, + .privexp_len = 256, + .prime1 = {0xf4, 0x4f, 0x5e, 0x42, 0x46, 0x39, 0x1f, 0x48, + 0x2b, 0x2f, 0x52, 0x96, 0xe3, 0x60, 0x2e, 0xb3, + 0x4a, 0xa1, 0x36, 0x42, 0x77, 0x10, 0xf7, 0xc0, + 0x41, 0x6d, 0x40, 0x3f, 0xd6, 0x9d, 0x4b, 0x29, + 0x13, 0x0c, 0xfe, 0xbe, 0xf3, 0x4e, 0x88, 0x5a, + 0xbd, 0xb1, 0xa8, 0xa0, 0xa5, 0xf0, 0xe9, 0xb5, + 0xc3, 0x3e, 0x1f, 0xc3, 0xbf, 0xc2, 0x85, 0xb1, + 0xae, 0x17, 0xe4, 0x0c, 0xc6, 0x7a, 0x19, 0x13, + 0xdd, 0x56, 0x37, 0x19, 0x81, 0x5e, 0xba, 0xf8, + 0x51, 0x4c, 0x2a, 0x7a, 0xa0, 0x01, 0x8e, 0x63, + 0xb6, 0xc6, 0x31, 0xdc, 0x31, 0x5a, 0x46, 0x23, + 0x57, 0x16, 0x42, 0x3d, 0x11, 0xff, 0x58, 0x03, + 0x4e, 0x61, 0x06, 0x45, 0x70, 0x36, 0x06, 0x91, + 0x9f, 0x5c, 0x7c, 0xe2, 0x66, 0x0c, 0xd1, 0x48, + 0xbd, 0x9e, 0xfc, 0x12, 0x3d, 0x9c, 0x54, 0xb6, + 0x70, 0x55, 0x90, 0xd0, 0x06, 0xcf, 0xcf, 0x3f}, + .prime1_len = 128, + .prime2 = {0xe9, 0xd4, 0x98, 0x41, 0xe0, 0xe0, 0xa6, 0xad, + 0x0d, 0x51, 0x78, 0x57, 0x13, 0x3e, 0x36, 0xdc, + 0x72, 0xc1, 0xbd, 0xd9, 0x0f, 0x91, 0x74, 0xb5, + 0x2e, 0x26, 0x57, 0x0f, 0x37, 0x36, 0x40, 0xf1, + 0xc1, 0x85, 0xe7, 0xea, 0x8e, 0x2e, 0xd7, 0xf1, + 0xe4, 0xeb, 0xb9, 0x51, 0xf7, 0x0a, 0x58, 0x02, + 0x36, 0x33, 0xb0, 0x09, 0x7a, 0xec, 0x67, 0xc6, + 0xdc, 0xb8, 0x00, 0xfc, 0x1a, 0x67, 0xf9, 0xbb, + 0x05, 0x63, 0x61, 0x0f, 0x08, 0xeb, 0xc8, 0x74, + 0x6a, 0xd1, 0x29, 0x77, 0x21, 0x36, 0xeb, 0x1d, + 0xda, 0xf4, 0x64, 0x36, 0x45, 0x0d, 0x31, 0x83, + 0x32, 0xa8, 0x49, 0x82, 0xfe, 0x5d, 0x28, 0xdb, + 0xe5, 0xb3, 0xe9, 0x12, 0x40, 0x7c, 0x3e, 0x0e, + 0x03, 0x10, 0x0d, 0x87, 0xd4, 0x36, 0xee, 0x40, + 0x9e, 0xec, 0x1c, 0xf8, 0x5e, 0x80, 0xab, 0xa0, + 0x79, 0xb2, 0xe6, 0x10, 0x6b, 0x97, 0xbc, 0xed}, + .prime2_len = 128, + .exp1 = {0xed, 0x10, 0x2a, 0xcd, 0xb2, 0x68, 0x71, 0x53, + 0x4d, 0x1c, 0x41, 0x4e, 0xca, 0xd9, 0xa4, 0xd7, + 0x32, 0xfe, 0x95, 0xb1, 0x0e, 0xea, 0x37, 0x0d, + 0xa6, 0x2f, 0x05, 0xde, 0x2c, 0x39, 0x3b, 0x1a, + 0x63, 0x33, 0x03, 0xea, 0x74, 0x1b, 0x6b, 0x32, + 0x69, 0xc9, 0x7f, 0x70, 0x4b, 0x35, 0x27, 0x02, + 0xc9, 0xae, 0x79, 0x92, 0x2f, 0x7b, 0xe8, 0xd1, + 0x0d, 0xb6, 0x7f, 0x02, 0x6a, 0x81, 0x45, 0xde, + 0x41, 0xb3, 0x0c, 0x0a, 0x42, 0xbf, 0x92, 0x3b, + 0xac, 0x5f, 0x75, 0x04, 0xc2, 0x48, 0x60, 0x4b, + 0x9f, 0xaa, 0x57, 0xed, 0x6b, 0x32, 0x46, 0xc6, + 0xba, 0x15, 0x8e, 0x36, 0xc6, 0x44, 0xf8, 0xb9, + 0x54, 0x8f, 0xcf, 0x4f, 0x07, 0xe0, 0x54, 0xa5, + 0x6f, 0x76, 0x86, 0x74, 0x05, 0x44, 0x40, 0xbc, + 0x0d, 0xcb, 0xbc, 0x9b, 0x52, 0x8f, 0x64, 0xa0, + 0x17, 0x06, 0xe0, 0x5b, 0x0b, 0x91, 0x10, 0x6f}, + .exp1_len = 128, + .exp2 = {0x68, 0x27, 0x92, 0x4a, 0x85, 0xe8, 0x8b, 0x55, + 0xba, 0x00, 0xf8, 0x21, 0x91, 0x28, 0xbd, 0x37, + 0x24, 0xc6, 0xb7, 0xd1, 0xdf, 0xe5, 0x62, 0x9e, + 0xf1, 0x97, 0x92, 0x5f, 0xec, 0xaf, 0xf5, 0xed, + 0xb9, 0xcd, 0xf3, 0xa7, 0xbe, 0xfd, 0x8e, 0xa2, + 0xe8, 0xdd, 0x37, 0x07, 0x13, 0x8b, 0x3f, 0xf8, + 0x7c, 0x3c, 0x39, 0xc5, 0x7f, 0x43, 0x9e, 0x56, + 0x2e, 0x2a, 0xa8, 0x05, 0xa3, 0x9d, 0x7c, 0xd7, + 0x99, 0x66, 0xd2, 0xec, 0xe7, 0x84, 0x5f, 0x1d, + 0xbc, 0x16, 0xbe, 0xe9, 0x99, 0x99, 0xe4, 0xd0, + 0xbf, 0x9e, 0xec, 0xa4, 0x5f, 0xcd, 0xa8, 0xa8, + 0x50, 0x00, 0x35, 0xfe, 0x6b, 0x5f, 0x03, 0xbc, + 0x2f, 0x6d, 0x1b, 0xfc, 0x4d, 0x4d, 0x0a, 0x37, + 0x23, 0x96, 0x1a, 0xf0, 0xcd, 0xce, 0x4a, 0x01, + 0xee, 0xc8, 0x2d, 0x7f, 0x54, 0x58, 0xec, 0x19, + 0xe7, 0x1b, 0x90, 0xee, 0xef, 0x7d, 0xff, 0x61}, + .exp2_len = 128, + .coef = {0x57, 0xb7, 0x38, 0x88, 0xd1, 0x83, 0xa9, 0x9a, + 0x63, 0x07, 0x42, 0x22, 0x77, 0x55, 0x1a, 0x3d, + 0x9e, 0x18, 0xad, 0xf0, 0x6a, 0x91, 0xe8, 0xb5, + 0x5c, 0xef, 0xfe, 0xf9, 0x07, 0x7c, 0x84, 0x96, + 0x94, 0x8e, 0xcb, 0x3b, 0x16, 0xb7, 0x81, 0x55, + 0xcb, 0x2a, 0x3a, 0x57, 0xc1, 0x19, 0xd3, 0x79, + 0x95, 0x1c, 0x01, 0x0a, 0xa6, 0x35, 0xed, 0xcf, + 0x62, 0xd8, 0x4c, 0x5a, 0x12, 0x2a, 0x8d, 0x67, + 0xab, 0x5f, 0xa9, 0xe5, 0xa4, 0xa8, 0x77, 0x2a, + 0x1e, 0x94, 0x3b, 0xaf, 0xc7, 0x0a, 0xe3, 0xa4, + 0xc1, 0xf0, 0xf3, 0xa4, 0xdd, 0xff, 0xae, 0xfd, + 0x18, 0x92, 0xc8, 0xcb, 0x33, 0xbb, 0x0d, 0x0b, + 0x95, 0x90, 0xe9, 0x63, 0xa6, 0x91, 0x10, 0xfb, + 0x34, 0xdb, 0x7b, 0x90, 0x6f, 0xc4, 0xba, 0x28, + 0x36, 0x99, 0x5a, 0xac, 0x7e, 0x52, 0x74, 0x90, + 0xac, 0x95, 0x2a, 0x02, 0x26, 0x8a, 0x4f, 0x18}, + .coef_len = 128, + .msg = {0xf4, 0x5d, 0x55, 0xf3, 0x55, 0x51, 0xe9, 0x75, + 0xd6, 0xa8, 0xdc, 0x7e, 0xa9, 0xf4, 0x88, 0x59, + 0x39, 0x40, 0xcc, 0x75, 0x69, 0x4a, 0x27, 0x8f, + 0x27, 0xe5, 0x78, 0xa1, 0x63, 0xd8, 0x39, 0xb3, + 0x40, 0x40, 0x84, 0x18, 0x08, 0xcf, 0x9c, 0x58, + 0xc9, 0xb8, 0x72, 0x8b, 0xf5, 0xf9, 0xce, 0x8e, + 0xe8, 0x11, 0xea, 0x91, 0x71, 0x4f, 0x47, 0xba, + 0xb9, 0x2d, 0x0f, 0x6d, 0x5a, 0x26, 0xfc, 0xfe, + 0xea, 0x6c, 0xd9, 0x3b, 0x91, 0x0c, 0x0a, 0x2c, + 0x96, 0x3e, 0x64, 0xeb, 0x18, 0x23, 0xf1, 0x02, + 0x75, 0x3d, 0x41, 0xf0, 0x33, 0x59, 0x10, 0xad, + 0x3a, 0x97, 0x71, 0x04, 0xf1, 0xaa, 0xf6, 0xc3, + 0x74, 0x27, 0x16, 0xa9, 0x75, 0x5d, 0x11, 0xb8, + 0xee, 0xd6, 0x90, 0x47, 0x7f, 0x44, 0x5c, 0x5d, + 0x27, 0x20, 0x8b, 0x2e, 0x28, 0x43, 0x30, 0xfa, + 0x3d, 0x30, 0x14, 0x23, 0xfa, 0x7f, 0x2d, 0x08, + 0x6e, 0x0a, 0xd0, 0xb8, 0x92, 0xb9, 0xdb, 0x54, + 0x4e, 0x45, 0x6d, 0x3f, 0x0d, 0xab, 0x85, 0xd9, + 0x53, 0xc1, 0x2d, 0x34, 0x0a, 0xa8, 0x73, 0xed, + 0xa7, 0x27, 0xc8, 0xa6, 0x49, 0xdb, 0x7f, 0xa6, + 0x37, 0x40, 0xe2, 0x5e, 0x9a, 0xf1, 0x53, 0x3b, + 0x30, 0x7e, 0x61, 0x32, 0x99, 0x93, 0x11, 0x0e, + 0x95, 0x19, 0x4e, 0x03, 0x93, 0x99, 0xc3, 0x82, + 0x4d, 0x24, 0xc5, 0x1f, 0x22, 0xb2, 0x6b, 0xde, + 0x10, 0x24, 0xcd, 0x39, 0x59, 0x58, 0xa2, 0xdf, + 0xeb, 0x48, 0x16, 0xa6, 0xe8, 0xad, 0xed, 0xb5, + 0x0b, 0x1f, 0x6b, 0x56, 0xd0, 0xb3, 0x06, 0x0f, + 0xf0, 0xf1, 0xc4, 0xcb, 0x0d, 0x0e, 0x00, 0x1d, + 0xd5, 0x9d, 0x73, 0xbe, 0x12}, + .msg_len = 229, + .sig = {0xb7, 0x5a, 0x54, 0x66, 0xb6, 0x5d, 0x0f, 0x30, + 0x0e, 0xf5, 0x38, 0x33, 0xf2, 0x17, 0x5c, 0x8a, + 0x34, 0x7a, 0x38, 0x04, 0xfc, 0x63, 0x45, 0x1d, + 0xc9, 0x02, 0xf0, 0xb7, 0x1f, 0x90, 0x83, 0x45, + 0x9e, 0xd3, 0x7a, 0x51, 0x79, 0xa3, 0xb7, 0x23, + 0xa5, 0x3f, 0x10, 0x51, 0x64, 0x2d, 0x77, 0x37, + 0x4c, 0x4c, 0x6c, 0x8d, 0xbb, 0x1c, 0xa2, 0x05, + 0x25, 0xf5, 0xc9, 0xf3, 0x2d, 0xb7, 0x76, 0x95, + 0x35, 0x56, 0xda, 0x31, 0x29, 0x0e, 0x22, 0x19, + 0x74, 0x82, 0xce, 0xb6, 0x99, 0x06, 0xc4, 0x6a, + 0x75, 0x8f, 0xb0, 0xe7, 0x40, 0x9b, 0xa8, 0x01, + 0x07, 0x7d, 0x2a, 0x0a, 0x20, 0xea, 0xe7, 0xd1, + 0xd6, 0xd3, 0x92, 0xab, 0x49, 0x57, 0xe8, 0x6b, + 0x76, 0xf0, 0x65, 0x2d, 0x68, 0xb8, 0x39, 0x88, + 0xa7, 0x8f, 0x26, 0xe1, 0x11, 0x72, 0xea, 0x60, + 0x9b, 0xf8, 0x49, 0xfb, 0xbd, 0x78, 0xad, 0x7e, + 0xdc, 0xe2, 0x1d, 0xe6, 0x62, 0xa0, 0x81, 0x36, + 0x8c, 0x04, 0x06, 0x07, 0xce, 0xe2, 0x9d, 0xb0, + 0x62, 0x72, 0x27, 0xf4, 0x49, 0x63, 0xad, 0x17, + 0x1d, 0x22, 0x93, 0xb6, 0x33, 0xa3, 0x92, 0xe3, + 0x31, 0xdc, 0xa5, 0x4f, 0xe3, 0x08, 0x27, 0x52, + 0xf4, 0x3f, 0x63, 0xc1, 0x61, 0xb4, 0x47, 0xa4, + 0xc6, 0x5a, 0x68, 0x75, 0x67, 0x0d, 0x5f, 0x66, + 0x00, 0xfc, 0xc8, 0x60, 0xa1, 0xca, 0xeb, 0x0a, + 0x88, 0xf8, 0xfd, 0xec, 0x4e, 0x56, 0x43, 0x98, + 0xa5, 0xc4, 0x6c, 0x87, 0xf6, 0x8c, 0xe0, 0x70, + 0x01, 0xf6, 0x21, 0x3a, 0xbe, 0x0a, 0xb5, 0x62, + 0x5f, 0x87, 0xd1, 0x90, 0x25, 0xf0, 0x8d, 0x81, + 0xda, 0xc7, 0xbd, 0x45, 0x86, 0xbc, 0x93, 0x82, + 0x19, 0x1f, 0x6d, 0x28, 0x80, 0xf6, 0x22, 0x7e, + 0x5d, 0xf3, 0xee, 0xd2, 0x1e, 0x77, 0x92, 0xd2, + 0x49, 0x48, 0x04, 0x87, 0xf3, 0x65, 0x52, 0x61}, + .sig_len = 256, + .chunks = {50, 100, 0, 75, 4}, + .num_chunks = 5, + }, + { // 43 + .mod = {0xdf, 0x27, 0x1f, 0xd2, 0x5f, 0x86, 0x44, 0x49, + 0x6b, 0x0c, 0x81, 0xbe, 0x4b, 0xd5, 0x02, 0x97, + 0xef, 0x09, 0x9b, 0x00, 0x2a, 0x6f, 0xd6, 0x77, + 0x27, 0xeb, 0x44, 0x9c, 0xea, 0x56, 0x6e, 0xd6, + 0xa3, 0x98, 0x1a, 0x71, 0x31, 0x2a, 0x14, 0x1c, + 0xab, 0xc9, 0x81, 0x5c, 0x12, 0x09, 0xe3, 0x20, + 0xa2, 0x5b, 0x32, 0x46, 0x4e, 0x99, 0x99, 0xf1, + 0x8c, 0xa1, 0x3a, 0x9f, 0xd3, 0x89, 0x25, 0x58, + 0xf9, 0xe0, 0xad, 0xef, 0xdd, 0x36, 0x50, 0xdd, + 0x23, 0xa3, 0xf0, 0x36, 0xd6, 0x0f, 0xe3, 0x98, + 0x84, 0x37, 0x06, 0xa4, 0x0b, 0x0b, 0x84, 0x62, + 0xc8, 0xbe, 0xe3, 0xbc, 0xe1, 0x2f, 0x1f, 0x28, + 0x60, 0xc2, 0x44, 0x4c, 0xdc, 0x6a, 0x44, 0x47, + 0x6a, 0x75, 0xff, 0x4a, 0xa2, 0x42, 0x73, 0xcc, + 0xbe, 0x3b, 0xf8, 0x02, 0x48, 0x46, 0x5f, 0x8f, + 0xf8, 0xc3, 0xa7, 0xf3, 0x36, 0x7d, 0xfc, 0x0d, + 0xf5, 0xb6, 0x50, 0x9a, 0x4f, 0x82, 0x81, 0x1c, + 0xed, 0xd8, 0x1c, 0xda, 0xaa, 0x73, 0xc4, 0x91, + 0xda, 0x41, 0x21, 0x70, 0xd5, 0x44, 0xd4, 0xba, + 0x96, 0xb9, 0x7f, 0x0a, 0xfc, 0x80, 0x65, 0x49, + 0x8d, 0x3a, 0x49, 0xfd, 0x91, 0x09, 0x92, 0xa1, + 0xf0, 0x72, 0x5b, 0xe2, 0x4f, 0x46, 0x5c, 0xfe, + 0x7e, 0x0e, 0xab, 0xf6, 0x78, 0x99, 0x6c, 0x50, + 0xbc, 0x5e, 0x75, 0x24, 0xab, 0xf7, 0x3f, 0x15, + 0xe5, 0xbe, 0xf7, 0xd5, 0x18, 0x39, 0x4e, 0x31, + 0x38, 0xce, 0x49, 0x44, 0x50, 0x6a, 0xaa, 0xaf, + 0x3f, 0x9b, 0x23, 0x6d, 0xca, 0xb8, 0xfc, 0x00, + 0xf8, 0x7a, 0xf5, 0x96, 0xfd, 0xc3, 0xd9, 0xd6, + 0xc7, 0x5c, 0xd5, 0x08, 0x36, 0x2f, 0xae, 0x2c, + 0xbe, 0xdd, 0xcc, 0x4c, 0x74, 0x50, 0xb1, 0x7b, + 0x77, 0x6c, 0x07, 0x9e, 0xcc, 0xa1, 0xf2, 0x56, + 0x35, 0x1a, 0x43, 0xb9, 0x7d, 0xbe, 0x21, 0x53}, + .mod_len = 256, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x5b, 0xd9, 0x10, 0x25, 0x78, 0x30, 0xdc, 0xe1, + 0x75, 0x20, 0xb0, 0x34, 0x41, 0xa5, 0x1a, 0x8c, + 0xab, 0x94, 0x02, 0x0a, 0xc6, 0xec, 0xc2, 0x52, + 0xc8, 0x08, 0xf3, 0x74, 0x3c, 0x95, 0xb7, 0xc8, + 0x3b, 0x8c, 0x8a, 0xf1, 0xa5, 0x01, 0x43, 0x46, + 0xeb, 0xc4, 0x24, 0x2c, 0xdf, 0xb5, 0xd7, 0x18, + 0xe3, 0x0a, 0x73, 0x3e, 0x71, 0xf2, 0x91, 0xe4, + 0xd4, 0x73, 0xb6, 0x1b, 0xfb, 0xa6, 0xda, 0xca, + 0xed, 0x0a, 0x77, 0xbd, 0x1f, 0x09, 0x50, 0xae, + 0x3c, 0x91, 0xa8, 0xf9, 0x01, 0x11, 0x88, 0x25, + 0x89, 0xe1, 0xd6, 0x27, 0x65, 0xee, 0x67, 0x1e, + 0x7b, 0xae, 0xea, 0x30, 0x9f, 0x64, 0xd4, 0x47, + 0xbb, 0xcf, 0xa9, 0xea, 0x12, 0xdc, 0xe0, 0x5e, + 0x9e, 0xa8, 0x93, 0x9b, 0xc5, 0xfe, 0x61, 0x08, + 0x58, 0x12, 0x79, 0xc9, 0x82, 0xb3, 0x08, 0x79, + 0x4b, 0x34, 0x48, 0xe7, 0xf7, 0xb9, 0x52, 0x29, + 0x2d, 0xf8, 0x8c, 0x80, 0xcb, 0x40, 0x14, 0x2c, + 0x4b, 0x5c, 0xf5, 0xf8, 0xdd, 0xaa, 0x08, 0x91, + 0x67, 0x8d, 0x61, 0x0e, 0x58, 0x2f, 0xcb, 0x88, + 0x0f, 0x0d, 0x70, 0x7c, 0xaf, 0x47, 0xd0, 0x9a, + 0x84, 0xe1, 0x4c, 0xa6, 0x58, 0x41, 0xe5, 0xa3, + 0xab, 0xc5, 0xe9, 0xdb, 0xa9, 0x40, 0x75, 0xa9, + 0x08, 0x43, 0x41, 0xf0, 0xed, 0xad, 0x9b, 0x68, + 0xe3, 0xb8, 0xe0, 0x82, 0xb8, 0x0b, 0x6e, 0x6e, + 0x8a, 0x05, 0x47, 0xb4, 0x4f, 0xb5, 0x06, 0x1b, + 0x6a, 0x91, 0x31, 0x60, 0x3a, 0x55, 0x37, 0xdd, + 0xab, 0xd0, 0x1d, 0x8e, 0x86, 0x3d, 0x89, 0x22, + 0xe9, 0xaa, 0x3e, 0x4b, 0xfa, 0xea, 0x0b, 0x39, + 0xd7, 0x92, 0x83, 0xad, 0x2c, 0xbc, 0x8a, 0x59, + 0xcc, 0xe7, 0xa6, 0xec, 0xf4, 0xe4, 0xc8, 0x1e, + 0xd4, 0xc6, 0x59, 0x1c, 0x80, 0x7d, 0xef, 0xd7, + 0x1a, 0xb0, 0x68, 0x66, 0xbb, 0x5e, 0x77, 0x45}, + .privexp_len = 256, + .prime1 = {0xf4, 0x4f, 0x5e, 0x42, 0x46, 0x39, 0x1f, 0x48, + 0x2b, 0x2f, 0x52, 0x96, 0xe3, 0x60, 0x2e, 0xb3, + 0x4a, 0xa1, 0x36, 0x42, 0x77, 0x10, 0xf7, 0xc0, + 0x41, 0x6d, 0x40, 0x3f, 0xd6, 0x9d, 0x4b, 0x29, + 0x13, 0x0c, 0xfe, 0xbe, 0xf3, 0x4e, 0x88, 0x5a, + 0xbd, 0xb1, 0xa8, 0xa0, 0xa5, 0xf0, 0xe9, 0xb5, + 0xc3, 0x3e, 0x1f, 0xc3, 0xbf, 0xc2, 0x85, 0xb1, + 0xae, 0x17, 0xe4, 0x0c, 0xc6, 0x7a, 0x19, 0x13, + 0xdd, 0x56, 0x37, 0x19, 0x81, 0x5e, 0xba, 0xf8, + 0x51, 0x4c, 0x2a, 0x7a, 0xa0, 0x01, 0x8e, 0x63, + 0xb6, 0xc6, 0x31, 0xdc, 0x31, 0x5a, 0x46, 0x23, + 0x57, 0x16, 0x42, 0x3d, 0x11, 0xff, 0x58, 0x03, + 0x4e, 0x61, 0x06, 0x45, 0x70, 0x36, 0x06, 0x91, + 0x9f, 0x5c, 0x7c, 0xe2, 0x66, 0x0c, 0xd1, 0x48, + 0xbd, 0x9e, 0xfc, 0x12, 0x3d, 0x9c, 0x54, 0xb6, + 0x70, 0x55, 0x90, 0xd0, 0x06, 0xcf, 0xcf, 0x3f}, + .prime1_len = 128, + .prime2 = {0xe9, 0xd4, 0x98, 0x41, 0xe0, 0xe0, 0xa6, 0xad, + 0x0d, 0x51, 0x78, 0x57, 0x13, 0x3e, 0x36, 0xdc, + 0x72, 0xc1, 0xbd, 0xd9, 0x0f, 0x91, 0x74, 0xb5, + 0x2e, 0x26, 0x57, 0x0f, 0x37, 0x36, 0x40, 0xf1, + 0xc1, 0x85, 0xe7, 0xea, 0x8e, 0x2e, 0xd7, 0xf1, + 0xe4, 0xeb, 0xb9, 0x51, 0xf7, 0x0a, 0x58, 0x02, + 0x36, 0x33, 0xb0, 0x09, 0x7a, 0xec, 0x67, 0xc6, + 0xdc, 0xb8, 0x00, 0xfc, 0x1a, 0x67, 0xf9, 0xbb, + 0x05, 0x63, 0x61, 0x0f, 0x08, 0xeb, 0xc8, 0x74, + 0x6a, 0xd1, 0x29, 0x77, 0x21, 0x36, 0xeb, 0x1d, + 0xda, 0xf4, 0x64, 0x36, 0x45, 0x0d, 0x31, 0x83, + 0x32, 0xa8, 0x49, 0x82, 0xfe, 0x5d, 0x28, 0xdb, + 0xe5, 0xb3, 0xe9, 0x12, 0x40, 0x7c, 0x3e, 0x0e, + 0x03, 0x10, 0x0d, 0x87, 0xd4, 0x36, 0xee, 0x40, + 0x9e, 0xec, 0x1c, 0xf8, 0x5e, 0x80, 0xab, 0xa0, + 0x79, 0xb2, 0xe6, 0x10, 0x6b, 0x97, 0xbc, 0xed}, + .prime2_len = 128, + .exp1 = {0xed, 0x10, 0x2a, 0xcd, 0xb2, 0x68, 0x71, 0x53, + 0x4d, 0x1c, 0x41, 0x4e, 0xca, 0xd9, 0xa4, 0xd7, + 0x32, 0xfe, 0x95, 0xb1, 0x0e, 0xea, 0x37, 0x0d, + 0xa6, 0x2f, 0x05, 0xde, 0x2c, 0x39, 0x3b, 0x1a, + 0x63, 0x33, 0x03, 0xea, 0x74, 0x1b, 0x6b, 0x32, + 0x69, 0xc9, 0x7f, 0x70, 0x4b, 0x35, 0x27, 0x02, + 0xc9, 0xae, 0x79, 0x92, 0x2f, 0x7b, 0xe8, 0xd1, + 0x0d, 0xb6, 0x7f, 0x02, 0x6a, 0x81, 0x45, 0xde, + 0x41, 0xb3, 0x0c, 0x0a, 0x42, 0xbf, 0x92, 0x3b, + 0xac, 0x5f, 0x75, 0x04, 0xc2, 0x48, 0x60, 0x4b, + 0x9f, 0xaa, 0x57, 0xed, 0x6b, 0x32, 0x46, 0xc6, + 0xba, 0x15, 0x8e, 0x36, 0xc6, 0x44, 0xf8, 0xb9, + 0x54, 0x8f, 0xcf, 0x4f, 0x07, 0xe0, 0x54, 0xa5, + 0x6f, 0x76, 0x86, 0x74, 0x05, 0x44, 0x40, 0xbc, + 0x0d, 0xcb, 0xbc, 0x9b, 0x52, 0x8f, 0x64, 0xa0, + 0x17, 0x06, 0xe0, 0x5b, 0x0b, 0x91, 0x10, 0x6f}, + .exp1_len = 128, + .exp2 = {0x68, 0x27, 0x92, 0x4a, 0x85, 0xe8, 0x8b, 0x55, + 0xba, 0x00, 0xf8, 0x21, 0x91, 0x28, 0xbd, 0x37, + 0x24, 0xc6, 0xb7, 0xd1, 0xdf, 0xe5, 0x62, 0x9e, + 0xf1, 0x97, 0x92, 0x5f, 0xec, 0xaf, 0xf5, 0xed, + 0xb9, 0xcd, 0xf3, 0xa7, 0xbe, 0xfd, 0x8e, 0xa2, + 0xe8, 0xdd, 0x37, 0x07, 0x13, 0x8b, 0x3f, 0xf8, + 0x7c, 0x3c, 0x39, 0xc5, 0x7f, 0x43, 0x9e, 0x56, + 0x2e, 0x2a, 0xa8, 0x05, 0xa3, 0x9d, 0x7c, 0xd7, + 0x99, 0x66, 0xd2, 0xec, 0xe7, 0x84, 0x5f, 0x1d, + 0xbc, 0x16, 0xbe, 0xe9, 0x99, 0x99, 0xe4, 0xd0, + 0xbf, 0x9e, 0xec, 0xa4, 0x5f, 0xcd, 0xa8, 0xa8, + 0x50, 0x00, 0x35, 0xfe, 0x6b, 0x5f, 0x03, 0xbc, + 0x2f, 0x6d, 0x1b, 0xfc, 0x4d, 0x4d, 0x0a, 0x37, + 0x23, 0x96, 0x1a, 0xf0, 0xcd, 0xce, 0x4a, 0x01, + 0xee, 0xc8, 0x2d, 0x7f, 0x54, 0x58, 0xec, 0x19, + 0xe7, 0x1b, 0x90, 0xee, 0xef, 0x7d, 0xff, 0x61}, + .exp2_len = 128, + .coef = {0x57, 0xb7, 0x38, 0x88, 0xd1, 0x83, 0xa9, 0x9a, + 0x63, 0x07, 0x42, 0x22, 0x77, 0x55, 0x1a, 0x3d, + 0x9e, 0x18, 0xad, 0xf0, 0x6a, 0x91, 0xe8, 0xb5, + 0x5c, 0xef, 0xfe, 0xf9, 0x07, 0x7c, 0x84, 0x96, + 0x94, 0x8e, 0xcb, 0x3b, 0x16, 0xb7, 0x81, 0x55, + 0xcb, 0x2a, 0x3a, 0x57, 0xc1, 0x19, 0xd3, 0x79, + 0x95, 0x1c, 0x01, 0x0a, 0xa6, 0x35, 0xed, 0xcf, + 0x62, 0xd8, 0x4c, 0x5a, 0x12, 0x2a, 0x8d, 0x67, + 0xab, 0x5f, 0xa9, 0xe5, 0xa4, 0xa8, 0x77, 0x2a, + 0x1e, 0x94, 0x3b, 0xaf, 0xc7, 0x0a, 0xe3, 0xa4, + 0xc1, 0xf0, 0xf3, 0xa4, 0xdd, 0xff, 0xae, 0xfd, + 0x18, 0x92, 0xc8, 0xcb, 0x33, 0xbb, 0x0d, 0x0b, + 0x95, 0x90, 0xe9, 0x63, 0xa6, 0x91, 0x10, 0xfb, + 0x34, 0xdb, 0x7b, 0x90, 0x6f, 0xc4, 0xba, 0x28, + 0x36, 0x99, 0x5a, 0xac, 0x7e, 0x52, 0x74, 0x90, + 0xac, 0x95, 0x2a, 0x02, 0x26, 0x8a, 0x4f, 0x18}, + .coef_len = 128, + .msg = {0xc1, 0x4b, 0x4c, 0x60, 0x75, 0xb2, 0xf9, 0xaa, + 0xd6, 0x61, 0xde, 0xf4, 0xec, 0xfd, 0x3c, 0xb9, + 0x33, 0xc6, 0x23, 0xf4, 0xe6, 0x3b, 0xf5, 0x34, + 0x10, 0xd2, 0xf0, 0x16, 0xd1, 0xab, 0x98, 0xe2, + 0x72, 0x9e, 0xcc, 0xf8, 0x00, 0x6c, 0xd8, 0xe0, + 0x80, 0x50, 0x73, 0x7d, 0x95, 0xfd, 0xbf, 0x29, + 0x6b, 0x66, 0xf5, 0xb9, 0x79, 0x2a, 0x90, 0x29, + 0x36, 0xc4, 0xf7, 0xac, 0x69, 0xf5, 0x14, 0x53, + 0xce, 0x43, 0x69, 0x45, 0x2d, 0xc2, 0x2d, 0x96, + 0xf0, 0x37, 0x74, 0x81, 0x14, 0x66, 0x20, 0x00, + 0xdd, 0x9c, 0xd3, 0xa5, 0xe1, 0x79, 0xf4, 0xe0, + 0xf8, 0x1f, 0xa6, 0xa0, 0x31, 0x1c, 0xa1, 0xae, + 0xe6, 0x51, 0x9a, 0x0f, 0x63, 0xce, 0xc7, 0x8d, + 0x27, 0xbb, 0x72, 0x63, 0x93, 0xfb, 0x7f, 0x1f, + 0x88, 0xcd, 0xe7, 0xc9, 0x7f, 0x8a, 0x66, 0xcd, + 0x66, 0x30, 0x12, 0x81, 0xda, 0xc3, 0xf3, 0xa4, + 0x33, 0x24, 0x8c, 0x75, 0xd6, 0xc2, 0xdc, 0xd7, + 0x08, 0xb6, 0xa9, 0x7b, 0x0a, 0x3f, 0x32, 0x5e, + 0x0b, 0x29, 0x64, 0xf8, 0xa5, 0x81, 0x9e, 0x47, + 0x9b}, + .msg_len = 153, + .sig = {0xaf, 0xa7, 0x34, 0x34, 0x62, 0xbe, 0xa1, 0x22, + 0xcc, 0x14, 0x9f, 0xca, 0x70, 0xab, 0xda, 0xe7, + 0x94, 0x46, 0x67, 0x7d, 0xb5, 0x37, 0x36, 0x66, + 0xaf, 0x7d, 0xc3, 0x13, 0x01, 0x5f, 0x4d, 0xe7, + 0x86, 0xe6, 0xe3, 0x94, 0x94, 0x6f, 0xad, 0x3c, + 0xc0, 0xe2, 0xb0, 0x2b, 0xed, 0xba, 0x50, 0x47, + 0xfe, 0x9e, 0x2d, 0x7d, 0x09, 0x97, 0x05, 0xe4, + 0xa3, 0x9f, 0x28, 0x68, 0x32, 0x79, 0xcf, 0x0a, + 0xc8, 0x5c, 0x15, 0x30, 0x41, 0x22, 0x42, 0xc0, + 0xe9, 0x18, 0x95, 0x3b, 0xe0, 0x00, 0xe9, 0x39, + 0xcf, 0x3b, 0xf1, 0x82, 0x52, 0x5e, 0x19, 0x93, + 0x70, 0xfa, 0x79, 0x07, 0xeb, 0xa6, 0x9d, 0x5d, + 0xb4, 0x63, 0x10, 0x17, 0xc0, 0xe3, 0x6d, 0xf7, + 0x03, 0x79, 0xb5, 0xdb, 0x8d, 0x4c, 0x69, 0x5a, + 0x97, 0x9a, 0x8e, 0x61, 0x73, 0x22, 0x40, 0x65, + 0xd7, 0xdc, 0x15, 0x13, 0x2e, 0xf2, 0x8c, 0xd8, + 0x22, 0x79, 0x51, 0x63, 0x06, 0x3b, 0x54, 0xc6, + 0x51, 0x14, 0x1b, 0xe8, 0x6d, 0x36, 0xe3, 0x67, + 0x35, 0xbc, 0x61, 0xf3, 0x1f, 0xca, 0x57, 0x4e, + 0x53, 0x09, 0xf3, 0xa3, 0xbb, 0xdf, 0x91, 0xef, + 0xf1, 0x2b, 0x99, 0xe9, 0xcc, 0x17, 0x44, 0xf1, + 0xee, 0x9a, 0x1b, 0xd2, 0x2c, 0x5b, 0xad, 0x96, + 0xad, 0x48, 0x19, 0x29, 0x25, 0x1f, 0x03, 0x43, + 0xfd, 0x36, 0xbc, 0xf0, 0xac, 0xde, 0x7f, 0x11, + 0xe5, 0xad, 0x60, 0x97, 0x77, 0x21, 0x20, 0x27, + 0x96, 0xfe, 0x06, 0x1f, 0x9a, 0xda, 0x1f, 0xc4, + 0xc8, 0xe0, 0x0d, 0x60, 0x22, 0xa8, 0x35, 0x75, + 0x85, 0xff, 0xe9, 0xfd, 0xd5, 0x93, 0x31, 0xa2, + 0x8c, 0x4a, 0xa3, 0x12, 0x15, 0x88, 0xfb, 0x6c, + 0xf6, 0x83, 0x96, 0xd8, 0xac, 0x05, 0x46, 0x59, + 0x95, 0x00, 0xc9, 0x70, 0x85, 0x00, 0xa5, 0x97, + 0x2b, 0xd5, 0x4f, 0x72, 0xcf, 0x8d, 0xb0, 0xc8}, + .sig_len = 256, + .chunks = {80, -1, 73}, + .num_chunks = 3, + }, + { // 44 + .mod = {0xdf, 0x27, 0x1f, 0xd2, 0x5f, 0x86, 0x44, 0x49, + 0x6b, 0x0c, 0x81, 0xbe, 0x4b, 0xd5, 0x02, 0x97, + 0xef, 0x09, 0x9b, 0x00, 0x2a, 0x6f, 0xd6, 0x77, + 0x27, 0xeb, 0x44, 0x9c, 0xea, 0x56, 0x6e, 0xd6, + 0xa3, 0x98, 0x1a, 0x71, 0x31, 0x2a, 0x14, 0x1c, + 0xab, 0xc9, 0x81, 0x5c, 0x12, 0x09, 0xe3, 0x20, + 0xa2, 0x5b, 0x32, 0x46, 0x4e, 0x99, 0x99, 0xf1, + 0x8c, 0xa1, 0x3a, 0x9f, 0xd3, 0x89, 0x25, 0x58, + 0xf9, 0xe0, 0xad, 0xef, 0xdd, 0x36, 0x50, 0xdd, + 0x23, 0xa3, 0xf0, 0x36, 0xd6, 0x0f, 0xe3, 0x98, + 0x84, 0x37, 0x06, 0xa4, 0x0b, 0x0b, 0x84, 0x62, + 0xc8, 0xbe, 0xe3, 0xbc, 0xe1, 0x2f, 0x1f, 0x28, + 0x60, 0xc2, 0x44, 0x4c, 0xdc, 0x6a, 0x44, 0x47, + 0x6a, 0x75, 0xff, 0x4a, 0xa2, 0x42, 0x73, 0xcc, + 0xbe, 0x3b, 0xf8, 0x02, 0x48, 0x46, 0x5f, 0x8f, + 0xf8, 0xc3, 0xa7, 0xf3, 0x36, 0x7d, 0xfc, 0x0d, + 0xf5, 0xb6, 0x50, 0x9a, 0x4f, 0x82, 0x81, 0x1c, + 0xed, 0xd8, 0x1c, 0xda, 0xaa, 0x73, 0xc4, 0x91, + 0xda, 0x41, 0x21, 0x70, 0xd5, 0x44, 0xd4, 0xba, + 0x96, 0xb9, 0x7f, 0x0a, 0xfc, 0x80, 0x65, 0x49, + 0x8d, 0x3a, 0x49, 0xfd, 0x91, 0x09, 0x92, 0xa1, + 0xf0, 0x72, 0x5b, 0xe2, 0x4f, 0x46, 0x5c, 0xfe, + 0x7e, 0x0e, 0xab, 0xf6, 0x78, 0x99, 0x6c, 0x50, + 0xbc, 0x5e, 0x75, 0x24, 0xab, 0xf7, 0x3f, 0x15, + 0xe5, 0xbe, 0xf7, 0xd5, 0x18, 0x39, 0x4e, 0x31, + 0x38, 0xce, 0x49, 0x44, 0x50, 0x6a, 0xaa, 0xaf, + 0x3f, 0x9b, 0x23, 0x6d, 0xca, 0xb8, 0xfc, 0x00, + 0xf8, 0x7a, 0xf5, 0x96, 0xfd, 0xc3, 0xd9, 0xd6, + 0xc7, 0x5c, 0xd5, 0x08, 0x36, 0x2f, 0xae, 0x2c, + 0xbe, 0xdd, 0xcc, 0x4c, 0x74, 0x50, 0xb1, 0x7b, + 0x77, 0x6c, 0x07, 0x9e, 0xcc, 0xa1, 0xf2, 0x56, + 0x35, 0x1a, 0x43, 0xb9, 0x7d, 0xbe, 0x21, 0x53}, + .mod_len = 256, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x5b, 0xd9, 0x10, 0x25, 0x78, 0x30, 0xdc, 0xe1, + 0x75, 0x20, 0xb0, 0x34, 0x41, 0xa5, 0x1a, 0x8c, + 0xab, 0x94, 0x02, 0x0a, 0xc6, 0xec, 0xc2, 0x52, + 0xc8, 0x08, 0xf3, 0x74, 0x3c, 0x95, 0xb7, 0xc8, + 0x3b, 0x8c, 0x8a, 0xf1, 0xa5, 0x01, 0x43, 0x46, + 0xeb, 0xc4, 0x24, 0x2c, 0xdf, 0xb5, 0xd7, 0x18, + 0xe3, 0x0a, 0x73, 0x3e, 0x71, 0xf2, 0x91, 0xe4, + 0xd4, 0x73, 0xb6, 0x1b, 0xfb, 0xa6, 0xda, 0xca, + 0xed, 0x0a, 0x77, 0xbd, 0x1f, 0x09, 0x50, 0xae, + 0x3c, 0x91, 0xa8, 0xf9, 0x01, 0x11, 0x88, 0x25, + 0x89, 0xe1, 0xd6, 0x27, 0x65, 0xee, 0x67, 0x1e, + 0x7b, 0xae, 0xea, 0x30, 0x9f, 0x64, 0xd4, 0x47, + 0xbb, 0xcf, 0xa9, 0xea, 0x12, 0xdc, 0xe0, 0x5e, + 0x9e, 0xa8, 0x93, 0x9b, 0xc5, 0xfe, 0x61, 0x08, + 0x58, 0x12, 0x79, 0xc9, 0x82, 0xb3, 0x08, 0x79, + 0x4b, 0x34, 0x48, 0xe7, 0xf7, 0xb9, 0x52, 0x29, + 0x2d, 0xf8, 0x8c, 0x80, 0xcb, 0x40, 0x14, 0x2c, + 0x4b, 0x5c, 0xf5, 0xf8, 0xdd, 0xaa, 0x08, 0x91, + 0x67, 0x8d, 0x61, 0x0e, 0x58, 0x2f, 0xcb, 0x88, + 0x0f, 0x0d, 0x70, 0x7c, 0xaf, 0x47, 0xd0, 0x9a, + 0x84, 0xe1, 0x4c, 0xa6, 0x58, 0x41, 0xe5, 0xa3, + 0xab, 0xc5, 0xe9, 0xdb, 0xa9, 0x40, 0x75, 0xa9, + 0x08, 0x43, 0x41, 0xf0, 0xed, 0xad, 0x9b, 0x68, + 0xe3, 0xb8, 0xe0, 0x82, 0xb8, 0x0b, 0x6e, 0x6e, + 0x8a, 0x05, 0x47, 0xb4, 0x4f, 0xb5, 0x06, 0x1b, + 0x6a, 0x91, 0x31, 0x60, 0x3a, 0x55, 0x37, 0xdd, + 0xab, 0xd0, 0x1d, 0x8e, 0x86, 0x3d, 0x89, 0x22, + 0xe9, 0xaa, 0x3e, 0x4b, 0xfa, 0xea, 0x0b, 0x39, + 0xd7, 0x92, 0x83, 0xad, 0x2c, 0xbc, 0x8a, 0x59, + 0xcc, 0xe7, 0xa6, 0xec, 0xf4, 0xe4, 0xc8, 0x1e, + 0xd4, 0xc6, 0x59, 0x1c, 0x80, 0x7d, 0xef, 0xd7, + 0x1a, 0xb0, 0x68, 0x66, 0xbb, 0x5e, 0x77, 0x45}, + .privexp_len = 256, + .prime1 = {0xf4, 0x4f, 0x5e, 0x42, 0x46, 0x39, 0x1f, 0x48, + 0x2b, 0x2f, 0x52, 0x96, 0xe3, 0x60, 0x2e, 0xb3, + 0x4a, 0xa1, 0x36, 0x42, 0x77, 0x10, 0xf7, 0xc0, + 0x41, 0x6d, 0x40, 0x3f, 0xd6, 0x9d, 0x4b, 0x29, + 0x13, 0x0c, 0xfe, 0xbe, 0xf3, 0x4e, 0x88, 0x5a, + 0xbd, 0xb1, 0xa8, 0xa0, 0xa5, 0xf0, 0xe9, 0xb5, + 0xc3, 0x3e, 0x1f, 0xc3, 0xbf, 0xc2, 0x85, 0xb1, + 0xae, 0x17, 0xe4, 0x0c, 0xc6, 0x7a, 0x19, 0x13, + 0xdd, 0x56, 0x37, 0x19, 0x81, 0x5e, 0xba, 0xf8, + 0x51, 0x4c, 0x2a, 0x7a, 0xa0, 0x01, 0x8e, 0x63, + 0xb6, 0xc6, 0x31, 0xdc, 0x31, 0x5a, 0x46, 0x23, + 0x57, 0x16, 0x42, 0x3d, 0x11, 0xff, 0x58, 0x03, + 0x4e, 0x61, 0x06, 0x45, 0x70, 0x36, 0x06, 0x91, + 0x9f, 0x5c, 0x7c, 0xe2, 0x66, 0x0c, 0xd1, 0x48, + 0xbd, 0x9e, 0xfc, 0x12, 0x3d, 0x9c, 0x54, 0xb6, + 0x70, 0x55, 0x90, 0xd0, 0x06, 0xcf, 0xcf, 0x3f}, + .prime1_len = 128, + .prime2 = {0xe9, 0xd4, 0x98, 0x41, 0xe0, 0xe0, 0xa6, 0xad, + 0x0d, 0x51, 0x78, 0x57, 0x13, 0x3e, 0x36, 0xdc, + 0x72, 0xc1, 0xbd, 0xd9, 0x0f, 0x91, 0x74, 0xb5, + 0x2e, 0x26, 0x57, 0x0f, 0x37, 0x36, 0x40, 0xf1, + 0xc1, 0x85, 0xe7, 0xea, 0x8e, 0x2e, 0xd7, 0xf1, + 0xe4, 0xeb, 0xb9, 0x51, 0xf7, 0x0a, 0x58, 0x02, + 0x36, 0x33, 0xb0, 0x09, 0x7a, 0xec, 0x67, 0xc6, + 0xdc, 0xb8, 0x00, 0xfc, 0x1a, 0x67, 0xf9, 0xbb, + 0x05, 0x63, 0x61, 0x0f, 0x08, 0xeb, 0xc8, 0x74, + 0x6a, 0xd1, 0x29, 0x77, 0x21, 0x36, 0xeb, 0x1d, + 0xda, 0xf4, 0x64, 0x36, 0x45, 0x0d, 0x31, 0x83, + 0x32, 0xa8, 0x49, 0x82, 0xfe, 0x5d, 0x28, 0xdb, + 0xe5, 0xb3, 0xe9, 0x12, 0x40, 0x7c, 0x3e, 0x0e, + 0x03, 0x10, 0x0d, 0x87, 0xd4, 0x36, 0xee, 0x40, + 0x9e, 0xec, 0x1c, 0xf8, 0x5e, 0x80, 0xab, 0xa0, + 0x79, 0xb2, 0xe6, 0x10, 0x6b, 0x97, 0xbc, 0xed}, + .prime2_len = 128, + .exp1 = {0xed, 0x10, 0x2a, 0xcd, 0xb2, 0x68, 0x71, 0x53, + 0x4d, 0x1c, 0x41, 0x4e, 0xca, 0xd9, 0xa4, 0xd7, + 0x32, 0xfe, 0x95, 0xb1, 0x0e, 0xea, 0x37, 0x0d, + 0xa6, 0x2f, 0x05, 0xde, 0x2c, 0x39, 0x3b, 0x1a, + 0x63, 0x33, 0x03, 0xea, 0x74, 0x1b, 0x6b, 0x32, + 0x69, 0xc9, 0x7f, 0x70, 0x4b, 0x35, 0x27, 0x02, + 0xc9, 0xae, 0x79, 0x92, 0x2f, 0x7b, 0xe8, 0xd1, + 0x0d, 0xb6, 0x7f, 0x02, 0x6a, 0x81, 0x45, 0xde, + 0x41, 0xb3, 0x0c, 0x0a, 0x42, 0xbf, 0x92, 0x3b, + 0xac, 0x5f, 0x75, 0x04, 0xc2, 0x48, 0x60, 0x4b, + 0x9f, 0xaa, 0x57, 0xed, 0x6b, 0x32, 0x46, 0xc6, + 0xba, 0x15, 0x8e, 0x36, 0xc6, 0x44, 0xf8, 0xb9, + 0x54, 0x8f, 0xcf, 0x4f, 0x07, 0xe0, 0x54, 0xa5, + 0x6f, 0x76, 0x86, 0x74, 0x05, 0x44, 0x40, 0xbc, + 0x0d, 0xcb, 0xbc, 0x9b, 0x52, 0x8f, 0x64, 0xa0, + 0x17, 0x06, 0xe0, 0x5b, 0x0b, 0x91, 0x10, 0x6f}, + .exp1_len = 128, + .exp2 = {0x68, 0x27, 0x92, 0x4a, 0x85, 0xe8, 0x8b, 0x55, + 0xba, 0x00, 0xf8, 0x21, 0x91, 0x28, 0xbd, 0x37, + 0x24, 0xc6, 0xb7, 0xd1, 0xdf, 0xe5, 0x62, 0x9e, + 0xf1, 0x97, 0x92, 0x5f, 0xec, 0xaf, 0xf5, 0xed, + 0xb9, 0xcd, 0xf3, 0xa7, 0xbe, 0xfd, 0x8e, 0xa2, + 0xe8, 0xdd, 0x37, 0x07, 0x13, 0x8b, 0x3f, 0xf8, + 0x7c, 0x3c, 0x39, 0xc5, 0x7f, 0x43, 0x9e, 0x56, + 0x2e, 0x2a, 0xa8, 0x05, 0xa3, 0x9d, 0x7c, 0xd7, + 0x99, 0x66, 0xd2, 0xec, 0xe7, 0x84, 0x5f, 0x1d, + 0xbc, 0x16, 0xbe, 0xe9, 0x99, 0x99, 0xe4, 0xd0, + 0xbf, 0x9e, 0xec, 0xa4, 0x5f, 0xcd, 0xa8, 0xa8, + 0x50, 0x00, 0x35, 0xfe, 0x6b, 0x5f, 0x03, 0xbc, + 0x2f, 0x6d, 0x1b, 0xfc, 0x4d, 0x4d, 0x0a, 0x37, + 0x23, 0x96, 0x1a, 0xf0, 0xcd, 0xce, 0x4a, 0x01, + 0xee, 0xc8, 0x2d, 0x7f, 0x54, 0x58, 0xec, 0x19, + 0xe7, 0x1b, 0x90, 0xee, 0xef, 0x7d, 0xff, 0x61}, + .exp2_len = 128, + .coef = {0x57, 0xb7, 0x38, 0x88, 0xd1, 0x83, 0xa9, 0x9a, + 0x63, 0x07, 0x42, 0x22, 0x77, 0x55, 0x1a, 0x3d, + 0x9e, 0x18, 0xad, 0xf0, 0x6a, 0x91, 0xe8, 0xb5, + 0x5c, 0xef, 0xfe, 0xf9, 0x07, 0x7c, 0x84, 0x96, + 0x94, 0x8e, 0xcb, 0x3b, 0x16, 0xb7, 0x81, 0x55, + 0xcb, 0x2a, 0x3a, 0x57, 0xc1, 0x19, 0xd3, 0x79, + 0x95, 0x1c, 0x01, 0x0a, 0xa6, 0x35, 0xed, 0xcf, + 0x62, 0xd8, 0x4c, 0x5a, 0x12, 0x2a, 0x8d, 0x67, + 0xab, 0x5f, 0xa9, 0xe5, 0xa4, 0xa8, 0x77, 0x2a, + 0x1e, 0x94, 0x3b, 0xaf, 0xc7, 0x0a, 0xe3, 0xa4, + 0xc1, 0xf0, 0xf3, 0xa4, 0xdd, 0xff, 0xae, 0xfd, + 0x18, 0x92, 0xc8, 0xcb, 0x33, 0xbb, 0x0d, 0x0b, + 0x95, 0x90, 0xe9, 0x63, 0xa6, 0x91, 0x10, 0xfb, + 0x34, 0xdb, 0x7b, 0x90, 0x6f, 0xc4, 0xba, 0x28, + 0x36, 0x99, 0x5a, 0xac, 0x7e, 0x52, 0x74, 0x90, + 0xac, 0x95, 0x2a, 0x02, 0x26, 0x8a, 0x4f, 0x18}, + .coef_len = 128, + .msg = {0xd0, 0x23, 0x71, 0xad, 0x7e, 0xe4, 0x8b, 0xbf, + 0xdb, 0x27, 0x63, 0xde, 0x7a, 0x84, 0x3b, 0x94, + 0x08, 0xce, 0x5e, 0xb5, 0xab, 0xf8, 0x47, 0xca, + 0x3d, 0x73, 0x59, 0x86, 0xdf, 0x84, 0xe9, 0x06, + 0x0b, 0xdb, 0xcd, 0xd3, 0xa5, 0x5b, 0xa5, 0x5d, + 0xde, 0x20, 0xd4, 0x76, 0x1e, 0x1a, 0x21, 0xd2, + 0x25, 0xc1, 0xa1, 0x86, 0xf4, 0xac, 0x4b, 0x30, + 0x19, 0xd3, 0xad, 0xf7, 0x8f, 0xe6, 0x33, 0x46, + 0x67, 0xf5, 0x6f, 0x70, 0xc9, 0x01, 0xa0, 0xa2, + 0x70, 0x0c, 0x6f, 0x0d, 0x56, 0xad, 0xd7, 0x19, + 0x59, 0x2d, 0xc8, 0x8f, 0x6d, 0x23, 0x06, 0xc7, + 0x00, 0x9f, 0x6e, 0x7a, 0x63, 0x5b, 0x4c, 0xb3, + 0xa5, 0x02, 0xdf, 0xe6, 0x8d, 0xdc, 0x58, 0xd0, + 0x3b, 0xe1, 0x0a, 0x11, 0x70, 0x00, 0x4f, 0xe7, + 0x4d, 0xd3, 0xe4, 0x6b, 0x82, 0x59, 0x1f, 0xf7, + 0x54, 0x14, 0xf0, 0xc4, 0xa0, 0x3e, 0x60, 0x5e, + 0x20, 0x52, 0x4f, 0x24, 0x16, 0xf1, 0x2e, 0xca, + 0x58, 0x9f, 0x11, 0x1b, 0x75, 0xd6, 0x39, 0xc6, + 0x1b, 0xaa, 0x80, 0xca, 0xfd, 0x05, 0xcf, 0x35, + 0x00, 0x24, 0x4a, 0x21, 0x9e, 0xd9, 0xce, 0xd9, + 0xf0, 0xb1, 0x02, 0x97, 0x18, 0x2b, 0x65, 0x3b, + 0x52, 0x6f, 0x40, 0x0f, 0x29, 0x53, 0xba, 0x21, + 0x4d, 0x5b, 0xcd, 0x47, 0x88, 0x41, 0x32, 0x87, + 0x2a, 0xe9, 0x0d, 0x4d, 0x6b, 0x1f, 0x42, 0x15, + 0x39, 0xf9, 0xf3, 0x46, 0x62, 0xa5, 0x6d, 0xc0, + 0xe7, 0xb4, 0xb9, 0x23, 0xb6, 0x23, 0x1e, 0x30, + 0xd2, 0x67, 0x67, 0x97, 0x81, 0x7f, 0x7c, 0x33, + 0x7b, 0x5a, 0xc8, 0x24, 0xba, 0x93, 0x14, 0x3b, + 0x33, 0x81, 0xfa, 0x3d, 0xce, 0x0e, 0x6a, 0xeb, + 0xd3, 0x8e, 0x67, 0x73, 0x51, 0x87, 0xb1, 0xeb, + 0xd9, 0x5c, 0x02}, + .msg_len = 243, + .sig = {0x3b, 0xac, 0x63, 0xf8, 0x6e, 0x3b, 0x70, 0x27, + 0x12, 0x03, 0x10, 0x6b, 0x9c, 0x79, 0xaa, 0xbd, + 0x9f, 0x47, 0x7c, 0x56, 0xe4, 0xee, 0x58, 0xa4, + 0xfc, 0xe5, 0xba, 0xf2, 0xca, 0xb4, 0x96, 0x0f, + 0x88, 0x39, 0x1c, 0x9c, 0x23, 0x69, 0x8b, 0xe7, + 0x5c, 0x99, 0xae, 0xdf, 0x9e, 0x1a, 0xbf, 0x17, + 0x05, 0xbe, 0x1d, 0xac, 0x33, 0x14, 0x0a, 0xdb, + 0x48, 0xeb, 0x31, 0xf4, 0x50, 0xbb, 0x9e, 0xfe, + 0x83, 0xb7, 0xb9, 0x0d, 0xb7, 0xf1, 0x57, 0x6d, + 0x33, 0xf4, 0x0c, 0x1c, 0xba, 0x4b, 0x8d, 0x6b, + 0x1d, 0x33, 0x23, 0x56, 0x4b, 0x0f, 0x17, 0x74, + 0x11, 0x4f, 0xa7, 0xc0, 0x8e, 0x6d, 0x1e, 0x20, + 0xdd, 0x8f, 0xbb, 0xa9, 0xb6, 0xac, 0x7a, 0xd4, + 0x1e, 0x26, 0xb4, 0x56, 0x8f, 0x4a, 0x8a, 0xac, + 0xbf, 0xd1, 0x78, 0xa8, 0xf8, 0xd2, 0xc9, 0xd5, + 0xf5, 0xb8, 0x81, 0x12, 0x93, 0x5a, 0x8b, 0xc9, + 0xae, 0x32, 0xcd, 0xa4, 0x0b, 0x8d, 0x20, 0x37, + 0x55, 0x10, 0x73, 0x50, 0x96, 0x53, 0x68, 0x18, + 0xce, 0x2b, 0x2d, 0xb7, 0x1a, 0x97, 0x72, 0xc9, + 0xb0, 0xdd, 0xa0, 0x9a, 0xe1, 0x01, 0x52, 0xfa, + 0x11, 0x46, 0x62, 0x18, 0xd0, 0x91, 0xb5, 0x3d, + 0x92, 0x54, 0x30, 0x61, 0xb7, 0x29, 0x4a, 0x55, + 0xbe, 0x82, 0xff, 0x35, 0xd5, 0xc3, 0x2f, 0xa2, + 0x33, 0xf0, 0x5a, 0xaa, 0xc7, 0x58, 0x50, 0x30, + 0x7e, 0xcf, 0x81, 0x38, 0x3c, 0x11, 0x16, 0x74, + 0x39, 0x7b, 0x1a, 0x1b, 0x9d, 0x3b, 0xf7, 0x61, + 0x2c, 0xcb, 0xe5, 0xba, 0xcd, 0x2b, 0x38, 0xf0, + 0xa9, 0x83, 0x97, 0xb2, 0x4c, 0x83, 0x65, 0x8f, + 0xb6, 0xc0, 0xb4, 0x14, 0x0e, 0xf1, 0x19, 0x70, + 0xc4, 0x63, 0x0d, 0x44, 0x34, 0x4e, 0x76, 0xea, + 0xed, 0x74, 0xdc, 0xbe, 0xe8, 0x11, 0xdb, 0xf6, + 0x57, 0x59, 0x41, 0xf0, 0x8a, 0x65, 0x23, 0xb8}, + .sig_len = 256, + .chunks = {100, 100, 43}, + .num_chunks = 3, + }, +}; + +struct RSA_PUBLISHED_TEST_VECTOR rsa_sha256_pkcs_sigver_published_tv[] = { + + { // #0 - 1024 bit key size + .mod = {0xa8, 0xd6, 0x8a, 0xcd, 0x41, 0x3c, 0x5e, 0x19, + 0x5d, 0x5e, 0xf0, 0x4e, 0x1b, 0x4f, 0xaa, 0xf2, + 0x42, 0x36, 0x5c, 0xb4, 0x50, 0x19, 0x67, 0x55, + 0xe9, 0x2e, 0x12, 0x15, 0xba, 0x59, 0x80, 0x2a, + 0xaf, 0xba, 0xdb, 0xf2, 0x56, 0x4d, 0xd5, 0x50, + 0x95, 0x6a, 0xbb, 0x54, 0xf8, 0xb1, 0xc9, 0x17, + 0x84, 0x4e, 0x5f, 0x36, 0x19, 0x5d, 0x10, 0x88, + 0xc6, 0x00, 0xe0, 0x7c, 0xad, 0xa5, 0xc0, 0x80, + 0xed, 0xe6, 0x79, 0xf5, 0x0b, 0x3d, 0xe3, 0x2c, + 0xf4, 0x02, 0x6e, 0x51, 0x45, 0x42, 0x49, 0x5c, + 0x54, 0xb1, 0x90, 0x37, 0x68, 0x79, 0x1a, 0xae, + 0x9e, 0x36, 0xf0, 0x82, 0xcd, 0x38, 0xe9, 0x41, + 0xad, 0xa8, 0x9b, 0xae, 0xca, 0xda, 0x61, 0xab, + 0x0d, 0xd3, 0x7a, 0xd5, 0x36, 0xbc, 0xb0, 0xa0, + 0x94, 0x62, 0x71, 0x59, 0x48, 0x36, 0xe9, 0x2a, + 0xb5, 0x51, 0x73, 0x01, 0xd4, 0x51, 0x76, 0xb5}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0xa3, 0xcd, 0x31, 0x70, 0x9d, 0x1f, 0xd2, 0x33, + 0x4d, 0x90, 0xf4, 0x16, 0xf3, 0x0c, 0x41, 0xcf, + 0x33, 0x49, 0xc6, 0x7a, 0xf1, 0x53, 0x14, 0x1c, + 0x17, 0x54, 0x29, 0x1b, 0x87, 0x65, 0x99, 0xa0, + 0xd0, 0x48, 0xbb, 0x66, 0xcb, 0x30, 0x4c, 0x0a, + 0x18, 0x4c, 0x2a, 0x5e, 0xef, 0xc0, 0x9c, 0x56, + 0x02, 0x78, 0x7e, 0x8a, 0xdf, 0xe4, 0x98, 0x4b, + 0xf9, 0xbd, 0x94, 0x0d, 0xa1, 0xf2, 0xb3, 0x65, + 0x4d, 0xe5, 0x90, 0x7d, 0xb9, 0xe2, 0xc3, 0x80, + 0xce, 0x7b, 0xe4, 0x0b, 0x2f, 0xd3, 0x76, 0xc2, + 0x8d, 0xee, 0xc3, 0x34, 0x6f, 0xcd, 0x3a, 0x1a, + 0xc9, 0xd7, 0x68, 0xaf, 0x39, 0x2d, 0x14, 0xb7, + 0x7b, 0x7c, 0x9f, 0x32, 0x93, 0x28, 0xa9, 0x7b, + 0xc5, 0xdc, 0x93, 0xab, 0x17, 0xce, 0x09, 0x3c, + 0x32, 0xbe, 0x3e, 0xab, 0x85, 0x07, 0x5b, 0x6e, + 0xbb, 0xeb, 0x29, 0x95, 0xe8, 0x66, 0x2d, 0x41}, + .privexp_len = 128, + .prime1 = {0xdf, 0xea, 0x98, 0x4c, 0xe4, 0x30, 0x7e, 0xaf, + 0xc0, 0xd1, 0x40, 0xc2, 0xbb, 0x82, 0x86, 0x1e, + 0x5d, 0xba, 0xc4, 0xf8, 0x56, 0x7c, 0xbc, 0x98, + 0x1d, 0x70, 0x44, 0x0d, 0xd6, 0x39, 0x49, 0x20, + 0x79, 0x03, 0x14, 0x86, 0x31, 0x5e, 0x30, 0x5e, + 0xb8, 0x3e, 0x59, 0x1c, 0x4a, 0x2e, 0x96, 0x06, + 0x49, 0x66, 0xf7, 0xc8, 0x94, 0xc3, 0xca, 0x35, + 0x19, 0x25, 0xb5, 0xce, 0x82, 0xd8, 0xef, 0x0d}, + .prime1_len = 64, + .prime2 = {0xc1, 0x07, 0xa2, 0xfe, 0x92, 0x4b, 0x76, 0xe2, + 0x06, 0xcb, 0x9b, 0xc4, 0xaf, 0x2a, 0xb7, 0x00, + 0x85, 0x47, 0xc0, 0x08, 0x46, 0xbf, 0x6d, 0x06, + 0x80, 0xb3, 0xea, 0xc3, 0xeb, 0xcb, 0xd0, 0xc7, + 0xfd, 0x7a, 0x54, 0xc2, 0xb9, 0x89, 0x9b, 0x08, + 0xf8, 0x0c, 0xde, 0x1d, 0x36, 0x91, 0xea, 0xaa, + 0x28, 0x16, 0xb1, 0xeb, 0x11, 0x82, 0x2d, 0x6b, + 0xe7, 0xbe, 0xaf, 0x4e, 0x30, 0x97, 0x7c, 0x49}, + .prime2_len = 64, + .exp1 = {0xcd, 0x39, 0x54, 0x71, 0x54, 0xcb, 0x65, 0xb1, + 0x6b, 0xc5, 0xdd, 0xd7, 0x1c, 0xc8, 0xda, 0x67, + 0xc6, 0x7c, 0x41, 0xbf, 0x62, 0x75, 0x5c, 0xdd, + 0x06, 0x4e, 0x38, 0xf1, 0x7d, 0xa0, 0x6f, 0x77, + 0x85, 0xb1, 0xdf, 0x03, 0xc7, 0x07, 0x8e, 0xc9, + 0xa1, 0x8f, 0xf3, 0x58, 0x4c, 0x5d, 0x3a, 0x3f, + 0x74, 0xd3, 0x1c, 0xd3, 0x08, 0x16, 0x12, 0xa4, + 0x6b, 0xf1, 0xf6, 0x19, 0xda, 0x2f, 0x3d, 0x99}, + .exp1_len = 64, + .exp2 = {0xc0, 0x6d, 0xd1, 0x82, 0x80, 0xea, 0xf4, 0x1f, + 0xcd, 0x70, 0x6a, 0xdf, 0xbf, 0x54, 0x10, 0xcd, + 0x57, 0x10, 0xb9, 0x12, 0x47, 0x1d, 0x0c, 0x1e, + 0x00, 0x6d, 0xdb, 0xaa, 0xe6, 0xc4, 0xef, 0x64, + 0x7f, 0x7f, 0xd5, 0x41, 0xad, 0xde, 0xcd, 0x0c, + 0x3a, 0xe3, 0xf1, 0x05, 0x24, 0x62, 0x80, 0x92, + 0x92, 0x96, 0x55, 0x55, 0xa6, 0xc5, 0xa4, 0x6c, + 0x3e, 0xc1, 0xac, 0x57, 0x81, 0x3f, 0x72, 0xe9}, + .exp2_len = 64, + .coef = {0x49, 0x80, 0xae, 0xd5, 0x25, 0xff, 0x0e, 0x0e, + 0xa4, 0x73, 0x7a, 0x4e, 0x61, 0x19, 0x2e, 0x2b, + 0x11, 0x09, 0x05, 0xf1, 0xc4, 0xf2, 0xf6, 0x4d, + 0x04, 0x2f, 0xd9, 0xa5, 0x22, 0xd5, 0xe5, 0x73, + 0xfc, 0xfa, 0xd2, 0x01, 0x03, 0xef, 0x52, 0x80, + 0xc6, 0x4b, 0xe8, 0x7a, 0x38, 0x50, 0x55, 0xb7, + 0x6d, 0x7f, 0x56, 0xdf, 0xef, 0xdf, 0xb2, 0xca, + 0x98, 0xb5, 0xc9, 0x55, 0x90, 0x2f, 0x08, 0x84}, + .coef_len = 64, + .msg = {0xff, 0x23, 0xe0, 0x0f, 0x81, 0x9b, 0xae, 0x42, + 0x4e, 0x41, 0xd6, 0xb7, 0x62, 0xea, 0x6b, 0x88, + 0x80, 0x1e, 0x65, 0x1c, 0x83, 0x1c, 0x96, 0x4a, + 0xf3, 0x1d, 0xe0, 0xc1, 0xd6, 0xdd, 0xa4, 0xa7, + 0xc8, 0x58, 0x7d, 0x80, 0x4e, 0xd1, 0x2f, 0x52, + 0x68, 0x19, 0xda, 0x06, 0x65, 0x0e, 0x74, 0x12, + 0xfb, 0x62, 0x75, 0x55, 0x97, 0x9e, 0xd4, 0x42, + 0xf2, 0x66, 0x33, 0x41, 0xe5, 0xfe, 0x57, 0x52, + 0x7e, 0x0d, 0xda, 0xf4, 0x53, 0xa1, 0x24, 0x45, + 0x16, 0x74, 0x97, 0x6a, 0x6a, 0x6e, 0x0a, 0x31, + 0xf5, 0x6a, 0x79, 0xf5, 0xb7, 0x3d, 0xfa, 0xc3, + 0x9a, 0xf4, 0xf3, 0xba, 0x4a, 0x5e, 0x8b, 0xb8, + 0x46, 0xcb, 0x5e, 0x33, 0x38, 0x12, 0x75, 0x64, + 0x82, 0xd9, 0x75, 0xab, 0x19, 0x10, 0x16, 0x2f, + 0x96, 0xbf, 0xd7, 0xc5, 0x8a, 0x02, 0xf1, 0x13, + 0x12, 0x51, 0x89, 0xf5, 0xac, 0x05, 0x29, 0x1f}, + .msg_len = 128, + + .sig = {0x2B, 0x6D, 0x3E, 0x5A, 0x19, 0x34, 0xA9, 0x47, + 0x78, 0xC2, 0x06, 0x87, 0xEA, 0xB1, 0x76, 0x6C, + 0x58, 0x3D, 0x89, 0x23, 0xA0, 0x06, 0xAA, 0x37, + 0x34, 0xFC, 0xCA, 0xE0, 0x5A, 0x0A, 0x21, 0x31, + 0x29, 0x3D, 0xC0, 0x0F, 0xBF, 0xCB, 0x05, 0x06, + 0x1A, 0x0D, 0x67, 0x79, 0xAC, 0xB7, 0x8D, 0xC5, + 0x01, 0xC6, 0xA1, 0x18, 0xCA, 0x1F, 0x0B, 0x05, + 0x26, 0x83, 0x32, 0x36, 0xC5, 0x79, 0x33, 0xAC, + 0x94, 0xFC, 0x2E, 0x66, 0x29, 0x7C, 0x8C, 0x12, + 0xD9, 0x13, 0x8F, 0x32, 0xAB, 0xF2, 0x60, 0xE4, + 0x17, 0x34, 0x65, 0x2E, 0x72, 0xDE, 0x15, 0x11, + 0xB6, 0x02, 0x46, 0x13, 0x88, 0xD2, 0xC7, 0xFB, + 0xCA, 0xE7, 0x0D, 0xF2, 0x1C, 0xE7, 0x19, 0xE0, + 0x5A, 0x48, 0x79, 0x50, 0x31, 0x32, 0x1A, 0xFA, + 0x39, 0xBF, 0xCC, 0xCF, 0x70, 0x1E, 0x96, 0x26, + 0x55, 0x71, 0x00, 0x71, 0xC7, 0x13, 0xC7, 0xEF}, + .sig_len = 128, + .chunks = {-1, 65, 63}, + .num_chunks = 3, + }, + { // #1 - 2048 bit key size + .mod = {0xdf, 0x27, 0x1f, 0xd2, 0x5f, 0x86, 0x44, 0x49, + 0x6b, 0x0c, 0x81, 0xbe, 0x4b, 0xd5, 0x02, 0x97, + 0xef, 0x09, 0x9b, 0x00, 0x2a, 0x6f, 0xd6, 0x77, + 0x27, 0xeb, 0x44, 0x9c, 0xea, 0x56, 0x6e, 0xd6, + 0xa3, 0x98, 0x1a, 0x71, 0x31, 0x2a, 0x14, 0x1c, + 0xab, 0xc9, 0x81, 0x5c, 0x12, 0x09, 0xe3, 0x20, + 0xa2, 0x5b, 0x32, 0x46, 0x4e, 0x99, 0x99, 0xf1, + 0x8c, 0xa1, 0x3a, 0x9f, 0xd3, 0x89, 0x25, 0x58, + 0xf9, 0xe0, 0xad, 0xef, 0xdd, 0x36, 0x50, 0xdd, + 0x23, 0xa3, 0xf0, 0x36, 0xd6, 0x0f, 0xe3, 0x98, + 0x84, 0x37, 0x06, 0xa4, 0x0b, 0x0b, 0x84, 0x62, + 0xc8, 0xbe, 0xe3, 0xbc, 0xe1, 0x2f, 0x1f, 0x28, + 0x60, 0xc2, 0x44, 0x4c, 0xdc, 0x6a, 0x44, 0x47, + 0x6a, 0x75, 0xff, 0x4a, 0xa2, 0x42, 0x73, 0xcc, + 0xbe, 0x3b, 0xf8, 0x02, 0x48, 0x46, 0x5f, 0x8f, + 0xf8, 0xc3, 0xa7, 0xf3, 0x36, 0x7d, 0xfc, 0x0d, + 0xf5, 0xb6, 0x50, 0x9a, 0x4f, 0x82, 0x81, 0x1c, + 0xed, 0xd8, 0x1c, 0xda, 0xaa, 0x73, 0xc4, 0x91, + 0xda, 0x41, 0x21, 0x70, 0xd5, 0x44, 0xd4, 0xba, + 0x96, 0xb9, 0x7f, 0x0a, 0xfc, 0x80, 0x65, 0x49, + 0x8d, 0x3a, 0x49, 0xfd, 0x91, 0x09, 0x92, 0xa1, + 0xf0, 0x72, 0x5b, 0xe2, 0x4f, 0x46, 0x5c, 0xfe, + 0x7e, 0x0e, 0xab, 0xf6, 0x78, 0x99, 0x6c, 0x50, + 0xbc, 0x5e, 0x75, 0x24, 0xab, 0xf7, 0x3f, 0x15, + 0xe5, 0xbe, 0xf7, 0xd5, 0x18, 0x39, 0x4e, 0x31, + 0x38, 0xce, 0x49, 0x44, 0x50, 0x6a, 0xaa, 0xaf, + 0x3f, 0x9b, 0x23, 0x6d, 0xca, 0xb8, 0xfc, 0x00, + 0xf8, 0x7a, 0xf5, 0x96, 0xfd, 0xc3, 0xd9, 0xd6, + 0xc7, 0x5c, 0xd5, 0x08, 0x36, 0x2f, 0xae, 0x2c, + 0xbe, 0xdd, 0xcc, 0x4c, 0x74, 0x50, 0xb1, 0x7b, + 0x77, 0x6c, 0x07, 0x9e, 0xcc, 0xa1, 0xf2, 0x56, + 0x35, 0x1a, 0x43, 0xb9, 0x7d, 0xbe, 0x21, 0x53}, + .mod_len = 256, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x5b, 0xd9, 0x10, 0x25, 0x78, 0x30, 0xdc, 0xe1, + 0x75, 0x20, 0xb0, 0x34, 0x41, 0xa5, 0x1a, 0x8c, + 0xab, 0x94, 0x02, 0x0a, 0xc6, 0xec, 0xc2, 0x52, + 0xc8, 0x08, 0xf3, 0x74, 0x3c, 0x95, 0xb7, 0xc8, + 0x3b, 0x8c, 0x8a, 0xf1, 0xa5, 0x01, 0x43, 0x46, + 0xeb, 0xc4, 0x24, 0x2c, 0xdf, 0xb5, 0xd7, 0x18, + 0xe3, 0x0a, 0x73, 0x3e, 0x71, 0xf2, 0x91, 0xe4, + 0xd4, 0x73, 0xb6, 0x1b, 0xfb, 0xa6, 0xda, 0xca, + 0xed, 0x0a, 0x77, 0xbd, 0x1f, 0x09, 0x50, 0xae, + 0x3c, 0x91, 0xa8, 0xf9, 0x01, 0x11, 0x88, 0x25, + 0x89, 0xe1, 0xd6, 0x27, 0x65, 0xee, 0x67, 0x1e, + 0x7b, 0xae, 0xea, 0x30, 0x9f, 0x64, 0xd4, 0x47, + 0xbb, 0xcf, 0xa9, 0xea, 0x12, 0xdc, 0xe0, 0x5e, + 0x9e, 0xa8, 0x93, 0x9b, 0xc5, 0xfe, 0x61, 0x08, + 0x58, 0x12, 0x79, 0xc9, 0x82, 0xb3, 0x08, 0x79, + 0x4b, 0x34, 0x48, 0xe7, 0xf7, 0xb9, 0x52, 0x29, + 0x2d, 0xf8, 0x8c, 0x80, 0xcb, 0x40, 0x14, 0x2c, + 0x4b, 0x5c, 0xf5, 0xf8, 0xdd, 0xaa, 0x08, 0x91, + 0x67, 0x8d, 0x61, 0x0e, 0x58, 0x2f, 0xcb, 0x88, + 0x0f, 0x0d, 0x70, 0x7c, 0xaf, 0x47, 0xd0, 0x9a, + 0x84, 0xe1, 0x4c, 0xa6, 0x58, 0x41, 0xe5, 0xa3, + 0xab, 0xc5, 0xe9, 0xdb, 0xa9, 0x40, 0x75, 0xa9, + 0x08, 0x43, 0x41, 0xf0, 0xed, 0xad, 0x9b, 0x68, + 0xe3, 0xb8, 0xe0, 0x82, 0xb8, 0x0b, 0x6e, 0x6e, + 0x8a, 0x05, 0x47, 0xb4, 0x4f, 0xb5, 0x06, 0x1b, + 0x6a, 0x91, 0x31, 0x60, 0x3a, 0x55, 0x37, 0xdd, + 0xab, 0xd0, 0x1d, 0x8e, 0x86, 0x3d, 0x89, 0x22, + 0xe9, 0xaa, 0x3e, 0x4b, 0xfa, 0xea, 0x0b, 0x39, + 0xd7, 0x92, 0x83, 0xad, 0x2c, 0xbc, 0x8a, 0x59, + 0xcc, 0xe7, 0xa6, 0xec, 0xf4, 0xe4, 0xc8, 0x1e, + 0xd4, 0xc6, 0x59, 0x1c, 0x80, 0x7d, 0xef, 0xd7, + 0x1a, 0xb0, 0x68, 0x66, 0xbb, 0x5e, 0x77, 0x45}, + .privexp_len = 256, + .prime1 = {0xf4, 0x4f, 0x5e, 0x42, 0x46, 0x39, 0x1f, 0x48, + 0x2b, 0x2f, 0x52, 0x96, 0xe3, 0x60, 0x2e, 0xb3, + 0x4a, 0xa1, 0x36, 0x42, 0x77, 0x10, 0xf7, 0xc0, + 0x41, 0x6d, 0x40, 0x3f, 0xd6, 0x9d, 0x4b, 0x29, + 0x13, 0x0c, 0xfe, 0xbe, 0xf3, 0x4e, 0x88, 0x5a, + 0xbd, 0xb1, 0xa8, 0xa0, 0xa5, 0xf0, 0xe9, 0xb5, + 0xc3, 0x3e, 0x1f, 0xc3, 0xbf, 0xc2, 0x85, 0xb1, + 0xae, 0x17, 0xe4, 0x0c, 0xc6, 0x7a, 0x19, 0x13, + 0xdd, 0x56, 0x37, 0x19, 0x81, 0x5e, 0xba, 0xf8, + 0x51, 0x4c, 0x2a, 0x7a, 0xa0, 0x01, 0x8e, 0x63, + 0xb6, 0xc6, 0x31, 0xdc, 0x31, 0x5a, 0x46, 0x23, + 0x57, 0x16, 0x42, 0x3d, 0x11, 0xff, 0x58, 0x03, + 0x4e, 0x61, 0x06, 0x45, 0x70, 0x36, 0x06, 0x91, + 0x9f, 0x5c, 0x7c, 0xe2, 0x66, 0x0c, 0xd1, 0x48, + 0xbd, 0x9e, 0xfc, 0x12, 0x3d, 0x9c, 0x54, 0xb6, + 0x70, 0x55, 0x90, 0xd0, 0x06, 0xcf, 0xcf, 0x3f}, + .prime1_len = 128, + .prime2 = {0xe9, 0xd4, 0x98, 0x41, 0xe0, 0xe0, 0xa6, 0xad, + 0x0d, 0x51, 0x78, 0x57, 0x13, 0x3e, 0x36, 0xdc, + 0x72, 0xc1, 0xbd, 0xd9, 0x0f, 0x91, 0x74, 0xb5, + 0x2e, 0x26, 0x57, 0x0f, 0x37, 0x36, 0x40, 0xf1, + 0xc1, 0x85, 0xe7, 0xea, 0x8e, 0x2e, 0xd7, 0xf1, + 0xe4, 0xeb, 0xb9, 0x51, 0xf7, 0x0a, 0x58, 0x02, + 0x36, 0x33, 0xb0, 0x09, 0x7a, 0xec, 0x67, 0xc6, + 0xdc, 0xb8, 0x00, 0xfc, 0x1a, 0x67, 0xf9, 0xbb, + 0x05, 0x63, 0x61, 0x0f, 0x08, 0xeb, 0xc8, 0x74, + 0x6a, 0xd1, 0x29, 0x77, 0x21, 0x36, 0xeb, 0x1d, + 0xda, 0xf4, 0x64, 0x36, 0x45, 0x0d, 0x31, 0x83, + 0x32, 0xa8, 0x49, 0x82, 0xfe, 0x5d, 0x28, 0xdb, + 0xe5, 0xb3, 0xe9, 0x12, 0x40, 0x7c, 0x3e, 0x0e, + 0x03, 0x10, 0x0d, 0x87, 0xd4, 0x36, 0xee, 0x40, + 0x9e, 0xec, 0x1c, 0xf8, 0x5e, 0x80, 0xab, 0xa0, + 0x79, 0xb2, 0xe6, 0x10, 0x6b, 0x97, 0xbc, 0xed}, + .prime2_len = 128, + .exp1 = {0xed, 0x10, 0x2a, 0xcd, 0xb2, 0x68, 0x71, 0x53, + 0x4d, 0x1c, 0x41, 0x4e, 0xca, 0xd9, 0xa4, 0xd7, + 0x32, 0xfe, 0x95, 0xb1, 0x0e, 0xea, 0x37, 0x0d, + 0xa6, 0x2f, 0x05, 0xde, 0x2c, 0x39, 0x3b, 0x1a, + 0x63, 0x33, 0x03, 0xea, 0x74, 0x1b, 0x6b, 0x32, + 0x69, 0xc9, 0x7f, 0x70, 0x4b, 0x35, 0x27, 0x02, + 0xc9, 0xae, 0x79, 0x92, 0x2f, 0x7b, 0xe8, 0xd1, + 0x0d, 0xb6, 0x7f, 0x02, 0x6a, 0x81, 0x45, 0xde, + 0x41, 0xb3, 0x0c, 0x0a, 0x42, 0xbf, 0x92, 0x3b, + 0xac, 0x5f, 0x75, 0x04, 0xc2, 0x48, 0x60, 0x4b, + 0x9f, 0xaa, 0x57, 0xed, 0x6b, 0x32, 0x46, 0xc6, + 0xba, 0x15, 0x8e, 0x36, 0xc6, 0x44, 0xf8, 0xb9, + 0x54, 0x8f, 0xcf, 0x4f, 0x07, 0xe0, 0x54, 0xa5, + 0x6f, 0x76, 0x86, 0x74, 0x05, 0x44, 0x40, 0xbc, + 0x0d, 0xcb, 0xbc, 0x9b, 0x52, 0x8f, 0x64, 0xa0, + 0x17, 0x06, 0xe0, 0x5b, 0x0b, 0x91, 0x10, 0x6f}, + .exp1_len = 128, + .exp2 = {0x68, 0x27, 0x92, 0x4a, 0x85, 0xe8, 0x8b, 0x55, + 0xba, 0x00, 0xf8, 0x21, 0x91, 0x28, 0xbd, 0x37, + 0x24, 0xc6, 0xb7, 0xd1, 0xdf, 0xe5, 0x62, 0x9e, + 0xf1, 0x97, 0x92, 0x5f, 0xec, 0xaf, 0xf5, 0xed, + 0xb9, 0xcd, 0xf3, 0xa7, 0xbe, 0xfd, 0x8e, 0xa2, + 0xe8, 0xdd, 0x37, 0x07, 0x13, 0x8b, 0x3f, 0xf8, + 0x7c, 0x3c, 0x39, 0xc5, 0x7f, 0x43, 0x9e, 0x56, + 0x2e, 0x2a, 0xa8, 0x05, 0xa3, 0x9d, 0x7c, 0xd7, + 0x99, 0x66, 0xd2, 0xec, 0xe7, 0x84, 0x5f, 0x1d, + 0xbc, 0x16, 0xbe, 0xe9, 0x99, 0x99, 0xe4, 0xd0, + 0xbf, 0x9e, 0xec, 0xa4, 0x5f, 0xcd, 0xa8, 0xa8, + 0x50, 0x00, 0x35, 0xfe, 0x6b, 0x5f, 0x03, 0xbc, + 0x2f, 0x6d, 0x1b, 0xfc, 0x4d, 0x4d, 0x0a, 0x37, + 0x23, 0x96, 0x1a, 0xf0, 0xcd, 0xce, 0x4a, 0x01, + 0xee, 0xc8, 0x2d, 0x7f, 0x54, 0x58, 0xec, 0x19, + 0xe7, 0x1b, 0x90, 0xee, 0xef, 0x7d, 0xff, 0x61}, + .exp2_len = 128, + .coef = {0x57, 0xb7, 0x38, 0x88, 0xd1, 0x83, 0xa9, 0x9a, + 0x63, 0x07, 0x42, 0x22, 0x77, 0x55, 0x1a, 0x3d, + 0x9e, 0x18, 0xad, 0xf0, 0x6a, 0x91, 0xe8, 0xb5, + 0x5c, 0xef, 0xfe, 0xf9, 0x07, 0x7c, 0x84, 0x96, + 0x94, 0x8e, 0xcb, 0x3b, 0x16, 0xb7, 0x81, 0x55, + 0xcb, 0x2a, 0x3a, 0x57, 0xc1, 0x19, 0xd3, 0x79, + 0x95, 0x1c, 0x01, 0x0a, 0xa6, 0x35, 0xed, 0xcf, + 0x62, 0xd8, 0x4c, 0x5a, 0x12, 0x2a, 0x8d, 0x67, + 0xab, 0x5f, 0xa9, 0xe5, 0xa4, 0xa8, 0x77, 0x2a, + 0x1e, 0x94, 0x3b, 0xaf, 0xc7, 0x0a, 0xe3, 0xa4, + 0xc1, 0xf0, 0xf3, 0xa4, 0xdd, 0xff, 0xae, 0xfd, + 0x18, 0x92, 0xc8, 0xcb, 0x33, 0xbb, 0x0d, 0x0b, + 0x95, 0x90, 0xe9, 0x63, 0xa6, 0x91, 0x10, 0xfb, + 0x34, 0xdb, 0x7b, 0x90, 0x6f, 0xc4, 0xba, 0x28, + 0x36, 0x99, 0x5a, 0xac, 0x7e, 0x52, 0x74, 0x90, + 0xac, 0x95, 0x2a, 0x02, 0x26, 0x8a, 0x4f, 0x18}, + .coef_len = 128, + .msg = {0xf4, 0x5d, 0x55, 0xf3, 0x55, 0x51, 0xe9, 0x75, + 0xd6, 0xa8, 0xdc, 0x7e, 0xa9, 0xf4, 0x88, 0x59, + 0x39, 0x40, 0xcc, 0x75, 0x69, 0x4a, 0x27, 0x8f, + 0x27, 0xe5, 0x78, 0xa1, 0x63, 0xd8, 0x39, 0xb3, + 0x40, 0x40, 0x84, 0x18, 0x08, 0xcf, 0x9c, 0x58, + 0xc9, 0xb8, 0x72, 0x8b, 0xf5, 0xf9, 0xce, 0x8e, + 0xe8, 0x11, 0xea, 0x91, 0x71, 0x4f, 0x47, 0xba, + 0xb9, 0x2d, 0x0f, 0x6d, 0x5a, 0x26, 0xfc, 0xfe, + 0xea, 0x6c, 0xd9, 0x3b, 0x91, 0x0c, 0x0a, 0x2c, + 0x96, 0x3e, 0x64, 0xeb, 0x18, 0x23, 0xf1, 0x02, + 0x75, 0x3d, 0x41, 0xf0, 0x33, 0x59, 0x10, 0xad, + 0x3a, 0x97, 0x71, 0x04, 0xf1, 0xaa, 0xf6, 0xc3, + 0x74, 0x27, 0x16, 0xa9, 0x75, 0x5d, 0x11, 0xb8, + 0xee, 0xd6, 0x90, 0x47, 0x7f, 0x44, 0x5c, 0x5d, + 0x27, 0x20, 0x8b, 0x2e, 0x28, 0x43, 0x30, 0xfa, + 0x3d, 0x30, 0x14, 0x23, 0xfa, 0x7f, 0x2d, 0x08, + 0x6e, 0x0a, 0xd0, 0xb8, 0x92, 0xb9, 0xdb, 0x54, + 0x4e, 0x45, 0x6d, 0x3f, 0x0d, 0xab, 0x85, 0xd9, + 0x53, 0xc1, 0x2d, 0x34, 0x0a, 0xa8, 0x73, 0xed, + 0xa7, 0x27, 0xc8, 0xa6, 0x49, 0xdb, 0x7f, 0xa6, + 0x37, 0x40, 0xe2, 0x5e, 0x9a, 0xf1, 0x53, 0x3b, + 0x30, 0x7e, 0x61, 0x32, 0x99, 0x93, 0x11, 0x0e, + 0x95, 0x19, 0x4e, 0x03, 0x93, 0x99, 0xc3, 0x82, + 0x4d, 0x24, 0xc5, 0x1f, 0x22, 0xb2, 0x6b, 0xde, + 0x10, 0x24, 0xcd, 0x39, 0x59, 0x58, 0xa2, 0xdf, + 0xeb, 0x48, 0x16, 0xa6, 0xe8, 0xad, 0xed, 0xb5, + 0x0b, 0x1f, 0x6b, 0x56, 0xd0, 0xb3, 0x06, 0x0f, + 0xf0, 0xf1, 0xc4, 0xcb, 0x0d, 0x0e, 0x00, 0x1d, + 0xd5, 0x9d, 0x73, 0xbe, 0x12}, + .msg_len = 229, + + .sig = {0x4E, 0x9B, 0x96, 0x4E, 0x3F, 0x8A, 0x24, 0x5A, + 0x2A, 0x3F, 0x34, 0x43, 0x1A, 0x9B, 0xFC, 0xA1, + 0xF4, 0xAF, 0x37, 0x3B, 0x6C, 0x85, 0x24, 0xAF, + 0x63, 0x62, 0x9E, 0x22, 0x24, 0x66, 0xCD, 0x9A, + 0xEF, 0x81, 0x26, 0xFC, 0xC0, 0xD6, 0x04, 0x1E, + 0x41, 0x7C, 0x2E, 0x83, 0x2B, 0x32, 0x70, 0x3B, + 0xDB, 0x16, 0x3B, 0x4A, 0xA8, 0x29, 0x3C, 0xC4, + 0x7F, 0xE5, 0x5E, 0xF9, 0x5A, 0xDC, 0xD4, 0xA9, + 0x2F, 0x47, 0x85, 0x3C, 0xCB, 0x89, 0x1F, 0xFA, + 0xB2, 0x13, 0x11, 0xAD, 0xF8, 0x42, 0xDD, 0x35, + 0x47, 0xC4, 0x86, 0x0B, 0x95, 0x87, 0xF4, 0x0B, + 0x24, 0xF4, 0x5F, 0x59, 0xAD, 0x8A, 0xC7, 0x08, + 0x7B, 0x3B, 0x5A, 0xD9, 0x73, 0xCC, 0x9D, 0x72, + 0xBB, 0x73, 0x17, 0x66, 0x92, 0x64, 0x6A, 0x84, + 0x16, 0x14, 0x47, 0x94, 0x39, 0xB5, 0x01, 0x74, + 0x6F, 0x12, 0x41, 0x43, 0x9C, 0x45, 0xB5, 0x7E, + 0xAB, 0x4C, 0xF9, 0x22, 0xE1, 0x21, 0x33, 0x13, + 0x8A, 0xD3, 0x00, 0xCD, 0x42, 0xF1, 0x53, 0x77, + 0x69, 0x42, 0x4E, 0x29, 0xC6, 0x26, 0xAC, 0x7C, + 0xA7, 0x81, 0x2A, 0xF2, 0x59, 0x00, 0x45, 0x48, + 0x0E, 0x33, 0x6E, 0x4B, 0x3E, 0x3E, 0x1D, 0x61, + 0xB7, 0x9A, 0x6C, 0x96, 0x5C, 0x2A, 0x9C, 0xBE, + 0x47, 0xE3, 0x57, 0xA2, 0x8C, 0x07, 0x3A, 0x31, + 0x58, 0x94, 0xC7, 0x4E, 0xE3, 0x38, 0xD0, 0xA9, + 0x42, 0xCA, 0xEB, 0xDD, 0x13, 0x88, 0x6E, 0xEE, + 0x95, 0x88, 0xB5, 0xB5, 0x2F, 0xDE, 0x7E, 0x1B, + 0xDC, 0x75, 0xEA, 0x8B, 0xA6, 0x6A, 0xDA, 0xF3, + 0xD3, 0x80, 0x05, 0xAC, 0xA8, 0x54, 0x31, 0xA2, + 0x5A, 0x28, 0x78, 0x2C, 0x95, 0xE8, 0x74, 0xD0, + 0x90, 0x9A, 0x26, 0xCC, 0x4D, 0x99, 0xCF, 0xE9, + 0xB4, 0x1E, 0x5B, 0x06, 0x78, 0x3D, 0x98, 0x06, + 0xB9, 0xA4, 0xE0, 0xC1, 0x81, 0xE9, 0xA8, 0x61}, + .sig_len = 256, + .chunks = {50, 100, 0, 75, 4}, + .num_chunks = 5, + } +}; + +struct RSA_PUBLISHED_TEST_VECTOR rsa_sha384_pkcs_sigver_published_tv[] = { + + { // #0 1024 bit key size + .mod = {0xa8, 0xd6, 0x8a, 0xcd, 0x41, 0x3c, 0x5e, 0x19, + 0x5d, 0x5e, 0xf0, 0x4e, 0x1b, 0x4f, 0xaa, 0xf2, + 0x42, 0x36, 0x5c, 0xb4, 0x50, 0x19, 0x67, 0x55, + 0xe9, 0x2e, 0x12, 0x15, 0xba, 0x59, 0x80, 0x2a, + 0xaf, 0xba, 0xdb, 0xf2, 0x56, 0x4d, 0xd5, 0x50, + 0x95, 0x6a, 0xbb, 0x54, 0xf8, 0xb1, 0xc9, 0x17, + 0x84, 0x4e, 0x5f, 0x36, 0x19, 0x5d, 0x10, 0x88, + 0xc6, 0x00, 0xe0, 0x7c, 0xad, 0xa5, 0xc0, 0x80, + 0xed, 0xe6, 0x79, 0xf5, 0x0b, 0x3d, 0xe3, 0x2c, + 0xf4, 0x02, 0x6e, 0x51, 0x45, 0x42, 0x49, 0x5c, + 0x54, 0xb1, 0x90, 0x37, 0x68, 0x79, 0x1a, 0xae, + 0x9e, 0x36, 0xf0, 0x82, 0xcd, 0x38, 0xe9, 0x41, + 0xad, 0xa8, 0x9b, 0xae, 0xca, 0xda, 0x61, 0xab, + 0x0d, 0xd3, 0x7a, 0xd5, 0x36, 0xbc, 0xb0, 0xa0, + 0x94, 0x62, 0x71, 0x59, 0x48, 0x36, 0xe9, 0x2a, + 0xb5, 0x51, 0x73, 0x01, 0xd4, 0x51, 0x76, 0xb5}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0xa3, 0xcd, 0x31, 0x70, 0x9d, 0x1f, 0xd2, 0x33, + 0x4d, 0x90, 0xf4, 0x16, 0xf3, 0x0c, 0x41, 0xcf, + 0x33, 0x49, 0xc6, 0x7a, 0xf1, 0x53, 0x14, 0x1c, + 0x17, 0x54, 0x29, 0x1b, 0x87, 0x65, 0x99, 0xa0, + 0xd0, 0x48, 0xbb, 0x66, 0xcb, 0x30, 0x4c, 0x0a, + 0x18, 0x4c, 0x2a, 0x5e, 0xef, 0xc0, 0x9c, 0x56, + 0x02, 0x78, 0x7e, 0x8a, 0xdf, 0xe4, 0x98, 0x4b, + 0xf9, 0xbd, 0x94, 0x0d, 0xa1, 0xf2, 0xb3, 0x65, + 0x4d, 0xe5, 0x90, 0x7d, 0xb9, 0xe2, 0xc3, 0x80, + 0xce, 0x7b, 0xe4, 0x0b, 0x2f, 0xd3, 0x76, 0xc2, + 0x8d, 0xee, 0xc3, 0x34, 0x6f, 0xcd, 0x3a, 0x1a, + 0xc9, 0xd7, 0x68, 0xaf, 0x39, 0x2d, 0x14, 0xb7, + 0x7b, 0x7c, 0x9f, 0x32, 0x93, 0x28, 0xa9, 0x7b, + 0xc5, 0xdc, 0x93, 0xab, 0x17, 0xce, 0x09, 0x3c, + 0x32, 0xbe, 0x3e, 0xab, 0x85, 0x07, 0x5b, 0x6e, + 0xbb, 0xeb, 0x29, 0x95, 0xe8, 0x66, 0x2d, 0x41}, + .privexp_len = 128, + .prime1 = {0xdf, 0xea, 0x98, 0x4c, 0xe4, 0x30, 0x7e, 0xaf, + 0xc0, 0xd1, 0x40, 0xc2, 0xbb, 0x82, 0x86, 0x1e, + 0x5d, 0xba, 0xc4, 0xf8, 0x56, 0x7c, 0xbc, 0x98, + 0x1d, 0x70, 0x44, 0x0d, 0xd6, 0x39, 0x49, 0x20, + 0x79, 0x03, 0x14, 0x86, 0x31, 0x5e, 0x30, 0x5e, + 0xb8, 0x3e, 0x59, 0x1c, 0x4a, 0x2e, 0x96, 0x06, + 0x49, 0x66, 0xf7, 0xc8, 0x94, 0xc3, 0xca, 0x35, + 0x19, 0x25, 0xb5, 0xce, 0x82, 0xd8, 0xef, 0x0d}, + .prime1_len = 64, + .prime2 = {0xc1, 0x07, 0xa2, 0xfe, 0x92, 0x4b, 0x76, 0xe2, + 0x06, 0xcb, 0x9b, 0xc4, 0xaf, 0x2a, 0xb7, 0x00, + 0x85, 0x47, 0xc0, 0x08, 0x46, 0xbf, 0x6d, 0x06, + 0x80, 0xb3, 0xea, 0xc3, 0xeb, 0xcb, 0xd0, 0xc7, + 0xfd, 0x7a, 0x54, 0xc2, 0xb9, 0x89, 0x9b, 0x08, + 0xf8, 0x0c, 0xde, 0x1d, 0x36, 0x91, 0xea, 0xaa, + 0x28, 0x16, 0xb1, 0xeb, 0x11, 0x82, 0x2d, 0x6b, + 0xe7, 0xbe, 0xaf, 0x4e, 0x30, 0x97, 0x7c, 0x49}, + .prime2_len = 64, + .exp1 = {0xcd, 0x39, 0x54, 0x71, 0x54, 0xcb, 0x65, 0xb1, + 0x6b, 0xc5, 0xdd, 0xd7, 0x1c, 0xc8, 0xda, 0x67, + 0xc6, 0x7c, 0x41, 0xbf, 0x62, 0x75, 0x5c, 0xdd, + 0x06, 0x4e, 0x38, 0xf1, 0x7d, 0xa0, 0x6f, 0x77, + 0x85, 0xb1, 0xdf, 0x03, 0xc7, 0x07, 0x8e, 0xc9, + 0xa1, 0x8f, 0xf3, 0x58, 0x4c, 0x5d, 0x3a, 0x3f, + 0x74, 0xd3, 0x1c, 0xd3, 0x08, 0x16, 0x12, 0xa4, + 0x6b, 0xf1, 0xf6, 0x19, 0xda, 0x2f, 0x3d, 0x99}, + .exp1_len = 64, + .exp2 = {0xc0, 0x6d, 0xd1, 0x82, 0x80, 0xea, 0xf4, 0x1f, + 0xcd, 0x70, 0x6a, 0xdf, 0xbf, 0x54, 0x10, 0xcd, + 0x57, 0x10, 0xb9, 0x12, 0x47, 0x1d, 0x0c, 0x1e, + 0x00, 0x6d, 0xdb, 0xaa, 0xe6, 0xc4, 0xef, 0x64, + 0x7f, 0x7f, 0xd5, 0x41, 0xad, 0xde, 0xcd, 0x0c, + 0x3a, 0xe3, 0xf1, 0x05, 0x24, 0x62, 0x80, 0x92, + 0x92, 0x96, 0x55, 0x55, 0xa6, 0xc5, 0xa4, 0x6c, + 0x3e, 0xc1, 0xac, 0x57, 0x81, 0x3f, 0x72, 0xe9}, + .exp2_len = 64, + .coef = {0x49, 0x80, 0xae, 0xd5, 0x25, 0xff, 0x0e, 0x0e, + 0xa4, 0x73, 0x7a, 0x4e, 0x61, 0x19, 0x2e, 0x2b, + 0x11, 0x09, 0x05, 0xf1, 0xc4, 0xf2, 0xf6, 0x4d, + 0x04, 0x2f, 0xd9, 0xa5, 0x22, 0xd5, 0xe5, 0x73, + 0xfc, 0xfa, 0xd2, 0x01, 0x03, 0xef, 0x52, 0x80, + 0xc6, 0x4b, 0xe8, 0x7a, 0x38, 0x50, 0x55, 0xb7, + 0x6d, 0x7f, 0x56, 0xdf, 0xef, 0xdf, 0xb2, 0xca, + 0x98, 0xb5, 0xc9, 0x55, 0x90, 0x2f, 0x08, 0x84}, + .coef_len = 64, + .msg = {0xff, 0x23, 0xe0, 0x0f, 0x81, 0x9b, 0xae, 0x42, + 0x4e, 0x41, 0xd6, 0xb7, 0x62, 0xea, 0x6b, 0x88, + 0x80, 0x1e, 0x65, 0x1c, 0x83, 0x1c, 0x96, 0x4a, + 0xf3, 0x1d, 0xe0, 0xc1, 0xd6, 0xdd, 0xa4, 0xa7, + 0xc8, 0x58, 0x7d, 0x80, 0x4e, 0xd1, 0x2f, 0x52, + 0x68, 0x19, 0xda, 0x06, 0x65, 0x0e, 0x74, 0x12, + 0xfb, 0x62, 0x75, 0x55, 0x97, 0x9e, 0xd4, 0x42, + 0xf2, 0x66, 0x33, 0x41, 0xe5, 0xfe, 0x57, 0x52, + 0x7e, 0x0d, 0xda, 0xf4, 0x53, 0xa1, 0x24, 0x45, + 0x16, 0x74, 0x97, 0x6a, 0x6a, 0x6e, 0x0a, 0x31, + 0xf5, 0x6a, 0x79, 0xf5, 0xb7, 0x3d, 0xfa, 0xc3, + 0x9a, 0xf4, 0xf3, 0xba, 0x4a, 0x5e, 0x8b, 0xb8, + 0x46, 0xcb, 0x5e, 0x33, 0x38, 0x12, 0x75, 0x64, + 0x82, 0xd9, 0x75, 0xab, 0x19, 0x10, 0x16, 0x2f, + 0x96, 0xbf, 0xd7, 0xc5, 0x8a, 0x02, 0xf1, 0x13, + 0x12, 0x51, 0x89, 0xf5, 0xac, 0x05, 0x29, 0x1f}, + .msg_len = 128, + + .sig = {0x48, 0xA5, 0xEB, 0xAD, 0x50, 0x7A, 0x40, 0x46, + 0x93, 0x18, 0x0F, 0x80, 0xE0, 0x37, 0x28, 0x4B, + 0xFA, 0x4D, 0x16, 0x28, 0xC2, 0x3B, 0x95, 0xFC, + 0x21, 0x80, 0xE9, 0xEC, 0xFA, 0xE5, 0x12, 0x51, + 0xCE, 0x8A, 0x5C, 0xBA, 0x56, 0x6A, 0x0B, 0x30, + 0x69, 0xA2, 0xD3, 0xB3, 0xBF, 0xD3, 0x23, 0x5C, + 0x10, 0x78, 0xF5, 0xFE, 0x0E, 0x2B, 0x00, 0xDC, + 0xA7, 0x18, 0xC9, 0x3F, 0x88, 0x51, 0x4A, 0x66, + 0xDD, 0x10, 0x27, 0xC0, 0x22, 0xE7, 0xE8, 0x38, + 0xAB, 0x25, 0x93, 0x68, 0x42, 0x52, 0xE9, 0xC4, + 0xD0, 0xBD, 0x63, 0xC3, 0x5E, 0x01, 0x29, 0xEB, + 0xAB, 0x6B, 0x10, 0xB3, 0x54, 0x57, 0xD3, 0xB0, + 0xCA, 0x03, 0x60, 0xC0, 0x49, 0x57, 0x7E, 0x89, + 0x31, 0x8E, 0x33, 0x5D, 0x18, 0xDC, 0x13, 0xF7, + 0x20, 0x52, 0x1A, 0x7C, 0xA1, 0x6C, 0x87, 0x6A, + 0x3F, 0x77, 0x6B, 0xFE, 0xD2, 0x03, 0xF6, 0xA2}, + .sig_len = 128, + .chunks = {-1, 65, 63}, + .num_chunks = 3, + }, + { // #1 - 2048 bit key size + .mod = {0xdf, 0x27, 0x1f, 0xd2, 0x5f, 0x86, 0x44, 0x49, + 0x6b, 0x0c, 0x81, 0xbe, 0x4b, 0xd5, 0x02, 0x97, + 0xef, 0x09, 0x9b, 0x00, 0x2a, 0x6f, 0xd6, 0x77, + 0x27, 0xeb, 0x44, 0x9c, 0xea, 0x56, 0x6e, 0xd6, + 0xa3, 0x98, 0x1a, 0x71, 0x31, 0x2a, 0x14, 0x1c, + 0xab, 0xc9, 0x81, 0x5c, 0x12, 0x09, 0xe3, 0x20, + 0xa2, 0x5b, 0x32, 0x46, 0x4e, 0x99, 0x99, 0xf1, + 0x8c, 0xa1, 0x3a, 0x9f, 0xd3, 0x89, 0x25, 0x58, + 0xf9, 0xe0, 0xad, 0xef, 0xdd, 0x36, 0x50, 0xdd, + 0x23, 0xa3, 0xf0, 0x36, 0xd6, 0x0f, 0xe3, 0x98, + 0x84, 0x37, 0x06, 0xa4, 0x0b, 0x0b, 0x84, 0x62, + 0xc8, 0xbe, 0xe3, 0xbc, 0xe1, 0x2f, 0x1f, 0x28, + 0x60, 0xc2, 0x44, 0x4c, 0xdc, 0x6a, 0x44, 0x47, + 0x6a, 0x75, 0xff, 0x4a, 0xa2, 0x42, 0x73, 0xcc, + 0xbe, 0x3b, 0xf8, 0x02, 0x48, 0x46, 0x5f, 0x8f, + 0xf8, 0xc3, 0xa7, 0xf3, 0x36, 0x7d, 0xfc, 0x0d, + 0xf5, 0xb6, 0x50, 0x9a, 0x4f, 0x82, 0x81, 0x1c, + 0xed, 0xd8, 0x1c, 0xda, 0xaa, 0x73, 0xc4, 0x91, + 0xda, 0x41, 0x21, 0x70, 0xd5, 0x44, 0xd4, 0xba, + 0x96, 0xb9, 0x7f, 0x0a, 0xfc, 0x80, 0x65, 0x49, + 0x8d, 0x3a, 0x49, 0xfd, 0x91, 0x09, 0x92, 0xa1, + 0xf0, 0x72, 0x5b, 0xe2, 0x4f, 0x46, 0x5c, 0xfe, + 0x7e, 0x0e, 0xab, 0xf6, 0x78, 0x99, 0x6c, 0x50, + 0xbc, 0x5e, 0x75, 0x24, 0xab, 0xf7, 0x3f, 0x15, + 0xe5, 0xbe, 0xf7, 0xd5, 0x18, 0x39, 0x4e, 0x31, + 0x38, 0xce, 0x49, 0x44, 0x50, 0x6a, 0xaa, 0xaf, + 0x3f, 0x9b, 0x23, 0x6d, 0xca, 0xb8, 0xfc, 0x00, + 0xf8, 0x7a, 0xf5, 0x96, 0xfd, 0xc3, 0xd9, 0xd6, + 0xc7, 0x5c, 0xd5, 0x08, 0x36, 0x2f, 0xae, 0x2c, + 0xbe, 0xdd, 0xcc, 0x4c, 0x74, 0x50, 0xb1, 0x7b, + 0x77, 0x6c, 0x07, 0x9e, 0xcc, 0xa1, 0xf2, 0x56, + 0x35, 0x1a, 0x43, 0xb9, 0x7d, 0xbe, 0x21, 0x53}, + .mod_len = 256, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x5b, 0xd9, 0x10, 0x25, 0x78, 0x30, 0xdc, 0xe1, + 0x75, 0x20, 0xb0, 0x34, 0x41, 0xa5, 0x1a, 0x8c, + 0xab, 0x94, 0x02, 0x0a, 0xc6, 0xec, 0xc2, 0x52, + 0xc8, 0x08, 0xf3, 0x74, 0x3c, 0x95, 0xb7, 0xc8, + 0x3b, 0x8c, 0x8a, 0xf1, 0xa5, 0x01, 0x43, 0x46, + 0xeb, 0xc4, 0x24, 0x2c, 0xdf, 0xb5, 0xd7, 0x18, + 0xe3, 0x0a, 0x73, 0x3e, 0x71, 0xf2, 0x91, 0xe4, + 0xd4, 0x73, 0xb6, 0x1b, 0xfb, 0xa6, 0xda, 0xca, + 0xed, 0x0a, 0x77, 0xbd, 0x1f, 0x09, 0x50, 0xae, + 0x3c, 0x91, 0xa8, 0xf9, 0x01, 0x11, 0x88, 0x25, + 0x89, 0xe1, 0xd6, 0x27, 0x65, 0xee, 0x67, 0x1e, + 0x7b, 0xae, 0xea, 0x30, 0x9f, 0x64, 0xd4, 0x47, + 0xbb, 0xcf, 0xa9, 0xea, 0x12, 0xdc, 0xe0, 0x5e, + 0x9e, 0xa8, 0x93, 0x9b, 0xc5, 0xfe, 0x61, 0x08, + 0x58, 0x12, 0x79, 0xc9, 0x82, 0xb3, 0x08, 0x79, + 0x4b, 0x34, 0x48, 0xe7, 0xf7, 0xb9, 0x52, 0x29, + 0x2d, 0xf8, 0x8c, 0x80, 0xcb, 0x40, 0x14, 0x2c, + 0x4b, 0x5c, 0xf5, 0xf8, 0xdd, 0xaa, 0x08, 0x91, + 0x67, 0x8d, 0x61, 0x0e, 0x58, 0x2f, 0xcb, 0x88, + 0x0f, 0x0d, 0x70, 0x7c, 0xaf, 0x47, 0xd0, 0x9a, + 0x84, 0xe1, 0x4c, 0xa6, 0x58, 0x41, 0xe5, 0xa3, + 0xab, 0xc5, 0xe9, 0xdb, 0xa9, 0x40, 0x75, 0xa9, + 0x08, 0x43, 0x41, 0xf0, 0xed, 0xad, 0x9b, 0x68, + 0xe3, 0xb8, 0xe0, 0x82, 0xb8, 0x0b, 0x6e, 0x6e, + 0x8a, 0x05, 0x47, 0xb4, 0x4f, 0xb5, 0x06, 0x1b, + 0x6a, 0x91, 0x31, 0x60, 0x3a, 0x55, 0x37, 0xdd, + 0xab, 0xd0, 0x1d, 0x8e, 0x86, 0x3d, 0x89, 0x22, + 0xe9, 0xaa, 0x3e, 0x4b, 0xfa, 0xea, 0x0b, 0x39, + 0xd7, 0x92, 0x83, 0xad, 0x2c, 0xbc, 0x8a, 0x59, + 0xcc, 0xe7, 0xa6, 0xec, 0xf4, 0xe4, 0xc8, 0x1e, + 0xd4, 0xc6, 0x59, 0x1c, 0x80, 0x7d, 0xef, 0xd7, + 0x1a, 0xb0, 0x68, 0x66, 0xbb, 0x5e, 0x77, 0x45}, + .privexp_len = 256, + .prime1 = {0xf4, 0x4f, 0x5e, 0x42, 0x46, 0x39, 0x1f, 0x48, + 0x2b, 0x2f, 0x52, 0x96, 0xe3, 0x60, 0x2e, 0xb3, + 0x4a, 0xa1, 0x36, 0x42, 0x77, 0x10, 0xf7, 0xc0, + 0x41, 0x6d, 0x40, 0x3f, 0xd6, 0x9d, 0x4b, 0x29, + 0x13, 0x0c, 0xfe, 0xbe, 0xf3, 0x4e, 0x88, 0x5a, + 0xbd, 0xb1, 0xa8, 0xa0, 0xa5, 0xf0, 0xe9, 0xb5, + 0xc3, 0x3e, 0x1f, 0xc3, 0xbf, 0xc2, 0x85, 0xb1, + 0xae, 0x17, 0xe4, 0x0c, 0xc6, 0x7a, 0x19, 0x13, + 0xdd, 0x56, 0x37, 0x19, 0x81, 0x5e, 0xba, 0xf8, + 0x51, 0x4c, 0x2a, 0x7a, 0xa0, 0x01, 0x8e, 0x63, + 0xb6, 0xc6, 0x31, 0xdc, 0x31, 0x5a, 0x46, 0x23, + 0x57, 0x16, 0x42, 0x3d, 0x11, 0xff, 0x58, 0x03, + 0x4e, 0x61, 0x06, 0x45, 0x70, 0x36, 0x06, 0x91, + 0x9f, 0x5c, 0x7c, 0xe2, 0x66, 0x0c, 0xd1, 0x48, + 0xbd, 0x9e, 0xfc, 0x12, 0x3d, 0x9c, 0x54, 0xb6, + 0x70, 0x55, 0x90, 0xd0, 0x06, 0xcf, 0xcf, 0x3f}, + .prime1_len = 128, + .prime2 = {0xe9, 0xd4, 0x98, 0x41, 0xe0, 0xe0, 0xa6, 0xad, + 0x0d, 0x51, 0x78, 0x57, 0x13, 0x3e, 0x36, 0xdc, + 0x72, 0xc1, 0xbd, 0xd9, 0x0f, 0x91, 0x74, 0xb5, + 0x2e, 0x26, 0x57, 0x0f, 0x37, 0x36, 0x40, 0xf1, + 0xc1, 0x85, 0xe7, 0xea, 0x8e, 0x2e, 0xd7, 0xf1, + 0xe4, 0xeb, 0xb9, 0x51, 0xf7, 0x0a, 0x58, 0x02, + 0x36, 0x33, 0xb0, 0x09, 0x7a, 0xec, 0x67, 0xc6, + 0xdc, 0xb8, 0x00, 0xfc, 0x1a, 0x67, 0xf9, 0xbb, + 0x05, 0x63, 0x61, 0x0f, 0x08, 0xeb, 0xc8, 0x74, + 0x6a, 0xd1, 0x29, 0x77, 0x21, 0x36, 0xeb, 0x1d, + 0xda, 0xf4, 0x64, 0x36, 0x45, 0x0d, 0x31, 0x83, + 0x32, 0xa8, 0x49, 0x82, 0xfe, 0x5d, 0x28, 0xdb, + 0xe5, 0xb3, 0xe9, 0x12, 0x40, 0x7c, 0x3e, 0x0e, + 0x03, 0x10, 0x0d, 0x87, 0xd4, 0x36, 0xee, 0x40, + 0x9e, 0xec, 0x1c, 0xf8, 0x5e, 0x80, 0xab, 0xa0, + 0x79, 0xb2, 0xe6, 0x10, 0x6b, 0x97, 0xbc, 0xed}, + .prime2_len = 128, + .exp1 = {0xed, 0x10, 0x2a, 0xcd, 0xb2, 0x68, 0x71, 0x53, + 0x4d, 0x1c, 0x41, 0x4e, 0xca, 0xd9, 0xa4, 0xd7, + 0x32, 0xfe, 0x95, 0xb1, 0x0e, 0xea, 0x37, 0x0d, + 0xa6, 0x2f, 0x05, 0xde, 0x2c, 0x39, 0x3b, 0x1a, + 0x63, 0x33, 0x03, 0xea, 0x74, 0x1b, 0x6b, 0x32, + 0x69, 0xc9, 0x7f, 0x70, 0x4b, 0x35, 0x27, 0x02, + 0xc9, 0xae, 0x79, 0x92, 0x2f, 0x7b, 0xe8, 0xd1, + 0x0d, 0xb6, 0x7f, 0x02, 0x6a, 0x81, 0x45, 0xde, + 0x41, 0xb3, 0x0c, 0x0a, 0x42, 0xbf, 0x92, 0x3b, + 0xac, 0x5f, 0x75, 0x04, 0xc2, 0x48, 0x60, 0x4b, + 0x9f, 0xaa, 0x57, 0xed, 0x6b, 0x32, 0x46, 0xc6, + 0xba, 0x15, 0x8e, 0x36, 0xc6, 0x44, 0xf8, 0xb9, + 0x54, 0x8f, 0xcf, 0x4f, 0x07, 0xe0, 0x54, 0xa5, + 0x6f, 0x76, 0x86, 0x74, 0x05, 0x44, 0x40, 0xbc, + 0x0d, 0xcb, 0xbc, 0x9b, 0x52, 0x8f, 0x64, 0xa0, + 0x17, 0x06, 0xe0, 0x5b, 0x0b, 0x91, 0x10, 0x6f}, + .exp1_len = 128, + .exp2 = {0x68, 0x27, 0x92, 0x4a, 0x85, 0xe8, 0x8b, 0x55, + 0xba, 0x00, 0xf8, 0x21, 0x91, 0x28, 0xbd, 0x37, + 0x24, 0xc6, 0xb7, 0xd1, 0xdf, 0xe5, 0x62, 0x9e, + 0xf1, 0x97, 0x92, 0x5f, 0xec, 0xaf, 0xf5, 0xed, + 0xb9, 0xcd, 0xf3, 0xa7, 0xbe, 0xfd, 0x8e, 0xa2, + 0xe8, 0xdd, 0x37, 0x07, 0x13, 0x8b, 0x3f, 0xf8, + 0x7c, 0x3c, 0x39, 0xc5, 0x7f, 0x43, 0x9e, 0x56, + 0x2e, 0x2a, 0xa8, 0x05, 0xa3, 0x9d, 0x7c, 0xd7, + 0x99, 0x66, 0xd2, 0xec, 0xe7, 0x84, 0x5f, 0x1d, + 0xbc, 0x16, 0xbe, 0xe9, 0x99, 0x99, 0xe4, 0xd0, + 0xbf, 0x9e, 0xec, 0xa4, 0x5f, 0xcd, 0xa8, 0xa8, + 0x50, 0x00, 0x35, 0xfe, 0x6b, 0x5f, 0x03, 0xbc, + 0x2f, 0x6d, 0x1b, 0xfc, 0x4d, 0x4d, 0x0a, 0x37, + 0x23, 0x96, 0x1a, 0xf0, 0xcd, 0xce, 0x4a, 0x01, + 0xee, 0xc8, 0x2d, 0x7f, 0x54, 0x58, 0xec, 0x19, + 0xe7, 0x1b, 0x90, 0xee, 0xef, 0x7d, 0xff, 0x61}, + .exp2_len = 128, + .coef = {0x57, 0xb7, 0x38, 0x88, 0xd1, 0x83, 0xa9, 0x9a, + 0x63, 0x07, 0x42, 0x22, 0x77, 0x55, 0x1a, 0x3d, + 0x9e, 0x18, 0xad, 0xf0, 0x6a, 0x91, 0xe8, 0xb5, + 0x5c, 0xef, 0xfe, 0xf9, 0x07, 0x7c, 0x84, 0x96, + 0x94, 0x8e, 0xcb, 0x3b, 0x16, 0xb7, 0x81, 0x55, + 0xcb, 0x2a, 0x3a, 0x57, 0xc1, 0x19, 0xd3, 0x79, + 0x95, 0x1c, 0x01, 0x0a, 0xa6, 0x35, 0xed, 0xcf, + 0x62, 0xd8, 0x4c, 0x5a, 0x12, 0x2a, 0x8d, 0x67, + 0xab, 0x5f, 0xa9, 0xe5, 0xa4, 0xa8, 0x77, 0x2a, + 0x1e, 0x94, 0x3b, 0xaf, 0xc7, 0x0a, 0xe3, 0xa4, + 0xc1, 0xf0, 0xf3, 0xa4, 0xdd, 0xff, 0xae, 0xfd, + 0x18, 0x92, 0xc8, 0xcb, 0x33, 0xbb, 0x0d, 0x0b, + 0x95, 0x90, 0xe9, 0x63, 0xa6, 0x91, 0x10, 0xfb, + 0x34, 0xdb, 0x7b, 0x90, 0x6f, 0xc4, 0xba, 0x28, + 0x36, 0x99, 0x5a, 0xac, 0x7e, 0x52, 0x74, 0x90, + 0xac, 0x95, 0x2a, 0x02, 0x26, 0x8a, 0x4f, 0x18}, + .coef_len = 128, + .msg = {0xf4, 0x5d, 0x55, 0xf3, 0x55, 0x51, 0xe9, 0x75, + 0xd6, 0xa8, 0xdc, 0x7e, 0xa9, 0xf4, 0x88, 0x59, + 0x39, 0x40, 0xcc, 0x75, 0x69, 0x4a, 0x27, 0x8f, + 0x27, 0xe5, 0x78, 0xa1, 0x63, 0xd8, 0x39, 0xb3, + 0x40, 0x40, 0x84, 0x18, 0x08, 0xcf, 0x9c, 0x58, + 0xc9, 0xb8, 0x72, 0x8b, 0xf5, 0xf9, 0xce, 0x8e, + 0xe8, 0x11, 0xea, 0x91, 0x71, 0x4f, 0x47, 0xba, + 0xb9, 0x2d, 0x0f, 0x6d, 0x5a, 0x26, 0xfc, 0xfe, + 0xea, 0x6c, 0xd9, 0x3b, 0x91, 0x0c, 0x0a, 0x2c, + 0x96, 0x3e, 0x64, 0xeb, 0x18, 0x23, 0xf1, 0x02, + 0x75, 0x3d, 0x41, 0xf0, 0x33, 0x59, 0x10, 0xad, + 0x3a, 0x97, 0x71, 0x04, 0xf1, 0xaa, 0xf6, 0xc3, + 0x74, 0x27, 0x16, 0xa9, 0x75, 0x5d, 0x11, 0xb8, + 0xee, 0xd6, 0x90, 0x47, 0x7f, 0x44, 0x5c, 0x5d, + 0x27, 0x20, 0x8b, 0x2e, 0x28, 0x43, 0x30, 0xfa, + 0x3d, 0x30, 0x14, 0x23, 0xfa, 0x7f, 0x2d, 0x08, + 0x6e, 0x0a, 0xd0, 0xb8, 0x92, 0xb9, 0xdb, 0x54, + 0x4e, 0x45, 0x6d, 0x3f, 0x0d, 0xab, 0x85, 0xd9, + 0x53, 0xc1, 0x2d, 0x34, 0x0a, 0xa8, 0x73, 0xed, + 0xa7, 0x27, 0xc8, 0xa6, 0x49, 0xdb, 0x7f, 0xa6, + 0x37, 0x40, 0xe2, 0x5e, 0x9a, 0xf1, 0x53, 0x3b, + 0x30, 0x7e, 0x61, 0x32, 0x99, 0x93, 0x11, 0x0e, + 0x95, 0x19, 0x4e, 0x03, 0x93, 0x99, 0xc3, 0x82, + 0x4d, 0x24, 0xc5, 0x1f, 0x22, 0xb2, 0x6b, 0xde, + 0x10, 0x24, 0xcd, 0x39, 0x59, 0x58, 0xa2, 0xdf, + 0xeb, 0x48, 0x16, 0xa6, 0xe8, 0xad, 0xed, 0xb5, + 0x0b, 0x1f, 0x6b, 0x56, 0xd0, 0xb3, 0x06, 0x0f, + 0xf0, 0xf1, 0xc4, 0xcb, 0x0d, 0x0e, 0x00, 0x1d, + 0xd5, 0x9d, 0x73, 0xbe, 0x12}, + .msg_len = 229, + + .sig = {0x33, 0xDC, 0x82, 0x68, 0xBC, 0x5C, 0x9A, 0x57, + 0x53, 0xED, 0xB9, 0x14, 0x25, 0x5F, 0x1D, 0x2B, + 0xF3, 0xCE, 0x65, 0x22, 0x66, 0x38, 0x82, 0xC9, + 0x94, 0xFD, 0x10, 0x40, 0x93, 0xB2, 0xDE, 0xCF, + 0x17, 0x86, 0xB9, 0xC2, 0x54, 0x3F, 0x09, 0x01, + 0x67, 0x9E, 0xF6, 0x11, 0x81, 0xB0, 0x14, 0x24, + 0xEF, 0xC3, 0xDF, 0xE5, 0xF6, 0x22, 0x6C, 0x9E, + 0xA3, 0x12, 0x06, 0xB4, 0x02, 0xC6, 0x51, 0x1B, + 0x8B, 0x87, 0x51, 0xED, 0x1C, 0x9F, 0xAE, 0x97, + 0x74, 0x93, 0xEC, 0x2B, 0xE6, 0x70, 0xE9, 0x11, + 0xCB, 0x4F, 0xEE, 0xD0, 0xA6, 0x54, 0x8D, 0x53, + 0x2E, 0xA3, 0x61, 0xF7, 0x12, 0x68, 0x35, 0x7F, + 0x73, 0xED, 0x6F, 0xE4, 0x85, 0xB4, 0xFD, 0xC4, + 0x26, 0x58, 0x3A, 0xA9, 0xF7, 0x8E, 0x86, 0x17, + 0x4E, 0x25, 0xFB, 0xED, 0x7F, 0x06, 0x99, 0x37, + 0xB4, 0x8E, 0x53, 0x80, 0xB9, 0x01, 0x23, 0x95, + 0x52, 0x6C, 0xA8, 0xE2, 0x37, 0xA0, 0xDD, 0xB3, + 0xCB, 0xC8, 0xDF, 0xD2, 0xB3, 0x6E, 0x21, 0xDC, + 0x1A, 0x78, 0xED, 0xB3, 0x5F, 0x24, 0x9A, 0x84, + 0x10, 0x57, 0x94, 0xB5, 0x38, 0xC6, 0x60, 0x03, + 0x4D, 0x73, 0x92, 0x02, 0x07, 0x53, 0xB0, 0xC3, + 0xEB, 0x1D, 0xBC, 0x81, 0x5D, 0xC0, 0x13, 0x86, + 0x3F, 0x31, 0xAB, 0x4A, 0xAC, 0xD8, 0x9C, 0xBA, + 0xE3, 0x24, 0x87, 0x97, 0xD3, 0xCE, 0x97, 0xDF, + 0xC7, 0x85, 0xCB, 0xED, 0xA2, 0x98, 0x11, 0x49, + 0xE3, 0x03, 0x70, 0x7D, 0x84, 0x24, 0xC3, 0xAA, + 0xE3, 0xCD, 0x91, 0x34, 0x2B, 0x84, 0x18, 0x66, + 0x82, 0x0A, 0x82, 0xEA, 0x74, 0x3B, 0x66, 0xF4, + 0x82, 0x31, 0x69, 0x54, 0x84, 0xCD, 0x41, 0x24, + 0xEB, 0xFF, 0xDD, 0x20, 0xD7, 0x9C, 0x91, 0x4F, + 0xBA, 0xB2, 0x8F, 0x2D, 0xFB, 0x57, 0xC7, 0x05, + 0x1E, 0x72, 0x1C, 0x4C, 0x71, 0x2F, 0xE3, 0xDD}, + .sig_len = 256, + .chunks = {50, 100, 0, 75, 4}, + .num_chunks = 5, + } +}; + +struct RSA_PUBLISHED_TEST_VECTOR rsa_sha512_pkcs_sigver_published_tv[] = { + + { // 0 + .mod = {0xa8, 0xd6, 0x8a, 0xcd, 0x41, 0x3c, 0x5e, 0x19, + 0x5d, 0x5e, 0xf0, 0x4e, 0x1b, 0x4f, 0xaa, 0xf2, + 0x42, 0x36, 0x5c, 0xb4, 0x50, 0x19, 0x67, 0x55, + 0xe9, 0x2e, 0x12, 0x15, 0xba, 0x59, 0x80, 0x2a, + 0xaf, 0xba, 0xdb, 0xf2, 0x56, 0x4d, 0xd5, 0x50, + 0x95, 0x6a, 0xbb, 0x54, 0xf8, 0xb1, 0xc9, 0x17, + 0x84, 0x4e, 0x5f, 0x36, 0x19, 0x5d, 0x10, 0x88, + 0xc6, 0x00, 0xe0, 0x7c, 0xad, 0xa5, 0xc0, 0x80, + 0xed, 0xe6, 0x79, 0xf5, 0x0b, 0x3d, 0xe3, 0x2c, + 0xf4, 0x02, 0x6e, 0x51, 0x45, 0x42, 0x49, 0x5c, + 0x54, 0xb1, 0x90, 0x37, 0x68, 0x79, 0x1a, 0xae, + 0x9e, 0x36, 0xf0, 0x82, 0xcd, 0x38, 0xe9, 0x41, + 0xad, 0xa8, 0x9b, 0xae, 0xca, 0xda, 0x61, 0xab, + 0x0d, 0xd3, 0x7a, 0xd5, 0x36, 0xbc, 0xb0, 0xa0, + 0x94, 0x62, 0x71, 0x59, 0x48, 0x36, 0xe9, 0x2a, + 0xb5, 0x51, 0x73, 0x01, 0xd4, 0x51, 0x76, 0xb5}, + .mod_len = 128, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0xa3, 0xcd, 0x31, 0x70, 0x9d, 0x1f, 0xd2, 0x33, + 0x4d, 0x90, 0xf4, 0x16, 0xf3, 0x0c, 0x41, 0xcf, + 0x33, 0x49, 0xc6, 0x7a, 0xf1, 0x53, 0x14, 0x1c, + 0x17, 0x54, 0x29, 0x1b, 0x87, 0x65, 0x99, 0xa0, + 0xd0, 0x48, 0xbb, 0x66, 0xcb, 0x30, 0x4c, 0x0a, + 0x18, 0x4c, 0x2a, 0x5e, 0xef, 0xc0, 0x9c, 0x56, + 0x02, 0x78, 0x7e, 0x8a, 0xdf, 0xe4, 0x98, 0x4b, + 0xf9, 0xbd, 0x94, 0x0d, 0xa1, 0xf2, 0xb3, 0x65, + 0x4d, 0xe5, 0x90, 0x7d, 0xb9, 0xe2, 0xc3, 0x80, + 0xce, 0x7b, 0xe4, 0x0b, 0x2f, 0xd3, 0x76, 0xc2, + 0x8d, 0xee, 0xc3, 0x34, 0x6f, 0xcd, 0x3a, 0x1a, + 0xc9, 0xd7, 0x68, 0xaf, 0x39, 0x2d, 0x14, 0xb7, + 0x7b, 0x7c, 0x9f, 0x32, 0x93, 0x28, 0xa9, 0x7b, + 0xc5, 0xdc, 0x93, 0xab, 0x17, 0xce, 0x09, 0x3c, + 0x32, 0xbe, 0x3e, 0xab, 0x85, 0x07, 0x5b, 0x6e, + 0xbb, 0xeb, 0x29, 0x95, 0xe8, 0x66, 0x2d, 0x41}, + .privexp_len = 128, + .prime1 = {0xdf, 0xea, 0x98, 0x4c, 0xe4, 0x30, 0x7e, 0xaf, + 0xc0, 0xd1, 0x40, 0xc2, 0xbb, 0x82, 0x86, 0x1e, + 0x5d, 0xba, 0xc4, 0xf8, 0x56, 0x7c, 0xbc, 0x98, + 0x1d, 0x70, 0x44, 0x0d, 0xd6, 0x39, 0x49, 0x20, + 0x79, 0x03, 0x14, 0x86, 0x31, 0x5e, 0x30, 0x5e, + 0xb8, 0x3e, 0x59, 0x1c, 0x4a, 0x2e, 0x96, 0x06, + 0x49, 0x66, 0xf7, 0xc8, 0x94, 0xc3, 0xca, 0x35, + 0x19, 0x25, 0xb5, 0xce, 0x82, 0xd8, 0xef, 0x0d}, + .prime1_len = 64, + .prime2 = {0xc1, 0x07, 0xa2, 0xfe, 0x92, 0x4b, 0x76, 0xe2, + 0x06, 0xcb, 0x9b, 0xc4, 0xaf, 0x2a, 0xb7, 0x00, + 0x85, 0x47, 0xc0, 0x08, 0x46, 0xbf, 0x6d, 0x06, + 0x80, 0xb3, 0xea, 0xc3, 0xeb, 0xcb, 0xd0, 0xc7, + 0xfd, 0x7a, 0x54, 0xc2, 0xb9, 0x89, 0x9b, 0x08, + 0xf8, 0x0c, 0xde, 0x1d, 0x36, 0x91, 0xea, 0xaa, + 0x28, 0x16, 0xb1, 0xeb, 0x11, 0x82, 0x2d, 0x6b, + 0xe7, 0xbe, 0xaf, 0x4e, 0x30, 0x97, 0x7c, 0x49}, + .prime2_len = 64, + .exp1 = {0xcd, 0x39, 0x54, 0x71, 0x54, 0xcb, 0x65, 0xb1, + 0x6b, 0xc5, 0xdd, 0xd7, 0x1c, 0xc8, 0xda, 0x67, + 0xc6, 0x7c, 0x41, 0xbf, 0x62, 0x75, 0x5c, 0xdd, + 0x06, 0x4e, 0x38, 0xf1, 0x7d, 0xa0, 0x6f, 0x77, + 0x85, 0xb1, 0xdf, 0x03, 0xc7, 0x07, 0x8e, 0xc9, + 0xa1, 0x8f, 0xf3, 0x58, 0x4c, 0x5d, 0x3a, 0x3f, + 0x74, 0xd3, 0x1c, 0xd3, 0x08, 0x16, 0x12, 0xa4, + 0x6b, 0xf1, 0xf6, 0x19, 0xda, 0x2f, 0x3d, 0x99}, + .exp1_len = 64, + .exp2 = {0xc0, 0x6d, 0xd1, 0x82, 0x80, 0xea, 0xf4, 0x1f, + 0xcd, 0x70, 0x6a, 0xdf, 0xbf, 0x54, 0x10, 0xcd, + 0x57, 0x10, 0xb9, 0x12, 0x47, 0x1d, 0x0c, 0x1e, + 0x00, 0x6d, 0xdb, 0xaa, 0xe6, 0xc4, 0xef, 0x64, + 0x7f, 0x7f, 0xd5, 0x41, 0xad, 0xde, 0xcd, 0x0c, + 0x3a, 0xe3, 0xf1, 0x05, 0x24, 0x62, 0x80, 0x92, + 0x92, 0x96, 0x55, 0x55, 0xa6, 0xc5, 0xa4, 0x6c, + 0x3e, 0xc1, 0xac, 0x57, 0x81, 0x3f, 0x72, 0xe9}, + .exp2_len = 64, + .coef = {0x49, 0x80, 0xae, 0xd5, 0x25, 0xff, 0x0e, 0x0e, + 0xa4, 0x73, 0x7a, 0x4e, 0x61, 0x19, 0x2e, 0x2b, + 0x11, 0x09, 0x05, 0xf1, 0xc4, 0xf2, 0xf6, 0x4d, + 0x04, 0x2f, 0xd9, 0xa5, 0x22, 0xd5, 0xe5, 0x73, + 0xfc, 0xfa, 0xd2, 0x01, 0x03, 0xef, 0x52, 0x80, + 0xc6, 0x4b, 0xe8, 0x7a, 0x38, 0x50, 0x55, 0xb7, + 0x6d, 0x7f, 0x56, 0xdf, 0xef, 0xdf, 0xb2, 0xca, + 0x98, 0xb5, 0xc9, 0x55, 0x90, 0x2f, 0x08, 0x84}, + .coef_len = 64, + .msg = {0xff, 0x23, 0xe0, 0x0f, 0x81, 0x9b, 0xae, 0x42, + 0x4e, 0x41, 0xd6, 0xb7, 0x62, 0xea, 0x6b, 0x88, + 0x80, 0x1e, 0x65, 0x1c, 0x83, 0x1c, 0x96, 0x4a, + 0xf3, 0x1d, 0xe0, 0xc1, 0xd6, 0xdd, 0xa4, 0xa7, + 0xc8, 0x58, 0x7d, 0x80, 0x4e, 0xd1, 0x2f, 0x52, + 0x68, 0x19, 0xda, 0x06, 0x65, 0x0e, 0x74, 0x12, + 0xfb, 0x62, 0x75, 0x55, 0x97, 0x9e, 0xd4, 0x42, + 0xf2, 0x66, 0x33, 0x41, 0xe5, 0xfe, 0x57, 0x52, + 0x7e, 0x0d, 0xda, 0xf4, 0x53, 0xa1, 0x24, 0x45, + 0x16, 0x74, 0x97, 0x6a, 0x6a, 0x6e, 0x0a, 0x31, + 0xf5, 0x6a, 0x79, 0xf5, 0xb7, 0x3d, 0xfa, 0xc3, + 0x9a, 0xf4, 0xf3, 0xba, 0x4a, 0x5e, 0x8b, 0xb8, + 0x46, 0xcb, 0x5e, 0x33, 0x38, 0x12, 0x75, 0x64, + 0x82, 0xd9, 0x75, 0xab, 0x19, 0x10, 0x16, 0x2f, + 0x96, 0xbf, 0xd7, 0xc5, 0x8a, 0x02, 0xf1, 0x13, + 0x12, 0x51, 0x89, 0xf5, 0xac, 0x05, 0x29, 0x1f}, + .msg_len = 128, + + .sig = {0x49, 0xF0, 0xF7, 0x41, 0x32, 0x0A, 0x51, 0xAB, + 0xE5, 0x73, 0x8E, 0xD0, 0x7C, 0xBE, 0x2D, 0xE9, + 0x14, 0xC9, 0x93, 0xD9, 0xE0, 0x1C, 0x25, 0x85, + 0x01, 0xC7, 0xAA, 0x44, 0x40, 0x55, 0x9B, 0xB1, + 0xD4, 0x68, 0xDF, 0x89, 0xD0, 0x36, 0x2B, 0xBC, + 0xF6, 0x3B, 0x3F, 0x31, 0x8C, 0xFA, 0x57, 0x01, + 0x17, 0xB2, 0x37, 0x6F, 0x49, 0x95, 0x8F, 0x7C, + 0x13, 0x46, 0xE2, 0xB3, 0x53, 0x52, 0x5B, 0x07, + 0xD6, 0x05, 0x08, 0x6D, 0xAB, 0xD4, 0x21, 0x5A, + 0x94, 0x10, 0xE9, 0xAE, 0xCD, 0xED, 0x8C, 0x22, + 0x3B, 0xC5, 0x44, 0x3D, 0x64, 0x09, 0xBC, 0xC8, + 0x59, 0x38, 0x5D, 0x4A, 0xF1, 0x92, 0x86, 0x65, + 0xC7, 0xBA, 0x55, 0x5E, 0xB7, 0x51, 0xD1, 0x03, + 0x91, 0x7D, 0x05, 0x4C, 0x42, 0x11, 0xD7, 0xD0, + 0x7D, 0x17, 0xBB, 0x9F, 0x75, 0xED, 0xA7, 0xD0, + 0xFE, 0xE4, 0xDF, 0xF7, 0xDE, 0x57, 0x51, 0x98}, + .sig_len = 128, + .chunks = {-1, 65, 63}, + .num_chunks = 3}, + { // #1 - 2048 bit key size + .mod = {0xdf, 0x27, 0x1f, 0xd2, 0x5f, 0x86, 0x44, 0x49, + 0x6b, 0x0c, 0x81, 0xbe, 0x4b, 0xd5, 0x02, 0x97, + 0xef, 0x09, 0x9b, 0x00, 0x2a, 0x6f, 0xd6, 0x77, + 0x27, 0xeb, 0x44, 0x9c, 0xea, 0x56, 0x6e, 0xd6, + 0xa3, 0x98, 0x1a, 0x71, 0x31, 0x2a, 0x14, 0x1c, + 0xab, 0xc9, 0x81, 0x5c, 0x12, 0x09, 0xe3, 0x20, + 0xa2, 0x5b, 0x32, 0x46, 0x4e, 0x99, 0x99, 0xf1, + 0x8c, 0xa1, 0x3a, 0x9f, 0xd3, 0x89, 0x25, 0x58, + 0xf9, 0xe0, 0xad, 0xef, 0xdd, 0x36, 0x50, 0xdd, + 0x23, 0xa3, 0xf0, 0x36, 0xd6, 0x0f, 0xe3, 0x98, + 0x84, 0x37, 0x06, 0xa4, 0x0b, 0x0b, 0x84, 0x62, + 0xc8, 0xbe, 0xe3, 0xbc, 0xe1, 0x2f, 0x1f, 0x28, + 0x60, 0xc2, 0x44, 0x4c, 0xdc, 0x6a, 0x44, 0x47, + 0x6a, 0x75, 0xff, 0x4a, 0xa2, 0x42, 0x73, 0xcc, + 0xbe, 0x3b, 0xf8, 0x02, 0x48, 0x46, 0x5f, 0x8f, + 0xf8, 0xc3, 0xa7, 0xf3, 0x36, 0x7d, 0xfc, 0x0d, + 0xf5, 0xb6, 0x50, 0x9a, 0x4f, 0x82, 0x81, 0x1c, + 0xed, 0xd8, 0x1c, 0xda, 0xaa, 0x73, 0xc4, 0x91, + 0xda, 0x41, 0x21, 0x70, 0xd5, 0x44, 0xd4, 0xba, + 0x96, 0xb9, 0x7f, 0x0a, 0xfc, 0x80, 0x65, 0x49, + 0x8d, 0x3a, 0x49, 0xfd, 0x91, 0x09, 0x92, 0xa1, + 0xf0, 0x72, 0x5b, 0xe2, 0x4f, 0x46, 0x5c, 0xfe, + 0x7e, 0x0e, 0xab, 0xf6, 0x78, 0x99, 0x6c, 0x50, + 0xbc, 0x5e, 0x75, 0x24, 0xab, 0xf7, 0x3f, 0x15, + 0xe5, 0xbe, 0xf7, 0xd5, 0x18, 0x39, 0x4e, 0x31, + 0x38, 0xce, 0x49, 0x44, 0x50, 0x6a, 0xaa, 0xaf, + 0x3f, 0x9b, 0x23, 0x6d, 0xca, 0xb8, 0xfc, 0x00, + 0xf8, 0x7a, 0xf5, 0x96, 0xfd, 0xc3, 0xd9, 0xd6, + 0xc7, 0x5c, 0xd5, 0x08, 0x36, 0x2f, 0xae, 0x2c, + 0xbe, 0xdd, 0xcc, 0x4c, 0x74, 0x50, 0xb1, 0x7b, + 0x77, 0x6c, 0x07, 0x9e, 0xcc, 0xa1, 0xf2, 0x56, + 0x35, 0x1a, 0x43, 0xb9, 0x7d, 0xbe, 0x21, 0x53}, + .mod_len = 256, + .pub_exp = {0x01, 0x00, 0x01}, + .pubexp_len = 3, + .priv_exp = {0x5b, 0xd9, 0x10, 0x25, 0x78, 0x30, 0xdc, 0xe1, + 0x75, 0x20, 0xb0, 0x34, 0x41, 0xa5, 0x1a, 0x8c, + 0xab, 0x94, 0x02, 0x0a, 0xc6, 0xec, 0xc2, 0x52, + 0xc8, 0x08, 0xf3, 0x74, 0x3c, 0x95, 0xb7, 0xc8, + 0x3b, 0x8c, 0x8a, 0xf1, 0xa5, 0x01, 0x43, 0x46, + 0xeb, 0xc4, 0x24, 0x2c, 0xdf, 0xb5, 0xd7, 0x18, + 0xe3, 0x0a, 0x73, 0x3e, 0x71, 0xf2, 0x91, 0xe4, + 0xd4, 0x73, 0xb6, 0x1b, 0xfb, 0xa6, 0xda, 0xca, + 0xed, 0x0a, 0x77, 0xbd, 0x1f, 0x09, 0x50, 0xae, + 0x3c, 0x91, 0xa8, 0xf9, 0x01, 0x11, 0x88, 0x25, + 0x89, 0xe1, 0xd6, 0x27, 0x65, 0xee, 0x67, 0x1e, + 0x7b, 0xae, 0xea, 0x30, 0x9f, 0x64, 0xd4, 0x47, + 0xbb, 0xcf, 0xa9, 0xea, 0x12, 0xdc, 0xe0, 0x5e, + 0x9e, 0xa8, 0x93, 0x9b, 0xc5, 0xfe, 0x61, 0x08, + 0x58, 0x12, 0x79, 0xc9, 0x82, 0xb3, 0x08, 0x79, + 0x4b, 0x34, 0x48, 0xe7, 0xf7, 0xb9, 0x52, 0x29, + 0x2d, 0xf8, 0x8c, 0x80, 0xcb, 0x40, 0x14, 0x2c, + 0x4b, 0x5c, 0xf5, 0xf8, 0xdd, 0xaa, 0x08, 0x91, + 0x67, 0x8d, 0x61, 0x0e, 0x58, 0x2f, 0xcb, 0x88, + 0x0f, 0x0d, 0x70, 0x7c, 0xaf, 0x47, 0xd0, 0x9a, + 0x84, 0xe1, 0x4c, 0xa6, 0x58, 0x41, 0xe5, 0xa3, + 0xab, 0xc5, 0xe9, 0xdb, 0xa9, 0x40, 0x75, 0xa9, + 0x08, 0x43, 0x41, 0xf0, 0xed, 0xad, 0x9b, 0x68, + 0xe3, 0xb8, 0xe0, 0x82, 0xb8, 0x0b, 0x6e, 0x6e, + 0x8a, 0x05, 0x47, 0xb4, 0x4f, 0xb5, 0x06, 0x1b, + 0x6a, 0x91, 0x31, 0x60, 0x3a, 0x55, 0x37, 0xdd, + 0xab, 0xd0, 0x1d, 0x8e, 0x86, 0x3d, 0x89, 0x22, + 0xe9, 0xaa, 0x3e, 0x4b, 0xfa, 0xea, 0x0b, 0x39, + 0xd7, 0x92, 0x83, 0xad, 0x2c, 0xbc, 0x8a, 0x59, + 0xcc, 0xe7, 0xa6, 0xec, 0xf4, 0xe4, 0xc8, 0x1e, + 0xd4, 0xc6, 0x59, 0x1c, 0x80, 0x7d, 0xef, 0xd7, + 0x1a, 0xb0, 0x68, 0x66, 0xbb, 0x5e, 0x77, 0x45}, + .privexp_len = 256, + .prime1 = {0xf4, 0x4f, 0x5e, 0x42, 0x46, 0x39, 0x1f, 0x48, + 0x2b, 0x2f, 0x52, 0x96, 0xe3, 0x60, 0x2e, 0xb3, + 0x4a, 0xa1, 0x36, 0x42, 0x77, 0x10, 0xf7, 0xc0, + 0x41, 0x6d, 0x40, 0x3f, 0xd6, 0x9d, 0x4b, 0x29, + 0x13, 0x0c, 0xfe, 0xbe, 0xf3, 0x4e, 0x88, 0x5a, + 0xbd, 0xb1, 0xa8, 0xa0, 0xa5, 0xf0, 0xe9, 0xb5, + 0xc3, 0x3e, 0x1f, 0xc3, 0xbf, 0xc2, 0x85, 0xb1, + 0xae, 0x17, 0xe4, 0x0c, 0xc6, 0x7a, 0x19, 0x13, + 0xdd, 0x56, 0x37, 0x19, 0x81, 0x5e, 0xba, 0xf8, + 0x51, 0x4c, 0x2a, 0x7a, 0xa0, 0x01, 0x8e, 0x63, + 0xb6, 0xc6, 0x31, 0xdc, 0x31, 0x5a, 0x46, 0x23, + 0x57, 0x16, 0x42, 0x3d, 0x11, 0xff, 0x58, 0x03, + 0x4e, 0x61, 0x06, 0x45, 0x70, 0x36, 0x06, 0x91, + 0x9f, 0x5c, 0x7c, 0xe2, 0x66, 0x0c, 0xd1, 0x48, + 0xbd, 0x9e, 0xfc, 0x12, 0x3d, 0x9c, 0x54, 0xb6, + 0x70, 0x55, 0x90, 0xd0, 0x06, 0xcf, 0xcf, 0x3f}, + .prime1_len = 128, + .prime2 = {0xe9, 0xd4, 0x98, 0x41, 0xe0, 0xe0, 0xa6, 0xad, + 0x0d, 0x51, 0x78, 0x57, 0x13, 0x3e, 0x36, 0xdc, + 0x72, 0xc1, 0xbd, 0xd9, 0x0f, 0x91, 0x74, 0xb5, + 0x2e, 0x26, 0x57, 0x0f, 0x37, 0x36, 0x40, 0xf1, + 0xc1, 0x85, 0xe7, 0xea, 0x8e, 0x2e, 0xd7, 0xf1, + 0xe4, 0xeb, 0xb9, 0x51, 0xf7, 0x0a, 0x58, 0x02, + 0x36, 0x33, 0xb0, 0x09, 0x7a, 0xec, 0x67, 0xc6, + 0xdc, 0xb8, 0x00, 0xfc, 0x1a, 0x67, 0xf9, 0xbb, + 0x05, 0x63, 0x61, 0x0f, 0x08, 0xeb, 0xc8, 0x74, + 0x6a, 0xd1, 0x29, 0x77, 0x21, 0x36, 0xeb, 0x1d, + 0xda, 0xf4, 0x64, 0x36, 0x45, 0x0d, 0x31, 0x83, + 0x32, 0xa8, 0x49, 0x82, 0xfe, 0x5d, 0x28, 0xdb, + 0xe5, 0xb3, 0xe9, 0x12, 0x40, 0x7c, 0x3e, 0x0e, + 0x03, 0x10, 0x0d, 0x87, 0xd4, 0x36, 0xee, 0x40, + 0x9e, 0xec, 0x1c, 0xf8, 0x5e, 0x80, 0xab, 0xa0, + 0x79, 0xb2, 0xe6, 0x10, 0x6b, 0x97, 0xbc, 0xed}, + .prime2_len = 128, + .exp1 = {0xed, 0x10, 0x2a, 0xcd, 0xb2, 0x68, 0x71, 0x53, + 0x4d, 0x1c, 0x41, 0x4e, 0xca, 0xd9, 0xa4, 0xd7, + 0x32, 0xfe, 0x95, 0xb1, 0x0e, 0xea, 0x37, 0x0d, + 0xa6, 0x2f, 0x05, 0xde, 0x2c, 0x39, 0x3b, 0x1a, + 0x63, 0x33, 0x03, 0xea, 0x74, 0x1b, 0x6b, 0x32, + 0x69, 0xc9, 0x7f, 0x70, 0x4b, 0x35, 0x27, 0x02, + 0xc9, 0xae, 0x79, 0x92, 0x2f, 0x7b, 0xe8, 0xd1, + 0x0d, 0xb6, 0x7f, 0x02, 0x6a, 0x81, 0x45, 0xde, + 0x41, 0xb3, 0x0c, 0x0a, 0x42, 0xbf, 0x92, 0x3b, + 0xac, 0x5f, 0x75, 0x04, 0xc2, 0x48, 0x60, 0x4b, + 0x9f, 0xaa, 0x57, 0xed, 0x6b, 0x32, 0x46, 0xc6, + 0xba, 0x15, 0x8e, 0x36, 0xc6, 0x44, 0xf8, 0xb9, + 0x54, 0x8f, 0xcf, 0x4f, 0x07, 0xe0, 0x54, 0xa5, + 0x6f, 0x76, 0x86, 0x74, 0x05, 0x44, 0x40, 0xbc, + 0x0d, 0xcb, 0xbc, 0x9b, 0x52, 0x8f, 0x64, 0xa0, + 0x17, 0x06, 0xe0, 0x5b, 0x0b, 0x91, 0x10, 0x6f}, + .exp1_len = 128, + .exp2 = {0x68, 0x27, 0x92, 0x4a, 0x85, 0xe8, 0x8b, 0x55, + 0xba, 0x00, 0xf8, 0x21, 0x91, 0x28, 0xbd, 0x37, + 0x24, 0xc6, 0xb7, 0xd1, 0xdf, 0xe5, 0x62, 0x9e, + 0xf1, 0x97, 0x92, 0x5f, 0xec, 0xaf, 0xf5, 0xed, + 0xb9, 0xcd, 0xf3, 0xa7, 0xbe, 0xfd, 0x8e, 0xa2, + 0xe8, 0xdd, 0x37, 0x07, 0x13, 0x8b, 0x3f, 0xf8, + 0x7c, 0x3c, 0x39, 0xc5, 0x7f, 0x43, 0x9e, 0x56, + 0x2e, 0x2a, 0xa8, 0x05, 0xa3, 0x9d, 0x7c, 0xd7, + 0x99, 0x66, 0xd2, 0xec, 0xe7, 0x84, 0x5f, 0x1d, + 0xbc, 0x16, 0xbe, 0xe9, 0x99, 0x99, 0xe4, 0xd0, + 0xbf, 0x9e, 0xec, 0xa4, 0x5f, 0xcd, 0xa8, 0xa8, + 0x50, 0x00, 0x35, 0xfe, 0x6b, 0x5f, 0x03, 0xbc, + 0x2f, 0x6d, 0x1b, 0xfc, 0x4d, 0x4d, 0x0a, 0x37, + 0x23, 0x96, 0x1a, 0xf0, 0xcd, 0xce, 0x4a, 0x01, + 0xee, 0xc8, 0x2d, 0x7f, 0x54, 0x58, 0xec, 0x19, + 0xe7, 0x1b, 0x90, 0xee, 0xef, 0x7d, 0xff, 0x61}, + .exp2_len = 128, + .coef = {0x57, 0xb7, 0x38, 0x88, 0xd1, 0x83, 0xa9, 0x9a, + 0x63, 0x07, 0x42, 0x22, 0x77, 0x55, 0x1a, 0x3d, + 0x9e, 0x18, 0xad, 0xf0, 0x6a, 0x91, 0xe8, 0xb5, + 0x5c, 0xef, 0xfe, 0xf9, 0x07, 0x7c, 0x84, 0x96, + 0x94, 0x8e, 0xcb, 0x3b, 0x16, 0xb7, 0x81, 0x55, + 0xcb, 0x2a, 0x3a, 0x57, 0xc1, 0x19, 0xd3, 0x79, + 0x95, 0x1c, 0x01, 0x0a, 0xa6, 0x35, 0xed, 0xcf, + 0x62, 0xd8, 0x4c, 0x5a, 0x12, 0x2a, 0x8d, 0x67, + 0xab, 0x5f, 0xa9, 0xe5, 0xa4, 0xa8, 0x77, 0x2a, + 0x1e, 0x94, 0x3b, 0xaf, 0xc7, 0x0a, 0xe3, 0xa4, + 0xc1, 0xf0, 0xf3, 0xa4, 0xdd, 0xff, 0xae, 0xfd, + 0x18, 0x92, 0xc8, 0xcb, 0x33, 0xbb, 0x0d, 0x0b, + 0x95, 0x90, 0xe9, 0x63, 0xa6, 0x91, 0x10, 0xfb, + 0x34, 0xdb, 0x7b, 0x90, 0x6f, 0xc4, 0xba, 0x28, + 0x36, 0x99, 0x5a, 0xac, 0x7e, 0x52, 0x74, 0x90, + 0xac, 0x95, 0x2a, 0x02, 0x26, 0x8a, 0x4f, 0x18}, + .coef_len = 128, + .msg = {0xf4, 0x5d, 0x55, 0xf3, 0x55, 0x51, 0xe9, 0x75, + 0xd6, 0xa8, 0xdc, 0x7e, 0xa9, 0xf4, 0x88, 0x59, + 0x39, 0x40, 0xcc, 0x75, 0x69, 0x4a, 0x27, 0x8f, + 0x27, 0xe5, 0x78, 0xa1, 0x63, 0xd8, 0x39, 0xb3, + 0x40, 0x40, 0x84, 0x18, 0x08, 0xcf, 0x9c, 0x58, + 0xc9, 0xb8, 0x72, 0x8b, 0xf5, 0xf9, 0xce, 0x8e, + 0xe8, 0x11, 0xea, 0x91, 0x71, 0x4f, 0x47, 0xba, + 0xb9, 0x2d, 0x0f, 0x6d, 0x5a, 0x26, 0xfc, 0xfe, + 0xea, 0x6c, 0xd9, 0x3b, 0x91, 0x0c, 0x0a, 0x2c, + 0x96, 0x3e, 0x64, 0xeb, 0x18, 0x23, 0xf1, 0x02, + 0x75, 0x3d, 0x41, 0xf0, 0x33, 0x59, 0x10, 0xad, + 0x3a, 0x97, 0x71, 0x04, 0xf1, 0xaa, 0xf6, 0xc3, + 0x74, 0x27, 0x16, 0xa9, 0x75, 0x5d, 0x11, 0xb8, + 0xee, 0xd6, 0x90, 0x47, 0x7f, 0x44, 0x5c, 0x5d, + 0x27, 0x20, 0x8b, 0x2e, 0x28, 0x43, 0x30, 0xfa, + 0x3d, 0x30, 0x14, 0x23, 0xfa, 0x7f, 0x2d, 0x08, + 0x6e, 0x0a, 0xd0, 0xb8, 0x92, 0xb9, 0xdb, 0x54, + 0x4e, 0x45, 0x6d, 0x3f, 0x0d, 0xab, 0x85, 0xd9, + 0x53, 0xc1, 0x2d, 0x34, 0x0a, 0xa8, 0x73, 0xed, + 0xa7, 0x27, 0xc8, 0xa6, 0x49, 0xdb, 0x7f, 0xa6, + 0x37, 0x40, 0xe2, 0x5e, 0x9a, 0xf1, 0x53, 0x3b, + 0x30, 0x7e, 0x61, 0x32, 0x99, 0x93, 0x11, 0x0e, + 0x95, 0x19, 0x4e, 0x03, 0x93, 0x99, 0xc3, 0x82, + 0x4d, 0x24, 0xc5, 0x1f, 0x22, 0xb2, 0x6b, 0xde, + 0x10, 0x24, 0xcd, 0x39, 0x59, 0x58, 0xa2, 0xdf, + 0xeb, 0x48, 0x16, 0xa6, 0xe8, 0xad, 0xed, 0xb5, + 0x0b, 0x1f, 0x6b, 0x56, 0xd0, 0xb3, 0x06, 0x0f, + 0xf0, 0xf1, 0xc4, 0xcb, 0x0d, 0x0e, 0x00, 0x1d, + 0xd5, 0x9d, 0x73, 0xbe, 0x12}, + .msg_len = 229, + + .sig = {0xBF, 0x29, 0x62, 0xC5, 0x00, 0xE4, 0xD9, 0x1F, + 0x23, 0x4F, 0x3E, 0xF1, 0x48, 0xAE, 0x32, 0xD4, + 0xEA, 0xE9, 0x09, 0x29, 0xBD, 0x57, 0x92, 0xAE, + 0x83, 0x19, 0xE4, 0x12, 0xE9, 0x23, 0xC3, 0x76, + 0x41, 0xD0, 0x18, 0xE4, 0x82, 0xD6, 0x55, 0xCE, + 0x2D, 0x48, 0x6F, 0x36, 0xD1, 0x5E, 0x78, 0x68, + 0x89, 0x3F, 0x79, 0xC7, 0xBD, 0xC4, 0x3B, 0x2A, + 0xDE, 0xF2, 0x0F, 0xF7, 0x92, 0x9C, 0xBC, 0x29, + 0xA0, 0xBF, 0xC0, 0x05, 0x72, 0x8F, 0x68, 0xCE, + 0x0F, 0x8E, 0x9A, 0xD7, 0x59, 0x47, 0x79, 0x33, + 0xE9, 0x51, 0x35, 0x5A, 0x46, 0x88, 0x52, 0x71, + 0x24, 0xB9, 0x02, 0x7F, 0xA7, 0xDA, 0x96, 0x3D, + 0xF5, 0x75, 0x5B, 0x9F, 0x42, 0x1A, 0xC6, 0x68, + 0x6A, 0x92, 0x78, 0x4A, 0xA9, 0xE1, 0x2D, 0xF8, + 0x1B, 0x2D, 0xE8, 0x42, 0xAD, 0xDF, 0x3A, 0x8B, + 0x4F, 0xFA, 0x03, 0xF8, 0x65, 0xF3, 0xAA, 0x9C, + 0x62, 0x3D, 0x27, 0x9F, 0xCE, 0xEF, 0xDC, 0xDA, + 0xD9, 0x75, 0x51, 0x89, 0x6F, 0x62, 0x33, 0x5A, + 0x7A, 0xFF, 0x26, 0xD3, 0x54, 0x85, 0xDE, 0x49, + 0x51, 0x1A, 0x8B, 0x5A, 0x0A, 0xD4, 0x05, 0xD3, + 0x53, 0x21, 0x8F, 0xD6, 0x98, 0xC0, 0x13, 0x67, + 0x2D, 0x99, 0x5D, 0xB7, 0x84, 0x1D, 0x51, 0x6B, + 0xC7, 0x86, 0xA6, 0x92, 0xC9, 0x93, 0xD7, 0x03, + 0x5C, 0x74, 0xAF, 0xBC, 0x6C, 0xB5, 0x5F, 0xD3, + 0xD4, 0x6E, 0x4E, 0x14, 0x15, 0x02, 0x8B, 0x2D, + 0xB1, 0x06, 0xCD, 0xB1, 0x59, 0x13, 0xF1, 0x84, + 0x7D, 0x7F, 0xDE, 0x33, 0x96, 0xF1, 0x05, 0x1E, + 0x8E, 0x58, 0x22, 0x91, 0x58, 0x71, 0x5A, 0xEA, + 0x85, 0x4B, 0x8B, 0xE3, 0x56, 0x67, 0xED, 0xC5, + 0x7F, 0xEA, 0x8A, 0xAC, 0x32, 0x7C, 0xE3, 0xE0, + 0x43, 0xF2, 0x84, 0x93, 0x5E, 0x8F, 0x19, 0x9D, + 0x6C, 0x2E, 0xA6, 0x05, 0x80, 0x76, 0x30, 0xF6}, + .sig_len = 256, + .chunks = {50, 100, 0, 75, 4}, + .num_chunks = 5, + } +}; + +struct PUBLISHED_TEST_SUITE_INFO { + const char *name; + unsigned int tvcount; + struct RSA_PUBLISHED_TEST_VECTOR *tv; + CK_MECHANISM mech; + unsigned int result; +}; + +#define NUM_OF_PUBLISHED_TESTSUITES 4 +struct PUBLISHED_TEST_SUITE_INFO published_test_suites[] = { + { + .name = "RSA SHA-1 PKCS v1.5", + .tvcount = 45, + .tv = rsa_sha1_pkcs_sigver_published_tv, + .mech = {CKM_SHA1_RSA_PKCS, 0, 0}, + }, + { + .name = "RSA SHA256 PKCS v1.5", + .tvcount = 2, + .tv = rsa_sha256_pkcs_sigver_published_tv, + .mech = {CKM_SHA256_RSA_PKCS, 0, 0}, + }, + { + .name = "RSA SHA384 PKCS v1.5", + .tvcount = 2, + .tv = rsa_sha384_pkcs_sigver_published_tv, + .mech = {CKM_SHA384_RSA_PKCS, 0, 0}, + }, + { + .name = "RSA SHA512 PKCS v1.5", + .tvcount = 2, + .tv = rsa_sha512_pkcs_sigver_published_tv, + .mech = {CKM_SHA512_RSA_PKCS, 0, 0}, + } +}; + +CK_RSA_PKCS_OAEP_PARAMS oaep_params_sha1 = {CKM_SHA_1, CKG_MGF1_SHA1, CKZ_DATA_SPECIFIED, NULL, 0}; +CK_RSA_PKCS_OAEP_PARAMS oaep_params_sha256 = {CKM_SHA256, CKG_MGF1_SHA256, CKZ_DATA_SPECIFIED, NULL, 0}; + +#define NUM_OF_ENCDEC_IMPORT_TESTSUITES 4 +struct PUBLISHED_TEST_SUITE_INFO rsa_encdec_import_test_suites[] = { + { + .name = "RSA PKCS", + .tvcount = 45, + .tv = rsa_sha1_pkcs_sigver_published_tv, + .mech = {CKM_RSA_PKCS, 0, 0}, + }, + { + .name = "RSA PKCS OAEP (SHA1)", + .tvcount = 45, + .tv = rsa_sha1_pkcs_sigver_published_tv, + .mech = {CKM_RSA_PKCS_OAEP, &oaep_params_sha1, sizeof(oaep_params_sha1)}, + }, + { + .name = "RSA PKCS OAEP (SHA256)", + .tvcount = 2, + .tv = rsa_sha256_pkcs_sigver_published_tv, + .mech = {CKM_RSA_PKCS_OAEP, &oaep_params_sha256, sizeof(oaep_params_sha256)}, + }, + { + .name = "RSA X.509", + .tvcount = 45, + .tv = rsa_sha1_pkcs_sigver_published_tv, + .mech = {CKM_RSA_X_509, 0, 0}, + }, +}; diff --git a/testcases/crypto/rsa_func.c b/testcases/crypto/rsa_func.c new file mode 100644 index 0000000..05f5872 --- /dev/null +++ b/testcases/crypto/rsa_func.c @@ -0,0 +1,1811 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2011-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 + */ + + /* + * openCryptoki testcase for RSA + * + * August 18, 2011 + * + * Fionnuala Gunter + */ + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "common.c" +#include "regress.h" +#include "mech_to_str.h" + +#include "rsa.h" + +/** + * Note: do_EncryptDecryptRSA fails if we don't manually + * remove padding from decrypted values. This might be a bug. + **/ + + +/* This function should test: + * RSA Key Generation, CKM_RSA_PKCS_KEY_PAIR_GEN + * RSA Encryption, mechanism chosen by caller + * RSA Decryption, mechanism chosen by caller + * + * 1. Generate RSA Key Pair + * 2. Generate plaintext + * 3. Encrypt plaintext + * 4. Decrypt encrypted data + * 5. Compare plaintext with decrypted data + * + */ +CK_RV do_EncryptDecryptRSA(struct GENERATED_TEST_SUITE_INFO *tsuite) +{ + unsigned int i, j; + CK_BYTE original[BIG_REQUEST]; + CK_ULONG original_len; + CK_BYTE crypt[BIG_REQUEST]; + CK_ULONG crypt_len; + CK_BYTE decrypt[BIG_REQUEST]; + CK_ULONG decrypt_len; + CK_MECHANISM mech; + CK_OBJECT_HANDLE publ_key, priv_key; + CK_SLOT_ID slot_id = SLOT_ID; + CK_SESSION_HANDLE session; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rc, loc_rc; + CK_RSA_PKCS_OAEP_PARAMS oaep_params; + + char *s; + + // begin testsuite + testsuite_begin("%s Encrypt Decrypt.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + // skip tests if the slot doesn't support this mechanism + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + // iterate over test vectors + for (i = 0; i < tsuite->tvcount; i++) { + + // get public exponent from test vector + if (p11_ahex_dump(&s, tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len) == NULL) { + testcase_error("p11_ahex_dump() failed"); + rc = -1; + goto testcase_cleanup; + } + // begin testcase + testcase_begin("%s Encrypt and Decrypt with test vector %d." + "\npubl_exp='%s', modbits=%ld, publ_exp_len=%ld, " + "inputlen=%ld.", tsuite->name, i, s, + tsuite->tv[i].modbits, + tsuite->tv[i].publ_exp_len, tsuite->tv[i].inputlen); + + rc = CKR_OK; // set rc + + if (!keysize_supported(slot_id, tsuite->mech.mechanism, + tsuite->tv[i].modbits)) { + testcase_skip("Token in slot %ld cannot be used with " + "modbits.='%ld'", SLOT_ID, tsuite->tv[i].modbits); + continue; + } + + if (is_ep11_token(slot_id)) { + if (!is_valid_ep11_pubexp(tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len)) { + testcase_skip("EP11 Token cannot " + "be used with publ_exp.='%s'", s); + continue; + } + } + // cca special cases: + // cca token can only use the following public exponents + // 0x03 or 0x010001 (65537) + // so skip test if invalid public exponent is used + if (is_cca_token(slot_id)) { + if (!is_valid_cca_pubexp(tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len)) { + testcase_skip("CCA Token cannot " + "be used with publ_exp.='%s'", s); + continue; + } + } + // tpm special cases: + // tpm token can only use public exponent 0x010001 (65537) + // so skip test if invalid public exponent is used + if (is_tpm_token(slot_id)) { + if ((!is_valid_tpm_pubexp(tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len)) + || (!is_valid_tpm_modbits(tsuite->tv[i].modbits))) { + testcase_skip("TPM Token cannot " "be used with publ_exp.='%s'", + s); + continue; + } + } + + if (is_icsf_token(slot_id)) { + if (!is_valid_icsf_pubexp(tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len) || + (tsuite->tv[i].modbits < 1024)) { + testcase_skip("ICSF Token cannot be used with " + "publ_exp='%s'.", s); + continue; + } + } + + free(s); + + // clear buffers + memset(original, 0, BIG_REQUEST); + memset(crypt, 0, BIG_REQUEST); + memset(decrypt, 0, BIG_REQUEST); + + // get test vector parameters + original_len = tsuite->tv[i].inputlen; + + // generate key pair + rc = generate_RSA_PKCS_KeyPair(session, + tsuite->tv[i].modbits, + tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len, + &publ_key, &priv_key); + + if (rc != CKR_OK) { + testcase_error("generate_RSA_PKCS_KeyPair(), " + "rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // generate plaintext + for (j = 0; j < original_len; j++) { + original[j] = (j + 1) % 255; + } + + // set cipher buffer length + crypt_len = BIG_REQUEST; + decrypt_len = BIG_REQUEST; + + // get mech + mech = tsuite->mech; + if (mech.mechanism == CKM_RSA_PKCS_OAEP) { + oaep_params = tsuite->tv[i].oaep_params; + mech.pParameter = &oaep_params; + mech.ulParameterLen = sizeof(CK_RSA_PKCS_OAEP_PARAMS); + } + // initialize (public key) encryption + rc = funcs->C_EncryptInit(session, &mech, publ_key); + if (rc != CKR_OK) { + if (rc == CKR_MECHANISM_PARAM_INVALID && + mech.mechanism == CKM_RSA_PKCS_OAEP && + is_ep11_token(slot_id) && + (oaep_params.hashAlg != CKM_SHA_1 || + oaep_params.mgf != CKG_MGF1_SHA1)) { + testcase_skip("EP11 Token does not support RSA OAEP with hash " + "and/or MGF other than SHA-1"); + goto tv_cleanup; + } + + testcase_error("C_EncryptInit, rc=%s", p11_get_ckr(rc)); + goto error; + } + // do (public key) encryption + rc = funcs->C_Encrypt(session, + original, original_len, crypt, &crypt_len); + if (rc != CKR_OK) { + testcase_error("C_Encrypt, rc=%s", p11_get_ckr(rc)); + goto error; + } + // initialize (private key) decryption + rc = funcs->C_DecryptInit(session, &mech, priv_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit, rc=%s", p11_get_ckr(rc)); + goto error; + } + // do (private key) decryption + rc = funcs->C_Decrypt(session, crypt, crypt_len, decrypt, &decrypt_len); + if (rc != CKR_OK) { + testcase_error("C_Decrypt, rc=%s", p11_get_ckr(rc)); + goto error; + } + // FIXME: there shouldn't be any padding here + // remove padding if mech is CKM_RSA_X_509 + if (mech.mechanism == CKM_RSA_X_509) { + memmove(decrypt, + decrypt + decrypt_len - original_len, original_len); + decrypt_len = original_len; + } + // check results + testcase_new_assertion(); + + if (decrypt_len != original_len) { + testcase_fail("decrypted length does not match" + "original data length.\n expected length = %ld," + "but found length=%ld.\n", original_len, decrypt_len); + } else if (memcmp(decrypt, original, original_len)) { + testcase_fail("decrypted data does not match " "original data."); + } else { + testcase_pass("C_Encrypt and C_Decrypt."); + } + + // clean up +tv_cleanup: + rc = funcs->C_DestroyObject(session, publ_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + goto error; + } + + rc = funcs->C_DestroyObject(session, priv_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + goto error; + } + } + + goto testcase_cleanup; +error: + loc_rc = funcs->C_DestroyObject(session, publ_key); + if (loc_rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); + } + + loc_rc = funcs->C_DestroyObject(session, priv_key); + if (loc_rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); + } + +testcase_cleanup: + testcase_user_logout(); + loc_rc = funcs->C_CloseAllSessions(slot_id); + if (loc_rc != CKR_OK) { + testcase_error("C_CloseAllSessions, rc=%s", p11_get_ckr(loc_rc)); + } + + return rc; +} + +/** + * Note: do_EncryptDecryptImportRSA fails if we don't manually + * remove padding from decrypted values. This might be a bug. + **/ + + +/* This function should test: + * RSA Key Import + * RSA Encryption, mechanism chosen by caller + * RSA Decryption, mechanism chosen by caller + * + * 1. Import RSA Key Pair + * 2. Generate plaintext + * 3. Encrypt plaintext + * 4. Decrypt encrypted data + * 5. Compare plaintext with decrypted data + * + */ +CK_RV do_EncryptDecryptImportRSA(struct PUBLISHED_TEST_SUITE_INFO *tsuite) +{ + unsigned int i, j; + CK_BYTE original[BIG_REQUEST]; + CK_ULONG original_len; + CK_BYTE crypt[BIG_REQUEST]; + CK_ULONG crypt_len; + CK_BYTE decrypt[BIG_REQUEST]; + CK_ULONG decrypt_len; + CK_MECHANISM mech; + CK_OBJECT_HANDLE publ_key, priv_key; + CK_SLOT_ID slot_id = SLOT_ID; + CK_SESSION_HANDLE session; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rc, loc_rc; + + char *s; + + // begin testsuite + testsuite_begin("%s Encrypt Decrypt Import.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + // skip tests if the slot doesn't support this mechanism + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + // iterate over test vectors + for (i = 0; i < tsuite->tvcount; i++) { + + // get public exponent from test vector + if (p11_ahex_dump(&s, tsuite->tv[i].pub_exp, + tsuite->tv[i].pubexp_len) == NULL) { + testcase_error("p11_ahex_dump() failed"); + rc = -1; + goto testcase_cleanup; + } + // begin testcase + testcase_begin("%s Encrypt and Decrypt Import with test vector %d." + "\npubl_exp='%s', modbits=%ld, publ_exp_len=%ld.", + tsuite->name, i, s, + tsuite->tv[i].mod_len * 8, + tsuite->tv[i].pubexp_len); + + rc = CKR_OK; // set rc + + if (!keysize_supported(slot_id, tsuite->mech.mechanism, + tsuite->tv[i].mod_len * 8)) { + testcase_skip("Token in slot %ld cannot be used with " + "modbits.='%ld'", SLOT_ID, tsuite->tv[i].mod_len * 8); + continue; + } + + if (is_ep11_token(slot_id)) { + if (!is_valid_ep11_pubexp(tsuite->tv[i].pub_exp, + tsuite->tv[i].pubexp_len)) { + testcase_skip("EP11 Token cannot " + "be used with publ_exp.='%s'", s); + continue; + } + // modulus length must be multiple of 128 byte + // skip test if modulus length has unsuported size + if ((tsuite->tv[i].mod_len % 128) != 0) { + testcase_skip("EP11 Token cannot be used with " + "this test vector."); + continue; + } + } + + // special case for ica + // prime1, prime2, exp1, exp2, coef + // must be size mod_len/2 or smaller + // skip test if prime1, or prime2, or exp1, + // or exp2 or coef are too long + if (is_ica_token(slot_id)) { + // check sizes + if ((tsuite->tv[i].prime1_len > + (tsuite->tv[i].mod_len / 2)) || + (tsuite->tv[i].prime2_len > + (tsuite->tv[i].mod_len / 2)) || + (tsuite->tv[i].exp1_len > + (tsuite->tv[i].mod_len / 2)) || + (tsuite->tv[i].exp2_len > + (tsuite->tv[i].mod_len / 2)) || + (tsuite->tv[i].coef_len > (tsuite->tv[i].mod_len / 2))) { + testcase_skip("ICA Token cannot be used with " + "this test vector."); + continue; + } + + } + + // cca special cases: + // cca token can only use the following public exponents + // 0x03 or 0x010001 (65537) + // so skip test if invalid public exponent is used + if (is_cca_token(slot_id)) { + if (!is_valid_cca_pubexp(tsuite->tv[i].pub_exp, + tsuite->tv[i].pubexp_len)) { + testcase_skip("CCA Token cannot " + "be used with publ_exp.='%s'", s); + continue; + } + } + // tpm special cases: + // tpm token can only use public exponent 0x010001 (65537) + // so skip test if invalid public exponent is used + if (is_tpm_token(slot_id)) { + if ((!is_valid_tpm_pubexp(tsuite->tv[i].pub_exp, + tsuite->tv[i].pubexp_len)) + || (!is_valid_tpm_modbits(tsuite->tv[i].mod_len * 8))) { + testcase_skip("TPM Token cannot " "be used with publ_exp.='%s'", + s); + continue; + } + } + + if (is_icsf_token(slot_id)) { + if (!is_valid_icsf_pubexp(tsuite->tv[i].pub_exp, + tsuite->tv[i].pubexp_len) || + (tsuite->tv[i].mod_len * 8 < 1024)) { + testcase_skip("ICSF Token cannot be used with " + "publ_exp='%s'.", s); + continue; + } + } + + free(s); + + // clear buffers + memset(original, 0, BIG_REQUEST); + memset(crypt, 0, BIG_REQUEST); + memset(decrypt, 0, BIG_REQUEST); + + original_len = 10; + + // create (private) key handle + rc = create_RSAPrivateKey(session, + tsuite->tv[i].mod, + tsuite->tv[i].pub_exp, + tsuite->tv[i].priv_exp, + tsuite->tv[i].prime1, + tsuite->tv[i].prime2, + tsuite->tv[i].exp1, + tsuite->tv[i].exp2, + tsuite->tv[i].coef, + tsuite->tv[i].mod_len, + tsuite->tv[i].pubexp_len, + tsuite->tv[i].privexp_len, + tsuite->tv[i].prime1_len, + tsuite->tv[i].prime2_len, + tsuite->tv[i].exp1_len, + tsuite->tv[i].exp2_len, + tsuite->tv[i].coef_len, &priv_key); + if (rc != CKR_OK) { + testcase_error("create_RSAPrivateKey(), rc=%s", p11_get_ckr(rc)); + goto error; + } + + // create (public) key handle + rc = create_RSAPublicKey(session, + tsuite->tv[i].mod, + tsuite->tv[i].pub_exp, + tsuite->tv[i].mod_len, + tsuite->tv[i].pubexp_len, &publ_key); + if (rc != CKR_OK) { + testcase_error("create_RSAPublicKey(), rc=%s", p11_get_ckr(rc)); + goto error; + } + + // generate plaintext + for (j = 0; j < original_len; j++) { + original[j] = (j + 1) % 255; + } + + // set cipher buffer length + crypt_len = BIG_REQUEST; + decrypt_len = BIG_REQUEST; + + // get mech + mech = tsuite->mech; + // initialize (public key) encryption + rc = funcs->C_EncryptInit(session, &mech, publ_key); + if (rc != CKR_OK) { + if (rc == CKR_MECHANISM_PARAM_INVALID && + mech.mechanism == CKM_RSA_PKCS_OAEP && + is_ep11_token(slot_id) && + (((CK_RSA_PKCS_OAEP_PARAMS *)mech.pParameter)->hashAlg != + CKM_SHA_1 || + ((CK_RSA_PKCS_OAEP_PARAMS *)mech.pParameter)->mgf != + CKG_MGF1_SHA1)) { + testcase_skip("EP11 Token does not support RSA OAEP with hash " + "and/or MGF other than SHA-1"); + goto tv_cleanup; + } + + testcase_error("C_EncryptInit, rc=%s", p11_get_ckr(rc)); + goto tv_cleanup; + } + // do (public key) encryption + rc = funcs->C_Encrypt(session, + original, original_len, crypt, &crypt_len); + if (rc != CKR_OK) { + testcase_error("C_Encrypt, rc=%s", p11_get_ckr(rc)); + goto tv_cleanup; + } + // initialize (private key) decryption + rc = funcs->C_DecryptInit(session, &mech, priv_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit, rc=%s", p11_get_ckr(rc)); + goto tv_cleanup; + } + // do (private key) decryption + rc = funcs->C_Decrypt(session, crypt, crypt_len, decrypt, &decrypt_len); + if (rc != CKR_OK) { + testcase_error("C_Decrypt, rc=%s", p11_get_ckr(rc)); + goto tv_cleanup; + } + // FIXME: there shouldn't be any padding here + // remove padding if mech is CKM_RSA_X_509 + if (mech.mechanism == CKM_RSA_X_509) { + memmove(decrypt, + decrypt + decrypt_len - original_len, original_len); + decrypt_len = original_len; + } + // check results + testcase_new_assertion(); + + if (decrypt_len != original_len) { + testcase_fail("decrypted length does not match" + "original data length.\n expected length = %ld," + "but found length=%ld.\n", original_len, decrypt_len); + } else if (memcmp(decrypt, original, original_len)) { + testcase_fail("decrypted data does not match " "original data."); + } else { + testcase_pass("C_Encrypt and C_Decrypt."); + } + + // clean up +tv_cleanup: + rc = funcs->C_DestroyObject(session, publ_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + goto error; + } + + rc = funcs->C_DestroyObject(session, priv_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + goto error; + } + } + + goto testcase_cleanup; +error: + loc_rc = funcs->C_DestroyObject(session, publ_key); + if (loc_rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); + } + + loc_rc = funcs->C_DestroyObject(session, priv_key); + if (loc_rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); + } + +testcase_cleanup: + testcase_user_logout(); + loc_rc = funcs->C_CloseAllSessions(slot_id); + if (loc_rc != CKR_OK) { + testcase_error("C_CloseAllSessions, rc=%s", p11_get_ckr(loc_rc)); + } + + return rc; +} + +/* This function should test: + * RSA Key Generation, usign CKM_RSA_PKCS_KEY_PAIR_GEN + * RSA Sign, mechanism chosen by caller + * RSA Verify, mechanism chosen by caller + * + * 1. Generate RSA Key Pair + * 2. Generate message + * 3. Sign message + * 4. Verify signature + * + */ +CK_RV do_SignVerifyRSA(struct GENERATED_TEST_SUITE_INFO * tsuite, + CK_BBOOL recover_mode) +{ + unsigned int i; // test vector index + unsigned int j; // message byte index + CK_BYTE message[MAX_MESSAGE_SIZE]; + CK_ULONG message_len; + CK_BYTE signature[MAX_SIGNATURE_SIZE]; + CK_ULONG signature_len; + CK_BYTE out_message[MAX_MESSAGE_SIZE]; + CK_ULONG out_message_len; + + CK_MECHANISM mech; + CK_OBJECT_HANDLE publ_key, priv_key; + + CK_SLOT_ID slot_id = SLOT_ID; + CK_SESSION_HANDLE session; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rc, loc_rc; + + char *s; + + // begin testsuite + testsuite_begin("%s Sign%s Verify%s.", tsuite->name, + recover_mode ? "Recover" : "", + recover_mode ? "Recover" : ""); + testcase_rw_session(); + testcase_user_login(); + + // skip tests if the slot doesn't support this mechanism + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + if (recover_mode) { + if (!mech_supported_flags(slot_id, tsuite->mech.mechanism, + CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support Sign/VerifyRecover with %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + } + // iterate over test vectors + for (i = 0; i < tsuite->tvcount; i++) { + + // get public exponent from test vector + if (p11_ahex_dump(&s, tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len) == NULL) { + testcase_error("p11_ahex_dump() failed"); + rc = -1; + goto testcase_cleanup; + } + // begin test + testcase_begin("%s Sign%s and Verify%s with test vector %d, " + "\npubl_exp='%s', mod_bits='%lu', keylen='%lu'.", + tsuite->name, recover_mode ? "Recover" : "", + recover_mode ? "Recover" : "", i, s, + tsuite->tv[i].modbits, tsuite->tv[i].keylen); + + if (!keysize_supported(slot_id, tsuite->mech.mechanism, + tsuite->tv[i].modbits)) { + testcase_skip("Token in slot %ld cannot be used with " + "modbits.='%ld'", SLOT_ID, tsuite->tv[i].modbits); + continue; + } + + if (is_ep11_token(slot_id)) { + if (!is_valid_ep11_pubexp(tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len)) { + testcase_skip("EP11 Token cannot " + "be used with publ_exp.='%s'", s); + continue; + } + } + + if (is_cca_token(slot_id)) { + if (!is_valid_cca_pubexp(tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len)) { + testcase_skip("CCA Token cannot " + "be used with publ_exp='%s'.", s); + continue; + } + } + + if (is_tpm_token(slot_id)) { + if ((!is_valid_tpm_pubexp(tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len)) + || (!is_valid_tpm_modbits(tsuite->tv[i].modbits))) { + testcase_skip("TPM Token cannot " "be used with publ_exp='%s'.", + s); + continue; + } + } + + if (is_icsf_token(slot_id)) { + if (!is_valid_icsf_pubexp(tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len) || + (tsuite->tv[i].modbits < 1024)) { + testcase_skip("ICSF Token cannot be used with " + "publ_exp='%s'.", s); + continue; + } + } + // free memory + free(s); + + rc = CKR_OK; // set rc + + // clear buffers + memset(message, 0, MAX_MESSAGE_SIZE); + memset(signature, 0, MAX_SIGNATURE_SIZE); + memset(out_message, 0, MAX_MESSAGE_SIZE); + + // get test vector parameters + message_len = tsuite->tv[i].inputlen; + + // generate key pair + rc = generate_RSA_PKCS_KeyPair(session, + tsuite->tv[i].modbits, + tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len, + &publ_key, &priv_key); + if (rc != CKR_OK) { + testcase_error("generate_RSA_PKCS_KeyPair(), " + "rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // generate message + for (j = 0; j < message_len; j++) { + message[j] = (j + 1) % 255; + } + + // get mech + mech = tsuite->mech; + + // initialize Sign (length only) + if (recover_mode) + rc = funcs->C_SignRecoverInit(session, &mech, priv_key); + else + rc = funcs->C_SignInit(session, &mech, priv_key); + if (rc != CKR_OK) { + testcase_error("C_Sign%sInit(), rc=%s", + recover_mode ? "Recover" : "", p11_get_ckr(rc)); + goto error; + } + // set buffer size + signature_len = MAX_SIGNATURE_SIZE; + + // do Sign + if (recover_mode) + rc = funcs->C_SignRecover(session, message, message_len, + signature, &signature_len); + else + rc = funcs->C_Sign(session, message, message_len, + signature, &signature_len); + if (rc != CKR_OK) { + testcase_error("C_Sign%s(), rc=%s signature len=%ld", + recover_mode ? "Recover" : "", + p11_get_ckr(rc), signature_len); + goto error; + } + // initialize Verify + if (recover_mode) + rc = funcs->C_VerifyRecoverInit(session, &mech, publ_key); + else + rc = funcs->C_VerifyInit(session, &mech, publ_key); + if (rc != CKR_OK) { + testcase_error("C_Verify%sInit(), rc=%s", + recover_mode ? "Recover" : "", p11_get_ckr(rc)); + goto error; + } + // do Verify + if (recover_mode) { + out_message_len = sizeof(out_message); + rc = funcs->C_VerifyRecover(session, signature, signature_len, + out_message, &out_message_len); + } else { + rc = funcs->C_Verify(session, message, message_len, + signature, signature_len); + } + + // check results + testcase_new_assertion(); + if (rc == CKR_OK) { + if (recover_mode) { + if (mech.mechanism == CKM_RSA_X_509) { + // out_message may have been left padded with binary zeros + if (memcmp(&message[out_message_len - message_len], + out_message, message_len) != 0) { + testcase_fail("C_VerifyRecover() message does not match"); + } else { + testcase_pass("C_VerifyRecover."); + } + } else { + if (out_message_len != message_len || + memcmp(message, out_message, message_len) != 0) { + testcase_fail("C_VerifyRecover() message does not match"); + } else { + testcase_pass("C_VerifyRecover."); + } + } + } else { + testcase_pass("C_Verify."); + } + } else { + testcase_fail("C_Verify%s(), rc=%s", recover_mode ? "Recover" : "", + p11_get_ckr(rc)); + } + + // clean up + rc = funcs->C_DestroyObject(session, publ_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + + rc = funcs->C_DestroyObject(session, priv_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + } + goto testcase_cleanup; +error: + loc_rc = funcs->C_DestroyObject(session, publ_key); + if (loc_rc != CKR_OK) { + testcase_error("C_DestroyObject, rc=%s.", p11_get_ckr(loc_rc)); + } + loc_rc = funcs->C_DestroyObject(session, priv_key); + if (loc_rc != CKR_OK) { + testcase_error("C_DestroyObject, rc=%s.", p11_get_ckr(loc_rc)); + } + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloesAllSessions, rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + + +/* This function should test: + * RSA Key Generation, usign CKM_RSA_PKCS_KEY_PAIR_GEN + * RSA-PSS Sign, mechanism chosen by caller + * RSA-PSS Verify, mechanism chosen by caller + * + * 1. Generate RSA Key Pair + * 2. Generate message + * 3. Generate hash for the message if required by mechanism. + * 4. Sign message + * 5. Verify signature + * + */ +#define MAX_HASH_SIZE 64 +CK_RV do_SignVerify_RSAPSS(struct GENERATED_TEST_SUITE_INFO * tsuite) +{ + unsigned int i; // test vector index + unsigned int j; // message byte index + CK_BYTE message[MAX_MESSAGE_SIZE]; + CK_BYTE signature[MAX_SIGNATURE_SIZE]; + CK_BYTE hash[MAX_HASH_SIZE]; + CK_ULONG message_len, signature_len, h_len; + + CK_MECHANISM mech; + CK_OBJECT_HANDLE publ_key, priv_key; + + CK_SLOT_ID slot_id = SLOT_ID; + CK_SESSION_HANDLE session; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rc, loc_rc; + CK_RSA_PKCS_PSS_PARAMS pss_params; + + char *s; + + // begin testsuite + testsuite_begin("%s Sign Verify.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + // skip tests if the slot doesn't support this mechanism + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + // iterate over test vectors + for (i = 0; i < tsuite->tvcount; i++) { + + // get public exponent from test vector + if (p11_ahex_dump(&s, tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len) == NULL) { + testcase_error("p11_ahex_dump() failed"); + rc = -1; + goto testcase_cleanup; + } + // begin test + testcase_begin("%s Sign and Verify with test vector %d, " + "\npubl_exp='%s', mod_bits='%lu', keylen='%lu'.", + tsuite->name, i, s, + tsuite->tv[i].modbits, tsuite->tv[i].keylen); + + if (!keysize_supported(slot_id, tsuite->mech.mechanism, + tsuite->tv[i].modbits)) { + testcase_skip("Token in slot %ld cannot be used with " + "modbits.='%ld'", SLOT_ID, tsuite->tv[i].modbits); + continue; + } + // free memory + free(s); + + rc = CKR_OK; // set rc + + // clear buffers + memset(message, 0, MAX_MESSAGE_SIZE); + memset(signature, 0, MAX_SIGNATURE_SIZE); + + // get test vector parameters + message_len = tsuite->tv[i].inputlen; + + // generate key pair + rc = generate_RSA_PKCS_KeyPair(session, tsuite->tv[i].modbits, + tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len, &publ_key, + &priv_key); + if (rc != CKR_OK) { + testcase_error("generate_RSA_PKCS_KeyPair(), " + "rc=%s", p11_get_ckr(rc)); + goto error; + } + // generate message + for (j = 0; j < message_len; j++) { + message[j] = (j + 1) % 255; + } + + if (tsuite->mech.mechanism == CKM_RSA_PKCS_PSS) { + // create digest of message to pass to C_Sign + mech.mechanism = tsuite->tv[i].pss_params.hashAlg; + mech.pParameter = 0; + mech.ulParameterLen = 0; + + h_len = MAX_HASH_SIZE; + + rc = funcs->C_DigestInit(session, &mech); + if (rc != CKR_OK) { + testcase_error("C_DigestInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + rc = funcs->C_Digest(session, message, message_len, hash, &h_len); + if (rc != CKR_OK) { + testcase_error("C_Digest rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + // set mechanism for signing + mech = tsuite->mech; + pss_params = tsuite->tv[i].pss_params; + mech.pParameter = &pss_params; + mech.ulParameterLen = sizeof(CK_RSA_PKCS_PSS_PARAMS); + + // initialize Sign + rc = funcs->C_SignInit(session, &mech, priv_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit(), rc=%s", p11_get_ckr(rc)); + goto error; + } + // set buffer size + signature_len = MAX_SIGNATURE_SIZE; + + // do Sign + if (mech.mechanism == CKM_RSA_PKCS_PSS) + rc = funcs->C_Sign(session, hash, h_len, signature, &signature_len); + else + rc = funcs->C_Sign(session, message, message_len, + signature, &signature_len); + if (rc != CKR_OK) { + testcase_error("C_Sign(), rc=%s signature len=%ld", + p11_get_ckr(rc), signature_len); + goto error; + } + // initialize Verify + rc = funcs->C_VerifyInit(session, &mech, publ_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit(), rc=%s", p11_get_ckr(rc)); + } + // do Verify + if (mech.mechanism == CKM_RSA_PKCS_PSS) + rc = funcs->C_Verify(session, hash, h_len, signature, + signature_len); + else + rc = funcs->C_Verify(session, message, message_len, + signature, signature_len); + + // check results + testcase_new_assertion(); + if (rc == CKR_OK) + testcase_pass("C_Verify."); + else + testcase_fail("C_Verify(), rc=%s", p11_get_ckr(rc)); + + // clean up + rc = funcs->C_DestroyObject(session, publ_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + + rc = funcs->C_DestroyObject(session, priv_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + } + goto testcase_cleanup; +error: + loc_rc = funcs->C_DestroyObject(session, publ_key); + if (loc_rc != CKR_OK) { + testcase_error("C_DestroyObject, rc=%s.", p11_get_ckr(loc_rc)); + } + loc_rc = funcs->C_DestroyObject(session, priv_key); + if (loc_rc != CKR_OK) { + testcase_error("C_DestroyObject, rc=%s.", p11_get_ckr(loc_rc)); + } + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloesAllSessions, rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + + +/* This function should test: + * RSA Key Generation, using CKM_PKCS_KEY_PAIR_GEN + * RSA Public-Key Wrap + * RSA Private-Key Unwrap + * + */ +CK_RV do_WrapUnwrapRSA(struct GENERATED_TEST_SUITE_INFO * tsuite) +{ + unsigned int i = 0, j = 0; + char *s = NULL; + CK_OBJECT_HANDLE publ_key, priv_key, secret_key, unwrapped_key; + CK_BYTE_PTR wrapped_key = NULL; + CK_ULONG wrapped_keylen, unwrapped_keylen = 0; + CK_MECHANISM wrap_mech, keygen_mech, mech; + CK_BYTE clear[32], cipher[32], re_cipher[32]; + CK_ULONG cipher_len = 32, re_cipher_len = 32; + CK_RSA_PKCS_OAEP_PARAMS oaep_params; + + CK_SESSION_HANDLE session; + CK_FLAGS flags; + CK_SLOT_ID slot_id = SLOT_ID; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rc, loc_rc; + + CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; + CK_KEY_TYPE key_type; + CK_ATTRIBUTE unwrap_tmpl[] = { + {CKA_CLASS, &key_class, sizeof(CK_OBJECT_CLASS)}, + {CKA_KEY_TYPE, &key_type, sizeof(CK_KEY_TYPE)}, + {CKA_VALUE_LEN, &unwrapped_keylen, sizeof(CK_ULONG)} + }; + CK_ULONG unwrap_tmpl_len; + + // begin test suite + testsuite_begin("%s Wrap Unwrap.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + /* create some data */ + for (j = 0; j < 32; j++) + clear[j] = j; + + // skip all tests if the slot doesn't support this mechanism + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } else if (!wrap_supported(slot_id, tsuite->mech)) { + // skip all tests if the slot doesn't support wrapping + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support key wrapping", + (unsigned int) slot_id); + goto testcase_cleanup; + } + + for (i = 0; i < tsuite->tvcount; i++) { + // skip if the slot doesn't support the keygen mechanism + if (!mech_supported(slot_id, tsuite->tv[i].keytype.mechanism)) { + testcase_skip("Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->tv[i].keytype.mechanism), + (unsigned int) tsuite->tv[i].keytype.mechanism); + continue; + } + + if (!keysize_supported(slot_id, tsuite->mech.mechanism, + tsuite->tv[i].modbits)) { + testcase_skip("Token in slot %ld cannot be used with " + "modbits.='%ld'", SLOT_ID, tsuite->tv[i].modbits); + continue; + } + // get public exponent from test vector + if (p11_ahex_dump(&s, tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len) == NULL) { + testcase_error("p11_ahex_dump() failed"); + rc = -1; + goto testcase_cleanup; + } + + if (is_ep11_token(slot_id)) { + if (!is_valid_ep11_pubexp(tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len)) { + testcase_skip("EP11 Token cannot " + "be used with publ_exp.='%s'", s); + continue; + } + } + if (is_icsf_token(slot_id)) { + if (!is_valid_icsf_pubexp(tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len) || + (tsuite->tv[i].modbits < 1024)) { + testcase_skip("ICSF Token cannot be used with " + "publ_exp='%s'.", s); + continue; + } + } + + // begin test + testcase_begin("%s Wrap Unwrap with test vector %d, " + "\npubl_exp='%s', mod_bits='%lu', keylen='%lu', " + "keytype='%s'", tsuite->name, i, s, + tsuite->tv[i].modbits, tsuite->tv[i].keylen, + p11_get_ckm(tsuite->tv[i].keytype.mechanism)); + + // free memory + if (s) + free(s); + + // get key gen mechanism + keygen_mech = tsuite->tv[i].keytype; + + // get wrapping mechanism + wrap_mech = tsuite->mech; + if (wrap_mech.mechanism == CKM_RSA_PKCS_OAEP) { + oaep_params = tsuite->tv[i].oaep_params; + wrap_mech.pParameter = &oaep_params; + wrap_mech.ulParameterLen = sizeof(CK_RSA_PKCS_OAEP_PARAMS); + } + // clear out buffers + memset(cipher, 0, sizeof(cipher)); + memset(re_cipher, 0, sizeof(re_cipher)); + + // initialize buffer lengths + wrapped_keylen = PKCS11_MAX_PIN_LEN; + + // generate RSA key pair + rc = generate_RSA_PKCS_KeyPair(session, tsuite->tv[i].modbits, + tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len, + &publ_key, &priv_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKeyPair() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // generate secret key + rc = generate_SecretKey(session, tsuite->tv[i].keylen, + &keygen_mech, &secret_key); + if (rc != CKR_OK) { + testcase_error("generate_SecretKey(), rc=%s", p11_get_ckr(rc)); + goto error; + } + + /* Testcase Goals: + * 1. Encrypt data. + * 2. Use RSA to wrap the secret key we just used to encrypt. + * 3. Use RSA to unwrap the secret key. + * 4. Decrypt with the newly unwrapped key to get original data. + * + * The first assertion will be the success of RSA to wrap and + * unwrap the secret key. + * The second assertion will be the success of the unwrapped + * key to decrypt the original text. + * Note: Generic secret keys are not used for encrypt/decrypt + * by default. So they will not be included in second + * assertion. + */ + if (keygen_mech.mechanism != CKM_GENERIC_SECRET_KEY_GEN) { + switch (keygen_mech.mechanism) { + case CKM_AES_KEY_GEN: + mech.mechanism = CKM_AES_ECB; + key_type = CKK_AES; + break; + case CKM_DES3_KEY_GEN: + mech.mechanism = CKM_DES3_ECB; + key_type = CKK_DES3; + break; + case CKM_DES_KEY_GEN: + mech.mechanism = CKM_DES_ECB; + key_type = CKK_DES; + break; + case CKM_CDMF_KEY_GEN: + mech.mechanism = CKM_CDMF_ECB; + key_type = CKK_CDMF; + break; + default: + testcase_error("unknown mech"); + goto error; + } + + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rc = funcs->C_EncryptInit(session, &mech, secret_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit secret_key " + ": rc = %s", p11_get_ckr(rc)); + goto error; + } + + rc = funcs->C_Encrypt(session, clear, 32, cipher, &cipher_len); + if (rc != CKR_OK) { + testcase_error("C_Encrypt secret_key: rc = %s", + p11_get_ckr(rc)); + goto error; + } + } else { + key_type = CKK_GENERIC_SECRET; + } + + testcase_new_assertion(); /* assertion #1 */ + // wrap key (length only) + rc = funcs->C_WrapKey(session, &wrap_mech, publ_key, secret_key, + NULL, &wrapped_keylen); + if (rc != CKR_OK) { + if (rc == CKR_MECHANISM_PARAM_INVALID && + wrap_mech.mechanism == CKM_RSA_PKCS_OAEP && + is_ep11_token(slot_id) && + (oaep_params.hashAlg != CKM_SHA_1 || + oaep_params.mgf != CKG_MGF1_SHA1)) { + testcase_skip("EP11 Token does not support RSA OAEP with hash " + "and/or MGF other than SHA-1"); + goto tv_cleanup; + } + + testcase_error("C_WrapKey(), rc=%s.", p11_get_ckr(rc)); + goto error; + } + // allocate memory for wrapped_key + wrapped_key = calloc(sizeof(CK_BYTE), wrapped_keylen); + if (wrapped_key == NULL) { + testcase_error("Can't allocate memory for %lu bytes.", + sizeof(CK_BYTE) * wrapped_keylen); + rc = CKR_HOST_MEMORY; + goto error; + } + // wrap key + rc = funcs->C_WrapKey(session, &wrap_mech, publ_key, secret_key, + wrapped_key, &wrapped_keylen); + if (rc != CKR_OK) { + testcase_fail("C_WrapKey, rc=%s", p11_get_ckr(rc)); + goto error; + } + + /* variable key length specific case: + * According to PKCS#11 v2.2 section 12.1.12 + * CKM_RSA_X_509 does not wrap the key type, key length, + * or any other information about the key; the application + * must convey these separately, and supply them when + * unwrapping the key. + */ + if (((keygen_mech.mechanism == CKM_AES_KEY_GEN) || + (keygen_mech.mechanism == CKM_GENERIC_SECRET_KEY_GEN)) && + (wrap_mech.mechanism == CKM_RSA_X_509)) { + unwrapped_keylen = tsuite->tv[i].keylen; + unwrap_tmpl_len = 3; + } else { + unwrap_tmpl_len = 2; + } + + // unwrap key + rc = funcs->C_UnwrapKey(session, &wrap_mech, priv_key, + wrapped_key, wrapped_keylen, + unwrap_tmpl, unwrap_tmpl_len, &unwrapped_key); + if (rc != CKR_OK) { + testcase_fail("C_UnwrapKey, rc=%s", p11_get_ckr(rc)); + goto error; + } else { + testcase_pass("wrapped and unwrapped key successful."); + } + + /* now decrypt the message with the unwrapped key */ + + if (keygen_mech.mechanism != CKM_GENERIC_SECRET_KEY_GEN) { + rc = funcs->C_DecryptInit(session, &mech, unwrapped_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit unwrapped_key: " + " rc = %s", p11_get_ckr(rc)); + goto error; + } + + rc = funcs->C_Decrypt(session, cipher, cipher_len, + re_cipher, &re_cipher_len); + if (rc != CKR_OK) { + testcase_error("C_Decrypt unwrapped_key: " + "rc = %s", p11_get_ckr(rc)); + goto error; + } + + testcase_new_assertion(); + + if (memcmp(clear, re_cipher, 32) != 0) { + testcase_fail("ERROR:data mismatch\n"); + goto error; + } else { + testcase_pass("Decrypted data is correct."); + } + } + // clean up +tv_cleanup: + if (wrapped_key) { + free(wrapped_key); + wrapped_key = NULL; + } + + rc = funcs->C_DestroyObject(session, secret_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + + rc = funcs->C_DestroyObject(session, publ_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + + rc = funcs->C_DestroyObject(session, priv_key); + if (rc != CKR_OK) + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + goto testcase_cleanup; + +error: + if (wrapped_key) { + free(wrapped_key); + wrapped_key = NULL; + } + + funcs->C_DestroyObject(session, secret_key); + funcs->C_DestroyObject(session, publ_key); + funcs->C_DestroyObject(session, priv_key); + +testcase_cleanup: + testcase_user_logout(); + loc_rc = funcs->C_CloseAllSessions(slot_id); + if (loc_rc != CKR_OK) { + testcase_error("C_CloseAllSessions(), rc=%s.", p11_get_ckr(loc_rc)); + } + + return rc; +} + + +/* This function should test: + * C_Sign, mechanism chosen by caller + * + * 1. Get message from test vector + * 2. Get expected signature from test vector + * 3. Sign message + * 4. Compare expected signature with actual signature + * + */ +CK_RV do_SignRSA(struct PUBLISHED_TEST_SUITE_INFO * tsuite) +{ + unsigned int i; + CK_BYTE message[MAX_MESSAGE_SIZE]; + CK_BYTE actual[MAX_SIGNATURE_SIZE]; + CK_BYTE expected[MAX_SIGNATURE_SIZE]; + CK_ULONG message_len, actual_len, expected_len; + + CK_MECHANISM mech; + CK_OBJECT_HANDLE priv_key; + + CK_SLOT_ID slot_id = SLOT_ID; + CK_SESSION_HANDLE session; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rc, loc_rc; + + // begin testsuite + testsuite_begin("%s Sign. ", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + // skip tests if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + // iterate over test vectors + for (i = 0; i < tsuite->tvcount; i++) { + testcase_begin("%s Sign with test vector %d.", tsuite->name, i); + + rc = CKR_OK; // set return value + + // special case for ica + // prime1, prime2, exp1, exp2, coef + // must be size mod_len/2 or smaller + // skip test if prime1, or prime2, or exp1, + // or exp2 or coef are too long + if (is_ica_token(slot_id)) { + // check sizes + if ((tsuite->tv[i].prime1_len > + (tsuite->tv[i].mod_len / 2)) || + (tsuite->tv[i].prime2_len > + (tsuite->tv[i].mod_len / 2)) || + (tsuite->tv[i].exp1_len > + (tsuite->tv[i].mod_len / 2)) || + (tsuite->tv[i].exp2_len > + (tsuite->tv[i].mod_len / 2)) || + (tsuite->tv[i].coef_len > (tsuite->tv[i].mod_len / 2))) { + testcase_skip("ICA Token cannot be used with " + "this test vector."); + continue; + } + + } + // special case for EP11 + // modulus length must be multiple of 128 byte + // skip test if modulus length has unsuported size + if (is_ep11_token(slot_id)) { + if ((tsuite->tv[i].mod_len % 128) != 0) { + testcase_skip("EP11 Token cannot be used with " + "this test vector."); + continue; + } + } + + if (is_tpm_token(slot_id)) { + if ((!is_valid_tpm_pubexp(tsuite->tv[i].pub_exp, + tsuite->tv[i].pubexp_len)) + || (!is_valid_tpm_modbits(tsuite->tv[i].mod_len))) { + testcase_skip("TPM Token cannot " + "be used with this test vector."); + continue; + } + } + // clear buffers + memset(message, 0, MAX_MESSAGE_SIZE); + memset(actual, 0, MAX_SIGNATURE_SIZE); + memset(expected, 0, MAX_SIGNATURE_SIZE); + + actual_len = MAX_SIGNATURE_SIZE; // set buffer size + + // get message + message_len = tsuite->tv[i].msg_len; + memcpy(message, tsuite->tv[i].msg, message_len); + + // get (expected) signature + expected_len = tsuite->tv[i].sig_len; + memcpy(expected, tsuite->tv[i].sig, expected_len); + + // create (private) key handle + rc = create_RSAPrivateKey(session, + tsuite->tv[i].mod, + tsuite->tv[i].pub_exp, + tsuite->tv[i].priv_exp, + tsuite->tv[i].prime1, + tsuite->tv[i].prime2, + tsuite->tv[i].exp1, + tsuite->tv[i].exp2, + tsuite->tv[i].coef, + tsuite->tv[i].mod_len, + tsuite->tv[i].pubexp_len, + tsuite->tv[i].privexp_len, + tsuite->tv[i].prime1_len, + tsuite->tv[i].prime2_len, + tsuite->tv[i].exp1_len, + tsuite->tv[i].exp2_len, + tsuite->tv[i].coef_len, &priv_key); + if (rc != CKR_OK) { + testcase_error("create_RSAPrivateKey(), rc=%s", p11_get_ckr(rc)); + goto error; + } + // set mechanism + mech = tsuite->mech; + + // initialize signing + rc = funcs->C_SignInit(session, &mech, priv_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit(), rc=%s.", p11_get_ckr(rc)); + goto error; + } + // do signing + rc = funcs->C_Sign(session, message, message_len, actual, &actual_len); + + if (rc != CKR_OK) { + testcase_error("C_Sign(), rc=%s.", p11_get_ckr(rc)); + goto skip; + } + // check results + testcase_new_assertion(); + + if (actual_len != expected_len) { + testcase_fail("%s Sign with test vector %d failed. " + "Expected len=%ld, found len=%ld.", + tsuite->name, i, expected_len, actual_len); + } else if (memcmp(actual, expected, expected_len)) { + testcase_fail("%s Sign with test vector %d failed. " + "Signature data does not match test vector " + "signature.", tsuite->name, i); + + } else { + testcase_pass("C_Sign."); + } +skip: + // clean up + rc = funcs->C_DestroyObject(session, priv_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + goto testcase_cleanup; +error: + loc_rc = funcs->C_DestroyObject(session, priv_key); + if (loc_rc != CKR_OK) { + testcase_error("C_DestroyObject, rc=%s.", p11_get_ckr(loc_rc)); + } +testcase_cleanup: + testcase_user_logout(); + loc_rc = funcs->C_CloseAllSessions(slot_id); + if (loc_rc != CKR_OK) { + testcase_error("C_CloseAllSessions, rc=%s.", p11_get_ckr(loc_rc)); + } + + return rc; +} + +/* This function should test: + * C_Verify, mechanism chosen by caller + * + * 1. Get message from test vector + * 2. Get signature from test vector + * 3. Verify signature + * + */ +CK_RV do_VerifyRSA(struct PUBLISHED_TEST_SUITE_INFO * tsuite) +{ + unsigned int i; + CK_BYTE actual[MAX_SIGNATURE_SIZE]; + CK_BYTE message[MAX_MESSAGE_SIZE]; + CK_ULONG message_len; + CK_BYTE signature[MAX_SIGNATURE_SIZE]; + CK_ULONG signature_len; + + CK_MECHANISM mech; + CK_OBJECT_HANDLE publ_key; + + CK_SLOT_ID slot_id = SLOT_ID; + CK_SESSION_HANDLE session; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rc, loc_rc; + + // begin testsuite + testsuite_begin("%s Verify.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + // skip tests if the slot doesn't support this mechanism + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + // iterate over test vectors + for (i = 0; i < tsuite->tvcount; i++) { + + testcase_begin("%s Verify with test vector %d.", tsuite->name, i); + + rc = CKR_OK; // set return value + + // special case for EP11 + // modulus length must be multiple of 128 byte + // skip test if modulus length has unsuported size + if (is_ep11_token(slot_id)) { + if ((tsuite->tv[i].mod_len % 128) != 0) { + testcase_skip("EP11 Token cannot be used with " + "this test vector."); + continue; + } + } + + if (is_tpm_token(slot_id)) { + if ((!is_valid_tpm_pubexp(tsuite->tv[i].pub_exp, + tsuite->tv[i].pubexp_len)) + || (!is_valid_tpm_modbits(tsuite->tv[i].mod_len))) { + testcase_skip("TPM Token cannot " + "be used with this test vector."); + continue; + } + } + // clear buffers + memset(message, 0, MAX_MESSAGE_SIZE); + memset(signature, 0, MAX_SIGNATURE_SIZE); + memset(actual, 0, MAX_SIGNATURE_SIZE); + + // get message + message_len = tsuite->tv[i].msg_len; + memcpy(message, tsuite->tv[i].msg, message_len); + + // get signature + signature_len = tsuite->tv[i].sig_len; + memcpy(signature, tsuite->tv[i].sig, signature_len); + + // create (public) key handle + rc = create_RSAPublicKey(session, + tsuite->tv[i].mod, + tsuite->tv[i].pub_exp, + tsuite->tv[i].mod_len, + tsuite->tv[i].pubexp_len, &publ_key); + + if (rc != CKR_OK) { + testcase_error("create_RSAPublicKey(), rc=%s", p11_get_ckr(rc)); + goto error; + } + // set mechanism + mech = tsuite->mech; + + // initialize verify + rc = funcs->C_VerifyInit(session, &mech, publ_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit(), rc=%s", p11_get_ckr(rc)); + goto error; + } + // do verify + rc = funcs->C_Verify(session, + message, message_len, signature, signature_len); + + // check result + testcase_new_assertion(); + + if (rc == CKR_OK) { + testcase_pass("C_Verify."); + } else { + testcase_fail("%s Sign Verify with test vector %d " + "failed.", tsuite->name, i); + } + + // clean up + rc = funcs->C_DestroyObject(session, publ_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + } + goto testcase_cleanup; +error: + loc_rc = funcs->C_DestroyObject(session, publ_key); + if (loc_rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); + } + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +CK_RV rsa_funcs() +{ + unsigned int i; + CK_RV rv = CKR_OK; + + // published (known answer) tests + for (i = 0; i < NUM_OF_PUBLISHED_TESTSUITES; i++) { + rv = do_SignRSA(&published_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + + rv = do_VerifyRSA(&published_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + } + + // generated sign verify tests + for (i = 0; i < NUM_OF_GENERATED_SIGVER_TESTSUITES; i++) { + rv = do_SignVerifyRSA(&generated_sigver_test_suites[i], FALSE); + if (rv != CKR_OK && (!no_stop)) + break; + } + + // generated sign verify tests for recover mode + for (i = 0; i < NUM_OF_GENERATED_SIGVER_TESTSUITES; i++) { + rv = do_SignVerifyRSA(&generated_sigver_test_suites[i], TRUE); + if (rv != CKR_OK && (!no_stop)) + break; + } + + for (i = 0; i < NUM_OF_GENERATED_PSS_TESTSUITES; i++) { + rv = do_SignVerify_RSAPSS(&generated_pss_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + } + + // generated crypto tests + for (i = 0; i < NUM_OF_GENERATED_CRYPTO_TESTSUITES; i++) { + rv = do_EncryptDecryptRSA(&generated_crypto_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + } + + for (i = 0; i < NUM_OF_GENERATED_OAEP_TESTSUITES; i++) { + rv = do_EncryptDecryptRSA(&generated_oaep_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + } + + for (i = 0; i < NUM_OF_GENERATED_OAEP_TESTSUITES; i++) { + rv = do_WrapUnwrapRSA(&generated_oaep_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + } + + // generated keywrap tests + for (i = 0; i < NUM_OF_GENERATED_KEYWRAP_TESTSUITES; i++) { + rv = do_WrapUnwrapRSA(&generated_keywrap_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + } + + // key import tests + for (i = 0; i < NUM_OF_ENCDEC_IMPORT_TESTSUITES; i++) { + rv = do_EncryptDecryptImportRSA(&rsa_encdec_import_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + } + + return rv; +} + +int main(int argc, char **argv) +{ + int rc; + CK_C_INITIALIZE_ARGS cinit_args; + CK_RV rv; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) { + return rc; + } + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: no_stop: %d\n", no_stop); + + rc = do_GetFunctionList(); + if (!rc) { + PRINT_ERR("ERROR do_GetFunctionList() Failed, rx = 0x%0x\n", rc); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + funcs->C_Initialize(&cinit_args); + { + CK_SESSION_HANDLE hsess = 0; + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) { + return rc; + } + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) { + return rc; + } + } + + testcase_setup(0); + rv = rsa_funcs(); + testcase_print_result(); + + funcs->C_Finalize(NULL); + + return rv; +} diff --git a/testcases/crypto/rsaupdate_func.c b/testcases/crypto/rsaupdate_func.c new file mode 100644 index 0000000..355aaa0 --- /dev/null +++ b/testcases/crypto/rsaupdate_func.c @@ -0,0 +1,1039 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2011-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 + */ + +/* + * openCryptoki testcase for RSA + * + * August 18, 2011 + * + * Fionnuala Gunter + */ + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "common.c" +#include "regress.h" +#include "mech_to_str.h" + +#include "rsa.h" + +#define CHUNK 20 + +/* This function should test: + * RSA Key Generation, usign CKM_RSA_PKCS_KEY_PAIR_GEN + * RSA SignUpdate for generated test vectors, mechanism chosen by caller + * RSA VerifyUpdate for generated test vectors, mechanism chosen by caller + * + * 1. Generate RSA Key Pair + * 2. Generate message + * 3. Sign message + * 4. Verify signature + * + */ +CK_RV do_SignVerifyUpdateRSA(struct GENERATED_TEST_SUITE_INFO *tsuite) +{ + unsigned int i; // test vector index + unsigned int j; // message byte index + int inc, count, len; + CK_BYTE message[MAX_MESSAGE_SIZE]; + CK_ULONG message_len; + CK_BYTE signature[MAX_SIGNATURE_SIZE]; + CK_ULONG signature_len; + + CK_MECHANISM mech; + CK_OBJECT_HANDLE publ_key, priv_key; + + CK_SLOT_ID slot_id = SLOT_ID; + CK_SESSION_HANDLE session; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rc, loc_rc; + + char *s; + + // begin testsuite + testsuite_begin("%s SignUpdate VerifyUpdate.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + // skip tests if the slot doesn't support this mechanism + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + + // iterate over test vectors + for (i = 0; i < tsuite->tvcount; i++) { + // get public exponent from test vector + if (p11_ahex_dump(&s, tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len) == NULL) { + testcase_error("p11_ahex_dump() failed"); + rc = -1; + goto testcase_cleanup; + } + + // begin test + testcase_begin("%s Sign and Verify with test vector %d, " + "\npubl_exp='%s', mod_bits='%lu', keylen='%lu'.", + tsuite->name, i, s, + tsuite->tv[i].modbits, tsuite->tv[i].keylen); + + if (!keysize_supported(slot_id, tsuite->mech.mechanism, + tsuite->tv[i].modbits)) { + testcase_skip("Token in slot %ld cannot be used with " + "modbits.='%ld'", SLOT_ID, tsuite->tv[i].modbits); + continue; + } + + if (is_ep11_token(slot_id)) { + if (!is_valid_ep11_pubexp(tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len)) { + testcase_skip("EP11 Token cannot " + "be used with publ_exp.='%s'", s); + continue; + } + } + + if (is_cca_token(slot_id)) { + if (!is_valid_cca_pubexp(tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len)) { + testcase_skip("CCA Token cannot " + "be used with publ_exp='%s'.", s); + continue; + } + } + + if (is_tpm_token(slot_id)) { + if ((!is_valid_tpm_pubexp(tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len)) + || (!is_valid_tpm_modbits(tsuite->tv[i].modbits))) { + testcase_skip("TPM Token cannot " "be used with publ_exp='%s'.", + s); + continue; + } + } + + if (is_icsf_token(slot_id)) { + if (!is_valid_icsf_pubexp(tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len) || + (tsuite->tv[i].modbits < 1024)) { + testcase_skip("ICSF Token cannot " + "be used with publ_exp='%s'.", s); + continue; + } + } + // free memory + free(s); + + rc = CKR_OK; // set rc + + // clear buffers + memset(message, 0, MAX_MESSAGE_SIZE); + memset(signature, 0, MAX_SIGNATURE_SIZE); + + // get test vector parameters + message_len = tsuite->tv[i].inputlen; + + // generate key pair + rc = generate_RSA_PKCS_KeyPair(session, + tsuite->tv[i].modbits, + tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len, + &publ_key, &priv_key); + if (rc != CKR_OK) { + testcase_error("generate_RSA_PKCS_KeyPair(), " + "rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // generate message + for (j = 0; j < message_len; j++) { + message[j] = (j + 1) % 255; + } + + // get mech + mech = tsuite->mech; + + // initialize Sign (length only) + rc = funcs->C_SignInit(session, &mech, priv_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit(), rc=%s", p11_get_ckr(rc)); + goto error; + } + // set buffer size + signature_len = 0; + + // do SignUpdate + len = message_len; + for (count = 0; len > 0; count += inc) { + if (len < CHUNK) + inc = len; + else + inc = CHUNK; + + rc = funcs->C_SignUpdate(session, message + count, inc); + if (rc != CKR_OK) { + testcase_error("C_SignUpdate(), rc=%s.", p11_get_ckr(rc)); + goto error; + } + len -= inc; + } + + /* get the required length */ + testcase_new_assertion(); + rc = funcs->C_SignFinal(session, NULL, &signature_len); + if (rc != CKR_OK) { + testcase_error("C_SignFinal(),rc=%s.", p11_get_ckr(rc)); + goto error; + } + if (signature_len == (tsuite->tv[i].modbits / 8)) { + testcase_pass("C_SignFinal set output length."); + } else { + testcase_fail("C_SignFinal failed to set length: " + "expected %ld, got %ld.", + signature_len, tsuite->tv[i].modbits / 8); + goto error; + } + + rc = funcs->C_SignFinal(session, signature, &signature_len); + if (rc != CKR_OK) { + testcase_error("C_SignFinal(),rc=%s.", p11_get_ckr(rc)); + goto error; + } + // initialize Verify + rc = funcs->C_VerifyInit(session, &mech, publ_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit(), rc=%s", p11_get_ckr(rc)); + goto error; + } + // do VerifyUpdate + len = message_len; + for (count = 0; len > 0; count += inc) { + if (len < CHUNK) + inc = len; + else + inc = CHUNK; + + rc = funcs->C_VerifyUpdate(session, message + count, inc); + if (rc != CKR_OK) { + testcase_error("C_VerifyUpdate(), rc=%s.", p11_get_ckr(rc)); + goto error; + } + len -= inc; + } + rc = funcs->C_VerifyFinal(session, signature, signature_len); + + // check results + testcase_new_assertion(); + if (rc == CKR_OK) { + testcase_pass("C_VerifyFinal."); + } else { + testcase_fail("C_VerifyFinal, rc=%s", p11_get_ckr(rc)); + } + + // clean up + rc = funcs->C_DestroyObject(session, publ_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + + rc = funcs->C_DestroyObject(session, priv_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + } + goto testcase_cleanup; +error: + loc_rc = funcs->C_DestroyObject(session, publ_key); + if (loc_rc != CKR_OK) { + testcase_error("C_DestroyObject, rc=%s.", p11_get_ckr(loc_rc)); + } + loc_rc = funcs->C_DestroyObject(session, priv_key); + if (loc_rc != CKR_OK) { + testcase_error("C_DestroyObject, rc=%s.", p11_get_ckr(loc_rc)); + } + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloesAllSessions, rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + + +/* This function should test: + * RSA Key Generation, usign CKM_RSA_PKCS_KEY_PAIR_GEN + * RSA-PSS Sign, mechanism chosen by caller + * RSA-PSS Verify, mechanism chosen by caller + * + * 1. Generate RSA Key Pair + * 2. Generate message + * 3. Sign message + * 4. Verify signature + * + */ +#define MAX_HASH_SIZE 64 +CK_RV do_SignVerifyUpdate_RSAPSS(struct GENERATED_TEST_SUITE_INFO * tsuite) +{ + unsigned int i; // test vector index + unsigned int j; // message byte index + int len; + CK_BYTE message[MAX_MESSAGE_SIZE]; + CK_BYTE signature[MAX_SIGNATURE_SIZE]; + CK_ULONG message_len, signature_len, data_done; + + CK_MECHANISM mech; + CK_OBJECT_HANDLE publ_key, priv_key; + + CK_SLOT_ID slot_id = SLOT_ID; + CK_SESSION_HANDLE session; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rc, loc_rc; + CK_RSA_PKCS_PSS_PARAMS pss_params; + + char *s; + + // begin testsuite + testsuite_begin("%s SignUpdate VerifyUpdate.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + // skip tests if the slot doesn't support this mechanism + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + // iterate over test vectors + for (i = 0; i < tsuite->tvcount; i++) { + + // get public exponent from test vector + if (p11_ahex_dump(&s, tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len) == NULL) { + testcase_error("p11_ahex_dump() failed"); + rc = -1; + goto testcase_cleanup; + } + // begin test + testcase_begin("%s Sign and Verify with test vector %d, " + "\npubl_exp='%s', mod_bits='%lu', keylen='%lu'.", + tsuite->name, i, s, + tsuite->tv[i].modbits, tsuite->tv[i].keylen); + + if (!keysize_supported(slot_id, tsuite->mech.mechanism, + tsuite->tv[i].modbits)) { + testcase_skip("Token in slot %ld cannot be used with " + "modbits.='%ld'", SLOT_ID, tsuite->tv[i].modbits); + continue; + } + + if (is_ep11_token(slot_id)) { + if (!is_valid_ep11_pubexp(tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len)) { + testcase_skip("EP11 Token cannot " + "be used with publ_exp.='%s'", s); + continue; + } + } + // free memory + free(s); + + rc = CKR_OK; // set rc + + // clear buffers + memset(message, 0, MAX_MESSAGE_SIZE); + memset(signature, 0, MAX_SIGNATURE_SIZE); + + // get test vector parameters + message_len = tsuite->tv[i].inputlen; + + // generate key pair + rc = generate_RSA_PKCS_KeyPair(session, + tsuite->tv[i].modbits, + tsuite->tv[i].publ_exp, + tsuite->tv[i].publ_exp_len, + &publ_key, &priv_key); + if (rc != CKR_OK) { + testcase_error("generate_RSA_PKCS_KeyPair(), " + "rc=%s", p11_get_ckr(rc)); + goto error; + } + // generate message + for (j = 0; j < message_len; j++) { + message[j] = (j + 1) % 255; + } + + // set mechanism for signing the digest + mech = tsuite->mech; + pss_params = tsuite->tv[i].pss_params; + mech.pParameter = &pss_params; + mech.ulParameterLen = sizeof(CK_RSA_PKCS_PSS_PARAMS); + + // initialize Sign (length only) + rc = funcs->C_SignInit(session, &mech, priv_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit(), rc=%s", p11_get_ckr(rc)); + goto error; + } + // set buffer size + signature_len = 0; + data_done = 0; + + // do SignUpdate + if (tsuite->tv[i].num_chunks) { + CK_BYTE *data_chunk = NULL; + + for (j = 0; j < (unsigned int)tsuite->tv[i].num_chunks; j++) { + if (tsuite->tv[i].chunks[j] == -1) { + len = 0; + data_chunk = NULL; + } else if (tsuite->tv[i].chunks[j] == 0) { + len = 0; + data_chunk = (CK_BYTE *) ""; + } else { + len = tsuite->tv[i].chunks[j]; + data_chunk = message + data_done; + } + + rc = funcs->C_SignUpdate(session, data_chunk, len); + if (rc != CKR_OK) { + testcase_error("C_SignUpdate rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + data_done += len; + } + } else { + rc = funcs->C_SignUpdate(session, message, message_len); + if (rc != CKR_OK) { + testcase_error("C_SignUpdate rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + + + /* get the required length */ + testcase_new_assertion(); + rc = funcs->C_SignFinal(session, NULL, &signature_len); + if (rc != CKR_OK) { + testcase_error("C_SignFinal(),rc=%s.", p11_get_ckr(rc)); + goto error; + } + if (signature_len == (tsuite->tv[i].modbits / 8)) { + testcase_pass("C_SignFinal set output length."); + } else { + testcase_fail("C_SignFinal failed to set length: " + "expected %ld, got %ld.", + signature_len, tsuite->tv[i].modbits / 8); + goto error; + } + + rc = funcs->C_SignFinal(session, signature, &signature_len); + if (rc != CKR_OK) { + testcase_error("C_SignFinal(),rc=%s.", p11_get_ckr(rc)); + goto error; + } + // initialize Verify + rc = funcs->C_VerifyInit(session, &mech, publ_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit(), rc=%s", p11_get_ckr(rc)); + goto error; + } + // do VerifyUpdate + data_done = 0; + if (tsuite->tv[i].num_chunks) { + CK_BYTE *data_chunk = NULL; + + for (j = 0; j < (unsigned int)tsuite->tv[i].num_chunks; j++) { + if (tsuite->tv[i].chunks[j] == -1) { + len = 0; + data_chunk = NULL; + } else if (tsuite->tv[i].chunks[j] == 0) { + len = 0; + data_chunk = (CK_BYTE *) ""; + } else { + len = tsuite->tv[i].chunks[j]; + data_chunk = message + data_done; + } + + rc = funcs->C_VerifyUpdate(session, data_chunk, len); + if (rc != CKR_OK) { + testcase_error("C_VerifyUpdate rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + data_done += len; + } + } else { + rc = funcs->C_VerifyUpdate(session, message, message_len); + if (rc != CKR_OK) { + testcase_error("C_VerifyUpdate rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + rc = funcs->C_VerifyFinal(session, signature, signature_len); + + // check results + testcase_new_assertion(); + if (rc == CKR_OK) { + testcase_pass("C_VerifyFinal."); + } else { + testcase_fail("C_VerifyFinal(), rc=%s", p11_get_ckr(rc)); + } + + // clean up + rc = funcs->C_DestroyObject(session, publ_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + + rc = funcs->C_DestroyObject(session, priv_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + } + } + goto testcase_cleanup; +error: + loc_rc = funcs->C_DestroyObject(session, publ_key); + if (loc_rc != CKR_OK) { + testcase_error("C_DestroyObject, rc=%s.", p11_get_ckr(loc_rc)); + } + loc_rc = funcs->C_DestroyObject(session, priv_key); + if (loc_rc != CKR_OK) { + testcase_error("C_DestroyObject, rc=%s.", p11_get_ckr(loc_rc)); + } + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloesAllSessions, rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/* This function should test: + * C_Verify, mechanism chosen by caller + * + * 1. Get message from test vector + * 2. Get signature from test vector + * 3. Verify signature + * + */ +CK_RV do_VerifyUpdateRSA(struct PUBLISHED_TEST_SUITE_INFO * tsuite) +{ + unsigned int i, inc, len, j; + CK_BYTE actual[MAX_SIGNATURE_SIZE]; + CK_BYTE message[MAX_MESSAGE_SIZE]; + CK_ULONG message_len; + CK_BYTE signature[MAX_SIGNATURE_SIZE]; + CK_ULONG signature_len; + + CK_MECHANISM mech; + CK_OBJECT_HANDLE publ_key; + + CK_SLOT_ID slot_id = SLOT_ID; + CK_SESSION_HANDLE session; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rc, loc_rc; + + char *s; + + // begin testsuite + testsuite_begin("%s Verify.", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + // skip tests if the slot doesn't support this mechanism + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + // iterate over test vectors + for (i = 0; i < tsuite->tvcount; i++) { + + if (p11_ahex_dump(&s, tsuite->tv[i].pub_exp, + tsuite->tv[i].pubexp_len) == NULL) { + testcase_error("p11_ahex_dump() failed"); + rc = -1; + goto testcase_cleanup; + } + + testcase_begin("%s Verify with test vector %d.", tsuite->name, i); + + // special case for EP11 + // modulus length must be multiple of 128 byte + // skip test if modulus length has unsuported size + if (is_ep11_token(slot_id)) { + if ((tsuite->tv[i].mod_len % 128) != 0) { + testcase_skip("EP11 Token cannot be used with " + "this key size (no 128bit granularity)."); + continue; + } + } + + if (is_ep11_token(slot_id)) { + if (!is_valid_ep11_pubexp(tsuite->tv[i].pub_exp, + tsuite->tv[i].pubexp_len)) { + testcase_skip("EP11 Token cannot " + "be used with pub_exp.='%s'", s); + continue; + } + } + + if (is_tpm_token(slot_id)) { + if ((!is_valid_tpm_pubexp(tsuite->tv[i].pub_exp, + tsuite->tv[i].pubexp_len)) || + (!is_valid_tpm_modbits(tsuite->tv[i].mod_len))) { + testcase_skip("TPM Token cannot " + "be used with pub_exp='%s'.", s); + continue; + } + } + // free memory + free(s); + + rc = CKR_OK; // set return value + + // clear buffers + memset(message, 0, MAX_MESSAGE_SIZE); + memset(signature, 0, MAX_SIGNATURE_SIZE); + memset(actual, 0, MAX_SIGNATURE_SIZE); + + // get message + message_len = tsuite->tv[i].msg_len; + memcpy(message, tsuite->tv[i].msg, message_len); + + // get signature + signature_len = tsuite->tv[i].sig_len; + memcpy(signature, tsuite->tv[i].sig, signature_len); + + // create (public) key handle + rc = create_RSAPublicKey(session, + tsuite->tv[i].mod, + tsuite->tv[i].pub_exp, + tsuite->tv[i].mod_len, + tsuite->tv[i].pubexp_len, &publ_key); + + if (rc != CKR_OK) { + testcase_error("create_RSAPublicKey(), rc=%s", p11_get_ckr(rc)); + goto error; + } + // set mechanism + mech = tsuite->mech; + + // initialize verify + rc = funcs->C_VerifyInit(session, &mech, publ_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit(), rc=%s", p11_get_ckr(rc)); + goto error; + } + // do verify + len = message_len; + for (j = 0; len > 0; j += inc) { + if (len < CHUNK) + inc = len; + else + inc = CHUNK; + + rc = funcs->C_VerifyUpdate(session, message + j, inc); + if (rc != CKR_OK) { + testcase_error("C_VerifyUpdate(), rc=%s.", p11_get_ckr(rc)); + goto error; + } + len -= inc; + } + + // check result + testcase_new_assertion(); + + rc = funcs->C_VerifyFinal(session, signature, signature_len); + if (rc == CKR_OK) { + testcase_pass("C_Verify."); + } else { + testcase_fail("%s Sign Verify with test vector %d " + "failed.", tsuite->name, i); + } + + // clean up + rc = funcs->C_DestroyObject(session, publ_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + } + goto testcase_cleanup; +error: + loc_rc = funcs->C_DestroyObject(session, publ_key); + if (loc_rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); + } + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +/* This function should test: + * C_Sign_Update and C_SignFinal, mechanism chosen by caller + * + * 1. Get message from test vector + * 2. Get expected signature from test vector + * 3. Sign message + * 4. Compare expected signature with actual signature + * + */ +CK_RV do_SignUpdateRSA(struct PUBLISHED_TEST_SUITE_INFO * tsuite) +{ + unsigned int i, len, j; + CK_BYTE message[MAX_MESSAGE_SIZE]; + CK_BYTE actual[MAX_SIGNATURE_SIZE]; + CK_BYTE expected[MAX_SIGNATURE_SIZE]; + CK_ULONG message_len, actual_len, expected_len; + CK_ULONG data_done; + + CK_MECHANISM mech; + CK_OBJECT_HANDLE priv_key; + + CK_SLOT_ID slot_id = SLOT_ID; + CK_SESSION_HANDLE session; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rc, loc_rc; + char *s; + + // begin testsuite + testsuite_begin("%s Sign. ", tsuite->name); + testcase_rw_session(); + testcase_user_login(); + + // skip tests if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, tsuite->mech.mechanism)) { + testsuite_skip(tsuite->tvcount, + "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(tsuite->mech.mechanism), + (unsigned int) tsuite->mech.mechanism); + goto testcase_cleanup; + } + // iterate over test vectors + for (i = 0; i < tsuite->tvcount; i++) { + if (p11_ahex_dump(&s, tsuite->tv[i].pub_exp, + tsuite->tv[i].pubexp_len) == NULL) { + testcase_error("p11_ahex_dump() failed"); + rc = -1; + goto testcase_cleanup; + } + testcase_begin("%s Sign with test vector %d.", tsuite->name, i); + + // special case for ica + // prime1, prime2, exp1, exp2, coef + // must be size mod_len/2 or smaller + // skip test if prime1, or prime2, or exp1, + // or exp2 or coef are too long + if (is_ica_token(slot_id)) { + // check sizes + if ((tsuite->tv[i].prime1_len > + (tsuite->tv[i].mod_len / 2)) || + (tsuite->tv[i].prime2_len > + (tsuite->tv[i].mod_len / 2)) || + (tsuite->tv[i].exp1_len > + (tsuite->tv[i].mod_len / 2)) || + (tsuite->tv[i].exp2_len > + (tsuite->tv[i].mod_len / 2)) || + (tsuite->tv[i].coef_len > (tsuite->tv[i].mod_len / 2))) { + testcase_skip("ICA Token cannot be used with " + "this test vector."); + continue; + } + + } + // special case for EP11 + // modulus length must be multiple of 128 byte + // skip test if modulus length has unsuported size + if (is_ep11_token(slot_id)) { + if ((tsuite->tv[i].mod_len % 128) != 0) { + testcase_skip("EP11 Token cannot be used with " + "this key size (no 128bit granularity)."); + continue; + } + } + + if (is_ep11_token(slot_id)) { + if (!is_valid_ep11_pubexp(tsuite->tv[i].pub_exp, + tsuite->tv[i].pubexp_len)) { + testcase_skip("EP11 Token cannot " + "be used with publ_exp.='%s'", s); + continue; + } + } + + if (is_tpm_token(slot_id)) { + if ((!is_valid_tpm_pubexp(tsuite->tv[i].pub_exp, + tsuite->tv[i].pubexp_len)) || + (!is_valid_tpm_modbits(tsuite->tv[i].mod_len))) { + testcase_skip("TPM Token cannot " + "be used with pub_exp='%s'.", s); + continue; + } + } + + free(s); + + rc = CKR_OK; // set return value + + // clear buffers + memset(message, 0, MAX_MESSAGE_SIZE); + memset(actual, 0, MAX_SIGNATURE_SIZE); + memset(expected, 0, MAX_SIGNATURE_SIZE); + + actual_len = 0; // get this from opencryptoki + + data_done = 0; + + // get message + message_len = tsuite->tv[i].msg_len; + memcpy(message, tsuite->tv[i].msg, message_len); + + // get (expected) signature + expected_len = tsuite->tv[i].sig_len; + memcpy(expected, tsuite->tv[i].sig, expected_len); + + // create (private) key handle + rc = create_RSAPrivateKey(session, + tsuite->tv[i].mod, + tsuite->tv[i].pub_exp, + tsuite->tv[i].priv_exp, + tsuite->tv[i].prime1, + tsuite->tv[i].prime2, + tsuite->tv[i].exp1, + tsuite->tv[i].exp2, + tsuite->tv[i].coef, + tsuite->tv[i].mod_len, + tsuite->tv[i].pubexp_len, + tsuite->tv[i].privexp_len, + tsuite->tv[i].prime1_len, + tsuite->tv[i].prime2_len, + tsuite->tv[i].exp1_len, + tsuite->tv[i].exp2_len, + tsuite->tv[i].coef_len, &priv_key); + if (rc != CKR_OK) { + testcase_error("create_RSAPrivateKey(), rc=%s", p11_get_ckr(rc)); + goto error; + } + // set mechanism + mech = tsuite->mech; + + // initialize signing + rc = funcs->C_SignInit(session, &mech, priv_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit(), rc=%s.", p11_get_ckr(rc)); + goto error; + } + // do signing + if (tsuite->tv[i].num_chunks) { + CK_BYTE *data_chunk = NULL; + + for (j = 0; j < (unsigned int)tsuite->tv[i].num_chunks; j++) { + if (tsuite->tv[i].chunks[j] == -1) { + len = 0; + data_chunk = NULL; + } else if (tsuite->tv[i].chunks[j] == 0) { + len = 0; + data_chunk = (CK_BYTE *) ""; + } else { + len = tsuite->tv[i].chunks[j]; + data_chunk = message + data_done; + } + + rc = funcs->C_SignUpdate(session, data_chunk, len); + if (rc != CKR_OK) { + testcase_error("C_SignUpdate rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + data_done += len; + } + } else { + rc = funcs->C_SignUpdate(session, message, message_len); + if (rc != CKR_OK) { + testcase_error("C_SignUpdate rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + + /* get the required length */ + testcase_new_assertion(); + rc = funcs->C_SignFinal(session, NULL, &actual_len); + if (rc != CKR_OK) { + testcase_error("C_SignFinal(),rc=%s.", p11_get_ckr(rc)); + goto error; + } + if (actual_len == tsuite->tv[i].mod_len) { + testcase_pass("C_SignFinal set output length."); + } else { + testcase_fail("C_SignFinal failed to set length: " + "expected %ld, got %ld.", + actual_len, tsuite->tv[i].mod_len); + goto error; + } + + rc = funcs->C_SignFinal(session, actual, &actual_len); + if (rc != CKR_OK) { + testcase_error("C_SignFinal(),rc=%s.", p11_get_ckr(rc)); + goto error; + } + // check results + testcase_new_assertion(); + + if (actual_len != expected_len) { + testcase_fail("%s Sign with test vector %d failed. " + "Expected len=%ld, found len=%ld.", + tsuite->name, i, expected_len, actual_len); + } else if (memcmp(actual, expected, expected_len)) { + testcase_fail("%s Sign with test vector %d failed. " + "Signature data does not match test vector " + "signature.", tsuite->name, i); + + } else { + testcase_pass("C_Sign."); + } + + // clean up + rc = funcs->C_DestroyObject(session, priv_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); + goto testcase_cleanup; + } + } + goto testcase_cleanup; +error: + loc_rc = funcs->C_DestroyObject(session, priv_key); + if (loc_rc != CKR_OK) { + testcase_error("C_DestroyObject, rc=%s.", p11_get_ckr(loc_rc)); + } +testcase_cleanup: + testcase_user_logout(); + loc_rc = funcs->C_CloseAllSessions(slot_id); + if (loc_rc != CKR_OK) { + testcase_error("C_CloseAllSessions, rc=%s.", p11_get_ckr(loc_rc)); + } + + return rc; +} + +CK_RV rsa_funcs() +{ + unsigned int i; + CK_RV rv = CKR_OK; + + // published (known answer) tests + for (i = 0; i < NUM_OF_PUBLISHED_TESTSUITES; i++) { + rv = do_SignUpdateRSA(&published_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + } + + for (i = 0; i < NUM_OF_PUBLISHED_TESTSUITES; i++) { + rv = do_VerifyUpdateRSA(&published_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + } + + // generated sign verify tests + for (i = 0; i < NUM_OF_GENERATED_SIGVER_UPDATE_TESTSUITES; i++) { + rv = do_SignVerifyUpdateRSA(&generated_sigver_update_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + } + + for (i = 0; i < NUM_OF_GENERATED_PSS_UPDATE_TESTSUITES; i++) { + rv = do_SignVerifyUpdate_RSAPSS(&generated_pss_update_test_suites[i]); + if (rv != CKR_OK && (!no_stop)) + break; + } + + return rv; +} + +int main(int argc, char **argv) +{ + int rc; + CK_C_INITIALIZE_ARGS cinit_args; + CK_RV rv; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) { + return rc; + } + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: no_stop: %d\n", no_stop); + + rc = do_GetFunctionList(); + if (!rc) { + PRINT_ERR("ERROR do_GetFunctionList() Failed, rx = 0x%0x\n", rc); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + funcs->C_Initialize(&cinit_args); + { + CK_SESSION_HANDLE hsess = 0; + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) { + return rc; + } + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) { + return rc; + } + } + + testcase_setup(0); + rv = rsa_funcs(); + testcase_print_result(); + + funcs->C_Finalize(NULL); + + return rv; +} diff --git a/testcases/crypto/ssl3_func.c b/testcases/crypto/ssl3_func.c new file mode 100644 index 0000000..0034f41 --- /dev/null +++ b/testcases/crypto/ssl3_func.c @@ -0,0 +1,714 @@ +/* + * 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 + */ + +#include + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "common.c" +#include "mech_to_str.h" + +static CK_BBOOL true = TRUE; +static CK_BBOOL false = FALSE; + +// +// +CK_RV do_SignVerify_SSL3_MD5_MAC(CK_SESSION_HANDLE session) +{ + CK_MECHANISM mech; + CK_ULONG mac_size; + CK_ULONG i; + CK_RV rc = CKR_OK; + + CK_OBJECT_HANDLE h_key; + CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; + CK_KEY_TYPE key_type = CKK_GENERIC_SECRET; + CK_BBOOL false = FALSE; + CK_BYTE hash[MD5_HASH_LEN]; + CK_BYTE data[50]; + CK_BYTE data2[500]; + CK_BYTE key_data[48]; + CK_ULONG hash_len; + CK_ULONG data_len; + CK_ATTRIBUTE key_attribs[] = { + {CKA_CLASS, &key_class, sizeof(key_class)}, + {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, + {CKA_TOKEN, &false, sizeof(false)}, + {CKA_VALUE, &key_data, sizeof(key_data)} + }; + CK_SLOT_ID slot_id = SLOT_ID; + + testcase_begin("starting do_SignVerify_SSL3_MD5_MAC...\n"); + + mac_size = 16; + + mech.mechanism = CKM_SSL3_MD5_MAC; + mech.ulParameterLen = sizeof(CK_ULONG); + mech.pParameter = &mac_size; + + + /** skip test if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, mech.mechanism)) { + testsuite_skip(48, "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(mech.mechanism), + (unsigned int) mech.mechanism); + goto skipped; + } + + for (i = 0; i < 48; i++) + key_data[i] = i; + + memset(data, 0xb, 50); + data_len = 50; + + rc = funcs->C_CreateObject(session, key_attribs, 4, &h_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + testcase_new_assertion(); + rc = funcs->C_SignInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit() rc = %s", p11_get_ckr(rc)); + goto done; + } + + hash_len = sizeof(hash); + rc = funcs->C_Sign(session, data, data_len, hash, &hash_len); + if (rc != CKR_OK) { + testcase_fail("C_Sign() rc = %s", p11_get_ckr(rc)); + goto done; + } + + if (hash_len != mac_size) { + testcase_fail("Error: C_Sign generated bad MAC length\n"); + goto done; + } else { + testcase_pass("Successfully signed."); + } + + testcase_new_assertion(); + rc = funcs->C_VerifyInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit() rc = %s", p11_get_ckr(rc)); + goto done; + } + + rc = funcs->C_Verify(session, data, data_len, hash, hash_len); + if (rc != CKR_OK) + testcase_fail("C_Verify() rc = %s", p11_get_ckr(rc)); + else + testcase_pass("Successfully verified."); + + rc = funcs->C_DestroyObject(session, h_key); + if (rc != CKR_OK) { + testcase_error("C_DestroyObject() rc = %s", p11_get_ckr(rc)); + goto done; + } + // TESTCASE #2 + + for (i = 0; i < 48; i++) + key_data[i] = i; + + memset(data2, 0xb, 500); + data_len = 500; + + rc = funcs->C_CreateObject(session, key_attribs, 4, &h_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto done; + } + + testcase_new_assertion(); + rc = funcs->C_SignInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit() rc = %s", p11_get_ckr(rc)); + goto done; + } + + for (i = 0; i < 500; i += 100) { + rc = funcs->C_SignUpdate(session, &data2[i], 100); + if (rc != CKR_OK) { + testcase_error("Iteration #%ld, C_SignUpdate() rc = %s", i / 100, + p11_get_ckr(rc)); + goto done; + } + } + + hash_len = sizeof(hash); + rc = funcs->C_SignFinal(session, hash, &hash_len); + if (rc != CKR_OK) { + testcase_error("C_SignFinal() rc = %s", p11_get_ckr(rc)); + goto done; + } + + if (hash_len != mac_size) { + testcase_fail("Error: C_SignUpdate/Final generated bad MAC length\n"); + goto done; + } else { + testcase_pass("Sucessfully signed in multipart."); + } + + testcase_new_assertion(); + rc = funcs->C_VerifyInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit() rc = %s", p11_get_ckr(rc)); + goto done; + } + + for (i = 0; i < 500; i += 100) { + rc = funcs->C_VerifyUpdate(session, &data2[i], 100); + if (rc != CKR_OK) { + testcase_error("Iteration #%ld, C_VerifyUpdate() rc = %s", i / 100, + p11_get_ckr(rc)); + goto done; + } + } + + rc = funcs->C_VerifyFinal(session, hash, hash_len); + if (rc != CKR_OK) + testcase_fail("C_VerifyFinal rc = %s", p11_get_ckr(rc)); + else + testcase_pass("Successfully verified signature in multipart."); + +done: + if (funcs->C_DestroyObject(session, h_key) != CKR_OK) + testcase_error("C_DestroyObject failed."); + +skipped: + return rc; +} + + +// +// +CK_RV do_SignVerify_SSL3_SHA1_MAC(CK_SESSION_HANDLE session) +{ + CK_MECHANISM mech; + CK_ULONG mac_size; + CK_ULONG i; + CK_RV rc = CKR_OK; + + CK_OBJECT_HANDLE h_key; + CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; + CK_KEY_TYPE key_type = CKK_GENERIC_SECRET; + CK_BBOOL false = FALSE; + CK_BYTE hash[SHA1_HASH_LEN]; + CK_BYTE data[50]; + CK_BYTE key_data[48]; + CK_ULONG hash_len; + CK_ULONG data_len; + CK_ATTRIBUTE key_attribs[] = { + {CKA_CLASS, &key_class, sizeof(key_class)}, + {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, + {CKA_TOKEN, &false, sizeof(false)}, + {CKA_VALUE, &key_data, sizeof(key_data)} + }; + CK_SLOT_ID slot_id = SLOT_ID; + + testcase_begin("starting do_SignVerify_SSL3_SHA1_MAC...\n"); + + mac_size = 20; + + mech.mechanism = CKM_SSL3_SHA1_MAC; + mech.ulParameterLen = sizeof(CK_ULONG); + mech.pParameter = &mac_size; + + /** skip test if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, mech.mechanism)) { + testsuite_skip(48, "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(mech.mechanism), + (unsigned int) mech.mechanism); + goto skipped; + } + + for (i = 0; i < 48; i++) + key_data[i] = i; + + memset(data, 0xb, 50); + data_len = 50; + + rc = funcs->C_CreateObject(session, key_attribs, 4, &h_key); + if (rc != CKR_OK) { + testcase_error("C_CreateObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + testcase_new_assertion(); + rc = funcs->C_SignInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_fail("C_SignInit() rc = %s", p11_get_ckr(rc)); + goto done; + } + + hash_len = sizeof(hash); + rc = funcs->C_Sign(session, data, data_len, hash, &hash_len); + if (rc != CKR_OK) { + testcase_fail("C_Sign() rc = %s", p11_get_ckr(rc)); + goto done; + } + + if (hash_len != mac_size) { + testcase_fail("Error: C_Sign generated bad MAC length\n"); + goto done; + } else { + testcase_pass("Successfully signed."); + } + + testcase_new_assertion(); + rc = funcs->C_VerifyInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit() rc = %s", p11_get_ckr(rc)); + goto done; + } + + rc = funcs->C_Verify(session, data, data_len, hash, hash_len); + if (rc != CKR_OK) + testcase_fail("C_Verify() rc = %s", p11_get_ckr(rc)); + else + testcase_pass("Successfully verified signature."); + +done: + if (funcs->C_DestroyObject(session, h_key) != CKR_OK) + testcase_error("C_DestroyObject() failed."); + +skipped: + return rc; +} + + +// +// +CK_RV do_SSL3_PreMasterKeyGen(CK_SESSION_HANDLE session) +{ + CK_MECHANISM mech; + CK_VERSION version; + CK_OBJECT_HANDLE h_key; + CK_RV rc = CKR_OK; + CK_SLOT_ID slot_id = SLOT_ID; + + testcase_begin("starting do_SSL3_PreMasterKeyGen...\n"); + + version.major = 3; + version.minor = 0; + + mech.mechanism = CKM_SSL3_PRE_MASTER_KEY_GEN; + mech.pParameter = &version; + mech.ulParameterLen = sizeof(CK_VERSION); + + /** skip test if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, mech.mechanism)) { + testsuite_skip(1, "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(mech.mechanism), + (unsigned int) mech.mechanism); + goto done; + } + + testcase_new_assertion(); + rc = funcs->C_GenerateKey(session, &mech, NULL, 0, &h_key); + if (rc != CKR_OK) + testcase_fail("C_GenerateKey() rc = %s", p11_get_ckr(rc)); + else + testcase_pass("Successfully generated a generic secret key."); + + if (funcs->C_DestroyObject(session, h_key) != CKR_OK) + testcase_error("C_DestroyObject() failed"); + +done: + return rc; +} + + +// +// +CK_RV do_SSL3_MasterKeyDerive(CK_SESSION_HANDLE session) +{ + CK_MECHANISM mech; + CK_OBJECT_HANDLE h_pm_secret = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE h_mk = CK_INVALID_HANDLE; + CK_RV rc = CKR_OK; + + CK_VERSION version = { 3, 0 }; + CK_ATTRIBUTE pm_tmpl[] = { + {CKA_SENSITIVE, &false, sizeof(CK_BBOOL)}, + {CKA_EXTRACTABLE, &true, sizeof(CK_BBOOL)} + }; + + CK_BYTE client_random_data[256]; + CK_BYTE server_random_data[256]; + CK_ATTRIBUTE m_tmpl[] = { + {CKA_SENSITIVE, &true, sizeof(CK_BBOOL)}, + {CKA_EXTRACTABLE, &false, sizeof(CK_BBOOL)} + }; + + CK_SSL3_MASTER_KEY_DERIVE_PARAMS mk_params; + CK_ULONG i; + + CK_OBJECT_CLASS class; + CK_KEY_TYPE keyType; + CK_ATTRIBUTE test_tmpl[] = { + {CKA_CLASS, &class, sizeof(class)}, + {CKA_KEY_TYPE, &keyType, sizeof(keyType)} + }; + CK_SLOT_ID slot_id = SLOT_ID; + + testcase_begin("starting do_SSL3_MasterKeyDerive...\n"); + + // generate the pre-master secret key + // + mech.mechanism = CKM_SSL3_PRE_MASTER_KEY_GEN; + mech.pParameter = &version; + mech.ulParameterLen = sizeof(CK_VERSION); + + /** skip test if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, mech.mechanism)) { + testsuite_skip(32, "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(mech.mechanism), + (unsigned int) mech.mechanism); + goto skipped; + } + + testcase_new_assertion(); + rc = funcs->C_GenerateKey(session, &mech, pm_tmpl, 2, &h_pm_secret); + if (rc != CKR_OK) { + testcase_fail("C_GenerateKey() rc= %s", p11_get_ckr(rc)); + goto done; + } else { + testcase_pass("Successfully generated a generic secret key."); + } + + // derive a master key + // + + for (i = 0; i < 32; i++) { + client_random_data[i] = i; + server_random_data[i] = 32 - i; + } + + mk_params.pVersion = &version; + + mk_params.RandomInfo.pClientRandom = client_random_data; + mk_params.RandomInfo.pServerRandom = server_random_data; + mk_params.RandomInfo.ulClientRandomLen = 32; + mk_params.RandomInfo.ulServerRandomLen = 32; + + mech.mechanism = CKM_SSL3_MASTER_KEY_DERIVE; + mech.pParameter = &mk_params; + mech.ulParameterLen = sizeof(CK_SSL3_MASTER_KEY_DERIVE_PARAMS); + + testcase_new_assertion(); + rc = funcs->C_DeriveKey(session, &mech, h_pm_secret, m_tmpl, 2, &h_mk); + if (rc != CKR_OK) { + testcase_fail("C_DeriveKey() rc= %s", p11_get_ckr(rc)); + goto done; + } else { + testcase_pass("Successfully derived a key from pre-master."); + } + + /* + * This mechanism provides the following attributes: + * CKA_CLASS = CKO_SECRET_KEY + * CKA_KEY_TYPE = CKK_GENERIC_SECRET + * CKA_VALUE_LEN = 48 + * Check that the newly derived key has these. + */ + testcase_new_assertion(); + rc = funcs->C_GetAttributeValue(session, h_pm_secret, test_tmpl, 2); + if (rc != CKR_OK) { + testcase_error("C_GetAttributeValue() rc= %s", p11_get_ckr(rc)); + goto done; + } + if (*(CK_OBJECT_CLASS *) test_tmpl[0].pValue != CKO_SECRET_KEY) { + testcase_fail("Derived key has incorrect class."); + goto done; + } + + if (*(CK_KEY_TYPE *) test_tmpl[1].pValue != CKK_GENERIC_SECRET) { + testcase_fail("Derived key has incorrect key type."); + goto done; + } else { + testcase_pass("Derived key has correct attributes."); + } + +done: + if (funcs->C_DestroyObject(session, h_mk) != CKR_OK) + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + + if (funcs->C_DestroyObject(session, h_pm_secret) != CKR_OK) + testcase_error("C_DestroyObject() failed"); + +skipped: + return rc; +} + +CK_RV do_SSL3_MultipleKeysDerive(CK_SESSION_HANDLE session) +{ + CK_MECHANISM mech; + CK_OBJECT_HANDLE h_pm_secret; + CK_RV rc = CKR_OK; + CK_ULONG i; + + CK_VERSION version = { 3, 0 }; + CK_BBOOL true_value = TRUE; + CK_BBOOL false_value = FALSE; + CK_ATTRIBUTE pm_tmpl[] = { + {CKA_TOKEN, &true_value, sizeof(true_value)}, + }; + + CK_BYTE client_random_data[32]; + CK_BYTE server_random_data[32]; + CK_ATTRIBUTE incomplete_tmpl[] = { + {CKA_TOKEN, &false_value, sizeof(false_value)}, + {CKA_SENSITIVE, &false_value, sizeof(false_value)}, + {CKA_EXTRACTABLE, &true_value, sizeof(true_value)} + }; + + CK_OBJECT_CLASS class = CKO_SECRET_KEY; + CK_KEY_TYPE key_type = CKK_AES; + CK_ULONG key_len = 16; + CK_ATTRIBUTE complete_tmpl[] = { + {CKA_CLASS, &class, sizeof(class)}, + {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, + {CKA_VALUE_LEN, &key_len, sizeof(CK_ULONG)}, + {CKA_TOKEN, &false_value, sizeof(false_value)}, + {CKA_SENSITIVE, &false_value, sizeof(false_value)}, + {CKA_EXTRACTABLE, &true_value, sizeof(true_value)} + }; + + CK_BYTE iv_client[128 / 8] = { 0, }; + CK_BYTE iv_server[128 / 8] = { 0, }; + + CK_SSL3_KEY_MAT_OUT param_out = { + .hClientMacSecret = 0, + .hServerMacSecret = 0, + .hClientKey = 0, + .hServerKey = 0, + .pIVClient = iv_client, + .pIVServer = iv_server, + }; + + CK_SSL3_KEY_MAT_PARAMS params = { + .ulMacSizeInBits = 128, + .ulKeySizeInBits = key_len * 8, + .ulIVSizeInBits = 128, + .bIsExport = FALSE, + .RandomInfo = + { + .pClientRandom = client_random_data, + .ulClientRandomLen = sizeof(client_random_data), + .pServerRandom = server_random_data, + .ulServerRandomLen = sizeof(server_random_data), + }, + .pReturnedKeyMaterial = ¶m_out, + }; + CK_SLOT_ID slot_id = SLOT_ID; + + testcase_begin("starting do_SSL3_MultipleKeysDerive...\n"); + + // generate the pre-master secret key + // + mech.mechanism = CKM_SSL3_PRE_MASTER_KEY_GEN; + mech.pParameter = &version; + mech.ulParameterLen = sizeof(CK_VERSION); + + /** skip test if the slot doesn't support this mechanism **/ + if (!mech_supported(slot_id, mech.mechanism)) { + testsuite_skip(3, "Slot %u doesn't support %s (%u)", + (unsigned int) slot_id, + mech_to_str(mech.mechanism), + (unsigned int) mech.mechanism); + goto skipped; + } + + testcase_new_assertion(); + rc = funcs->C_GenerateKey(session, &mech, pm_tmpl, + sizeof(pm_tmpl) / sizeof(*pm_tmpl), &h_pm_secret); + if (rc != CKR_OK) { + testcase_fail("C_GenerateKey() rc= %s", p11_get_ckr(rc)); + goto done; + } else { + testcase_pass("Successfully generated a generic secret key."); + } + + for (i = 0; i < sizeof(client_random_data); i++) { + client_random_data[i] = i; + server_random_data[i] = sizeof(client_random_data) - i; + } + + mech.mechanism = CKM_SSL3_KEY_AND_MAC_DERIVE; + mech.pParameter = ¶ms; + mech.ulParameterLen = sizeof(params); + + /* + * Try deriving the key without required attributes... + */ + testcase_new_assertion(); + rc = funcs->C_DeriveKey(session, &mech, h_pm_secret, incomplete_tmpl, + sizeof(incomplete_tmpl) / sizeof(*incomplete_tmpl), + NULL); + if (rc != CKR_TEMPLATE_INCOMPLETE) { + testcase_fail("C_DeriveKey did not recognize missing attributes."); + goto done; + } else { + testcase_pass("Success, could not derive key without required " + "attributes."); + } + + /* + * Now derive key with required attributes... + */ + + testcase_new_assertion(); + rc = funcs->C_DeriveKey(session, &mech, h_pm_secret, complete_tmpl, + sizeof(complete_tmpl) / sizeof(*complete_tmpl), + NULL); + if (rc != CKR_OK) { + testcase_fail("C_DeriveKey() rc= %s", p11_get_ckr(rc)); + goto done; + } else { + testcase_pass("Successfully derived a keys from pre-master."); + } + + + if (funcs->C_DestroyObject(session, param_out.hClientMacSecret)) + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + if (funcs->C_DestroyObject(session, param_out.hServerMacSecret)) + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + if (funcs->C_DestroyObject(session, param_out.hClientKey)) + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + if (funcs->C_DestroyObject(session, param_out.hServerKey)) + testcase_error("C_DestroyObject rc=%s", p11_get_ckr(rc)); + +done: + if (funcs->C_DestroyObject(session, h_pm_secret) != CKR_OK) + testcase_error("C_DestroyObject() failed"); + +skipped: + return rc; +} + +CK_RV ssl3_functions() +{ + CK_RV rc; + SYSTEMTIME t1, t2; + CK_SLOT_ID slot_id = SLOT_ID; + CK_SESSION_HANDLE session; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + testcase_rw_session(); + testcase_user_login(); + + GetSystemTime(&t1); + rc = do_SSL3_PreMasterKeyGen(session); + if (rc && !no_stop) + goto testcase_cleanup; + GetSystemTime(&t2); + process_time(t1, t2); + + GetSystemTime(&t1); + rc = do_SSL3_MasterKeyDerive(session); + if (rc && !no_stop) + goto testcase_cleanup; + GetSystemTime(&t2); + process_time(t1, t2); + + GetSystemTime(&t1); + rc = do_SSL3_MultipleKeysDerive(session); + if (rc && !no_stop) + goto testcase_cleanup; + GetSystemTime(&t2); + process_time(t1, t2); + + GetSystemTime(&t1); + rc = do_SignVerify_SSL3_SHA1_MAC(session); + if (rc && !no_stop) + goto testcase_cleanup; + GetSystemTime(&t2); + process_time(t1, t2); + + GetSystemTime(&t1); + rc = do_SignVerify_SSL3_MD5_MAC(session); + if (rc && !no_stop) + return rc; + GetSystemTime(&t2); + process_time(t1, t2); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_error("C_CloseSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + int rc; + CK_RV rv; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: no_init: %d\n", no_init); + + rc = do_GetFunctionList(); + if (!rc) { + PRINT_ERR("ERROR do_GetFunctionList() Failed , rc = 0x%0x\n", rc); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + // SAB Add calls to ALL functions before the C_Initialize gets hit + + funcs->C_Initialize(&cinit_args); + + { + CK_SESSION_HANDLE hsess = 0; + + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + } + + testcase_setup(0); + + rv = ssl3_functions(); + + testcase_print_result(); + + funcs->C_Finalize(NULL); + + /* make sure we return non-zero if rv is non-zero */ + return ((rv == 0) || (rv % 256) ? (int)rv : -1); +} diff --git a/testcases/include/include.mk b/testcases/include/include.mk new file mode 100644 index 0000000..5ab1fce --- /dev/null +++ b/testcases/include/include.mk @@ -0,0 +1,3 @@ +noinst_HEADERS += \ + testcases/include/mech_to_str.h testcases/include/regress.h \ + testcases/include/rsadump.h testcases/include/windows.h diff --git a/testcases/include/mech_to_str.h b/testcases/include/mech_to_str.h new file mode 100644 index 0000000..2105ee8 --- /dev/null +++ b/testcases/include/mech_to_str.h @@ -0,0 +1,500 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2013-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 + */ + +#ifndef _MECH_TO_STR_ +#define _MECH_TO_STR_ +#include "pkcs11types.h" + +/* + * List generate with: + * + * grep CKM_ ../../usr/include/pkcs11/pkcs11types.h | + * awk '/^#/ { printf("\tif (mech == %s)\n\t\treturn \"%s\";\n", $2, $2); }' + * + */ +static inline const char *mech_to_str(CK_ULONG mech) +{ + if (mech == CKM_RSA_PKCS_KEY_PAIR_GEN) + return "CKM_RSA_PKCS_KEY_PAIR_GEN"; + if (mech == CKM_RSA_PKCS) + return "CKM_RSA_PKCS"; + if (mech == CKM_RSA_9796) + return "CKM_RSA_9796"; + if (mech == CKM_RSA_X_509) + return "CKM_RSA_X_509"; + if (mech == CKM_MD2_RSA_PKCS) + return "CKM_MD2_RSA_PKCS"; + if (mech == CKM_MD5_RSA_PKCS) + return "CKM_MD5_RSA_PKCS"; + if (mech == CKM_SHA1_RSA_PKCS) + return "CKM_SHA1_RSA_PKCS"; + if (mech == CKM_RIPEMD128_RSA_PKCS) + return "CKM_RIPEMD128_RSA_PKCS"; + if (mech == CKM_RIPEMD160_RSA_PKCS) + return "CKM_RIPEMD160_RSA_PKCS"; + if (mech == CKM_RSA_PKCS_OAEP) + return "CKM_RSA_PKCS_OAEP"; + if (mech == CKM_RSA_X9_31_KEY_PAIR_GEN) + return "CKM_RSA_X9_31_KEY_PAIR_GEN"; + if (mech == CKM_RSA_X9_31) + return "CKM_RSA_X9_31"; + if (mech == CKM_SHA1_RSA_X9_31) + return "CKM_SHA1_RSA_X9_31"; + if (mech == CKM_RSA_PKCS_PSS) + return "CKM_RSA_PKCS_PSS"; + if (mech == CKM_SHA1_RSA_PKCS_PSS) + return "CKM_SHA1_RSA_PKCS_PSS"; + if (mech == CKM_DSA_KEY_PAIR_GEN) + return "CKM_DSA_KEY_PAIR_GEN"; + if (mech == CKM_DSA) + return "CKM_DSA"; + if (mech == CKM_DSA_SHA1) + return "CKM_DSA_SHA1"; + if (mech == CKM_DH_PKCS_KEY_PAIR_GEN) + return "CKM_DH_PKCS_KEY_PAIR_GEN"; + if (mech == CKM_DH_PKCS_DERIVE) + return "CKM_DH_PKCS_DERIVE"; + if (mech == CKM_X9_42_DH_KEY_PAIR_GEN) + return "CKM_X9_42_DH_KEY_PAIR_GEN"; + if (mech == CKM_X9_42_DH_DERIVE) + return "CKM_X9_42_DH_DERIVE"; + if (mech == CKM_X9_42_DH_HYBRID_DERIVE) + return "CKM_X9_42_DH_HYBRID_DERIVE"; + if (mech == CKM_X9_42_MQV_DERIVE) + return "CKM_X9_42_MQV_DERIVE"; + if (mech == CKM_SHA224_RSA_PKCS) + return "CKM_SHA224_RSA_PKCS"; + if (mech == CKM_SHA256_RSA_PKCS) + return "CKM_SHA256_RSA_PKCS"; + if (mech == CKM_SHA384_RSA_PKCS) + return "CKM_SHA384_RSA_PKCS"; + if (mech == CKM_SHA512_RSA_PKCS) + return "CKM_SHA512_RSA_PKCS"; + if (mech == CKM_RC2_KEY_GEN) + return "CKM_RC2_KEY_GEN"; + if (mech == CKM_RC2_ECB) + return "CKM_RC2_ECB"; + if (mech == CKM_RC2_CBC) + return "CKM_RC2_CBC"; + if (mech == CKM_RC2_MAC) + return "CKM_RC2_MAC"; + if (mech == CKM_RC2_MAC_GENERAL) + return "CKM_RC2_MAC_GENERAL"; + if (mech == CKM_RC2_CBC_PAD) + return "CKM_RC2_CBC_PAD"; + if (mech == CKM_RC4_KEY_GEN) + return "CKM_RC4_KEY_GEN"; + if (mech == CKM_RC4) + return "CKM_RC4"; + if (mech == CKM_DES_KEY_GEN) + return "CKM_DES_KEY_GEN"; + if (mech == CKM_DES_ECB) + return "CKM_DES_ECB"; + if (mech == CKM_DES_CBC) + return "CKM_DES_CBC"; + if (mech == CKM_DES_MAC) + return "CKM_DES_MAC"; + if (mech == CKM_DES_MAC_GENERAL) + return "CKM_DES_MAC_GENERAL"; + if (mech == CKM_DES_CBC_PAD) + return "CKM_DES_CBC_PAD"; + if (mech == CKM_DES_OFB64) + return "CKM_DES_OFB64"; + if (mech == CKM_DES_CFB64) + return "CKM_DES_CFB64"; + if (mech == CKM_DES_CFB8) + return "CKM_DES_CFB8"; + if (mech == CKM_DES2_KEY_GEN) + return "CKM_DES2_KEY_GEN"; + if (mech == CKM_DES3_KEY_GEN) + return "CKM_DES3_KEY_GEN"; + if (mech == CKM_DES3_ECB) + return "CKM_DES3_ECB"; + if (mech == CKM_DES3_CBC) + return "CKM_DES3_CBC"; + if (mech == CKM_DES3_MAC) + return "CKM_DES3_MAC"; + if (mech == CKM_DES3_MAC_GENERAL) + return "CKM_DES3_MAC_GENERAL"; + if (mech == CKM_DES3_CBC_PAD) + return "CKM_DES3_CBC_PAD"; + if (mech == CKM_DES3_CMAC_GENERAL) + return "CKM_DES3_CMAC_GENERAL"; + if (mech == CKM_DES3_CMAC) + return "CKM_DES3_CMAC"; + if (mech == CKM_CDMF_KEY_GEN) + return "CKM_CDMF_KEY_GEN"; + if (mech == CKM_CDMF_ECB) + return "CKM_CDMF_ECB"; + if (mech == CKM_CDMF_CBC) + return "CKM_CDMF_CBC"; + if (mech == CKM_CDMF_MAC) + return "CKM_CDMF_MAC"; + if (mech == CKM_CDMF_MAC_GENERAL) + return "CKM_CDMF_MAC_GENERAL"; + if (mech == CKM_CDMF_CBC_PAD) + return "CKM_CDMF_CBC_PAD"; + if (mech == CKM_MD2) + return "CKM_MD2"; + if (mech == CKM_MD2_HMAC) + return "CKM_MD2_HMAC"; + if (mech == CKM_MD2_HMAC_GENERAL) + return "CKM_MD2_HMAC_GENERAL"; + if (mech == CKM_MD5) + return "CKM_MD5"; + if (mech == CKM_MD5_HMAC) + return "CKM_MD5_HMAC"; + if (mech == CKM_MD5_HMAC_GENERAL) + return "CKM_MD5_HMAC_GENERAL"; + if (mech == CKM_SHA_1) + return "CKM_SHA_1"; + if (mech == CKM_SHA_1_HMAC) + return "CKM_SHA_1_HMAC"; + if (mech == CKM_SHA_1_HMAC_GENERAL) + return "CKM_SHA_1_HMAC_GENERAL"; + if (mech == CKM_RIPEMD128) + return "CKM_RIPEMD128"; + if (mech == CKM_RIPEMD128_HMAC) + return "CKM_RIPEMD128_HMAC"; + if (mech == CKM_RIPEMD128_HMAC_GENERAL) + return "CKM_RIPEMD128_HMAC_GENERAL"; + if (mech == CKM_RIPEMD160) + return "CKM_RIPEMD160"; + if (mech == CKM_RIPEMD160_HMAC) + return "CKM_RIPEMD160_HMAC"; + if (mech == CKM_RIPEMD160_HMAC_GENERAL) + return "CKM_RIPEMD160_HMAC_GENERAL"; + if (mech == CKM_SHA224) + return "CKM_SHA224"; + if (mech == CKM_SHA224_HMAC) + return "CKM_SHA224_HMAC"; + if (mech == CKM_SHA224_HMAC_GENERAL) + return "CKM_SHA224_HMAC_GENERAL"; + if (mech == CKM_SHA256) + return "CKM_SHA256"; + if (mech == CKM_SHA256_HMAC) + return "CKM_SHA256_HMAC"; + if (mech == CKM_SHA256_HMAC_GENERAL) + return "CKM_SHA256_HMAC_GENERAL"; + if (mech == CKM_SHA384) + return "CKM_SHA384"; + if (mech == CKM_SHA384_HMAC) + return "CKM_SHA384_HMAC"; + if (mech == CKM_SHA384_HMAC_GENERAL) + return "CKM_SHA384_HMAC_GENERAL"; + if (mech == CKM_SHA512) + return "CKM_SHA512"; + if (mech == CKM_SHA512_HMAC) + return "CKM_SHA512_HMAC"; + if (mech == CKM_SHA512_HMAC_GENERAL) + return "CKM_SHA512_HMAC_GENERAL"; + if (mech == CKM_SHA512_224) + return "CKM_SHA512_224"; + if (mech == CKM_SHA512_224_HMAC) + return "CKM_SHA512_224_HMAC"; + if (mech == CKM_SHA512_224_HMAC_GENERAL) + return "CKM_SHA512_224_HMAC_GENERAL"; + if (mech == CKM_SHA512_256) + return "CKM_SHA512_256"; + if (mech == CKM_SHA512_256_HMAC) + return "CKM_SHA512_256_HMAC"; + if (mech == CKM_SHA512_256_HMAC_GENERAL) + return "CKM_SHA512_256_HMAC_GENERAL"; + if (mech == CKM_CAST_KEY_GEN) + return "CKM_CAST_KEY_GEN"; + if (mech == CKM_CAST_ECB) + return "CKM_CAST_ECB"; + if (mech == CKM_CAST_CBC) + return "CKM_CAST_CBC"; + if (mech == CKM_CAST_MAC) + return "CKM_CAST_MAC"; + if (mech == CKM_CAST_MAC_GENERAL) + return "CKM_CAST_MAC_GENERAL"; + if (mech == CKM_CAST_CBC_PAD) + return "CKM_CAST_CBC_PAD"; + if (mech == CKM_CAST3_KEY_GEN) + return "CKM_CAST3_KEY_GEN"; + if (mech == CKM_CAST3_ECB) + return "CKM_CAST3_ECB"; + if (mech == CKM_CAST3_CBC) + return "CKM_CAST3_CBC"; + if (mech == CKM_CAST3_MAC) + return "CKM_CAST3_MAC"; + if (mech == CKM_CAST3_MAC_GENERAL) + return "CKM_CAST3_MAC_GENERAL"; + if (mech == CKM_CAST3_CBC_PAD) + return "CKM_CAST3_CBC_PAD"; + if (mech == CKM_CAST5_KEY_GEN) + return "CKM_CAST5_KEY_GEN"; + if (mech == CKM_CAST128_KEY_GEN) + return "CKM_CAST128_KEY_GEN"; + if (mech == CKM_CAST5_ECB) + return "CKM_CAST5_ECB"; + if (mech == CKM_CAST128_ECB) + return "CKM_CAST128_ECB"; + if (mech == CKM_CAST5_CBC) + return "CKM_CAST5_CBC"; + if (mech == CKM_CAST128_CBC) + return "CKM_CAST128_CBC"; + if (mech == CKM_CAST5_MAC) + return "CKM_CAST5_MAC"; + if (mech == CKM_CAST128_MAC) + return "CKM_CAST128_MAC"; + if (mech == CKM_CAST5_MAC_GENERAL) + return "CKM_CAST5_MAC_GENERAL"; + if (mech == CKM_CAST128_MAC_GENERAL) + return "CKM_CAST128_MAC_GENERAL"; + if (mech == CKM_CAST5_CBC_PAD) + return "CKM_CAST5_CBC_PAD"; + if (mech == CKM_CAST128_CBC_PAD) + return "CKM_CAST128_CBC_PAD"; + if (mech == CKM_RC5_KEY_GEN) + return "CKM_RC5_KEY_GEN"; + if (mech == CKM_RC5_ECB) + return "CKM_RC5_ECB"; + if (mech == CKM_RC5_CBC) + return "CKM_RC5_CBC"; + if (mech == CKM_RC5_MAC) + return "CKM_RC5_MAC"; + if (mech == CKM_RC5_MAC_GENERAL) + return "CKM_RC5_MAC_GENERAL"; + if (mech == CKM_RC5_CBC_PAD) + return "CKM_RC5_CBC_PAD"; + if (mech == CKM_IDEA_KEY_GEN) + return "CKM_IDEA_KEY_GEN"; + if (mech == CKM_IDEA_ECB) + return "CKM_IDEA_ECB"; + if (mech == CKM_IDEA_CBC) + return "CKM_IDEA_CBC"; + if (mech == CKM_IDEA_MAC) + return "CKM_IDEA_MAC"; + if (mech == CKM_IDEA_MAC_GENERAL) + return "CKM_IDEA_MAC_GENERAL"; + if (mech == CKM_IDEA_CBC_PAD) + return "CKM_IDEA_CBC_PAD"; + if (mech == CKM_GENERIC_SECRET_KEY_GEN) + return "CKM_GENERIC_SECRET_KEY_GEN"; + if (mech == CKM_CONCATENATE_BASE_AND_KEY) + return "CKM_CONCATENATE_BASE_AND_KEY"; + if (mech == CKM_CONCATENATE_BASE_AND_DATA) + return "CKM_CONCATENATE_BASE_AND_DATA"; + if (mech == CKM_CONCATENATE_DATA_AND_BASE) + return "CKM_CONCATENATE_DATA_AND_BASE"; + if (mech == CKM_XOR_BASE_AND_DATA) + return "CKM_XOR_BASE_AND_DATA"; + if (mech == CKM_EXTRACT_KEY_FROM_KEY) + return "CKM_EXTRACT_KEY_FROM_KEY"; + if (mech == CKM_SSL3_PRE_MASTER_KEY_GEN) + return "CKM_SSL3_PRE_MASTER_KEY_GEN"; + if (mech == CKM_SSL3_MASTER_KEY_DERIVE) + return "CKM_SSL3_MASTER_KEY_DERIVE"; + if (mech == CKM_SSL3_KEY_AND_MAC_DERIVE) + return "CKM_SSL3_KEY_AND_MAC_DERIVE"; + if (mech == CKM_SSL3_MASTER_KEY_DERIVE_DH) + return "CKM_SSL3_MASTER_KEY_DERIVE_DH"; + if (mech == CKM_TLS_PRE_MASTER_KEY_GEN) + return "CKM_TLS_PRE_MASTER_KEY_GEN"; + if (mech == CKM_TLS_MASTER_KEY_DERIVE) + return "CKM_TLS_MASTER_KEY_DERIVE"; + if (mech == CKM_TLS_KEY_AND_MAC_DERIVE) + return "CKM_TLS_KEY_AND_MAC_DERIVE"; + if (mech == CKM_TLS_MASTER_KEY_DERIVE_DH) + return "CKM_TLS_MASTER_KEY_DERIVE_DH"; + if (mech == CKM_SSL3_MD5_MAC) + return "CKM_SSL3_MD5_MAC"; + if (mech == CKM_SSL3_SHA1_MAC) + return "CKM_SSL3_SHA1_MAC"; + if (mech == CKM_MD5_KEY_DERIVATION) + return "CKM_MD5_KEY_DERIVATION"; + if (mech == CKM_MD2_KEY_DERIVATION) + return "CKM_MD2_KEY_DERIVATION"; + if (mech == CKM_SHA1_KEY_DERIVATION) + return "CKM_SHA1_KEY_DERIVATION"; + if (mech == CKM_SHA224_KEY_DERIVATION) + return "CKM_SHA224_KEY_DERIVATION"; + if (mech == CKM_SHA256_KEY_DERIVATION) + return "CKM_SHA256_KEY_DERIVATION"; + if (mech == CKM_SHA384_KEY_DERIVATION) + return "CKM_SHA384_KEY_DERIVATION"; + if (mech == CKM_SHA512_KEY_DERIVATION) + return "CKM_SHA512_KEY_DERIVATION"; + if (mech == CKM_PBE_MD2_DES_CBC) + return "CKM_PBE_MD2_DES_CBC"; + if (mech == CKM_PBE_MD5_DES_CBC) + return "CKM_PBE_MD5_DES_CBC"; + if (mech == CKM_PBE_MD5_CAST_CBC) + return "CKM_PBE_MD5_CAST_CBC"; + if (mech == CKM_PBE_MD5_CAST3_CBC) + return "CKM_PBE_MD5_CAST3_CBC"; + if (mech == CKM_PBE_MD5_CAST5_CBC) + return "CKM_PBE_MD5_CAST5_CBC"; + if (mech == CKM_PBE_MD5_CAST128_CBC) + return "CKM_PBE_MD5_CAST128_CBC"; + if (mech == CKM_PBE_SHA1_CAST5_CBC) + return "CKM_PBE_SHA1_CAST5_CBC"; + if (mech == CKM_PBE_SHA1_CAST128_CBC) + return "CKM_PBE_SHA1_CAST128_CBC"; + if (mech == CKM_PBE_SHA1_RC4_128) + return "CKM_PBE_SHA1_RC4_128"; + if (mech == CKM_PBE_SHA1_RC4_40) + return "CKM_PBE_SHA1_RC4_40"; + if (mech == CKM_PBE_SHA1_DES3_EDE_CBC) + return "CKM_PBE_SHA1_DES3_EDE_CBC"; + if (mech == CKM_PBE_SHA1_DES2_EDE_CBC) + return "CKM_PBE_SHA1_DES2_EDE_CBC"; + if (mech == CKM_PBE_SHA1_RC2_128_CBC) + return "CKM_PBE_SHA1_RC2_128_CBC"; + if (mech == CKM_PBE_SHA1_RC2_40_CBC) + return "CKM_PBE_SHA1_RC2_40_CBC"; + if (mech == CKM_PKCS5_PBKD2) + return "CKM_PKCS5_PBKD2"; + if (mech == CKM_PBA_SHA1_WITH_SHA1_HMAC) + return "CKM_PBA_SHA1_WITH_SHA1_HMAC"; + if (mech == CKM_KEY_WRAP_LYNKS) + return "CKM_KEY_WRAP_LYNKS"; + if (mech == CKM_KEY_WRAP_SET_OAEP) + return "CKM_KEY_WRAP_SET_OAEP"; + if (mech == CKM_SKIPJACK_KEY_GEN) + return "CKM_SKIPJACK_KEY_GEN"; + if (mech == CKM_SKIPJACK_ECB64) + return "CKM_SKIPJACK_ECB64"; + if (mech == CKM_SKIPJACK_CBC64) + return "CKM_SKIPJACK_CBC64"; + if (mech == CKM_SKIPJACK_OFB64) + return "CKM_SKIPJACK_OFB64"; + if (mech == CKM_SKIPJACK_CFB64) + return "CKM_SKIPJACK_CFB64"; + if (mech == CKM_SKIPJACK_CFB32) + return "CKM_SKIPJACK_CFB32"; + if (mech == CKM_SKIPJACK_CFB16) + return "CKM_SKIPJACK_CFB16"; + if (mech == CKM_SKIPJACK_CFB8) + return "CKM_SKIPJACK_CFB8"; + if (mech == CKM_SKIPJACK_WRAP) + return "CKM_SKIPJACK_WRAP"; + if (mech == CKM_SKIPJACK_PRIVATE_WRAP) + return "CKM_SKIPJACK_PRIVATE_WRAP"; + if (mech == CKM_SKIPJACK_RELAYX) + return "CKM_SKIPJACK_RELAYX"; + if (mech == CKM_KEA_KEY_PAIR_GEN) + return "CKM_KEA_KEY_PAIR_GEN"; + if (mech == CKM_KEA_KEY_DERIVE) + return "CKM_KEA_KEY_DERIVE"; + if (mech == CKM_FORTEZZA_TIMESTAMP) + return "CKM_FORTEZZA_TIMESTAMP"; + if (mech == CKM_BATON_KEY_GEN) + return "CKM_BATON_KEY_GEN"; + if (mech == CKM_BATON_ECB128) + return "CKM_BATON_ECB128"; + if (mech == CKM_BATON_ECB96) + return "CKM_BATON_ECB96"; + if (mech == CKM_BATON_CBC128) + return "CKM_BATON_CBC128"; + if (mech == CKM_BATON_COUNTER) + return "CKM_BATON_COUNTER"; + if (mech == CKM_BATON_SHUFFLE) + return "CKM_BATON_SHUFFLE"; + if (mech == CKM_BATON_WRAP) + return "CKM_BATON_WRAP"; + if (mech == CKM_ECDSA_KEY_PAIR_GEN) + return "CKM_ECDSA_KEY_PAIR_GEN"; + if (mech == CKM_EC_KEY_PAIR_GEN) + return "CKM_EC_KEY_PAIR_GEN"; + if (mech == CKM_ECDSA) + return "CKM_ECDSA"; + if (mech == CKM_ECDSA_SHA1) + return "CKM_ECDSA_SHA1"; + if (mech == CKM_ECDSA_SHA224) + return "CKM_ECDSA_SHA224"; + if (mech == CKM_ECDSA_SHA256) + return "CKM_ECDSA_SHA256"; + if (mech == CKM_ECDSA_SHA384) + return "CKM_ECDSA_SHA384"; + if (mech == CKM_ECDSA_SHA512) + return "CKM_ECDSA_SHA512"; + if (mech == CKM_ECDH1_DERIVE) + return "CKM_ECDH1_DERIVE"; + if (mech == CKM_ECDH1_COFACTOR_DERIVE) + return "CKM_ECDH1_COFACTOR_DERIVE"; + if (mech == CKM_ECMQV_DERIVE) + return "CKM_ECMQV_DERIVE"; + if (mech == CKM_JUNIPER_KEY_GEN) + return "CKM_JUNIPER_KEY_GEN"; + if (mech == CKM_JUNIPER_ECB128) + return "CKM_JUNIPER_ECB128"; + if (mech == CKM_JUNIPER_CBC128) + return "CKM_JUNIPER_CBC128"; + if (mech == CKM_JUNIPER_COUNTER) + return "CKM_JUNIPER_COUNTER"; + if (mech == CKM_JUNIPER_SHUFFLE) + return "CKM_JUNIPER_SHUFFLE"; + if (mech == CKM_JUNIPER_WRAP) + return "CKM_JUNIPER_WRAP"; + if (mech == CKM_FASTHASH) + return "CKM_FASTHASH"; + if (mech == CKM_AES_KEY_GEN) + return "CKM_AES_KEY_GEN"; + if (mech == CKM_AES_ECB) + return "CKM_AES_ECB"; + if (mech == CKM_AES_CBC) + return "CKM_AES_CBC"; + if (mech == CKM_AES_MAC) + return "CKM_AES_MAC"; + if (mech == CKM_AES_MAC_GENERAL) + return "CKM_AES_MAC_GENERAL"; + if (mech == CKM_AES_CBC_PAD) + return "CKM_AES_CBC_PAD"; + if (mech == CKM_AES_CTR) + return "CKM_AES_CTR"; + if (mech == CKM_AES_GCM) + return "CKM_AES_GCM"; + if (mech == CKM_AES_OFB) + return "CKM_AES_OFB"; + if (mech == CKM_AES_CFB128) + return "CKM_AES_CFB128"; + if (mech == CKM_AES_CFB64) + return "CKM_AES_CFB64"; + if (mech == CKM_AES_CFB8) + return "CKM_AES_CFB8"; + if (mech == CKM_AES_CMAC_GENERAL) + return "CKM_AES_CMAC_GENERAL"; + if (mech == CKM_AES_CMAC) + return "CKM_AES_CMAC"; + if (mech == CKM_DSA_PARAMETER_GEN) + return "CKM_DSA_PARAMETER_GEN"; + if (mech == CKM_DH_PKCS_PARAMETER_GEN) + return "CKM_DH_PKCS_PARAMETER_GEN"; + if (mech == CKM_X9_42_DH_PARAMETER_GEN) + return "CKM_X9_42_DH_PARAMETER_GEN"; + if (mech == CKM_VENDOR_DEFINED) + return "CKM_VENDOR_DEFINED"; + if (mech == CKM_IBM_SHA3_224) + return "CKM_IBM_SHA3_224"; + if (mech == CKM_IBM_SHA3_256) + return "CKM_IBM_SHA3_256"; + if (mech == CKM_IBM_SHA3_384) + return "CKM_IBM_SHA3_384"; + if (mech == CKM_IBM_SHA3_512) + return "CKM_IBM_SHA3_512"; + if (mech == CKM_IBM_SHA3_224_HMAC) + return "CKM_IBM_SHA3_224_HMAC"; + if (mech == CKM_IBM_SHA3_256_HMAC) + return "CKM_IBM_SHA3_256_HMAC"; + if (mech == CKM_IBM_SHA3_384_HMAC) + return "CKM_IBM_SHA3_384_HMAC"; + if (mech == CKM_IBM_SHA3_512_HMAC) + return "CKM_IBM_SHA3_512_HMAC"; + if (mech == CKM_IBM_CMAC) + return "CKM_IBM_CMAC"; + + return "(unknown mech)"; +} + +#endif diff --git a/testcases/include/regress.h b/testcases/include/regress.h new file mode 100644 index 0000000..8c7c536 --- /dev/null +++ b/testcases/include/regress.h @@ -0,0 +1,323 @@ +/* + * 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 + */ + +#ifndef _REGRESS_H +#define _REGRESS_H + +#if !defined(TRUE) +#define TRUE 1 +#endif + +#if !defined(FALSE) +#define FALSE 0 +#endif + +#define DES_BLOCK_SIZE 8 +#define DES_KEY_LEN 8 + +#define SHA1_HASH_LEN 20 +#define MD2_HASH_LEN 16 +#define MD5_HASH_LEN 16 + +#define BIG_REQUEST 4096 + +#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) + +#include +#define SYSTEMTIME struct timeb +#define GetSystemTime(x) ftime((x)) + +#include + +#pragma GCC system_header +static struct timeval timev1; +static struct timeval timev2; +static struct timeval timev3; +static struct timeval timev4; +static struct timeval timevr; + +#ifndef timersub +/* We just need timersub, so instead of requiring _BSD_SOURCE, * + * define it just like glibc does */ +#define timersub(t1, t2, tr) \ + do { \ + (tr)->tv_sec = (t1)->tv_sec - (t2)->tv_sec; \ + (tr)->tv_usec = (t1)->tv_usec - (t2)->tv_usec; \ + if ((tr)->tv_usec < 0) { \ + --(tr)->tv_sec; \ + (tr)->tv_usec += 1000000; \ + } \ + } while (0) +#endif + +#include "p11util.h" + +extern CK_ULONG t_total; // total test assertions +extern CK_ULONG t_ran; // number of assertions ran +extern CK_ULONG t_passed; // number of assertions passed +extern CK_ULONG t_failed; // number of assertions failed +extern CK_ULONG t_skipped; // number of assertions skipped +extern CK_ULONG t_errors; // number of errors + +void process_time(SYSTEMTIME t1, SYSTEMTIME t2); +void show_error(char *str, CK_RV rc); +void print_hex(CK_BYTE * buf, CK_ULONG len); + +int do_GetFunctionList(void); + +void init_coprocessor(void); + +CK_RV C_GetFunctionList(CK_FUNCTION_LIST **); +CK_RV DummyFunction(CK_SLOT_ID id); + +int digest_functions(void); + +extern CK_FUNCTION_LIST *funcs; +extern CK_SLOT_ID SLOT_ID; + +void usage(char *fct); +int do_ParseArgs(int argc, char **argv); + +// these values are required when generating a PKCS DSA value. they were +// obtained by generating a DSA key pair on the 4758 with the default (random) +// values. these values are in big-endian format +// +extern CK_BYTE DSA_PUBL_PRIME[128]; +extern CK_BYTE DSA_PUBL_SUBPRIME[20]; +extern CK_BYTE DSA_PUBL_BASE[128]; + +extern CK_BBOOL skip_token_obj; +extern CK_BBOOL no_stop; +extern CK_BBOOL no_init; +extern CK_BBOOL securekey; + +int get_so_pin(CK_BYTE_PTR); +int get_user_pin(CK_BYTE_PTR); + +#define PKCS11_MAX_PIN_LEN 128 +#define PKCS11_SO_PIN_ENV_VAR "PKCS11_SO_PIN" +#define PKCS11_USER_PIN_ENV_VAR "PKCS11_USER_PIN" + +#define PRINT_ERR(fmt, ...) \ + fprintf(stderr, "%s:%d " fmt "\n", __FILE__, __LINE__, ## __VA_ARGS__) +#define PRINT(fmt, ...) \ + printf("%s:%d " fmt "\n", __FILE__, __LINE__, ## __VA_ARGS__) + + +/* show_error(char *_str, unsigned long _rc); */ +#define show_error(_str, _rc) \ + fprintf(stderr, "%s:%d: %s returned %lu (0x%lx) %s\n", \ + __FILE__, __LINE__, _str, _rc, _rc, \ + p11_get_ckr(_rc)) + +#define testcase_setup(total) \ + do { \ + t_total = 0; \ + t_errors = 0; \ + gettimeofday(&timev3, NULL); \ + } while (0) + +#define testsuite_begin(_fmt, ...) \ + do { \ + printf("------\n* TESTSUITE %s BEGIN " _fmt "\n", \ + __func__, ## __VA_ARGS__); \ + } while (0) + +#define testcase_begin(_fmt, ...) \ + do { \ + printf("------\n* TESTCASE %s BEGIN " _fmt "\n", \ + __func__, ## __VA_ARGS__); \ + gettimeofday(&timev1, NULL); \ + } while (0) + +#define testcase_begin_f(_func, _fmt, ...) \ + do { \ + printf("------\n* TESTCASE %s BEGIN " _fmt "\n", \ + _func, ## __VA_ARGS__); \ + gettimeofday(&timev1, NULL); \ + } while (0) + +#define testcase_new_assertion() \ + t_ran++; + +#define testcase_pass(_fmt, ...) \ + do { \ + gettimeofday(&timev2, NULL); \ + timersub(&timev2, &timev1, &timevr); \ + printf("* TESTCASE %s PASS (elapsed time %lds %ldus) " _fmt "\n\n", \ + __func__, timevr.tv_sec, timevr.tv_usec, ## __VA_ARGS__); \ + t_passed++; \ + } while (0) + +#define testcase_pass_f(_func, _fmt, ...) \ + do { \ + gettimeofday(&timev2, NULL); \ + timersub(&timev2, &timev1, &timevr); \ + printf("* TESTCASE %s PASS (elapsed time %lds %ldus) " _fmt "\n\n", \ + _func, timevr.tv_sec, timevr.tv_usec, ## __VA_ARGS__); \ + t_passed++; \ + } while (0) + +#define testsuite_skip(_n,_fmt, ...) \ + do { \ + printf("* TESTSUITE %s SKIP " _fmt "\n\n", \ + __func__, ## __VA_ARGS__); \ + t_skipped+= _n; \ + } while (0) + +#define testcase_skip(_fmt, ...) \ + do { \ + printf("* TESTCASE %s SKIP " _fmt "\n\n", \ + __func__, ## __VA_ARGS__); \ + t_skipped++; \ + } while (0) + +#define testcase_skip_f(_func, _fmt, ...) \ + do { \ + printf("* TESTCASE %s SKIP " _fmt "\n\n", \ + _func, ## __VA_ARGS__); \ + t_skipped++; \ + } while (0) + +#define testcase_notice(_fmt, ...) \ + do { \ + printf("* TESTCASE %s NOTICE " _fmt "\n", \ + __func__, ## __VA_ARGS__); \ + } while (0) + +#define testcase_notice_f(_func, _fmt, ...) \ + do { \ + printf("* TESTCASE %s NOTICE " _fmt "\n", \ + __func, ## __VA_ARGS__); \ + } while (0) + +#define testcase_fail(_fmt, ...) \ + do { \ + printf("* TESTCASE %s FAIL (%s:%d) " _fmt "\n", \ + __func__, __FILE__, __LINE__, ## __VA_ARGS__); \ + t_failed++; \ + } while (0) + +#define testcase_fail_f(_func, _fmt, ...) \ + do { \ + printf("* TESTCASE %s FAIL (%s:%d) " _fmt "\n", \ + _func, __FILE__, __LINE__, ## __VA_ARGS__); \ + t_failed++; \ + } while (0) + +#define testcase_error(_fmt, ...) \ + do { \ + printf("* TESTCASE %s ERROR (%s:%d)) " _fmt "\n", \ + __func__, __FILE__, __LINE__, ## __VA_ARGS__); \ + t_errors++; \ + } while (0) + +#define testcase_error_f(_func, _fmt, ...) \ + do { \ + printf("* TESTCASE %s ERROR (%s:%d)) " _fmt "\n", \ + _func, __FILE__, __LINE__, ## __VA_ARGS__); \ + t_errors++; \ + } while (0) + +#define testcase_print_result() \ + do { \ + gettimeofday(&timev4, NULL); \ + timersub(&timev4, &timev3, &timevr); \ + printf("Total=%lu, Ran=%lu, Passed=%lu, Failed=%lu, " \ + "Skipped=%lu, Errors=%lu (total elapsed time " \ + "%lds %ldus)\n", \ + (t_ran + t_skipped), t_ran, t_passed, t_failed, \ + t_skipped, t_errors, timevr.tv_sec, \ + timevr.tv_usec); \ + } while (0) + +#define testcase_rw_session() \ + do { \ + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; \ + rc = funcs->C_OpenSession(SLOT_ID, flags, NULL, NULL, &session ); \ + if (rc != CKR_OK) { \ + testcase_error("C_OpenSession() rc = %s", p11_get_ckr(rc)); \ + session = CK_INVALID_HANDLE; \ + goto testcase_cleanup; \ + } \ + } while (0) + +#define testcase_ro_session() \ + do { \ + flags = CKF_SERIAL_SESSION; \ + rc = funcs->C_OpenSession(SLOT_ID, flags, NULL, NULL, &session ); \ + if (rc != CKR_OK) { \ + testcase_error("C_OpenSession() rc = %s", p11_get_ckr(rc)); \ + session = CK_INVALID_HANDLE; \ + goto testcase_cleanup; \ + } \ + } while (0) + +#define testcase_close_session() \ + do { \ + if (session != CK_INVALID_HANDLE) { \ + rc = funcs->C_CloseSession(session); \ + if (rc != CKR_OK) { \ + testcase_error("C_CloseSession() rc = %s", p11_get_ckr(rc));\ + } \ + } \ + } while (0) + +#define testcase_closeall_session() \ + do { \ + rc = funcs->C_CloseAllSessions(SLOT_ID); \ + if (rc != CKR_OK) { \ + testcase_error("C_CloseAllSessions() rc = %s", p11_get_ckr(rc));\ + } \ + } while (0) + + +#define testcase_user_login() \ + do { \ + if (get_user_pin(user_pin)) { \ + testcase_error("get_user_pin() failed"); \ + testcase_closeall_session(); \ + exit(-1); \ + } \ + user_pin_len = (CK_ULONG) strlen( (char *) user_pin); \ + rc = funcs->C_Login(session, CKU_USER, user_pin, user_pin_len); \ + if (rc != CKR_OK) { \ + testcase_error("C_Login() rc = %s", p11_get_ckr(rc)); \ + goto testcase_cleanup; \ + } \ + } while (0) + +#define testcase_user_logout() \ + do { \ + if (session != CK_INVALID_HANDLE) { \ + rc = funcs->C_Logout(session); \ + if (rc != CKR_OK) { \ + testcase_error("C_Logout() rc = %s", p11_get_ckr(rc)); \ + } \ + } \ + } while (0) + + +#define testcase_so_login() \ + do { \ + if (get_so_pin(so_pin)) { \ + testcase_error("get_so_pin() failed"); \ + rc = -1; \ + goto testcase_cleanup; \ + } \ + so_pin_len = (CK_ULONG) strlen( (char *) so_pin); \ + rc = funcs->C_Login(session, CKU_SO, so_pin, so_pin_len); \ + if (rc != CKR_OK) { \ + testcase_error("C_Login() rc = %s", p11_get_ckr(rc)); \ + goto testcase_cleanup; \ + } \ + } while (0) + +#endif diff --git a/testcases/include/rsadump.h b/testcases/include/rsadump.h new file mode 100644 index 0000000..46ea0d5 --- /dev/null +++ b/testcases/include/rsadump.h @@ -0,0 +1,871 @@ +/* + * 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 + */ + +unsigned char Ciphertext[] = { + 0x3b, 0xad, 0xa7, 0x32, 0x7b, 0x79, 0x7e, 0x9a, + 0x29, 0x75, 0xcb, 0x20, 0x43, 0xe9, 0x29, 0x19, + 0xfe, 0xe6, 0xb6, 0xc5, 0xba, 0xab, 0x62, 0xd1, + 0x6a, 0xd4, 0xc5, 0xf5, 0x61, 0x8c, 0x87, 0xe9, + 0xc6, 0x99, 0xf7, 0xf6, 0x76, 0x38, 0x9d, 0xdd, + 0x44, 0xd, 0x46, 0xc4, 0x36, 0x55, 0x66, 0xb6, + 0x2, 0x65, 0xf2, 0xae, 0xb4, 0x9d, 0xe0, 0x83, + 0x91, 0x55, 0x26, 0xf5, 0x5d, 0x16, 0x95, 0x6b, + 0x68, 0x94, 0x64, 0x9c, 0x56, 0x38, 0x8b, 0xca, + 0x9e, 0xfe, 0x10, 0x95, 0x77, 0xed, 0x89, 0x2d, + 0xf, 0x58, 0x98, 0x75, 0xc2, 0xe0, 0xa0, 0xf3, + 0xbc, 0x1f, 0xfe, 0xf8, 0x30, 0xe7, 0xd4, 0xcb, + 0xea, 0x29, 0x5b, 0xbd, 0x50, 0xf2, 0xdf, 0xa6, + 0x83, 0xd6, 0x9a, 0x18, 0x8f, 0xba, 0x1, 0x8e, + 0xa0, 0xe1, 0xe8, 0x4e, 0x12, 0xfc, 0x7a, 0xb3, + 0xe6, 0x1c, 0xb9, 0x92, 0x37, 0x4a, 0x36, 0x15 +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0xae, 0x42, 0xf8, 0x65, 0xdb, 0xd, 0xf7, 0x57, + 0x4a, 0x6e, 0xfa, 0x5d, 0x4, 0xe2, 0xcb, 0x55, + 0x34, 0x29, 0x7e, 0x6e, 0x16, 0x8a, 0x77, 0xba, + 0x4a, 0xdf, 0x2c, 0x8, 0x80, 0x68, 0x4e, 0xf6, + 0xd2, 0xa4, 0x7d, 0x51, 0xd6, 0x53, 0x56, 0x17, + 0x99, 0xa7, 0x3b, 0x41, 0x60, 0xe4, 0xa2, 0xac, + 0x78, 0x6a, 0xf5, 0x9b, 0x45, 0x10, 0x1d, 0x81, + 0x57, 0xf0, 0x29, 0x52, 0x7d, 0x50, 0x61, 0xb7, + 0x9c, 0x2b, 0x7a, 0x92, 0x34, 0x54, 0x93, 0x13, + 0xfe, 0x38, 0x4a, 0x9a, 0x3, 0xdf, 0xa, 0xcd, + 0x3b, 0x89, 0x2a, 0x29, 0x12, 0xdc, 0xbe, 0xb3, + 0x30, 0x59, 0x89, 0xfc, 0x4f, 0x90, 0xe2, 0x73, + 0x1b, 0x27, 0xc5, 0xe1, 0x80, 0xd0, 0x2d, 0x15, + 0xbe, 0xbf, 0x5d, 0x64, 0xb3, 0x16, 0x3c, 0xc4, + 0xa6, 0x95, 0x1e, 0xee, 0x89, 0xb3, 0x98, 0xf0, + 0x72, 0xe2, 0xb9, 0x3e, 0xe4, 0xe4, 0x33, 0x8 +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0x3b, 0xea, 0x52, 0xf3, 0x17, 0xf7, 0x58, 0x43, + 0xf1, 0xa3, 0xce, 0x9b, 0xee, 0xaf, 0x3e, 0xa6, + 0x16, 0x6c, 0x2f, 0x24, 0xd2, 0xe, 0xe7, 0xb3, + 0x70, 0x16, 0xfa, 0xd4, 0xfe, 0xb8, 0xa, 0x36, + 0xb9, 0x1d, 0x38, 0x4d, 0xbe, 0xa1, 0x36, 0x4f, + 0x88, 0xf1, 0xfe, 0xc4, 0x67, 0x93, 0x6e, 0xb, + 0x28, 0xa5, 0x83, 0xbb, 0x11, 0x53, 0x4, 0xa3, + 0x7e, 0x4, 0xe, 0xe8, 0x65, 0x2d, 0x31, 0x80, + 0xd6, 0xf0, 0xdd, 0x6b, 0xdb, 0x99, 0x5c, 0x8c, + 0x7d, 0x5e, 0x7e, 0x37, 0xea, 0xaf, 0xb4, 0x39, + 0xd0, 0x7b, 0xa, 0x70, 0x8c, 0x1b, 0xae, 0x81, + 0xbf, 0x57, 0xcc, 0x29, 0x97, 0x98, 0x6, 0xf7, + 0xce, 0x82, 0x6e, 0x70, 0xa7, 0x7b, 0x2e, 0xa, + 0x1, 0x98, 0xb5, 0xf0, 0xa9, 0x85, 0x8c, 0xcb, + 0xcb, 0xed, 0xd6, 0x9b, 0x4e, 0x5f, 0x3, 0xd, + 0x49, 0xe9, 0x91, 0x10, 0xb6, 0x39, 0x7d, 0x2e +}; + +unsigned char decrypted[] = { + 0xc9, 0x9f, + 0x36, 0x76, 0x31, 0x62, 0xc3, 0xbb, 0xcc, 0x30, + 0xa1, 0xa3, 0x9e, 0x40, 0xc, 0x76, 0x48, 0x8, + 0x20, 0x5b, 0xa9, 0xe1, 0xed, 0x6d, 0xa8, 0xec, + 0xd6, 0x2f, 0x1a, 0xa, 0xf5, 0x14, 0xca, 0x31, + 0xea, 0xd6, 0x15, 0xa2, 0x7a, 0xdc, 0x6f, 0x95, + 0x2f, 0x1, 0x91, 0x6d, 0x36, 0xe8, 0x9e, 0x5b, + 0xbd, 0xc4, 0x25, 0x99, 0xce, 0x2b, 0x1e, 0xde, + 0xf7, 0x5d, 0x19, 0xf8, 0xb, 0x23, 0xc6, 0x1d, + 0x9d, 0xd, 0x54, 0x7, 0x44, 0x47, 0x12, 0xd2, + 0x32, 0xc7, 0x84, 0xf0, 0xd9, 0x34, 0x64, 0xf4, + 0x5d, 0x16, 0x1d, 0xce, 0x63, 0xee, 0xe9, 0xc, + 0xed, 0xf4, 0x73, 0xcf, 0xde, 0x24, 0x12, 0xb1, + 0x2d, 0xab, 0xbc, 0x4a, 0xe5, 0x9c, 0xbb, 0xb3, + 0x8d, 0x46, 0x87, 0x4a, 0x6c, 0x7b, 0xcf, 0x7f, + 0xac, 0xfe, 0x9a, 0x46, 0x4d, 0x2b, 0x48, 0xa0 +}; + +unsigned char Ciphertext[] = { + 0xaf, 0xbd, 0x64, 0x83, 0x74, 0xc5, 0x69, 0xca, + 0xbd, 0x29, 0xff, 0x20, 0x59, 0x80, 0x9e, 0x43, + 0xa4, 0x9f, 0x85, 0x2c, 0x67, 0xb0, 0x6f, 0x84, + 0xdb, 0x7a, 0x4, 0xa3, 0x34, 0x80, 0xc, 0x73, + 0x2f, 0x41, 0x8f, 0x3b, 0x51, 0xf8, 0xca, 0xa9, + 0x86, 0x49, 0x2e, 0x79, 0x20, 0x3e, 0xd1, 0x44, + 0xa5, 0xaf, 0xe0, 0xce, 0x38, 0x98, 0x8a, 0x8a, + 0xa9, 0x23, 0xa0, 0x2b, 0x7, 0xba, 0x6d, 0x51, + 0xbd, 0x78, 0x8b, 0x33, 0x3d, 0xda, 0xc8, 0x2d, + 0x0, 0x61, 0x3d, 0x8f, 0xfe, 0x74, 0x2d, 0xb4, + 0xee, 0x55, 0xd2, 0x8f, 0x52, 0x72, 0x77, 0x13, + 0xaa, 0xfa, 0x8d, 0x2e, 0xf5, 0x5d, 0x7c, 0xd5, + 0x6b, 0x45, 0xe7, 0xa9, 0x2e, 0xc4, 0x46, 0xcd, + 0x96, 0x77, 0x7f, 0x30, 0x6e, 0xc9, 0x9c, 0xd4, + 0x9a, 0x0, 0x51, 0xba, 0xd8, 0x3f, 0xd4, 0x32, + 0x75, 0x6, 0x87, 0x2e, 0x5, 0x57, 0xcc, 0x4d +}; + +unsigned char Ciphertext[] = { + 0x0, 0x2, 0x47, 0x8e, 0x78, 0xa8, 0xce, 0x95, + 0x74, 0x3, 0x61, 0xa, 0x29, 0x3a, 0xd1, 0x90, + 0x56, 0x40, 0xb6, 0xfc, 0x83, 0xd8, 0x86, 0xf1, + 0xb7, 0x81, 0xff, 0x0, 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1 +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0x20, 0x0, 0xcd, 0x48, 0x20, 0x0, 0xcc, 0xa8, + 0x20, 0x0, 0xea, 0x50, 0x0, 0x0, 0x0, 0x0, + 0x2f, 0xf2, 0x26, 0xc0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x3, 0xfb, 0x0, 0x0, 0x3, 0xfb, + 0x2f, 0xf2, 0x26, 0xe0, 0x0, 0x0, 0x0, 0x0, + 0x20, 0x0, 0xc7, 0xb8, 0x0, 0x0, 0x0, 0x1, + 0x2f, 0xf2, 0x26, 0xd0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x20, 0x0, 0xcc, 0xa8, 0x0, 0x1, 0xea, 0x40 +}; + +unsigned char Ciphertext[] = { + 0xa1, 0x8c, 0x70, 0xa7, 0xda, 0x2, 0x4a, 0x1e, + 0x5c, 0xac, 0x7b, 0x63, 0x87, 0x31, 0x84, 0x30, + 0x8b, 0x4e, 0x88, 0x5c, 0x8d, 0xb, 0x61, 0x4f, + 0xe8, 0x5c, 0xef, 0x10, 0xc4, 0x56, 0xdd, 0x75, + 0x1d, 0x60, 0xb9, 0xce, 0x7c, 0xf2, 0xb3, 0xb6, + 0x4d, 0xc2, 0xa3, 0x4d, 0xd7, 0x70, 0x76, 0xba, + 0x1e, 0xb9, 0x43, 0xa3, 0x5a, 0xa2, 0xe1, 0x3f, + 0xe3, 0x94, 0x22, 0x74, 0x8, 0x27, 0x39, 0x34, + 0x32, 0x98, 0xb9, 0xcf, 0xee, 0x8d, 0x63, 0x27, + 0x42, 0xe, 0x37, 0x88, 0x75, 0xbf, 0xd5, 0x1b, + 0xf0, 0xc6, 0x1a, 0xe1, 0xf9, 0xc3, 0x51, 0x27, + 0xeb, 0xcd, 0x9, 0x3d, 0x64, 0xed, 0x83, 0xbf, + 0x7d, 0xc5, 0x8f, 0x8, 0xda, 0x5d, 0xa8, 0xc0, + 0xf2, 0x81, 0x13, 0x2d, 0x75, 0xc, 0x9e, 0x9d, + 0x11, 0x85, 0xf8, 0xe7, 0x24, 0xa5, 0x80, 0xfc, + 0xc8, 0x53, 0xa7, 0x6b, 0x6c, 0xc9, 0x63, 0x7f +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0x54, 0x67, 0x5d, 0xf0, 0x55, 0x10, 0x91, 0xd8, + 0xb2, 0x90, 0x66, 0x1f, 0x38, 0x44, 0xad, 0xb4, + 0xc0, 0x49, 0x7a, 0xe4, 0xda, 0xd2, 0xda, 0x35, + 0x1e, 0xb, 0x2, 0x57, 0xa6, 0xbe, 0xf7, 0x91, + 0x33, 0x62, 0x2a, 0xbc, 0x16, 0xfe, 0xd6, 0xdf, + 0xf4, 0x3, 0xde, 0xf6, 0x28, 0x4d, 0xbe, 0xc6, + 0x7a, 0x62, 0x4e, 0xa1, 0x20, 0xdf, 0x52, 0x7c, + 0xfa, 0x5, 0x5a, 0xf4, 0x14, 0x32, 0x77, 0x77, + 0x86, 0x91, 0xd5, 0xb1, 0x74, 0xa3, 0xd8, 0x26, + 0x8e, 0xe5, 0x6e, 0x8a, 0xe0, 0x80, 0x9d, 0x18, + 0xa8, 0x56, 0x42, 0x71, 0xf7, 0x7f, 0xbb, 0x78, + 0x85, 0x1f, 0x1d, 0x80, 0x4f, 0x26, 0x6, 0xf6, + 0x2f, 0x1e, 0xf7, 0x32, 0xb6, 0xa5, 0x52, 0x18, + 0xb4, 0xfe, 0x9f, 0x9, 0xec, 0xf0, 0xfd, 0x8d, + 0xfa, 0x74, 0x6a, 0x61, 0xd9, 0x9b, 0xa1, 0x36, + 0xcb, 0x95, 0xfd, 0xc2, 0xf6, 0xd3, 0xba, 0x31 +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0xdb, 0x5c, 0x2c, 0xa2, 0x1c, 0xdc, 0xd0, 0x19, + 0x78, 0xff, 0x14, 0x39, 0xb5, 0x6, 0xf7, 0x8b, + 0x76, 0x94, 0x2b, 0x7a, 0xd5, 0xc2, 0xf5, 0x30, + 0xe1, 0x77, 0x4f, 0x47, 0x8f, 0x45, 0xa6, 0x65, + 0x2b, 0xf7, 0xf2, 0xb7, 0x3c, 0x4a, 0x99, 0x98, + 0xf7, 0x8, 0x9d, 0xc6, 0x9b, 0x7a, 0x7e, 0x18, + 0x94, 0x80, 0x19, 0x28, 0xa2, 0xa8, 0x2f, 0x1b, + 0x7d, 0x1b, 0x10, 0xc9, 0xf5, 0x87, 0x22, 0xdb, + 0xac, 0xb1, 0x71, 0x3f, 0x0, 0x54, 0xe4, 0xe8, + 0x84, 0xf2, 0xc5, 0x59, 0xb7, 0x1, 0x11, 0x2a, + 0x8, 0xdb, 0x8c, 0xd, 0x98, 0x7c, 0x33, 0xd1, + 0x26, 0x1e, 0x2e, 0x3, 0x7, 0xba, 0x6a, 0x3c, + 0xe6, 0xb3, 0x96, 0x50, 0x5f, 0xb6, 0xc2, 0x8f, + 0xf2, 0xe9, 0x5e, 0xf1, 0x1, 0xc3, 0x6, 0xb5, + 0x5d, 0xd6, 0x7, 0x9b, 0x6c, 0x4, 0xf, 0xde, + 0xc5, 0xc8, 0xfd, 0x9a, 0x5d, 0x46, 0x1f, 0xc +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0xba, 0x2d, 0x8, 0xe5, 0xa5, 0xf, 0x1, 0xb0, + 0xe5, 0x10, 0xe4, 0xaf, 0x9e, 0xa6, 0x49, 0x76, + 0xc1, 0x33, 0x6b, 0x9a, 0x56, 0x5, 0x4a, 0x92, + 0xf7, 0xbf, 0xc8, 0x2b, 0x73, 0xfb, 0xd8, 0x75, + 0xc5, 0xcc, 0x4e, 0xfb, 0x90, 0x34, 0x3a, 0xc5, + 0x3b, 0x64, 0xaa, 0x22, 0x5, 0xb5, 0xf8, 0xe9, + 0xae, 0x28, 0xb1, 0x5f, 0x4b, 0x8b, 0x1d, 0xca, + 0x8f, 0x1a, 0xac, 0xb7, 0x9b, 0x65, 0x64, 0x92, + 0x64, 0x1f, 0x1, 0x82, 0x14, 0x5, 0x97, 0x94, + 0x1b, 0x35, 0xe9, 0x66, 0x10, 0xea, 0x71, 0x29, + 0xb1, 0x10, 0xb0, 0xc, 0xb1, 0x6a, 0xef, 0x2c, + 0xa, 0x0, 0xb6, 0x69, 0x41, 0xbc, 0x42, 0xd4, + 0xce, 0x8e, 0xab, 0x6b, 0xc, 0xd5, 0xa7, 0x59, + 0x23, 0x5c, 0x8, 0xaa, 0x2c, 0x50, 0x98, 0xc4, + 0xd7, 0xb6, 0xfb, 0xa3, 0x4, 0x8b, 0x44, 0xe4, + 0x4f, 0xdb, 0xe1, 0x2, 0x96, 0x27, 0xee, 0x8f +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0xb6, 0x5a, 0x92, 0x39, 0xcc, 0xea, 0x88, 0x14, + 0x2, 0x94, 0x28, 0x40, 0x53, 0xcd, 0x4c, 0xda, + 0x33, 0xc0, 0xa5, 0x4f, 0xf8, 0xbb, 0xe4, 0xb8, + 0x6f, 0xcb, 0xd0, 0xcd, 0x9a, 0xda, 0x2e, 0x0, + 0x7b, 0xb6, 0x4, 0xed, 0x5, 0x3f, 0x76, 0xe9, + 0x30, 0xae, 0x40, 0x1c, 0xd3, 0xcc, 0x2e, 0xc0, + 0x98, 0xf0, 0x87, 0xc7, 0xa9, 0x8a, 0x8, 0x43, + 0x8c, 0x63, 0xcb, 0xac, 0xad, 0x52, 0x8f, 0x62, + 0xf7, 0x1e, 0x41, 0xa0, 0x3e, 0xcd, 0x47, 0x38, + 0x37, 0x62, 0x99, 0x30, 0xb1, 0xde, 0x96, 0x72, + 0x83, 0x7e, 0xc8, 0x2d, 0xc7, 0x2f, 0x93, 0x68, + 0x10, 0xa8, 0xf, 0x16, 0x63, 0x3b, 0xb6, 0xd8, + 0xb3, 0x2, 0xc1, 0xb, 0xbd, 0x46, 0xd, 0x5e, + 0x5e, 0x93, 0x99, 0x49, 0x88, 0xb0, 0xf, 0xf, + 0x89, 0x9, 0x2d, 0x8a, 0x7f, 0xa2, 0x2c, 0x20, + 0xc3, 0x63, 0xfe, 0x65, 0xe1, 0xaf, 0x94, 0x8e +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0x1f, 0x8b, 0x24, 0x1, 0x65, 0x44, 0x0, 0xe2, + 0x6e, 0x55, 0x10, 0xcd, 0x56, 0x95, 0xb8, 0x41, + 0x60, 0xa0, 0x22, 0xaa, 0xd0, 0x49, 0x24, 0xad, + 0x9a, 0xc4, 0xa, 0xc4, 0xd1, 0x66, 0xac, 0x77, + 0x38, 0xeb, 0x31, 0x4f, 0x77, 0xe9, 0x18, 0xce, + 0x78, 0xea, 0x45, 0x57, 0x4a, 0x99, 0x83, 0xac, + 0xef, 0xec, 0x7f, 0x41, 0x2d, 0x95, 0x29, 0x2b, + 0x8e, 0xb8, 0xde, 0xbd, 0x3f, 0xae, 0xe1, 0x26, + 0x23, 0xaf, 0x4e, 0x4f, 0xd, 0xab, 0xe8, 0xbd, + 0xdc, 0xf7, 0x3f, 0x4b, 0x4d, 0xde, 0x37, 0xfc, + 0xff, 0x10, 0x21, 0x43, 0x62, 0xf, 0x2c, 0xe3, + 0x4, 0x62, 0xfa, 0x37, 0x27, 0xa8, 0x71, 0x6, + 0x73, 0xc4, 0x7d, 0x60, 0xe2, 0xe1, 0x44, 0x86, + 0xe3, 0x6c, 0x24, 0xef, 0x28, 0xee, 0x1, 0x26, + 0xc8, 0xf6, 0x51, 0x14, 0x87, 0xa7, 0xdc, 0x54, + 0x52, 0xc4, 0x57, 0xeb, 0x68, 0xba, 0xf4, 0x16 +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0x7, 0x11, 0xa2, 0xa1, 0xfd, 0x65, 0x29, 0x6, + 0xfb, 0x44, 0xa1, 0xfc, 0x6, 0x10, 0x7d, 0x3a, + 0xf5, 0x9e, 0x34, 0xa, 0xbc, 0x31, 0xf7, 0xc3, + 0x29, 0x62, 0xaf, 0x89, 0xfd, 0xcb, 0x37, 0x56, + 0xe0, 0x56, 0xd2, 0x1e, 0x90, 0x49, 0x98, 0xa3, + 0xd6, 0x79, 0xf5, 0xd3, 0xb6, 0x54, 0x30, 0x1e, + 0xd6, 0xf1, 0x56, 0x74, 0x8c, 0x9f, 0xfa, 0xed, + 0x1e, 0xc2, 0x91, 0x1e, 0x1b, 0x15, 0x91, 0x65, + 0xa4, 0x5f, 0xa4, 0x1d, 0x6e, 0x60, 0x8, 0xb0, + 0x12, 0xa8, 0xd8, 0xd6, 0xe2, 0x68, 0x7d, 0xa7, + 0x35, 0x8f, 0xff, 0x93, 0x31, 0xaf, 0xb7, 0x4b, + 0xa6, 0x9b, 0x78, 0xc0, 0xae, 0x99, 0xcf, 0x1d, + 0xf9, 0x7b, 0x4a, 0x84, 0xe1, 0x95, 0xde, 0x2b, + 0x71, 0x5, 0x80, 0x2c, 0xdb, 0xea, 0x32, 0x2c, + 0x3e, 0x5, 0xf2, 0x69, 0xab, 0xee, 0xf3, 0x6f, + 0x4a, 0x7a, 0x16, 0x21, 0xab, 0xcf, 0x28, 0x81 +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0x6a, 0x5, 0x1d, 0xeb, 0xb3, 0x85, 0x4f, 0xed, + 0xc7, 0xbb, 0xf2, 0xd4, 0xf1, 0x57, 0x8c, 0x2a, + 0x9c, 0x2e, 0x5f, 0x9a, 0xda, 0x7d, 0x3, 0x5b, + 0x7a, 0x55, 0x44, 0xff, 0xe8, 0x75, 0x70, 0x7e, + 0x1e, 0x4f, 0x91, 0xa8, 0xcb, 0x5d, 0x6f, 0x14, + 0xf6, 0xfb, 0xa7, 0xf3, 0x0, 0x32, 0x15, 0xac, + 0xe0, 0xff, 0xc, 0x4b, 0xb2, 0x7b, 0x55, 0xd, + 0x9a, 0x3d, 0x42, 0x32, 0xdc, 0x59, 0xc3, 0xd1, + 0xfb, 0x69, 0x2f, 0x7d, 0xfd, 0xe4, 0x56, 0x3e, + 0xad, 0x56, 0x59, 0xdb, 0xe4, 0xd6, 0x23, 0xb5, + 0x89, 0x58, 0xa9, 0x32, 0x50, 0x6e, 0x38, 0x55, + 0x5c, 0x3, 0x1f, 0xb7, 0x44, 0xa6, 0x60, 0x95, + 0x9c, 0xf8, 0x47, 0x91, 0x4f, 0xd2, 0xf, 0xa6, + 0x92, 0xb, 0xb2, 0x60, 0xa8, 0x42, 0xb2, 0x32, + 0x58, 0x73, 0xf3, 0x12, 0x31, 0x2b, 0x59, 0xfc, + 0x71, 0x6f, 0x64, 0x26, 0x45, 0x6f, 0x99, 0x4c +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0xe, 0xe5, 0xf1, 0x7c, 0x72, 0x1c, 0xfb, 0x0, + 0xb4, 0x6a, 0xe, 0xe8, 0xaf, 0x1b, 0x62, 0x1, + 0x66, 0x13, 0x3a, 0x7e, 0x7f, 0xec, 0xfb, 0xfc, + 0x47, 0xbb, 0x4f, 0x99, 0xab, 0x1d, 0x1b, 0x1c, + 0x45, 0x49, 0xe4, 0x9a, 0x23, 0x28, 0xcb, 0x81, + 0xd3, 0x59, 0x63, 0x54, 0x11, 0x9b, 0x22, 0x43, + 0x2f, 0xc7, 0x58, 0x78, 0xe1, 0x16, 0x7f, 0x6e, + 0x29, 0xdd, 0xe3, 0x4b, 0xb8, 0x27, 0x69, 0x9f, + 0x9d, 0x8e, 0x49, 0xcd, 0x85, 0xf, 0xfa, 0xa9, + 0xf3, 0x6a, 0xe6, 0xce, 0x47, 0x49, 0x43, 0xfb, + 0x49, 0xd5, 0x1f, 0x1f, 0x10, 0x73, 0x1a, 0x58, + 0x87, 0x83, 0x15, 0xc5, 0xf5, 0xbc, 0x9b, 0xdf, + 0x6, 0x6a, 0x7c, 0x39, 0xcf, 0xbd, 0xfd, 0xdc, + 0x8b, 0xc5, 0x22, 0x3c, 0x5e, 0x68, 0x4, 0x46, + 0x6, 0x76, 0x7a, 0xa, 0x44, 0x49, 0x5d, 0xe2, + 0xab, 0x65, 0x7, 0xe3, 0x3f, 0x9e, 0xac, 0x9f +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0x60, 0xd1, 0x8f, 0xd5, 0x23, 0x95, 0x95, 0xcb, + 0xd0, 0xa, 0x8e, 0x2, 0x1a, 0x56, 0x59, 0x4a, + 0x86, 0x5d, 0x88, 0x9e, 0xa1, 0x28, 0x52, 0x72, + 0x16, 0x25, 0x80, 0xac, 0x0, 0xe3, 0xc9, 0xfe, + 0xc0, 0x1c, 0x7a, 0x39, 0x6d, 0x54, 0x91, 0xf0, + 0x67, 0xb5, 0x6e, 0xf9, 0x3e, 0xf3, 0xae, 0x45, + 0x3b, 0x46, 0x54, 0x6e, 0x9d, 0xb, 0xc2, 0xa3, + 0x84, 0xa7, 0xc4, 0x0, 0xd3, 0xdf, 0x33, 0xf4, + 0x1a, 0xdf, 0x7a, 0x19, 0x16, 0x6, 0x34, 0xe7, + 0x39, 0xd7, 0x9e, 0x1e, 0x14, 0xbe, 0xaf, 0x1f, + 0xa8, 0x14, 0x79, 0xa6, 0x51, 0x40, 0xb8, 0xbf, + 0x5f, 0xa0, 0xb, 0xbe, 0x7b, 0x9b, 0x7f, 0x8a, + 0xdd, 0x43, 0x2e, 0x94, 0xe8, 0x4b, 0xcd, 0x12, + 0x12, 0x6e, 0x47, 0x87, 0xa2, 0x2c, 0xf5, 0x4, + 0xe2, 0xa7, 0xb6, 0xa3, 0x44, 0xa6, 0x3e, 0x4, + 0x8f, 0x6f, 0xa2, 0x66, 0xcb, 0x3, 0xa2, 0x7b +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0x56, 0x90, 0x8b, 0xd6, 0x83, 0x40, 0x0, 0x66, + 0x13, 0x6b, 0xd7, 0x31, 0x3c, 0x46, 0x55, 0x33, + 0xf2, 0x59, 0xa7, 0xdd, 0xb5, 0x2e, 0x33, 0x62, + 0xdd, 0xd5, 0x52, 0xf1, 0x8e, 0xf, 0x22, 0xc2, + 0x3a, 0x32, 0x5c, 0x85, 0x88, 0xf, 0x72, 0x5a, + 0xd3, 0x90, 0xd3, 0x28, 0x8a, 0x6f, 0x30, 0xdb, + 0xd5, 0x98, 0xbd, 0xaa, 0x1b, 0xb1, 0x96, 0x5e, + 0xed, 0x83, 0x63, 0xc5, 0x69, 0xea, 0x51, 0xb5, + 0xc1, 0x94, 0x15, 0xd9, 0xa, 0xfa, 0xb, 0xcb, + 0x59, 0xf3, 0xe9, 0xb5, 0x78, 0xfc, 0xc6, 0xd4, + 0xff, 0x81, 0xa4, 0x34, 0xc9, 0xdc, 0x9f, 0x9f, + 0x0, 0xa4, 0xc3, 0x4b, 0xd7, 0x47, 0xda, 0xe9, + 0x85, 0x29, 0xe9, 0x6f, 0x34, 0xaa, 0xe9, 0x7a, + 0x18, 0x48, 0x46, 0x27, 0x48, 0xd5, 0xe9, 0x52, + 0x79, 0x6d, 0xdb, 0x78, 0xa2, 0x7a, 0xb6, 0xf8, + 0xc1, 0xbd, 0x51, 0xb9, 0x29, 0x5e, 0x66, 0x8e +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0xb8, 0xdb, 0xa9, 0xea, 0x16, 0x89, 0x7b, 0xd8, + 0x68, 0xd2, 0xd, 0x49, 0x3c, 0xc2, 0x3e, 0x8c, + 0xf3, 0xb7, 0x57, 0xd1, 0x28, 0x62, 0x2, 0xc1, + 0x85, 0x5c, 0x12, 0x90, 0xeb, 0x83, 0x9e, 0x9b, + 0x51, 0x70, 0x50, 0x3, 0x8b, 0x6e, 0x3c, 0x28, + 0x41, 0x19, 0x7c, 0x2b, 0x45, 0x83, 0x20, 0xbc, + 0xfa, 0xce, 0x93, 0xb, 0xf1, 0xce, 0x69, 0xf5, + 0x87, 0xa6, 0xcf, 0xc3, 0x69, 0x74, 0xff, 0x31, + 0x44, 0x91, 0x2e, 0xb, 0xf0, 0x54, 0x2e, 0xbc, + 0x8a, 0x8, 0x6, 0xbb, 0x69, 0x74, 0x75, 0xa4, + 0x18, 0xa7, 0x5a, 0x68, 0x61, 0x90, 0x4b, 0x65, + 0x78, 0x96, 0xfb, 0xf9, 0xbe, 0xe7, 0xa7, 0xfd, + 0x4b, 0xc6, 0x4b, 0xe, 0x1c, 0x62, 0xa9, 0x82, + 0xb, 0x45, 0x93, 0x65, 0x3d, 0x2, 0xb9, 0xab, + 0xbc, 0x52, 0xc2, 0x38, 0xd8, 0x4d, 0xc6, 0x1f, + 0xc5, 0x9a, 0xd1, 0x91, 0x58, 0xe, 0xa9, 0x3b +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0x7a, 0xfb, 0xe2, 0x54, 0x44, 0xb7, 0x1f, 0x11, + 0xde, 0x9a, 0xa6, 0xcf, 0x32, 0x27, 0x3a, 0x87, + 0x44, 0x73, 0x27, 0x43, 0x92, 0xac, 0x6f, 0xd8, + 0xa3, 0x6c, 0x97, 0x64, 0x96, 0x41, 0xec, 0xe, + 0xe9, 0x7b, 0xb2, 0xfa, 0x41, 0x9, 0x50, 0xdb, + 0x7, 0xb7, 0x27, 0x4, 0xd4, 0x68, 0x46, 0x95, + 0xed, 0x14, 0x98, 0xa9, 0xe5, 0x3b, 0x13, 0xb0, + 0x99, 0x59, 0x3d, 0x6d, 0xeb, 0xa0, 0xdc, 0x49, + 0xd, 0x82, 0xd9, 0x22, 0x48, 0xa5, 0xd0, 0x3, + 0xea, 0x59, 0x45, 0xb6, 0x77, 0xc0, 0x5c, 0x42, + 0xae, 0x21, 0x50, 0x86, 0x9b, 0x98, 0x39, 0x3d, + 0x9f, 0x1c, 0xc3, 0x6d, 0x54, 0x8f, 0xe7, 0xe8, + 0xbf, 0x92, 0xd5, 0xbe, 0xcf, 0x99, 0x63, 0x10, + 0x82, 0xe8, 0xb4, 0x18, 0x6b, 0x6d, 0xc9, 0x5c, + 0xa2, 0x16, 0x5c, 0xaf, 0x18, 0xc9, 0x16, 0xfc, + 0x18, 0x86, 0x1, 0xce, 0x3c, 0x16, 0x86, 0x3c +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0x64, 0x83, 0x3c, 0x1a, 0x25, 0x86, 0xa9, 0x4a, + 0x93, 0x21, 0x6f, 0x22, 0xc1, 0xc6, 0x4e, 0x7c, + 0xfb, 0x2d, 0xfd, 0xb8, 0x58, 0x3c, 0xe1, 0xd1, + 0xc4, 0x4c, 0xd1, 0x25, 0x30, 0x12, 0x11, 0xfa, + 0x83, 0xef, 0x12, 0x48, 0xb, 0xa6, 0x81, 0x23, + 0x20, 0xf0, 0xbb, 0x3e, 0x29, 0x59, 0x3e, 0x19, + 0xc2, 0x98, 0x72, 0x32, 0x71, 0xe0, 0xd1, 0xf0, + 0xc4, 0x28, 0x65, 0xc2, 0x8f, 0xf0, 0xea, 0x53, + 0xf4, 0xf9, 0x10, 0x97, 0x1d, 0x32, 0xc4, 0xce, + 0x6, 0x7a, 0x68, 0x23, 0xe4, 0x19, 0x83, 0xc8, + 0x91, 0x6, 0x58, 0x1b, 0x56, 0x8f, 0xe2, 0x9b, + 0xec, 0x76, 0x1d, 0xe8, 0xa0, 0xe6, 0xcd, 0x58, + 0xfd, 0x92, 0xdf, 0xa2, 0xbb, 0x3d, 0x4c, 0x8b, + 0xa5, 0x65, 0x6a, 0x2d, 0xb8, 0xf7, 0x68, 0xa1, + 0x6d, 0xd6, 0x7c, 0xef, 0xe8, 0x79, 0x47, 0xaf, + 0xe3, 0xfe, 0x33, 0x4e, 0x9d, 0xc4, 0x1a, 0xae +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0x4e, 0xd3, 0x5f, 0x62, 0xb6, 0x51, 0x83, 0x2f, + 0xb6, 0x57, 0xa, 0xab, 0x39, 0xfc, 0x2, 0xb6, + 0x8b, 0x60, 0x67, 0x20, 0x94, 0xf2, 0xb5, 0x3a, + 0x2f, 0x29, 0xae, 0x7e, 0xc4, 0x59, 0xc6, 0x2f, + 0x2f, 0x1d, 0x9c, 0x69, 0x4, 0xbc, 0x8d, 0xba, + 0x9b, 0x8d, 0x39, 0x2a, 0x33, 0x50, 0x6c, 0x2c, + 0x79, 0xa4, 0x26, 0x8c, 0x23, 0x9, 0x85, 0x13, + 0xab, 0x9d, 0xc6, 0xb0, 0xf8, 0x19, 0x75, 0xc9, + 0xb2, 0x36, 0x1a, 0xee, 0x23, 0x5f, 0xa0, 0xfc, + 0x82, 0x2e, 0x59, 0xa1, 0x24, 0x17, 0x33, 0x53, + 0x84, 0x16, 0xbf, 0x61, 0x84, 0xfb, 0xc3, 0x5a, + 0x6b, 0x4b, 0x8a, 0xb8, 0x73, 0xb2, 0x87, 0x26, + 0xd1, 0xb8, 0x42, 0xad, 0xea, 0xd5, 0x5, 0x85, + 0xee, 0xda, 0x99, 0x64, 0xe3, 0xd6, 0xe5, 0xcb, + 0xce, 0x2e, 0xc2, 0xb6, 0xc1, 0x5d, 0x8b, 0xb9, + 0x5, 0x98, 0xf8, 0xf0, 0xca, 0xad, 0x77, 0x4a +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0x4d, 0xd9, 0x31, 0x58, 0xd2, 0x76, 0x30, 0xce, + 0xb8, 0x25, 0x3e, 0xf9, 0xb7, 0x5c, 0x22, 0xa4, + 0x74, 0x4a, 0xf1, 0xf8, 0xbd, 0x78, 0xa8, 0xd4, + 0x9d, 0xc8, 0x2f, 0x76, 0x60, 0x34, 0x95, 0xb, + 0x38, 0x50, 0xa5, 0x5c, 0xa2, 0xa6, 0x6a, 0xc1, + 0x42, 0x3d, 0x4c, 0x67, 0xbf, 0x3, 0x22, 0xa2, + 0xee, 0x13, 0x52, 0xdb, 0x11, 0xa3, 0xa, 0xac, + 0x31, 0x38, 0x6c, 0xeb, 0x29, 0x6c, 0xa0, 0x96, + 0x49, 0xbb, 0x2b, 0xfd, 0x5b, 0x27, 0xf5, 0x4f, + 0x1e, 0xe1, 0xbe, 0x4, 0xed, 0x52, 0xe2, 0xd6, + 0xcc, 0x70, 0x49, 0x63, 0x68, 0xc, 0xfe, 0xf4, + 0xad, 0x9e, 0xc7, 0xff, 0x33, 0x1a, 0x4f, 0xc7, + 0xa1, 0x6b, 0xaa, 0xd7, 0x0, 0x35, 0x47, 0x40, + 0xa9, 0x67, 0xca, 0x4b, 0xaf, 0x5e, 0x8, 0x50, + 0x9d, 0x67, 0xec, 0x76, 0xb4, 0x59, 0xe5, 0x22, + 0xf5, 0x8, 0x7c, 0x1a, 0xb8, 0xcd, 0x47, 0x64 +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0x13, 0xa8, 0x25, 0x8c, 0xdd, 0x44, 0xb9, 0x40, + 0xa, 0x2c, 0x0, 0xae, 0x7d, 0xd4, 0x61, 0x2c, + 0x1c, 0x4c, 0x14, 0xc8, 0x5f, 0x90, 0x57, 0xf6, + 0xbf, 0x7d, 0x45, 0x42, 0x26, 0x97, 0x1b, 0xc1, + 0x8c, 0x37, 0xa6, 0x78, 0xf3, 0xbb, 0x7a, 0x55, + 0xdc, 0x96, 0x5b, 0xdf, 0x30, 0xbb, 0x4f, 0x55, + 0x76, 0x13, 0x7b, 0xc0, 0x9f, 0x81, 0x57, 0xfe, + 0x5c, 0x1d, 0xc5, 0xc2, 0xc9, 0x53, 0x80, 0xf5, + 0xe6, 0x4a, 0xc0, 0x7b, 0x70, 0xe9, 0x31, 0x1e, + 0x42, 0xd, 0x6e, 0x11, 0x5d, 0xcf, 0x2d, 0x98, + 0x15, 0x2b, 0xee, 0x76, 0x26, 0x91, 0xe2, 0xd7, + 0x2d, 0xa5, 0x2b, 0xd0, 0xae, 0xa3, 0xe5, 0xc4, + 0x80, 0xf5, 0xbd, 0x87, 0xa6, 0x8c, 0x71, 0x44, + 0x3c, 0x14, 0x3d, 0xad, 0x21, 0x4d, 0x5d, 0x4c, + 0x3, 0x67, 0xf0, 0x83, 0x45, 0x3f, 0x9, 0x55, + 0xda, 0xe, 0xe, 0x36, 0x3e, 0xe0, 0x14, 0x31 +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0xa, 0x63, 0xe, 0xd8, 0x83, 0xcc, 0x6a, 0x26, + 0xda, 0xd9, 0x74, 0x56, 0xf9, 0x1e, 0x65, 0x71, + 0xd2, 0x89, 0x7b, 0xcd, 0x1a, 0x35, 0x44, 0xda, + 0x6a, 0x9e, 0xeb, 0xe5, 0xb6, 0x13, 0xcd, 0x73, + 0x7f, 0xcd, 0x5f, 0x8d, 0xb0, 0x42, 0xc4, 0x4b, + 0x5d, 0x80, 0xc4, 0x20, 0x82, 0xa, 0xbd, 0x84, + 0xfe, 0x1f, 0x43, 0x29, 0xa7, 0x9d, 0x32, 0x70, + 0xa2, 0xef, 0x80, 0x85, 0x3a, 0xc4, 0xd4, 0x1b, + 0x6f, 0x12, 0xa0, 0x8, 0x6e, 0x24, 0x39, 0x3f, + 0x69, 0x99, 0x18, 0xe4, 0xab, 0xe0, 0xed, 0x44, + 0x6f, 0xe3, 0x6, 0xf3, 0x62, 0x71, 0x1e, 0x85, + 0xdc, 0x2a, 0x2e, 0xeb, 0x8f, 0xa4, 0xbd, 0x47, + 0x9f, 0xe1, 0x9d, 0x4d, 0x37, 0x21, 0x58, 0x79, + 0x14, 0x15, 0x83, 0xe8, 0x4c, 0x72, 0x8e, 0x24, + 0x86, 0x6e, 0x99, 0x78, 0xa2, 0x85, 0x3d, 0xce, + 0x69, 0x1e, 0x61, 0x75, 0x40, 0x98, 0x37, 0x8e +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0x49, 0x69, 0x1e, 0x89, 0xd6, 0x8d, 0xc1, 0xf7, + 0x10, 0xe1, 0xef, 0x52, 0xd3, 0x8c, 0xbc, 0xd6, + 0xd7, 0xc3, 0x77, 0xcd, 0xef, 0x8f, 0x18, 0x27, + 0xd8, 0xd0, 0x65, 0x75, 0x53, 0x8c, 0xc3, 0x4, + 0xf3, 0x5b, 0xe1, 0x6, 0x38, 0x7e, 0x58, 0xfe, + 0xaa, 0xa0, 0x75, 0x24, 0xb2, 0xa8, 0xd0, 0x1a, + 0x12, 0xed, 0xfa, 0x88, 0x8, 0xa, 0x9d, 0x40, + 0xc3, 0x4e, 0xa5, 0x6b, 0xd2, 0x43, 0xe9, 0xb5, + 0x55, 0xe7, 0x90, 0x2d, 0xa3, 0x30, 0x7e, 0x36, + 0x38, 0x7e, 0x86, 0x5, 0x4d, 0x86, 0x26, 0x35, + 0xa4, 0x16, 0xf1, 0x7f, 0xd, 0x4c, 0x1c, 0x5d, + 0x23, 0xbe, 0x21, 0xdd, 0x9d, 0xcd, 0x4c, 0x2, + 0x4, 0xee, 0x64, 0x42, 0x12, 0xf2, 0xaf, 0x34, + 0xe3, 0x6e, 0xa5, 0x12, 0x54, 0xec, 0x41, 0xe3, + 0xb3, 0x25, 0xef, 0xd0, 0x5, 0x9e, 0x52, 0xba, + 0xa9, 0x35, 0x9c, 0x9b, 0xf5, 0x86, 0xb, 0x46 +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; + +unsigned char Ciphertext[] = { + 0x53, 0xac, 0x92, 0x6, 0x7b, 0x30, 0x14, 0x5, + 0xbc, 0xf5, 0xe1, 0x3d, 0x57, 0xa5, 0xc1, 0x89, + 0x20, 0xdd, 0xe4, 0x21, 0xb, 0x13, 0x14, 0xe1, + 0xcd, 0xff, 0x58, 0x1, 0xbe, 0x3c, 0xf7, 0xda, + 0xef, 0x46, 0x1, 0xf0, 0x5d, 0xde, 0x4f, 0xbf, + 0x9a, 0xf8, 0xb2, 0x20, 0x1b, 0x6f, 0x8, 0x2f, + 0xaa, 0x73, 0xf9, 0xd4, 0x0, 0xfc, 0xb1, 0x77, + 0x6, 0x45, 0x84, 0x92, 0xcc, 0x99, 0xe1, 0x16, + 0x8b, 0x14, 0x7e, 0x87, 0x2f, 0x16, 0x54, 0x74, + 0x7d, 0xce, 0xcb, 0x35, 0x7c, 0x24, 0xd8, 0x3c, + 0xc0, 0x11, 0xaf, 0x8b, 0x4, 0xf8, 0xb1, 0x38, + 0xe, 0x93, 0x90, 0xa3, 0xd1, 0x85, 0x8e, 0x42, + 0xbc, 0x35, 0x63, 0xb2, 0xbc, 0xfc, 0x62, 0xb3, + 0xc8, 0xfa, 0xa, 0x35, 0xd, 0xbc, 0x2a, 0x13, + 0x61, 0xb0, 0x8a, 0xcb, 0x92, 0x1b, 0x29, 0x2b, + 0x2a, 0xf3, 0x8b, 0x3a, 0x4f, 0xd, 0xc6, 0xd6 +}; + +unsigned char decrypted[] = { + 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63 +}; diff --git a/testcases/include/windows.h b/testcases/include/windows.h new file mode 100644 index 0000000..346e2ec --- /dev/null +++ b/testcases/include/windows.h @@ -0,0 +1,2 @@ +// +// dummy file diff --git a/testcases/init_cca.sh b/testcases/init_cca.sh new file mode 100755 index 0000000..78a2e28 --- /dev/null +++ b/testcases/init_cca.sh @@ -0,0 +1,28 @@ +#!/bin/sh +# +# COPYRIGHT (c) International Business Machines Corp. 2010-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 +# + +for j in S A E; do + echo "---" + echo "CLEARING 'NEW' register for key type '$j'" + panel.exe -c -t $j + echo "Exit value was '$?'" + for i in F M L; do + echo " LOADING key type '$j', key part '$i'" + if [ "$j" = "E" ]; then + panel.exe -l -t $j -p $i 0202020202020202020202020202020202020202020202020202020202020202 + else + panel.exe -l -t $j -p $i 020202020202020202020202020202020202020202020202 + fi + echo " Exit value was '$?'" + done + echo "SETTING new key" + panel.exe -s -t $j + echo "Exit value was '$?'" +done diff --git a/testcases/init_token.sh.in b/testcases/init_token.sh.in new file mode 100755 index 0000000..f85d4ec --- /dev/null +++ b/testcases/init_token.sh.in @@ -0,0 +1,71 @@ +#!/usr/bin/expect -f +# +# 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 +# + +set timeout 5 + +spawn @sbindir@/pkcsconf -c [lindex $argv 0] -I +expect "Enter the SO PIN: " +sleep .1 +send "87654321\r" +sleep .1 +expect "label: " +sleep .1 +send "ibmtest\r" +sleep .1 +expect eof {} \ +"Incorrect PIN Entered." {exit 1} + +spawn @sbindir@/pkcsconf -c [lindex $argv 0] -P +expect "Enter the SO PIN: " +sleep .1 +send "87654321\r" +sleep .1 +expect "Enter the new SO PIN: " +sleep .1 +send "76543210\r" +sleep .1 +expect "Re-enter the new SO PIN: " +sleep .1 +send "76543210\r" +sleep .1 +expect eof {} \ +"Incorrect PIN Entered." {exit 1} + +spawn @sbindir@/pkcsconf -c [lindex $argv 0] -u +expect "Enter the SO PIN: " +sleep .1 +send "76543210\r" +sleep .1 +expect "Enter the new user PIN: " +sleep .1 +send "12345678\r" +sleep .1 +expect "Re-enter the new user PIN: " +sleep .1 +send "12345678\r" +sleep .1 +expect eof {} \ +"Incorrect PIN Entered." {exit 1} + +spawn @sbindir@/pkcsconf -c [lindex $argv 0] -p +expect "Enter user PIN: " +sleep .1 +send "12345678\r" +sleep .1 +expect "Enter the new user PIN: " +sleep .1 +send "01234567\r" +sleep .1 +expect "Re-enter the new user PIN: " +sleep .1 +send "01234567\r" +sleep .1 +expect eof {} \ +"Incorrect PIN Entered." {exit 1} diff --git a/testcases/init_tpmtoken.sh b/testcases/init_tpmtoken.sh new file mode 100755 index 0000000..5686215 --- /dev/null +++ b/testcases/init_tpmtoken.sh @@ -0,0 +1,33 @@ +#!/usr/bin/expect -f +# +# COPYRIGHT (c) International Business Machines Corp. 2010-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 +# + +spawn tpmtoken_init -y +set timeout 1 +expect { + "Enter the TPM security officer password: " { send "76543210\r"} +} + +set timeout 10 + +expect { + "Enter new password: " { send "76543210\r" } +} + +expect { + "Confirm password: " { send "76543210\r" } +} + +expect { + "Enter new password: " { send "01234567\r" } +} + +expect { + "Confirm password: " { send "01234567\r" } +} diff --git a/testcases/login/README b/testcases/login/README new file mode 100644 index 0000000..418680e --- /dev/null +++ b/testcases/login/README @@ -0,0 +1,5 @@ +login_tests.sh + TODO: To be tested. + +login_flags_tests + TODO: To be tested. diff --git a/testcases/login/digest_init.c b/testcases/login/digest_init.c new file mode 100644 index 0000000..aebc826 --- /dev/null +++ b/testcases/login/digest_init.c @@ -0,0 +1,139 @@ +/* + * 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 + */ + +#include +#include +#include +#include + +#include +#include + +#include "pkcs11types.h" + +#include "regress.h" +#include "common.c" + +int do_GetFunctionList(void); + +int do_digestInit(CK_FUNCTION_LIST * funcs, CK_SLOT_ID slot_id, + CK_USER_TYPE userType, char *pass) +{ + CK_RV rc; + CK_SESSION_HANDLE session; + CK_FLAGS flags = CKF_SERIAL_SESSION; + CK_MECHANISM mech; + + mech.mechanism = CKM_SHA_1; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + + flags |= CKF_RW_SESSION; + + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session); + if (rc != CKR_OK) { + show_error("C_OpenSession", rc); + return rc; + } + + rc = funcs->C_Login(session, userType, (CK_CHAR_PTR) pass, strlen(pass)); + if (rc != CKR_OK) { + show_error("C_Login", rc); + return rc; + } + + printf("Logged in successfully, calling C_DigestInit...\n"); + + rc = funcs->C_DigestInit(session, &mech); + if (rc != CKR_OK) { + show_error("C_DigestInit", rc); + funcs->C_Logout(session); + funcs->C_CloseSession(session); + return rc; + } + + printf("Success.\n"); + + rc = funcs->C_Logout(session); + if (rc != CKR_OK) { + show_error("C_Logout", rc); + return rc; + } + + printf("Logged out.\n"); + + rc = funcs->C_CloseSession(session); + if (rc != CKR_OK) { + show_error("C_CloseSession", rc); + return rc; + } + + return rc; +} + +void digest_init_usage(char *argv0) +{ + printf("usage: %s [-slot ] [-h] [-user|-so] -pass pass\n\n", argv0); + printf("By default, Slot #%lu is used, as user\n\n", SLOT_ID); + exit(-1); +} + +// +// +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + CK_USER_TYPE userType = CKU_USER; + CK_RV rc = 0; + CK_SLOT_ID slot_id = 0; + char *pass = NULL; + int i; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-pass") == 0) { + ++i; + pass = argv[i]; + } else if (strcmp(argv[i], "-slot") == 0) { + ++i; + slot_id = atoi(argv[i]); + } else if (strcmp(argv[i], "-so") == 0) { + userType = CKU_SO; + } else if (strcmp(argv[i], "-user") == 0) { + continue; + } else { + digest_init_usage(argv[0]); + } + } + + if (!pass) + digest_init_usage(argv[0]); + + if (slot_id != SLOT_ID) + printf("Using user specified slot %lu.\n", slot_id); + + rc = do_GetFunctionList(); + if (funcs == NULL) + return -1; + + memset(&cinit_args, 0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + rc = funcs->C_Initialize(&cinit_args); + if (rc != CKR_OK) { + show_error("C_Initialize", rc); + return -1; + } + + rc = do_digestInit(funcs, slot_id, userType, pass); + + funcs->C_Finalize(NULL); + + return rc; +} diff --git a/testcases/login/init_pin.c b/testcases/login/init_pin.c new file mode 100644 index 0000000..6cca186 --- /dev/null +++ b/testcases/login/init_pin.c @@ -0,0 +1,131 @@ +/* + * 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 + */ + +#include +#include +#include +#include + +#include +#include + +#include "pkcs11types.h" + +#include "regress.h" +#include "common.c" + +int do_GetFunctionList(void); + +int do_InitPIN(CK_FUNCTION_LIST * funcs, CK_SLOT_ID slot_id, char *sologinpass, + char *userinitpass) +{ + CK_RV rc; + CK_SESSION_HANDLE session; + CK_FLAGS flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session); + if (rc != CKR_OK) { + show_error("C_OpenSession", rc); + return rc; + } + + rc = funcs->C_Login(session, CKU_SO, (CK_CHAR_PTR) sologinpass, + strlen(sologinpass)); + if (rc != CKR_OK) { + show_error("C_Login", rc); + return rc; + } + + printf("Logged in the SO successfully, calling C_InitPIN...\n"); + + rc = funcs->C_InitPIN(session, (CK_CHAR_PTR) userinitpass, + strlen(userinitpass)); + if (rc != CKR_OK) { + show_error("C_InitPIN", rc); + funcs->C_Logout(session); + funcs->C_CloseSession(session); + return rc; + } + + printf("Success.\n"); + + rc = funcs->C_Logout(session); + if (rc != CKR_OK) { + show_error("C_Logout", rc); + return rc; + } + + printf("Logged out.\n"); + + rc = funcs->C_CloseSession(session); + if (rc != CKR_OK) { + show_error("C_CloseSession", rc); + return rc; + } + + return rc; +} + +void init_pin_usage(char *argv0) +{ + printf("usage: %s [-slot ] [-h] -sopass pass -userpass pass\n\n", + argv0); + printf("By default, Slot #%lu is used, as user\n\n", SLOT_ID); + exit(-1); +} + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + CK_RV rc = 0; + CK_SLOT_ID slot_id = 0; + char *sopass = NULL, *userpass = NULL; + int i; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-sopass") == 0) { + ++i; + sopass = argv[i]; + } else if (strcmp(argv[i], "-userpass") == 0) { + ++i; + userpass = argv[i]; + } else if (strcmp(argv[i], "-slot") == 0) { + ++i; + slot_id = atoi(argv[i]); + } else { + init_pin_usage(argv[0]); + } + } + + if (!sopass || !userpass) + init_pin_usage(argv[0]); + + if (slot_id != SLOT_ID) + printf("Using user specified slot %lu.\n", slot_id); + + rc = do_GetFunctionList(); + if (funcs == NULL) + return -1; + + memset(&cinit_args, 0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + rc = funcs->C_Initialize(&cinit_args); + if (rc != CKR_OK) { + show_error("C_Initialize", rc); + return -1; + } + + rc = do_InitPIN(funcs, slot_id, sopass, userpass); + + funcs->C_Finalize(NULL); + + return rc; +} diff --git a/testcases/login/init_tok.c b/testcases/login/init_tok.c new file mode 100644 index 0000000..a1703ca --- /dev/null +++ b/testcases/login/init_tok.c @@ -0,0 +1,115 @@ +/* + * 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 + */ + +// File: tok_obj.c +// +// Test driver for testing the proper storage of token objects +// + +#include +#include +#include +#include +#include + +#include "pkcs11types.h" + +#include "regress.h" +#include "common.c" + +int do_GetInfo(void); + +CK_RV C_GetFunctionList(CK_FUNCTION_LIST **); +int do_GetFunctionList(void); + +int do_inittoken(CK_FUNCTION_LIST * funcs, CK_BYTE * sopass) +{ + CK_BYTE label[32]; + int len; + CK_RV rc; + + memcpy(label, "L13 ", 32); + + for (len = 0; len < 31; len++) { + if (label[len] == '\0') { + label[len] = ' '; + break; + } + } + + rc = funcs->C_InitToken(SLOT_ID, NULL, strlen((char *) sopass), label); + if (rc != CKR_ARGUMENTS_BAD) { + show_error(" C_InitToken Fail #1", rc); + goto done; + } + + rc = funcs->C_InitToken(SLOT_ID, sopass, strlen((char *) sopass), NULL); + if (rc != CKR_ARGUMENTS_BAD) { + show_error(" C_InitToken Fail #2", rc); + goto done; + } + + rc = funcs->C_InitToken(SLOT_ID, sopass, strlen((char *) sopass), label); + if (rc != CKR_OK) { + show_error(" C_InitToken #1", rc); + goto done; + } + +done: + return rc; +} + + +int main(int argc, char **argv) +{ + CK_BYTE *pass = NULL; + int rc; + int i; + + SLOT_ID = 0; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-slot") == 0) { + SLOT_ID = atoi(argv[i + 1]); + i++; + } else if (strcmp(argv[i], "-pass") == 0) { + pass = (CK_BYTE_PTR) strdup(argv[i + 1]); + i++; + } else { + printf("usage: %s [-slot ] [-h] -pass pass\n\n", argv[0]); + printf("By default, Slot 0 is used\n\n"); + return -1; + } + } + + if (!pass) { + printf("usage: %s [-slot ] [-h] [-pass pass]\n\n", argv[0]); + printf("By default, Slot 0 is used\n\n"); + return -1; + } + + printf("Using slot #%lu...\n\n", SLOT_ID); + + rc = do_GetFunctionList(); + if ((rc != TRUE) || (funcs == NULL)) { + printf("do_GetFunctionList failed.\n"); + return rc; + } + + funcs->C_Initialize(NULL); + + rc = do_inittoken(funcs, pass); + + free(pass); + + funcs->C_Finalize(NULL); + + return rc; +} diff --git a/testcases/login/login.c b/testcases/login/login.c new file mode 100644 index 0000000..7de4a07 --- /dev/null +++ b/testcases/login/login.c @@ -0,0 +1,120 @@ +/* + * 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 + */ + +#include +#include +#include +#include + +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "common.c" + +int do_GetFunctionList(void); + +int do_LoginLogout(CK_FUNCTION_LIST * funcs, CK_SLOT_ID slot_id, + CK_USER_TYPE userType, char *pass) +{ + CK_RV rc; + CK_SESSION_HANDLE session; + CK_FLAGS flags = CKF_SERIAL_SESSION; + + if (userType == CKU_SO) { + flags |= CKF_RW_SESSION; + } + + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session); + if (rc != CKR_OK) { + show_error("C_OpenSession", rc); + return rc; + } + rc = funcs->C_Login(session, userType, (CK_CHAR_PTR) pass, strlen(pass)); + if (rc != CKR_OK) { + show_error("C_Login", rc); + return rc; + } + + printf("Logged in successfully, logging out...\n"); + + rc = funcs->C_Logout(session); + if (rc != CKR_OK) { + show_error("C_Logout", rc); + return rc; + } + + printf("Logged out.\n"); + + rc = funcs->C_CloseSession(session); + if (rc != CKR_OK) { + show_error("C_CloseSession", rc); + return (int) rc; + } + + return rc; +} + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + CK_USER_TYPE userType = CKU_USER; + CK_SLOT_ID slot_id = 0; + CK_RV rc = 0; + char *pass = NULL; + int i; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-pass") == 0) { + ++i; + pass = argv[i]; + } else if (strcmp(argv[i], "-slot") == 0) { + ++i; + slot_id = atoi(argv[i]); + } else if (strcmp(argv[i], "-user") == 0) { + userType = CKU_USER; + if (pass == NULL) + pass = "12345678"; + } else if (strcmp(argv[i], "-so") == 0) { + userType = CKU_SO; + if (pass == NULL) + pass = "87654321"; + } else { + printf + ("usage: %s [-slot ] [-h] [-pass passwd] [-user|-so]\n\n", + argv[0]); + printf("By default, Slot #%lu is used, as user\n\n", SLOT_ID); + return -1; + } + } + + if (slot_id != SLOT_ID) + printf("Using user specified slot %lu.\n", slot_id); + + rc = do_GetFunctionList(); + if (funcs == NULL) + return -1; + + memset(&cinit_args, 0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + rc = funcs->C_Initialize(&cinit_args); + if (rc != CKR_OK) { + show_error("C_Initialize", rc); + return -1; + } + + rc = do_LoginLogout(funcs, slot_id, userType, pass); + + funcs->C_Finalize(NULL); + + return rc; +} diff --git a/testcases/login/login.mk b/testcases/login/login.mk new file mode 100644 index 0000000..165350a --- /dev/null +++ b/testcases/login/login.mk @@ -0,0 +1,30 @@ +noinst_PROGRAMS += \ + testcases/login/login testcases/login/init_tok \ + testcases/login/set_pin testcases/login/init_pin \ + testcases/login/digest_init testcases/login/login_flags_test + +testcases_login_login_CFLAGS = ${testcases_inc} +testcases_login_login_LDADD = testcases/common/libcommon.la +testcases_login_login_SOURCES = \ + usr/lib/common/p11util.c testcases/login/login.c + +testcases_login_init_tok_CFLAGS = ${testcases_inc} +testcases_login_init_tok_LDADD = testcases/common/libcommon.la +testcases_login_init_tok_SOURCES = testcases/login/init_tok.c + +testcases_login_set_pin_CFLAGS = ${testcases_inc} +testcases_login_set_pin_LDADD = testcases/common/libcommon.la +testcases_login_set_pin_SOURCES = testcases/login/set_pin.c + +testcases_login_init_pin_CFLAGS = ${testcases_inc} +testcases_login_init_pin_LDADD = testcases/common/libcommon.la +testcases_login_init_pin_SOURCES = testcases/login/init_pin.c + +testcases_login_digest_init_CFLAGS = ${testcases_inc} +testcases_login_digest_init_LDADD = testcases/common/libcommon.la +testcases_login_digest_init_SOURCES = testcases/login/digest_init.c + +testcases_login_login_flags_test_CFLAGS = ${testcases_inc} +testcases_login_login_flags_test_LDADD = testcases/common/libcommon.la +testcases_login_login_flags_test_SOURCES = \ + usr/lib/common/p11util.c testcases/login/login_flags.c diff --git a/testcases/login/login_flags.c b/testcases/login/login_flags.c new file mode 100644 index 0000000..5fdd981 --- /dev/null +++ b/testcases/login/login_flags.c @@ -0,0 +1,308 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2002-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 + */ + +/* + * openCryptoki testcase + * - Tests the new login flags for v2.11 + * + * Feb 12, 2002 + * Kent Yoder + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" + +#define BAD_USER_PIN "534566346" +#define BAD_USER_PIN_LEN strlen(BAD_USER_PIN) + +int do_GetFunctionList(void); +int clean_up(void); + +CK_SLOT_ID slot_id; +CK_SESSION_HANDLE session_handle; +CK_SESSION_INFO si; +CK_TOKEN_INFO ti; + +void *dl_handle; + +int main(int argc, char **argv) +{ + int i; + CK_RV rc; + CK_C_INITIALIZE_ARGS initialize_args; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + /* Set default slot to 0 */ + slot_id = 0; + + /* Parse the command line */ + for (i = 1; i < argc; i++) { + if (strncmp(argv[i], "-slot", 5) == 0) { + slot_id = atoi(argv[i + 1]); + i++; + break; + } + } + + printf("Using slot %ld...\n\n", slot_id); + + if (do_GetFunctionList()) + return -1; + + /* There will be no multi-threaded Cryptoki access in this app */ + memset(&initialize_args, 0, sizeof(initialize_args)); + memset(&si, 0, sizeof(CK_SESSION_INFO)); + + if ((rc = funcs->C_Initialize(&initialize_args)) != CKR_OK) { + show_error("C_Initialize", rc); + return -1; + } + + if (get_user_pin(user_pin)) + return -1; + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + // + // Tests: + // + // 1. Open Session + // 2. Check that the session looks normal + // 3. Login/Logout as USER with correct PIN + // 4. Login as USER with an incorrect PIN + // 5. Check that USER PIN COUNT LOW set + // 6. Login as USER with an incorrect PIN + // 7. Check that USER PIN LAST TRY set + // 8. Login correctly + // 9. Check that flags are reset + // 10. Try to set a new PIN, but with newPIN == oldPIN + // 11. Check that we get CKR_PIN_INVALID + // 12. Login as USER with an incorrect PIN + // 13. Check that USER PIN COUNT LOW set + // 14. Login as USER with an incorrect PIN + // 15. Check that USER PIN LAST TRY set + // 16. Login as USER with incorrect PIN + // 17. Check that USER PIN LOCKED set + // + + /* 1. Open a session with the token */ + if ((rc = funcs->C_OpenSession(slot_id, + (CKF_SERIAL_SESSION | CKF_RW_SESSION), + NULL_PTR, + NULL_PTR, &session_handle)) != CKR_OK) { + show_error("C_OpenSession #1", rc); + goto done; + } + + + if ((rc = funcs->C_GetSessionInfo(session_handle, &si)) != CKR_OK) { + show_error("C_GetSessionInfo #1", rc); + goto session_close; + } + + /* 2. Test the slot_id change. This used to be hard coded to 1. + * It should now be the slot number of the token we're using + */ + if (si.slotID != slot_id) { + printf("Test #2 failed. Slot ID was %ld, expected %ld\n", si.slotID, + slot_id); + goto session_close; + } + + if ((rc = funcs->C_GetTokenInfo(slot_id, &ti)) != CKR_OK) { + show_error("C_GetTokenInfo #2", rc); + goto session_close; + } + + if (ti.flags & CKF_USER_PIN_LOCKED) { + printf("The USER's PIN is locked for the token in slot %ld.\n" + "Please reset the USER's PIN and re-run this test.\n", slot_id); + goto session_close; + } + + if (!(ti.flags & CKF_TOKEN_INITIALIZED)) { + printf("The token in slot %ld is uninitialized.\n", slot_id); + goto session_close; + } + // 3. Login/Logout with correct USER PIN + rc = funcs->C_Login(session_handle, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + show_error("C_Login #3", rc); + goto session_close; + } + + rc = funcs->C_Logout(session_handle); + if (rc != CKR_OK) { + show_error("C_Logout #3", rc); + goto session_close; + } + // 4. Login as USER with an incorrect PIN + rc = funcs->C_Login(session_handle, CKU_USER, (CK_CHAR_PTR) BAD_USER_PIN, + BAD_USER_PIN_LEN); + if (rc != CKR_PIN_INCORRECT) { + show_error("Test #4", rc); + goto session_close; + } + + if ((rc = funcs->C_GetTokenInfo(slot_id, &ti)) != CKR_OK) { + show_error("C_GetTokenInfo #4", rc); + goto session_close; + } + // 5. Check that USER PIN COUNT LOW set + if (((ti.flags & CKF_USER_PIN_COUNT_LOW) == 0) || + (ti.flags & CKF_USER_PIN_FINAL_TRY) || + (ti.flags & CKF_USER_PIN_LOCKED)) { + printf("Test #5 failed. Token flags: %p.\n", (void *) ti.flags); + goto session_close; + } + // 6. Login as USER with an incorrect PIN + rc = funcs->C_Login(session_handle, CKU_USER, (CK_CHAR_PTR) BAD_USER_PIN, + BAD_USER_PIN_LEN); + if (rc != CKR_PIN_INCORRECT) { + show_error("C_Login #6", rc); + goto session_close; + } + + if ((rc = funcs->C_GetTokenInfo(slot_id, &ti)) != CKR_OK) { + show_error("C_GetTokenInfo #6", rc); + goto session_close; + } + // 7. Check that USER PIN LAST TRY set + if ((ti.flags & CKF_USER_PIN_COUNT_LOW) || + ((ti.flags & CKF_USER_PIN_FINAL_TRY) == 0) || + (ti.flags & CKF_USER_PIN_LOCKED)) { + printf("Test #7 failed. Token flags: %p.\n", (void *) ti.flags); + goto session_close; + } + // 8. Login correctly + rc = funcs->C_Login(session_handle, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + show_error("C_Login #8", rc); + goto session_close; + } + + if ((rc = funcs->C_GetTokenInfo(slot_id, &ti)) != CKR_OK) { + show_error("C_GetTokenInfo #8", rc); + goto session_close; + } + // 9. Check that flags are reset + if ((ti.flags & CKF_USER_PIN_COUNT_LOW) || + (ti.flags & CKF_USER_PIN_FINAL_TRY) || + (ti.flags & CKF_USER_PIN_LOCKED)) { + + printf("Test #9 failed. Token flags: %p.\n", (void *) ti.flags); + goto session_close; + } + // 10. Try to set a new PIN, but with newPIN == oldPIN + // 11. Check that we get CKR_PIN_INVALID + rc = funcs->C_SetPIN(session_handle, user_pin, user_pin_len, + user_pin, user_pin_len); + if (rc != CKR_PIN_INVALID) { + show_error("Test #10", rc); + goto session_close; + } + // 12. Login as USER with an incorrect PIN + rc = funcs->C_Login(session_handle, CKU_USER, (CK_CHAR_PTR) BAD_USER_PIN, + BAD_USER_PIN_LEN); + if (rc != CKR_PIN_INCORRECT) { + show_error("C_Login #12", rc); + goto session_close; + } + + if ((rc = funcs->C_GetTokenInfo(slot_id, &ti)) != CKR_OK) { + show_error("C_GetTokenInfo #12", rc); + goto session_close; + } + // 13. Check that USER PIN COUNT LOW set + if (((ti.flags & CKF_USER_PIN_COUNT_LOW) == 0) || + (ti.flags & CKF_USER_PIN_FINAL_TRY) || + (ti.flags & CKF_USER_PIN_LOCKED)) { + printf("Test #13 failed. Token flags: %p.\n", (void *) ti.flags); + goto session_close; + } + // 14. Login as USER with an incorrect PIN + rc = funcs->C_Login(session_handle, CKU_USER, (CK_CHAR_PTR) BAD_USER_PIN, + BAD_USER_PIN_LEN); + if (rc != CKR_PIN_INCORRECT) { + show_error("C_Login #14", rc); + goto session_close; + } + + if ((rc = funcs->C_GetTokenInfo(slot_id, &ti)) != CKR_OK) { + show_error("C_GetTokenInfo #14", rc); + goto session_close; + } + // 15. Check that USER PIN LAST TRY set + if ((ti.flags & CKF_USER_PIN_COUNT_LOW) || + ((ti.flags & CKF_USER_PIN_FINAL_TRY) == 0) || + (ti.flags & CKF_USER_PIN_LOCKED)) { + printf("Test #15 failed. Token flags: %p.\n", (void *) ti.flags); + goto session_close; + } + + // 16. Login as USER with incorrect PIN + rc = funcs->C_Login(session_handle, CKU_USER, (CK_CHAR_PTR) BAD_USER_PIN, + BAD_USER_PIN_LEN); + if (rc != CKR_PIN_INCORRECT) { + show_error("C_Login #16", rc); + goto session_close; + } + + if ((rc = funcs->C_GetTokenInfo(slot_id, &ti)) != CKR_OK) { + show_error("C_GetTokenInfo #16", rc); + goto session_close; + } + // 17. Check that USER PIN LOCKED set + if ((ti.flags & CKF_USER_PIN_COUNT_LOW) || + (ti.flags & CKF_USER_PIN_FINAL_TRY) || + ((ti.flags & CKF_USER_PIN_LOCKED) == 0)) { + + printf("Test #17 failed. Token flags: %p.\n", (void *) ti.flags); + goto session_close; + } + + printf("Tests succeeded. USER PIN is now locked for slot %ld.\n" + "Re-running this test should return CKR_PIN_LOCKED.\n" + "To unlock this slot, run the init_tok testcase on the slot.\n", + slot_id); + +session_close: + + /* Close the session */ + if ((rc = funcs->C_CloseSession(session_handle)) != CKR_OK) + show_error("C_CloseSession", rc); + +done: + /* Call C_Finalize and dlclose the library */ + return clean_up(); +} + +int clean_up(void) +{ + CK_RV rc; + + if ((rc = funcs->C_Finalize(NULL)) != CKR_OK) + show_error("C_Finalize", rc); + + /* Decrement the reference count to libopencryptoki.so */ + dlclose(dl_handle); + + return rc; +} diff --git a/testcases/login/login_test.sh b/testcases/login/login_test.sh new file mode 100755 index 0000000..833fd55 --- /dev/null +++ b/testcases/login/login_test.sh @@ -0,0 +1,179 @@ +#!/bin/sh +# +# 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 +# +# login_test.sh +# +# Kent Yoder +# +# usage: login_test.sh -slot [n] +# +# By default, slot 0 is used. This script will run through several +# scenarios WRT login's to the PKCS#11 API. It expects a completely +# uninitialized token, such as right after installation. It is +# expected that the token will be reinitialized after running this test. +# +set -x + + +DEFAULT_SO_PIN=${P11_SO_PWD:=87654321} +DEFAULT_USER_PIN=${P11_USER_PWD:=12345678} + +NEW_USER_PIN1=${NEW_P11_USER_PWD:=userPW1} +NEW_USER_PIN2=${NEW_P11_USER_PWD2:=userPW2} +NEW_SO_PIN1=${NEW_P11_SO_PWD:=so_PW1} +NEW_SO_PIN2=${NEW_P11_SO_PWD2:=so_PW2} +BAD_PIN=bad + +CKR_PIN_EXPIRED=163 +CKR_PIN_INVALID=161 +CKR_PIN_INCORRECT=160 +CKR_USER_PIN_NOT_INITIALIZED=2 +CKR_OK=0 + +#init the token +./init_tok $* -pass $DEFAULT_SO_PIN +if test $? -ne $CKR_OK; then + echo "TEST FAIL" + exit +fi + +# Try to login as SO with a bad pass +./login $* -so -pass bad +if test $? -ne $CKR_PIN_INCORRECT; then + echo "TEST FAIL" + exit +fi + +# Try to login as USER before init +./login $* -user -pass $DEFAULT_USER_PIN +if test $? -ne $CKR_USER_PIN_NOT_INITIALIZED; then + echo "TEST FAIL" + exit +fi + +# Try a correct SO login, should SUCCEED +./login $* -so -pass $DEFAULT_SO_PIN +if test $? -ne $CKR_OK; then + echo "TEST FAIL" + exit +fi + +# Try to do something after logging in before PIN is set +./digest_init $* -so -pass $DEFAULT_SO_PIN +if test $? -ne $CKR_PIN_EXPIRED; then + echo "TEST FAIL" + exit +fi + +# Try to set pin to the default value +./set_pin $* -so -old $DEFAULT_SO_PIN -new $DEFAULT_SO_PIN +if test $? -ne $CKR_PIN_INVALID; then + echo "TEST FAIL" + exit +fi + +# Do a legitimate pin set for the SO +./set_pin $* -so -old $DEFAULT_SO_PIN -new $NEW_SO_PIN1 +if test $? -ne $CKR_OK; then + echo "TEST FAIL" + exit +fi + +# Init the USER PIN +./init_pin $* -sopass $NEW_SO_PIN1 -userpass $DEFAULT_USER_PIN +if test $? -ne $CKR_OK; then + echo "TEST_FAIL" + exit +fi + +# Try to set pin to the default value +./set_pin $* -user -old $DEFAULT_USER_PIN -new $DEFAULT_USER_PIN +if test $? -ne $CKR_PIN_INVALID; then + echo "TEST FAIL" + exit +fi + +# Do a legitimate pin set for the USER +./set_pin $* -user -old $DEFAULT_USER_PIN -new $NEW_USER_PIN1 +if test $? -ne $CKR_OK; then + echo "TEST FAIL" + exit +fi + +# login with the good pins +./login $* -so -pass $NEW_SO_PIN1 +if test $? -ne $CKR_OK; then + echo "TEST FAIL" + exit +fi + +./login $* -user -pass $NEW_USER_PIN1 +if test $? -ne $CKR_OK; then + echo "TEST FAIL" + exit +fi + +# Try login with bad pins +./login $* -so -pass $BAD_PIN +if test $? -ne $CKR_PIN_INCORRECT; then + echo "TEST FAIL" + exit +fi + +./login $* -user -pass $BAD_PIN +if test $? -ne $CKR_PIN_INCORRECT; then + echo "TEST FAIL" + exit +fi + +# try to change both pins back to defaults (should fail) +./set_pin $* -so -old $NEW_SO_PIN1 -new $DEFAULT_SO_PIN +if test $? -ne $CKR_PIN_INVALID; then + echo "TEST FAIL" + exit +fi + +./set_pin $* -user -old $NEW_USER_PIN1 -new $DEFAULT_USER_PIN +if test $? -ne $CKR_PIN_INVALID; then + echo "TEST FAIL" + exit +fi + +# change both pins legitimately +./set_pin $* -so -old $NEW_SO_PIN1 -new $NEW_SO_PIN2 +if test $? -ne $CKR_OK; then + echo "TEST FAIL" + exit +fi + +./set_pin $* -user -old $NEW_USER_PIN1 -new $NEW_USER_PIN2 +if test $? -ne $CKR_OK; then + echo "TEST FAIL" + exit +fi + +# login with new passes +./login $* -so -pass $NEW_SO_PIN2 +if test $? -ne $CKR_OK; then + echo "TEST FAIL" + exit +fi + +./login $* -user -pass $NEW_USER_PIN2 +if test $? -ne $CKR_OK; then + echo "TEST FAIL" + exit +fi + +echo "TEST SUCCEEDED" + +echo "Currently the SO Pin is set to \"$NEW_SO_PIN2\"" +echo "Currently the USER Pin is set to \"$NEW_USER_PIN2\"" + +exit 0 diff --git a/testcases/login/set_pin.c b/testcases/login/set_pin.c new file mode 100644 index 0000000..786ba71 --- /dev/null +++ b/testcases/login/set_pin.c @@ -0,0 +1,138 @@ +/* + * 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 + */ + + +#include +#include +#include +#include + +#include +#include + +#include "pkcs11types.h" + +#include "regress.h" +#include "common.c" + +int do_GetFunctionList(void); + +int do_SetPIN(CK_FUNCTION_LIST * funcs, CK_SLOT_ID slot_id, + CK_USER_TYPE userType, char *old, char *new) +{ + CK_RV rc; + CK_SESSION_HANDLE session; + CK_FLAGS flags = CKF_SERIAL_SESSION; + + flags |= CKF_RW_SESSION; + + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session); + if (rc != CKR_OK) { + show_error("C_OpenSession", rc); + return rc; + } + + rc = funcs->C_Login(session, userType, (CK_CHAR_PTR) old, strlen(old)); + if (rc != CKR_OK) { + show_error("C_Login", rc); + return rc; + } + + printf("Logged in successfully, calling C_SetPIN...\n"); + + rc = funcs->C_SetPIN(session, (CK_CHAR_PTR) old, strlen(old), + (CK_CHAR_PTR) new, strlen(new)); + if (rc != CKR_OK) { + show_error("C_SetPIN", rc); + funcs->C_Logout(session); + funcs->C_CloseSession(session); + return rc; + } else { + printf("Success.\n"); + } + + rc = funcs->C_Logout(session); + if (rc != CKR_OK) { + show_error("C_Logout", rc); + return rc; + } + + printf("Logged out.\n"); + + rc = funcs->C_CloseSession(session); + if (rc != CKR_OK) { + show_error("C_CloseSession", rc); + return rc; + } + + return rc; +} + +void set_pin_usage(char *argv0) +{ + printf("usage: %s [-slot ] [-h] [-user|-so] -old pass -new pass\n\n", + argv0); + printf("By default, Slot #%lu is used, as user\n\n", SLOT_ID); + exit(-1); +} + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + CK_USER_TYPE userType = CKU_USER; + CK_RV rc = 0; + CK_SLOT_ID slot_id = 0; + char *old = NULL, *new = NULL; + int i; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-old") == 0) { + ++i; + old = argv[i]; + } else if (strcmp(argv[i], "-new") == 0) { + ++i; + new = argv[i]; + } else if (strcmp(argv[i], "-slot") == 0) { + ++i; + slot_id = atoi(argv[i]); + } else if (strcmp(argv[i], "-so") == 0) { + userType = CKU_SO; + } else if (strcmp(argv[i], "-user") == 0) { + continue; + } else { + set_pin_usage(argv[0]); + } + } + + if (!old || !new) + set_pin_usage(argv[0]); + + if (slot_id != SLOT_ID) + printf("Using user specified slot %lu.\n", slot_id); + + rc = do_GetFunctionList(); + if (funcs == NULL) + return -1; + + memset(&cinit_args, 0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + rc = funcs->C_Initialize(&cinit_args); + if (rc != CKR_OK) { + show_error("C_Initialize", rc); + return -1; + } + + rc = do_SetPIN(funcs, slot_id, userType, old, new); + + funcs->C_Finalize(NULL); + + return rc; +} diff --git a/testcases/misc_tests/README b/testcases/misc_tests/README new file mode 100644 index 0000000..39a817c --- /dev/null +++ b/testcases/misc_tests/README @@ -0,0 +1,106 @@ +Miscellaneous tests + +obj_mgmt_tests + This testsuite performs various object management tasks. + + The do_CreateTokenObjects() and do_HWFeatureSearch() functions + create token objects and by default or skipped. + To include these two functions, use the "-noskip" option when issuing + the tests. + +spinlock_tests.sh + Tests the two spinlocks: /var/lock/LCK..opencryptoki which is used + when accessing shared memory for pkcsslotd and pkcs#11 api calls. + And /var/lock/LOCK..opencryptoki_stdll which is used when accessing + global shared memory in the STDLLs. + + The file, spinlock_tests.sh is a bash script that creates a + number of child processes. Each child process runs spinlock_child.sh + script. + + Quick Start Info: + + Execute testcase by, + spinlock_tests.sh -p -l -s + p: the amount of child processes to create + l: the number of times each child process executes + obj_mgmt_lock_tests + s: the slot to test + + For example, + spinlock_tests.sh -p 15 -l 5 -s 1 + + Additional Info: + + obj_mgmt_lock_tests + spinlock_child.sh + + The file, spinlock_tests.sh is a bash script that creates a + number of child processes. Each child process runs spinlock_child.sh + script. + + The file, spinlock_child.sh is a bash script that executes + obj_mgmt_lock_tests a number of times. + + obj_mgmt_lock_tests was derived from obj_mgmt.c. + It contains several api calls that will want to acquire the various + spinlocks. + + Usage: spinlock_child.sh -l -s + l: the number of times each child process executes obj_mgmt_lock_tests + s: the slot to test + + Usage: obj_mgmt_lock_tests -slot + +threadmkobj + TODO: To be tested. + +speed + TODO: To be tested. + The speed program is a performance oriented test program. It times + certain operations over multiple runs, and gives min, max, and average + times for these operations. Performace tests are run for: 2048 bit + RSA keygen, 10½4 bit RSA keygen, 1024 bit RSA signature generate, + 1024 bit RSA signature verify, triple DES encrypt/decrypt on a + 10K message, and SHA1 on a 10K message. + +tok_obj + TODO: To be tested. + This program is used to test object creation and modification. + The token does not need to be intitialized to use this application. + When run, a user is presented with a menu. From there, the user + must initialize the token and set the user PIN if this has not been + done previously. The menu choice for setting the user PIN sets it + to "12345678". + +tok_des + TODO: To be tested. + +tok_rsa + TODO: To be tested. + +fork + This testcase forks off a client process in various situations, e.g + before and after initialization, before and after session creation, + and ensures that the forked client process finds an uninitialized + Opencryptoki environment and does not have access to any of the + parent's sessions or objects. Also the parents sessions and objects + must still be available and functional in the parent process after the + fork. + + As per PKCS#11 standard, a forked child process is no PKCS#11 + application after the fork, and must initialize Opencryptoki using + C_Initialize() in order to use Opencryptoki. + + Usage: fork -slot + +multi_instance + This testcase open sessions on two different tokens within one process. + It ensures that both tokens operate independently, and that sessions of + objects opened with one token can not be used with the other one. + + To test multi-instance support of a token, the Opencryptoi configuration + must be set up that way that 2 tokens of the same type (e.g. 2 EP11 + tokens) exist. + + Usage: multi_instance -slot1 -slot2 diff --git a/testcases/misc_tests/fork.c b/testcases/misc_tests/fork.c new file mode 100644 index 0000000..40a304b --- /dev/null +++ b/testcases/misc_tests/fork.c @@ -0,0 +1,357 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2020 + * + * This program is provided under the terms of the Common Public License, + * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this + * software constitutes recipient's acceptance of CPL-1.0 terms which can be + * found in the file LICENSE file or at + * https://opensource.org/licenses/cpl1.0.php + */ + +/* File: fork.c + * + * Test driver. In-depth regression test for PKCS #11 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" + +CK_BYTE user_pin[128]; +CK_ULONG user_pin_len; +CK_SLOT_ID slot_id = 0; + +int do_GetFunctionList(void); + +CK_RV do_GenerateTokenRSAKeyPair(CK_SESSION_HANDLE sess, CK_BYTE *label, + CK_ULONG bits, CK_OBJECT_HANDLE *hPubKey, + CK_OBJECT_HANDLE *hPrivKey) +{ + CK_MECHANISM mech; + CK_RV rv; + CK_MECHANISM_INFO rsakeygeninfo; + CK_BBOOL false = 0; + CK_BYTE pub_exp[] = { 0x1, 0x0, 0x1 }; + CK_ATTRIBUTE pub_tmpl[] = { + {CKA_MODULUS_BITS, &bits, sizeof(bits)}, + {CKA_PUBLIC_EXPONENT, &pub_exp, sizeof(pub_exp)}, + {CKA_LABEL, label, (CK_ULONG) strlen((char *) label) + 1}, + {CKA_TOKEN, &false, sizeof(CK_BBOOL)} + }; + CK_ATTRIBUTE priv_tmpl[] = { + {CKA_LABEL, label, (CK_ULONG) strlen((char *) label) + 1}, + {CKA_TOKEN, &false, sizeof(CK_BBOOL)} + }; + + rv = funcs->C_GetMechanismInfo(slot_id, CKM_RSA_PKCS_KEY_PAIR_GEN, + &rsakeygeninfo); + if (rv != CKR_OK) { + testcase_fail("C_GetMechanismInfo(CKM_RSA_PKCS_KEY_PAIR_GEN) rc = %s", p11_get_ckr(rv)); + return rv;; + } + + mech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rv = funcs->C_GenerateKeyPair(sess, &mech, pub_tmpl, 4, priv_tmpl, 2, + hPubKey, hPrivKey); + if (rv != CKR_OK) { + testcase_fail("C_GenerateKeyPair rc = %s", p11_get_ckr(rv)); + return rv; + } + return CKR_OK; +} + +CK_RV do_fork(CK_SESSION_HANDLE parent_session, CK_OBJECT_HANDLE parent_object) +{ + pid_t child_pid; + int status = 1; + CK_FLAGS flags; + CK_SESSION_HANDLE session; + CK_RV rv; + CK_C_INITIALIZE_ARGS cinit_args; + CK_OBJECT_HANDLE hPubKey, hPrivKey; + + child_pid = fork(); + if (child_pid != 0) { + // parent process: wait until child exits + waitpid(child_pid, &status, 0); + return status; + } + + // child process flows here + testcase_setup(0); + t_ran = 0; + t_passed = 0; + t_skipped = 0; + t_failed = 0; + testcase_begin(".. in client process: %u", getpid()); + + // Ensure that OCK is not initialized in this fork now + testcase_new_assertion(); + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rv = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session); + if (rv != CKR_CRYPTOKI_NOT_INITIALIZED) { + testcase_fail("C_OpenSession (client) (expected CKR_CRYPTOKI_NOT_INITIALIZED) rc = %s", p11_get_ckr(rv)); + goto out; + } + testcase_pass("C_OpenSession (client)"); + + // Initialize + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + if ((rv = funcs->C_Initialize(&cinit_args))) { + testcase_fail("C_Initialize (client) rc = %s", p11_get_ckr(rv)); + goto out; + } + + // Check access to parent session + if (parent_session != CK_INVALID_HANDLE) { + testcase_new_assertion(); + rv = funcs->C_CloseSession(parent_session); + if (rv != CKR_SESSION_HANDLE_INVALID) { + testcase_fail("C_CloseSession (client) (expected CKR_SESSION_HANDLE_INVALID) rc = %s", p11_get_ckr(rv)); + goto close_session; + } + testcase_pass("C_CloseSession got expected error (client)"); + } + + // Open a session + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rv = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session); + if (rv != CKR_OK) { + testcase_fail("C_OpenSession (client) rc = %s", p11_get_ckr(rv)); + goto finalize; + } + + // Log in + rv = funcs->C_Login(session, CKU_USER, user_pin, user_pin_len); + if (rv != CKR_OK) { + testcase_fail("C_Login (client) rc = %s", p11_get_ckr(rv)); + goto close_session; + } + + // Check access to parent object + if (parent_object != CK_INVALID_HANDLE) { + testcase_new_assertion(); + rv = funcs->C_DestroyObject(session, parent_object); + if (rv != CKR_OBJECT_HANDLE_INVALID) { + testcase_fail("C_DestroyObject (client) (expected CKR_OBJECT_HANDLE_INVALID) rc = %s", p11_get_ckr(rv)); + goto close_session; + } + testcase_pass("C_DestroyObject got expected error (client)"); + } + + // generate a key pair + rv = do_GenerateTokenRSAKeyPair(session, (CK_BYTE *)"RSA-1024-CLIENT", + 1024, &hPubKey, &hPrivKey); + if (rv != CKR_OK) { + testcase_fail("do_GenerateTokenRSAKeyPair (client) rc = %s", p11_get_ckr(rv)); + goto close_session; + } + + rv = funcs->C_DestroyObject(session, hPubKey); + if (rv != CKR_OK) { + testcase_fail("C_DestroyObject (client) rc = %s", p11_get_ckr(rv)); + goto close_session; + } + + rv = funcs->C_DestroyObject(session, hPrivKey); + if (rv != CKR_OK) { + testcase_fail("C_DestroyObject (client) rc = %s", p11_get_ckr(rv)); + goto close_session; + } + + rv = 0; +close_session: + rv = funcs->C_CloseSession(session); + if (rv != CKR_OK) { + testcase_fail("C_CloseSession (client) rc = %s", p11_get_ckr(rv)); + } +finalize: + rv = funcs->C_Finalize(NULL); + if (rv != CKR_OK) { + testcase_fail("C_Finalize (client) rc = %s", p11_get_ckr(rv)); + goto out; + } +out: + + testcase_print_result(); + exit(rv); +} + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + int i, ret = 1; + CK_RV rv; + CK_SESSION_HANDLE session; + CK_FLAGS flags; + CK_OBJECT_HANDLE hPubKey, hPrivKey; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-slot") == 0) { + ++i; + slot_id = atoi(argv[i]); + } + + if (strcmp(argv[i], "-h") == 0) { + printf("usage: %s [-slot ] [-h]\n\n", argv[0]); + printf("By default, Slot #1 is used\n\n"); + return -1; + } + } + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + printf("Using slot #%lu...\n\n", slot_id); + + rv = do_GetFunctionList(); + if (rv != TRUE) { + testcase_fail("do_GetFunctionList() rc = %s", p11_get_ckr(rv)); + goto out; + } + + testcase_setup(0); + testcase_begin("Starting... Parent process: %u", getpid()); + + // Test fork before C_Initialize + testcase_new_assertion(); + rv = do_fork(CK_INVALID_HANDLE, CK_INVALID_HANDLE); + if (rv != CKR_OK) { + testcase_fail("do_fork() before C_Initialize rc = %s", p11_get_ckr(rv)); + goto out; + } + testcase_pass("do_fork() before C_Initialize"); + + // Initialize + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + if ((rv = funcs->C_Initialize(&cinit_args))) { + testcase_fail("C_Initialize (parent) rc = %s", p11_get_ckr(rv)); + goto out; + } + + // Test fork after C_Initialize + testcase_new_assertion(); + rv = do_fork(CK_INVALID_HANDLE, CK_INVALID_HANDLE); + if (rv != CKR_OK) { + testcase_fail("do_fork() after C_Initialize rc = %s", p11_get_ckr(rv)); + goto out; + } + testcase_pass("do_fork() after C_Initialize"); + + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rv = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session); + if (rv != CKR_OK) { + testcase_fail("C_OpenSession (parent) rc = %s", p11_get_ckr(rv)); + goto finalize; + } + + rv = funcs->C_Login(session, CKU_USER, user_pin, user_pin_len); + if (rv != CKR_OK) { + testcase_fail("C_Login (parent) rc = %s", p11_get_ckr(rv)); + goto close_session; + } + + // Test fork after C_OpenSession/C_Login + testcase_new_assertion(); + rv = do_fork(session, CK_INVALID_HANDLE); + if (rv != CKR_OK) { + testcase_fail("do_fork() after C_OpenSession rc = %s", p11_get_ckr(rv)); + goto out; + } + testcase_pass("do_fork() after C_OpenSession"); + + // generate a key pair + rv = do_GenerateTokenRSAKeyPair(session, (CK_BYTE *)"RSA-1024-PARENT", + 1024, &hPubKey, &hPrivKey); + if (rv != CKR_OK) { + testcase_fail("do_GenerateTokenRSAKeyPair (parent) rc = %s", p11_get_ckr(rv)); + goto close_session; + } + + // Test fork after Key Gen + testcase_new_assertion(); + rv = do_fork(session, hPrivKey); + if (rv != CKR_OK) { + testcase_fail("do_fork() after KeyGen rc = %s", p11_get_ckr(rv)); + goto out; + } + testcase_pass("do_fork() after KeyGen"); + + rv = funcs->C_DestroyObject(session, hPubKey); + if (rv != CKR_OK) { + testcase_fail("C_DestroyObject (parent) rc = %s", p11_get_ckr(rv)); + goto close_session; + } + + rv = funcs->C_DestroyObject(session, hPrivKey); + if (rv != CKR_OK) { + testcase_fail("C_DestroyObject (parent) rc = %s", p11_get_ckr(rv)); + goto close_session; + } + + rv = funcs->C_CloseSession(session); + if (rv != CKR_OK) { + testcase_fail("C_CloseSession (parent) rc = %s", p11_get_ckr(rv)); + goto finalize; + } + + // Test fork before C_Finalize + testcase_new_assertion(); + rv = do_fork(CK_INVALID_HANDLE, CK_INVALID_HANDLE); + if (rv != CKR_OK) { + testcase_fail("do_fork() before C_Finalize rc = %s", p11_get_ckr(rv)); + goto out; + } + testcase_pass("do_fork() before C_Finalize"); + + rv = funcs->C_Finalize(NULL); + if (rv != CKR_OK) { + testcase_fail("C_Finalize (parent) rc = %s", p11_get_ckr(rv)); + goto out; + } + + // Test fork after C_Finalize + testcase_new_assertion(); + rv = do_fork(CK_INVALID_HANDLE, CK_INVALID_HANDLE); + if (rv != CKR_OK) { + testcase_fail("do_fork() after C_Finalize rc = %s", p11_get_ckr(rv)); + goto out; + } + testcase_pass("do_fork() after C_Finalize"); + + ret = 0; + goto out; + +close_session: + rv = funcs->C_CloseSession(session); + if (rv != CKR_OK) { + testcase_fail("C_CloseSession (parent) rc = %s", p11_get_ckr(rv)); + ret = 1; + } +finalize: + rv = funcs->C_Finalize(NULL); + if (rv != CKR_OK) { + testcase_fail("C_Finalize (parent) rc = %s", p11_get_ckr(rv)); + ret = 1; + } +out: + testcase_print_result(); + return ret; +} diff --git a/testcases/misc_tests/misc_tests.mk b/testcases/misc_tests/misc_tests.mk new file mode 100644 index 0000000..0e0ac22 --- /dev/null +++ b/testcases/misc_tests/misc_tests.mk @@ -0,0 +1,57 @@ +noinst_PROGRAMS += \ + testcases/misc_tests/obj_mgmt_tests \ + testcases/misc_tests/obj_mgmt_lock_tests \ + testcases/misc_tests/speed testcases/misc_tests/threadmkobj \ + testcases/misc_tests/tok_obj testcases/misc_tests/tok_rsa \ + testcases/misc_tests/tok_des \ + testcases/misc_tests/fork testcases/misc_tests/multi_instance \ + testcases/misc_tests/obj_lock + +testcases_misc_tests_obj_mgmt_tests_CFLAGS = ${testcases_inc} +testcases_misc_tests_obj_mgmt_tests_LDADD = \ + testcases/common/libcommon.la +testcases_misc_tests_obj_mgmt_tests_SOURCES = \ + testcases/misc_tests/obj_mgmt.c + +testcases_misc_tests_obj_mgmt_lock_tests_CFLAGS = ${testcases_inc} +testcases_misc_tests_obj_mgmt_lock_tests_LDADD = \ + testcases/common/libcommon.la +testcases_misc_tests_obj_mgmt_lock_tests_SOURCES = \ + testcases/misc_tests/obj_mgmt_lock.c + +testcases_misc_tests_speed_CFLAGS = ${testcases_inc} +testcases_misc_tests_speed_LDADD = testcases/common/libcommon.la +testcases_misc_tests_speed_SOURCES = \ + usr/lib/common/p11util.c testcases/misc_tests/speed.c + +testcases_misc_tests_threadmkobj_CFLAGS = ${testcases_inc} +testcases_misc_tests_threadmkobj_LDADD = testcases/common/libcommon.la +testcases_misc_tests_threadmkobj_SOURCES = \ + usr/lib/common/p11util.c testcases/misc_tests/threadmkobj.c + +testcases_misc_tests_tok_obj_CFLAGS = ${testcases_inc} +testcases_misc_tests_tok_obj_LDADD = testcases/common/libcommon.la +testcases_misc_tests_tok_obj_SOURCES = \ + usr/lib/common/p11util.c testcases/misc_tests/tok_obj.c + +testcases_misc_tests_tok_rsa_CFLAGS = ${testcases_inc} +testcases_misc_tests_tok_rsa_LDADD = testcases/common/libcommon.la +testcases_misc_tests_tok_rsa_SOURCES = testcases/misc_tests/tok_rsa.c + +testcases_misc_tests_tok_des_CFLAGS = ${testcases_inc} +testcases_misc_tests_tok_des_LDADD = testcases/common/libcommon.la +testcases_misc_tests_tok_des_SOURCES = testcases/misc_tests/tok_des.c + +testcases_misc_tests_fork_CFLAGS = ${testcases_inc} +testcases_misc_tests_fork_LDADD = testcases/common/libcommon.la +testcases_misc_tests_fork_SOURCES = testcases/misc_tests/fork.c + +testcases_misc_tests_multi_instance_CFLAGS = ${testcases_inc} +testcases_misc_tests_multi_instance_LDADD = testcases/common/libcommon.la +testcases_misc_tests_multi_instance_SOURCES = \ + testcases/misc_tests/multi_instance.c + +testcases_misc_tests_obj_lock_CFLAGS = ${testcases_inc} +testcases_misc_tests_obj_lock_LDADD = testcases/common/libcommon.la +testcases_misc_tests_obj_lock_SOURCES = \ + testcases/misc_tests/obj_lock.c \ No newline at end of file diff --git a/testcases/misc_tests/multi_instance.c b/testcases/misc_tests/multi_instance.c new file mode 100644 index 0000000..c965b44 --- /dev/null +++ b/testcases/misc_tests/multi_instance.c @@ -0,0 +1,410 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2020 + * + * This program is provided under the terms of the Common Public License, + * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this + * software constitutes recipient's acceptance of CPL-1.0 terms which can be + * found in the file LICENSE file or at + * https://opensource.org/licenses/cpl1.0.php + */ + +/* File: multi_instance.c + * + * Test driver. In-depth regression test for PKCS #11 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" + + +int do_GetFunctionList(void); + +CK_RV do_GenerateTokenRSAKeyPair(CK_SLOT_ID slot_id, CK_SESSION_HANDLE sess, + CK_BYTE *label, CK_ULONG bits, + CK_OBJECT_HANDLE *hPubKey, + CK_OBJECT_HANDLE *hPrivKey) +{ + CK_MECHANISM mech; + CK_RV rv; + CK_MECHANISM_INFO rsakeygeninfo; + CK_BBOOL false = 0; + CK_BYTE pub_exp[] = { 0x1, 0x0, 0x1 }; + CK_ATTRIBUTE pub_tmpl[] = { + {CKA_MODULUS_BITS, &bits, sizeof(bits)}, + {CKA_PUBLIC_EXPONENT, &pub_exp, sizeof(pub_exp)}, + {CKA_LABEL, label, (CK_ULONG) strlen((char *) label) + 1}, + {CKA_TOKEN, &false, sizeof(CK_BBOOL)} + }; + CK_ATTRIBUTE priv_tmpl[] = { + {CKA_LABEL, label, (CK_ULONG) strlen((char *) label) + 1}, + {CKA_TOKEN, &false, sizeof(CK_BBOOL)} + }; + + rv = funcs->C_GetMechanismInfo(slot_id, CKM_RSA_PKCS_KEY_PAIR_GEN, + &rsakeygeninfo); + if (rv != CKR_OK) { + testcase_fail("C_GetMechanismInfo(CKM_RSA_PKCS_KEY_PAIR_GEN) rc = %s", p11_get_ckr(rv)); + return rv; + } + + mech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rv = funcs->C_GenerateKeyPair(sess, &mech, pub_tmpl, 4, priv_tmpl, 2, + hPubKey, hPrivKey); + if (rv != CKR_OK) { + testcase_fail("C_GenerateKeyPair rc = %s", p11_get_ckr(rv)); + return rv; + } + return CKR_OK; +} + + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + int i, ret = 1; + CK_BYTE user_pin[128]; + CK_ULONG user_pin_len; + CK_BYTE label[256]; + CK_SLOT_ID slot_id1 = 1, slot_id2 = 2; + CK_RV rv; + CK_SESSION_HANDLE session1 = CK_INVALID_HANDLE; + CK_SESSION_HANDLE session2 = CK_INVALID_HANDLE; + CK_FLAGS flags; + CK_OBJECT_HANDLE hPubKey1, hPrivKey1; + CK_OBJECT_HANDLE hPubKey2, hPrivKey2; + CK_BBOOL false = 0; + CK_OBJECT_HANDLE obj_list[10]; + CK_ULONG num_objs, num_wrong; + + CK_ATTRIBUTE attrs[] = { + {CKA_LABEL, label, sizeof(label) - 1}, + }; + + CK_ATTRIBUTE search_tmpl[] = { + {CKA_TOKEN, &false, sizeof(false)}, + }; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-slot1") == 0) { + ++i; + slot_id1 = atoi(argv[i]); + } + else if (strcmp(argv[i], "-slot2") == 0) { + ++i; + slot_id2 = atoi(argv[i]); + } + + if (strcmp(argv[i], "-h") == 0) { + printf("usage: %s [-slot1 ] [-slot2 ] [-h]\n\n", argv[0]); + printf("By default, Slot #1 and #2 are used\n\n"); + return -1; + } + } + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + printf("Using slots #%lu and #%lu...\n\n", slot_id1, slot_id2); + + rv = do_GetFunctionList(); + if (rv != TRUE) { + testcase_fail("do_GetFunctionList() rc = %s", p11_get_ckr(rv)); + goto out; + } + + testcase_setup(0); + testcase_begin("Starting..."); + + // Initialize + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + if ((rv = funcs->C_Initialize(&cinit_args))) { + testcase_fail("C_Initialize() rc = %s", p11_get_ckr(rv)); + goto out; + } + + // Open Session and login for slot 1 + testcase_new_assertion(); + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rv = funcs->C_OpenSession(slot_id1, flags, NULL, NULL, &session1); + if (rv != CKR_OK) { + testcase_fail("C_OpenSession() on slot %lu rc = %s", slot_id1, p11_get_ckr(rv)); + goto finalize; + } + testcase_pass("C_OpenSession on slot %lu", slot_id1); + + testcase_new_assertion(); + rv = funcs->C_Login(session1, CKU_USER, user_pin, user_pin_len); + if (rv != CKR_OK) { + testcase_fail("C_Login() on slot %lu rc = %s", slot_id1, p11_get_ckr(rv)); + goto close_session; + } + testcase_pass("C_Login as User on slot %lu", slot_id1); + + // Open Session and login for slot 2 + testcase_new_assertion(); + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rv = funcs->C_OpenSession(slot_id2, flags, NULL, NULL, &session2); + if (rv != CKR_OK) { + testcase_fail("C_OpenSession() on slot %lu rc = %s", slot_id1, p11_get_ckr(rv)); + goto close_session; + } + testcase_pass("C_OpenSession on slot %lu", slot_id2); + + testcase_new_assertion(); + rv = funcs->C_Login(session2, CKU_USER, user_pin, user_pin_len); + if (rv != CKR_OK) { + testcase_fail("C_Login() on slot %lu rc = %s\n", slot_id1, p11_get_ckr(rv)); + // ignore error + } else { + testcase_pass("C_Login as User on slot %lu", slot_id2); + } + + // generate a key pair for slot 1 + testcase_new_assertion(); + rv = do_GenerateTokenRSAKeyPair(slot_id1, session1, + (CK_BYTE *)"RSA-1024-SLOT1", + 1024, &hPubKey1, &hPrivKey1); + if (rv != CKR_OK) { + testcase_fail("do_GenerateTokenRSAKeyPair() on slot %lu rc = %s", slot_id1, p11_get_ckr(rv)); + goto close_session; + } + testcase_pass("do_GenerateTokenRSAKeyPair on slot %lu", slot_id1); + + // generate a key pair for slot 2 + testcase_new_assertion(); + rv = do_GenerateTokenRSAKeyPair(slot_id2, session2, + (CK_BYTE *)"RSA-1024-SLOT2", + 1024, &hPubKey2, &hPrivKey2); + if (rv != CKR_OK) { + testcase_fail("do_GenerateTokenRSAKeyPair() on slot %lu rc = %s", slot_id1, p11_get_ckr(rv)); + goto close_session; + } + testcase_pass("do_GenerateTokenRSAKeyPair on slot %lu", slot_id2); + + // Try to access an object from session2 in session 1 + testcase_new_assertion(); + attrs[0].ulValueLen = sizeof(label) - 1; + memset(label, 0, sizeof(label)); + rv = funcs->C_GetAttributeValue(session1, hPubKey2, attrs, 1); + if (rv == CKR_OK) { + // different sessions may use the same object handle namespace, so the + // object handle may actually be valid. Check the returned label to + // check if it is our object (expected), or the one from the other + // session + label[attrs[0].ulValueLen] = '\0'; + if (strcmp((char *)label, "RSA-1024-SLOT1") == 0) { + testcase_pass("C_GetAttributeValue for hPubKey2 on slot %lu got our object", slot_id1); + } else if (strcmp((char *)label, "RSA-1024-SLOT2") == 0) { + testcase_fail("C_GetAttributeValue for hPubKey2 on slot %lu got foreign object: %s\n", slot_id1, label); + } else { + testcase_pass("C_GetAttributeValue for hPubKey2 on slot %lu got a totaly different object", slot_id1); + } + } + else if (rv != CKR_OBJECT_HANDLE_INVALID) { + testcase_fail("C_GetAttributeValue for hPubKey2 on slot %lu rc = %s (expected CKR_OBJECT_HANDLE_INVALID)\n", slot_id1, p11_get_ckr(rv)); + } else { + testcase_pass("C_GetAttributeValue for hPubKey2 on slot %lu got expected error", slot_id1); + } + + // Try to access an object from session1 in session 2 + testcase_new_assertion(); + attrs[0].ulValueLen = sizeof(label) - 1; + memset(label, 0, sizeof(label)); + rv = funcs->C_GetAttributeValue(session2, hPubKey1, attrs, 1); + if (rv == CKR_OK) { + // different sessions may use the same object handle namespace, so the + // object handle may actually be valid. Check the returned label to + // check if it is our object (expected), or the one from the other + // session + label[attrs[0].ulValueLen] = '\0'; + if (strcmp((char *)label, "RSA-1024-SLOT2") == 0) { + testcase_pass("C_GetAttributeValue for hPubKey2 on slot %lu got our object", slot_id2); + } else if (strcmp((char *)label, "RSA-1024-SLOT1") == 0) { + testcase_fail("C_GetAttributeValue for hPubKey2 on slot %lu got foreign object: %s\n", slot_id2, label); + } else { + testcase_pass("C_GetAttributeValue for hPubKey2 on slot %lu got a totaly different object", slot_id2); + } + } + else if (rv != CKR_OBJECT_HANDLE_INVALID) { + testcase_fail("C_GetAttributeValue for hPubKey1 on slot %lu rc = %s (expected CKR_OBJECT_HANDLE_INVALID)\n", slot_id2, p11_get_ckr(rv)); + } else { + testcase_pass("C_GetAttributeValue for hPubKey1 on slot %lu got expected error", slot_id2); + } + + // Find all session object of session 1 + testcase_new_assertion(); + rv = funcs->C_FindObjectsInit(session1, search_tmpl, 1); + if (rv != CKR_OK) { + testcase_fail("C_FindObjectsInit() on slot %lu rc = %s", slot_id1, p11_get_ckr(rv)); + goto close_session; + } + + num_objs = 0; + rv = funcs->C_FindObjects(session1, obj_list, 10, &num_objs); + if (rv != CKR_OK) { + testcase_fail("C_FindObjects() on slot %lu rc = %s", slot_id1, p11_get_ckr(rv)); + goto close_session; + } + + /* We should have gotten back 2 RSA key objects */ + if (num_objs != 2) { + testcase_fail("C_FindObjects() on slot %lu found %lu objects (expected 2)\n", slot_id1, num_objs); + } else { + testcase_pass("C_FindObjects() on slot %lu found %lu objects (as expected)", slot_id1, num_objs); + } + + /* Examine the 2 objects... */ + testcase_new_assertion(); + num_wrong = 0; + for (i = 0; i < (int)num_objs; i++) { + // Check the label + attrs[0].ulValueLen = sizeof(label) - 1; + memset(label, 0, sizeof(label)); + rv = funcs->C_GetAttributeValue(session1, obj_list[i], attrs, 1); + if (rv != CKR_OK || + strcmp((char *)label, "RSA-1024-SLOT1") != 0) { + num_wrong++; + testcase_fail("C_FindObjects() on slot %lu found foreign object: %s\n", slot_id1, label); + } + } + if (num_wrong == 0) { + testcase_pass("C_FindObjects() on slot %lu found expected objects", slot_id1); + } + + rv = funcs->C_FindObjectsFinal(session1); + if (rv != CKR_OK) { + testcase_fail("C_FindObjectsFinal() on slot %lu rc = %s", slot_id1, p11_get_ckr(rv)); + goto close_session; + } + + // Find all session object of session 2 + testcase_new_assertion(); + rv = funcs->C_FindObjectsInit(session2, search_tmpl, 1); + if (rv != CKR_OK) { + testcase_fail("C_FindObjectsInit() on slot %lu rc = %s", slot_id2, p11_get_ckr(rv)); + goto close_session; + } + + num_objs = 0; + rv = funcs->C_FindObjects(session2, obj_list, 10, &num_objs); + if (rv != CKR_OK) { + testcase_fail("C_FindObjects() on slot %lu rc = %s", slot_id2, p11_get_ckr(rv)); + goto close_session; + } + + /* We should have gotten back 2 RSA key objects */ + if (num_objs != 2) { + testcase_fail("C_FindObjects() on slot %lu found %lu objects (expected 2)\n", slot_id2, num_objs); + } else { + testcase_pass("C_FindObjects() on slot %lu found %lu objects (as expected)", slot_id2, num_objs); + } + + /* Examine the 2 objects... */ + testcase_new_assertion(); + num_wrong = 0; + for (i = 0; i < (int)num_objs; i++) { + // Check the label + attrs[0].ulValueLen = sizeof(label) - 1; + 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) { + num_wrong++; + testcase_fail("C_FindObjects() on slot %lu found foreign object: %s\n", slot_id2, label); + //goto close_session; + } + } + if (num_wrong == 0) { + testcase_pass("C_FindObjects() on slot %lu found expected objects", slot_id2); + } + + rv = funcs->C_FindObjectsFinal(session2); + if (rv != CKR_OK) { + testcase_fail("C_FindObjectsFinal() on slot %lu rc = %s", slot_id2, p11_get_ckr(rv)); + goto close_session; + } + + // destroy objects for slot_id 1 + rv = funcs->C_DestroyObject(session1, hPubKey1); + if (rv != CKR_OK) { + testcase_fail("C_DestroyObject() on slot %lu rc = %s", slot_id1, p11_get_ckr(rv)); + goto close_session; + } + + rv = funcs->C_DestroyObject(session1, hPrivKey1); + if (rv != CKR_OK) { + testcase_fail("C_DestroyObject() on slot %lu rc = %s", slot_id1, p11_get_ckr(rv)); + goto close_session; + } + + // destroy objects for slot_id 2 + rv = funcs->C_DestroyObject(session2, hPubKey2); + if (rv != CKR_OK) { + testcase_fail("C_DestroyObject() on slot %lu rc = %s", slot_id2, p11_get_ckr(rv)); + goto close_session; + } + + rv = funcs->C_DestroyObject(session2, hPrivKey2); + if (rv != CKR_OK) { + testcase_fail("C_DestroyObject() on slot %lu rc = %s", slot_id2, p11_get_ckr(rv)); + goto close_session; + } + + // close all sessions of slot 1 + testcase_new_assertion(); + rv = funcs->C_CloseAllSessions(slot_id1); + if (rv != CKR_OK) { + testcase_fail("C_CloseAllSessions() on slot %lu rc = %s", slot_id1, p11_get_ckr(rv)); + goto close_session; + } + + // Close session 2 (should still be valid) + rv = funcs->C_CloseSession(session2); + if (rv != CKR_OK) { + testcase_fail("C_CloseSession() on slot %lu rc = %s", slot_id2, p11_get_ckr(rv)); + goto finalize; + } + testcase_pass("C_CloseAllSessions() on slot %lu only closed sessions of slot %lu", slot_id1, slot_id1); + + ret = 0; + goto finalize; + +close_session: + if (session1 != CK_INVALID_HANDLE) { + rv = funcs->C_CloseSession(session1); + if (rv != CKR_OK) { + testcase_fail("C_CloseSession() on slot %lu rc = %s", slot_id1, p11_get_ckr(rv)); + } + } + if (session2 != CK_INVALID_HANDLE) { + rv = funcs->C_CloseSession(session2); + if (rv != CKR_OK) { + testcase_fail("C_CloseSession() on slot %lu rc = %s", slot_id2, p11_get_ckr(rv)); + } + } +finalize: + rv = funcs->C_Finalize(NULL); + if (rv != CKR_OK) { + testcase_fail("C_Finalize() rc = %s", p11_get_ckr(rv)); + } +out: + testcase_print_result(); + return ret; +} diff --git a/testcases/misc_tests/obj_lock.c b/testcases/misc_tests/obj_lock.c new file mode 100644 index 0000000..5de20f2 --- /dev/null +++ b/testcases/misc_tests/obj_lock.c @@ -0,0 +1,412 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2020 + * + * This program is provided under the terms of the Common Public License, + * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this + * software constitutes recipient's acceptance of CPL-1.0 terms which can be + * found in the file LICENSE file or at + * https://opensource.org/licenses/cpl1.0.php + */ + +/* File: obj_lock.c + * + * Test driver. In-depth regression test for PKCS #11 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" + + +int do_GetFunctionList(void); + + +void *usage_thread_func(CK_OBJECT_HANDLE *h_key) +{ + CK_RV rv; + CK_SESSION_HANDLE session = CK_INVALID_HANDLE; + CK_FLAGS flags; + time_t t1, t2; + CK_BYTE original[1024]; + CK_BYTE cipher[1024]; + CK_BYTE clear[1024]; + CK_ULONG i, count, orig_len, cipher_len, clear_len; + CK_MECHANISM mech; + + CK_BYTE init_v[16] = { + 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0A, + 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10 + }; + + // open a session for this thread + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rv = funcs->C_OpenSession(SLOT_ID, flags, NULL, NULL, &session); + if (rv != CKR_OK) { + testcase_error("Thread %lu: C_OpenSession() rc = %s", pthread_self(), + p11_get_ckr(rv)); + goto end_thread; + } + + // clear buffers + memset(original, 0, sizeof(original)); + memset(clear, 0, sizeof(clear)); + memset(cipher, 0, sizeof(cipher)); + + // encrypt some data + orig_len = sizeof(original); + for (i = 0; i < orig_len; i++) + original[i] = i % 255; + + mech.mechanism = CKM_AES_CBC; + mech.ulParameterLen = 16; + mech.pParameter = init_v; + + testcase_begin("Thread %lu: Encrypt/Decrypt", pthread_self()); + + count = 0; + time(&t1); + do { + rv = funcs->C_EncryptInit(session, &mech, *h_key); + if (rv != CKR_OK) { + testcase_error("Thread %lu: C_EncryptInit rc=%s", pthread_self(), + p11_get_ckr(rv)); + goto close_session; + } + + cipher_len = sizeof(cipher); + rv = funcs->C_Encrypt(session, original, orig_len, cipher, &cipher_len); + if (rv != CKR_OK) { + testcase_error("Thread %lu: C_Encrypt rc=%s", pthread_self(), + p11_get_ckr(rv)); + goto close_session; + } + + rv = funcs->C_DecryptInit(session, &mech, *h_key); + if (rv != CKR_OK) { + testcase_error("Thread %lu: C_DecryptInit rc=%s", pthread_self(), + p11_get_ckr(rv)); + goto close_session; + } + + clear_len = sizeof(clear); + rv = funcs->C_Decrypt(session, cipher, cipher_len, clear, &clear_len); + if (rv != CKR_OK) { + testcase_error("Thread %lu: C_Decrypt rc=%s", pthread_self(), + p11_get_ckr(rv)); + goto close_session; + } + + time(&t2); + count++; + } while (difftime(t2, t1) < 10); + + testcase_pass("Thread %lu: ran %lu pairs of Encrypt/Decrypt", + pthread_self(), count); + +close_session: + // close the session + rv = funcs->C_CloseSession(session); + if (rv != CKR_OK) { + testcase_error("Thread %lu: C_CloseSession() rc = %s",pthread_self(), + p11_get_ckr(rv)); + } + +end_thread: + return NULL; +} + +void *alter_thread_func(CK_OBJECT_HANDLE *h_key) +{ + CK_RV rv; + CK_SESSION_HANDLE session = CK_INVALID_HANDLE; + CK_FLAGS flags; + CK_ULONG count; + time_t t1, t2; + CK_BYTE id[100]; + CK_ATTRIBUTE attribs[] = { + {CKA_ID, &id, sizeof(id)}, + }; + + // open a session for this thread + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rv = funcs->C_OpenSession(SLOT_ID, flags, NULL, NULL, &session); + if (rv != CKR_OK) { + testcase_error("Thread %lu: C_OpenSession() rc = %s", pthread_self(), + p11_get_ckr(rv)); + goto end_thread; + } + + testcase_begin("Thread %lu: Get/SetAttribute", pthread_self()); + + count = 0; + time(&t1); + do { + // Get attribute + attribs[0].ulValueLen = sizeof(id); + rv = funcs->C_GetAttributeValue(session, *h_key, attribs, 1); + if (rv != CKR_OK) { + testcase_error("Thread %lu: C_GetAttributeValue() rc = %s", pthread_self(), + p11_get_ckr(rv)); + goto close_session; + } + + // Set attribute + attribs[0].ulValueLen = sizeof(id); + memset(id, count, sizeof(id)); + + rv = funcs->C_SetAttributeValue(session, *h_key, attribs, 1); + if (rv != CKR_OK) { + testcase_error("Thread %lu: C_SetAttributeValue() rc = %s", pthread_self(), + p11_get_ckr(rv)); + goto close_session; + } + + time(&t2); + count++; + } while (difftime(t2, t1) < 10); + + testcase_pass("Thread %lu: ran %lu pairs of Get/SetAttribute", + pthread_self(), count); + +close_session: + // close the session + rv = funcs->C_CloseSession(session); + if (rv != CKR_OK) { + testcase_error("Thread %lu: C_CloseSession() rc = %s",pthread_self(), + p11_get_ckr(rv)); + } + +end_thread: + return NULL; +} + +int generate_key(CK_SESSION_HANDLE session, + CK_ULONG key_len, CK_BBOOL token_obj, + CK_MECHANISM * mechkey, CK_OBJECT_HANDLE * h_key) +{ + CK_CHAR label[] = "OBJ_LOCK_TEST_KEY"; + CK_BYTE id[100] = { 0 }; + CK_ATTRIBUTE key_gen_tmpl[] = { + {CKA_VALUE_LEN, &key_len, sizeof(CK_ULONG)}, + {CKA_TOKEN, &token_obj, sizeof(token_obj)}, + {CKA_ID, id, sizeof(id)}, + {CKA_LABEL, label, sizeof(label) - 1}, + }; + + CK_RV rc = funcs->C_GenerateKey(session, mechkey, key_gen_tmpl, 4, h_key); + + return rc; +} + +int find_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE * h_key) +{ + CK_RV rc; + CK_CHAR label[] = "OBJ_LOCK_TEST_KEY"; + CK_BBOOL true = TRUE; + CK_OBJECT_HANDLE obj_list[1] = { 0 }; + CK_ULONG find_count = 0; + CK_ATTRIBUTE find_tmpl[] = { + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_LABEL, label, sizeof(label) - 1}, + }; + + rc = funcs->C_FindObjectsInit(session, find_tmpl, 2); + if (rc != CKR_OK) + return rc; + + rc = funcs->C_FindObjects(session, obj_list, 1, &find_count); + if (rc != CKR_OK) + goto done; + + if (find_count != 1) { + rc = CKR_OBJECT_HANDLE_INVALID; + goto done; + } + + *h_key = obj_list[0]; + +done: + funcs->C_FindObjectsFinal(session); + return rc; +} + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + int k; + CK_BYTE user_pin[128]; + CK_ULONG user_pin_len; + CK_ULONG num_usage_threads = 2; + CK_ULONG num_alter_threads = 2; + CK_BBOOL token_obj = FALSE; + CK_BBOOL create_obj = TRUE; + CK_BBOOL destroy_obj = TRUE; + CK_RV rv; + CK_SESSION_HANDLE session = CK_INVALID_HANDLE; + CK_FLAGS flags; + CK_MECHANISM mech; + CK_OBJECT_HANDLE h_key; + CK_ULONG i; + pthread_t id[1000]; + + for (k = 1; k < argc; k++) { + if (strcmp(argv[k], "-slot") == 0) { + ++k; + SLOT_ID = atoi(argv[k]); + } + else if (strcmp(argv[k], "-usage-threads") == 0) { + ++k; + num_usage_threads = atoi(argv[k]); + } + else if (strcmp(argv[k], "-alter-threads") == 0) { + ++k; + num_alter_threads = atoi(argv[k]); + } + else if (strcmp(argv[k], "-token_obj") == 0) { + token_obj = TRUE; + } + else if (strcmp(argv[k], "-reuse_obj") == 0) { + create_obj = FALSE; + } + else if (strcmp(argv[k], "-keep_obj") == 0) { + destroy_obj = FALSE; + } + + if (strcmp(argv[k], "-h") == 0) { + printf("usage: %s [-slot ] [-usage-threads ] [-alter-threads ] [-token_obj] [-reuse_obj] [-keep_obj] [-h]\n\n", argv[0]); + printf("By default, Slot #1 are used with 2 usage and 2 alter threads\n\n"); + return -1; + } + } + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + printf("Using slot #%lu ...\n\n", SLOT_ID); + + rv = do_GetFunctionList(); + if (rv != TRUE) { + testcase_fail("do_GetFunctionList() rc = %s", p11_get_ckr(rv)); + goto out; + } + + testcase_setup(0); + testcase_begin("Starting..."); + + // Initialize + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + if ((rv = funcs->C_Initialize(&cinit_args))) { + testcase_fail("C_Initialize() rc = %s", p11_get_ckr(rv)); + goto out; + } + + // Open Session and login for slot 1 + testcase_new_assertion(); + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rv = funcs->C_OpenSession(SLOT_ID, flags, NULL, NULL, &session); + if (rv != CKR_OK) { + testcase_fail("C_OpenSession() rc = %s", p11_get_ckr(rv)); + goto finalize; + } + testcase_pass("C_OpenSession"); + + testcase_new_assertion(); + rv = funcs->C_Login(session, CKU_USER, user_pin, user_pin_len); + if (rv != CKR_OK) { + testcase_fail("C_Login() rc = %s", p11_get_ckr(rv)); + goto close_session; + } + testcase_pass("C_Login as User"); + + if (!token_obj || create_obj) { + // generate an AES key + testcase_new_assertion(); + mech.mechanism = CKM_AES_KEY_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rv = generate_key(session, 256 / 8, token_obj, &mech, &h_key); + if (rv != CKR_OK) { + testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rv)); + goto close_session; + } + testcase_pass("C_GenerateKey"); + } else { + // find the existing AES key + testcase_new_assertion(); + + rv = find_key(session, &h_key); + if (rv != CKR_OK) { + testcase_error("find_key rc=%s", p11_get_ckr(rv)); + goto close_session; + } + testcase_pass("find_key"); + } + // create the usage threads + testcase_new_assertion(); + for (i = 0; i < num_usage_threads; i++) { + printf("Creating usage thread %lu\n", i); + pthread_create(&id[i], NULL, (void *(*)(void *)) usage_thread_func, + (void *)&h_key); + } + + // create the alter threads + for (i = 0; i < num_alter_threads; i++) { + printf("Creating alter thread %lu\n", i); + pthread_create(&id[num_usage_threads + i], NULL, + (void *(*)(void *)) alter_thread_func, (void *)&h_key); + } + + // wait for all threads to end + for (i = 0; i < num_usage_threads + num_alter_threads; i++) { + pthread_join(id[i], NULL); + } + testcase_pass("All threads have ended"); + + if (!token_obj || destroy_obj) { + testcase_new_assertion(); + rv = funcs->C_DestroyObject(session, h_key); + if (rv != CKR_OK) { + testcase_fail("C_DestroyObject() rc = %s", p11_get_ckr(rv)); + } + testcase_pass("C_DestroyObject"); + } + +close_session: + testcase_new_assertion(); + if (session != CK_INVALID_HANDLE) { + rv = funcs->C_CloseSession(session); + if (rv != CKR_OK) { + testcase_fail("C_CloseSession() rc = %s", p11_get_ckr(rv)); + } + } + testcase_pass("C_CloseSession"); + +finalize: + testcase_new_assertion(); + rv = funcs->C_Finalize(NULL); + if (rv != CKR_OK) { + testcase_fail("C_Finalize() rc = %s", p11_get_ckr(rv)); + } + testcase_pass("C_Finalize"); + +out: + testcase_print_result(); + return 0; +} diff --git a/testcases/misc_tests/obj_mgmt.c b/testcases/misc_tests/obj_mgmt.c new file mode 100644 index 0000000..459b07f --- /dev/null +++ b/testcases/misc_tests/obj_mgmt.c @@ -0,0 +1,1478 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2012-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 + */ + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "common.c" + + +#define AES_KEY_SIZE_128 16 + +/* API Routines exercised that take /var/lock/LCK..opencryptoki spinlock. + * C_OpenSession + * C_CloseSession + * + * API Routines exercised that cause stdll to take /var/lock/opencryptoki_stdll + * spinlock. + * C_CreateObject + * C_Login + * + * 1) create a data object + * 2) create a certificate + * 3) create a key object + */ +CK_RV do_CreateSessionObject(void) +{ + CK_SLOT_ID slot_id; + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + CK_BYTE true = TRUE; + CK_BYTE false = FALSE; + + CK_OBJECT_HANDLE h_data; + CK_OBJECT_CLASS data_class = CKO_DATA; + CK_BYTE data_application[] = "Test Application"; + CK_BYTE data_value[] = "1234567890abcedfghijklmnopqrstuvwxyz"; + CK_ATTRIBUTE data_attribs[] = { + {CKA_CLASS, &data_class, sizeof(data_class)}, + {CKA_TOKEN, &false, sizeof(false)}, + {CKA_APPLICATION, &data_application, sizeof(data_application)}, + {CKA_VALUE, &data_value, sizeof(data_value)} + }; + + CK_OBJECT_HANDLE h_cert; + CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE cert_type = CKC_X_509; + CK_BYTE cert_subject[] = "Certificate subject"; + CK_BYTE cert_id[] = "Certificate ID"; + CK_BYTE cert_value[] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + CK_ATTRIBUTE cert_attribs[] = { + {CKA_CLASS, &cert_class, sizeof(cert_class)}, + {CKA_TOKEN, &false, sizeof(false)}, + {CKA_CERTIFICATE_TYPE, &cert_type, sizeof(cert_type)}, + {CKA_SUBJECT, &cert_subject, sizeof(cert_subject)}, + {CKA_ID, &cert_id, sizeof(cert_id)}, + {CKA_VALUE, &cert_value, sizeof(cert_value)} + }; + + CK_OBJECT_HANDLE h_key; + CK_OBJECT_CLASS key_class = CKO_PUBLIC_KEY; + CK_KEY_TYPE key_type = CKK_RSA; + CK_BYTE key_modulus[] = { + 0xa5, 0x6e, 0x4a, 0x0e, 0x70, 0x10, 0x17, 0x58, + 0x9a, 0x51, 0x87, 0xdc, 0x7e, 0xa8, 0x41, 0xd1, + 0x56, 0xf2, 0xec, 0x0e, 0x36, 0xad, 0x52, 0xa4, + 0x4d, 0xfe, 0xb1, 0xe6, 0x1f, 0x7a, 0xd9, 0x91, + 0xd8, 0xc5, 0x10, 0x56, 0xff, 0xed, 0xb1, 0x62, + 0xb4, 0xc0, 0xf2, 0x83, 0xa1, 0x2a, 0x88, 0xa3, + 0x94, 0xdf, 0xf5, 0x26, 0xab, 0x72, 0x91, 0xcb, + 0xb3, 0x07, 0xce, 0xab, 0xfc, 0xe0, 0xb1, 0xdf, + 0xd5, 0xcd, 0x95, 0x08, 0x09, 0x6d, 0x5b, 0x2b, + 0x8b, 0x6d, 0xf5, 0xd6, 0x71, 0xef, 0x63, 0x77, + 0xc0, 0x92, 0x1c, 0xb2, 0x3c, 0x27, 0x0a, 0x70, + 0xe2, 0x59, 0x8e, 0x6f, 0xf8, 0x9d, 0x19, 0xf1, + 0x05, 0xac, 0xc2, 0xd3, 0xf0, 0xcb, 0x35, 0xf2, + 0x92, 0x80, 0xe1, 0x38, 0x6b, 0x6f, 0x64, 0xc4, + 0xef, 0x22, 0xe1, 0xe1, 0xf2, 0x0d, 0x0c, 0xe8, + 0xcf, 0xfb, 0x22, 0x49, 0xbd, 0x9a, 0x21, 0x37 + }; + CK_BYTE key_exponent[] = { 0x01, 0x00, 0x01 }; + CK_ATTRIBUTE key_attribs[] = { + {CKA_CLASS, &key_class, sizeof(key_class)}, + {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, + {CKA_WRAP, &true, sizeof(true)}, + {CKA_MODULUS, &key_modulus, sizeof(key_modulus)}, + {CKA_PUBLIC_EXPONENT, &key_exponent, sizeof(key_exponent)} + }; + + testcase_begin("starting..."); + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + slot_id = SLOT_ID; + + // create a USER R/W session + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + testcase_fail("C_OpenSession() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + testcase_fail("C_Login() rc = %s", p11_get_ckr(rc)); + return rc; + } + + // now, create the objects + rc = funcs->C_CreateObject(h_session, data_attribs, 4, &h_data); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_CreateObject(h_session, cert_attribs, 6, &h_cert); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_CreateObject(h_session, key_attribs, 5, &h_key); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + // done...close the session and verify the object is deleted + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_fail("C_CloseAllSessions() rc=%s", p11_get_ckr(rc)); + return rc; + } + + testcase_pass("looks okay..."); + + return rc; +} + +/* API Routines exercised that take /var/lock/LCK..opencryptoki spinlock. + * C_OpenSession + * C_CloseSession + * + * API routines exercised that result in stdll taking + * /var/lock/opencryptoki_stdll spinlock. + * C_CreateObject + * C_CopyObject + * C_DestroyObject + * C_GetAttributeValue + * C_GetObjectSize + * + * 1) create a data object with no CKA_APPLICATION attribute + * 2) create a copy of the object specifying the CKA_APPLICATION attribute + * 3) extract the CK_VALUE attribute from the copy. Ensure matches the original + * 4) extract the CKA_APPLICATION attribute from the original. ensure empty. + * 5) extract the CKA_APPLICATION attribute from the copy. ensure is correct. + * 6) attempt to extract CK_PRIME from the original. ensure fails correctly. + * 7) attempt to extract CK_PRIME from a non-existant object. ensure fails + * correctly. + * 8) get the size of the original object and copied objects + * 9) destroy the original object. ensure this succeeds. + * A) destroy a non-existant object. ensure this fails correctly. + * B) get the size of the original object. ensure this fails correctly. + */ +CK_RV do_CopyObject(void) +{ + CK_SLOT_ID slot_id; + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_ULONG obj_size; + + CK_BYTE false = FALSE; + + CK_OBJECT_HANDLE h_data; + CK_OBJECT_CLASS data_class = CKO_DATA; + CK_BYTE data_application[] = "Test Application"; + CK_BYTE data_value[] = "1234567890abcedfghijklmnopqrstuvwxyz"; + CK_ATTRIBUTE data_attribs[] = { + {CKA_CLASS, &data_class, sizeof(data_class)}, + {CKA_TOKEN, &false, sizeof(false)}, + {CKA_VALUE, &data_value, sizeof(data_value)} + }; + + CK_OBJECT_HANDLE h_copy; + CK_ATTRIBUTE copy_attribs[] = { + {CKA_APPLICATION, &data_application, sizeof(data_application)} + }; + + CK_BYTE buf1[100]; + CK_ATTRIBUTE verify_attribs[] = { + {CKA_APPLICATION, &buf1, sizeof(buf1)} + }; + + CK_BYTE buf2[100]; + CK_ATTRIBUTE prime_attribs[] = { + {CKA_PRIME, &buf2, sizeof(buf2)} + }; + + testcase_begin("starting..."); + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + slot_id = SLOT_ID; + + /* create a USER R/W session */ + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + testcase_fail("C_OpenSession() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + testcase_fail("C_Login() rc = %s", p11_get_ckr(rc)); + return rc; + } + + + /* create the object */ + rc = funcs->C_CreateObject(h_session, data_attribs, 3, &h_data); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* create the copy */ + rc = funcs->C_CopyObject(h_session, h_data, copy_attribs, 1, &h_copy); + if (rc != CKR_OK) { + testcase_fail("C_CopyObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* now, try to extract the CKA_APPLICATION attribute from the original + * this will pull in the token's default value for CKA_APPLICATION which + */ + verify_attribs[0].ulValueLen = sizeof(buf1); + rc = funcs->C_GetAttributeValue(h_session, h_data, verify_attribs, 1); + if (rc != CKR_OK) { + testcase_fail("C_GetAttributeValue() rc=%s", p11_get_ckr(rc)); + return rc; + } + + /* now, try to extract the CKA_APPLICATION attribute from the copy */ + verify_attribs[0].ulValueLen = sizeof(buf1); + rc = funcs->C_GetAttributeValue(h_session, h_copy, verify_attribs, 1); + if (rc != CKR_OK) { + testcase_fail("C_GetAttributeValue() rc=%s", p11_get_ckr(rc)); + return rc; + } + + if (memcmp(&data_application, + verify_attribs[0].pValue, sizeof(data_application)) != 0) { + testcase_fail("extracted attribute doesn't match"); + return -1; + } + + /* now, try to extract CKA_PRIME from the original. + * this should not exist + */ + prime_attribs[0].ulValueLen = sizeof(buf2); + rc = funcs->C_GetAttributeValue(h_session, h_data, prime_attribs, 1); + if (rc != CKR_ATTRIBUTE_TYPE_INVALID) { + testcase_fail("C_GetAttributeValue() rc = %s (expected " + "CKR_ATTRIBUTE_TYPE_INVALID)", p11_get_ckr(rc)); + return rc; + } + + /* now, try to extract CKA_PRIME from a bogus object handle. + * this should not exist + */ + rc = funcs->C_GetAttributeValue(h_session, 98765, prime_attribs, 1); + if (rc != CKR_OBJECT_HANDLE_INVALID) { + testcase_fail("C_GetAttributeValue() rc = %s (expected " + "CKR_OBJECT_HANDLE_INVALID)", p11_get_ckr(rc)); + return rc; + } + + /* now, get the size of the original object */ + rc = funcs->C_GetObjectSize(h_session, h_data, &obj_size); + if (rc != CKR_OK) { + testcase_fail("C_GetObjectSize() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* now, destroy the original object */ + rc = funcs->C_DestroyObject(h_session, h_data); + if (rc != CKR_OK) { + testcase_fail("C_DestroyObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* now, destroy a non-existant object */ + rc = funcs->C_DestroyObject(h_session, h_data); + if (rc != CKR_OBJECT_HANDLE_INVALID) { + testcase_fail("C_GetAttributeValue() rc = %s (expected " + "CKR_OBJECT_HANDLE_INVALID)", p11_get_ckr(rc)); + return rc; + } + + + /* now, get the size of a non-existent object */ + rc = funcs->C_GetObjectSize(h_session, h_data, &obj_size); + if (rc != CKR_OBJECT_HANDLE_INVALID) { + testcase_fail("C_GetAttributeValue() rc = %s (expected " + "CKR_OBJECT_HANDLE_INVALID)", p11_get_ckr(rc)); + return rc; + } + + + /* done...close the session and verify the object is deleted */ + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_fail("C_CloseAllSessions() rc=%s", p11_get_ckr(rc)); + return rc; + } + + testcase_pass("Looks okay..."); + + return CKR_OK; +} + + +/* API Routines exercised that take /var/lock/LCK..opencryptoki spinlock. + * C_OpenSession + * C_CloseSession + * + * API routines exercised that result in stdll taking + * /var/lock/opencryptoki_stdll spinlock. + * C_CreateObject + * C_GetAttributeValue + * C_SetAttributeValue + * + * 1) create a certificate object with no CKA_SERIAL_NUMBER or CKA_ISSUER + * 2) add CKA_SERIAL_NUMBER and CKA_ISSUER and modify CKA_ID. + * verify this works. + * 3) try to modify CKA_VALUE and CKA_ID in a single call to + * C_SetAttributeValue. verify that this fails correctly and that + * the object is not modified. + */ +CK_RV do_SetAttributeValues(void) +{ + CK_SLOT_ID slot_id; + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + CK_BYTE false = FALSE; + + CK_OBJECT_HANDLE h_cert; + CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE cert_type = CKC_X_509; + CK_BYTE cert_subject[] = "Certificate subject"; + CK_BYTE cert_id[] = "Certificate ID"; + CK_BYTE cert_value[] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + + CK_ATTRIBUTE cert_attribs[] = { + {CKA_CLASS, &cert_class, sizeof(cert_class)}, + {CKA_TOKEN, &false, sizeof(false)}, + {CKA_CERTIFICATE_TYPE, &cert_type, sizeof(cert_type)}, + {CKA_SUBJECT, &cert_subject, sizeof(cert_subject)}, + {CKA_ID, &cert_id, sizeof(cert_id)}, + {CKA_VALUE, &cert_value, sizeof(cert_value)} + }; + + CK_BYTE cert_id2[] = "New ID"; + CK_BYTE cert_issuer[] = "Certificate Issuer"; + CK_BYTE cert_ser_no[] = "Serial Number: 12345"; + CK_ATTRIBUTE update_attr[] = { + {CKA_SERIAL_NUMBER, &cert_ser_no, sizeof(cert_ser_no)}, + {CKA_ISSUER, &cert_issuer, sizeof(cert_issuer)}, + {CKA_ID, &cert_id2, sizeof(cert_id2)} + }; + + CK_BYTE cert_value2[] = "Invalid Value"; + CK_BYTE cert_id3[] = "ID #3"; + CK_ATTRIBUTE invalid_attr[] = { + {CKA_VALUE, &cert_value2, sizeof(cert_value2)}, + {CKA_ID, &cert_id3, sizeof(cert_id3)} + }; + + testcase_begin("starting..."); + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + slot_id = SLOT_ID; + + /* create a USER R/W session */ + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + testcase_fail("C_OpenSession() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + testcase_fail("C_Login() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* create the object */ + rc = funcs->C_CreateObject(h_session, cert_attribs, 6, &h_cert); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* Add CKA_SERIAL_NUMBER and CKA_ISSUER and change the + * existing CKA_ID + */ + rc = funcs->C_SetAttributeValue(h_session, h_cert, update_attr, 3); + if (rc != CKR_OK) { + testcase_fail("C_SetAttributeValue() rc = %s", p11_get_ckr(rc)); + return rc; + } else { + CK_BYTE buf1[100]; + CK_BYTE buf2[100]; + CK_BYTE buf3[100]; + CK_ATTRIBUTE check1[] = { + {CKA_ISSUER, &buf1, sizeof(buf1)}, + {CKA_SERIAL_NUMBER, &buf2, sizeof(buf2)}, + {CKA_ID, &buf3, sizeof(buf3)} + }; + + rc = funcs->C_GetAttributeValue(h_session, h_cert, + (CK_ATTRIBUTE *) & check1, 3); + if (rc != CKR_OK) { + testcase_fail("C_GetAttributeValue() rc = %s", p11_get_ckr(rc)); + return rc; + } + + if (memcmp(check1[0].pValue, cert_issuer, check1[0].ulValueLen) != 0) { + testcase_fail("CKA_ISSUER mismatch"); + return -1; + } + + if (memcmp(check1[1].pValue, cert_ser_no, check1[1].ulValueLen) != 0) { + testcase_fail("CKA_SERIAL_NUMBER mismatch"); + return -1; + } + + if (memcmp(check1[2].pValue, cert_id2, check1[2].ulValueLen) != 0) { + testcase_fail("CKA_ID mismatch"); + return -1; + } + } + + /* the next template tries to update a CK_ID (valid) and + * CKA_VALUE (read-only). the entire operation should fail -- no + * attributes should get modified + */ + rc = funcs->C_SetAttributeValue(h_session, h_cert, invalid_attr, 2); + if (rc != CKR_ATTRIBUTE_READ_ONLY) { + testcase_fail("C_SetAttributeValue() rc = %s (expected " + "CKR_ATTRIBUTE_READ_ONLY)", p11_get_ckr(rc)); + return rc; + } else { + CK_BYTE buf1[100]; + CK_ATTRIBUTE check1[] = { + {CKA_ID, &buf1, sizeof(buf1)} + }; + + rc = funcs->C_GetAttributeValue(h_session, h_cert, check1, 1); + if (rc != CKR_OK) { + testcase_fail("C_GetAttributeValue() rc = %s", p11_get_ckr(rc)); + return rc; + } + + if (memcmp(check1[0].pValue, cert_id2, check1[0].ulValueLen) != 0) { + testcase_fail("CKA_ID mismatch"); + return -1; + } + } + + /* done...close the session and verify the object is deleted */ + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_fail("C_CloseAllSessions() rc = %s", p11_get_ckr(rc)); + return rc; + } + + testcase_pass("Looks okay..."); + + return rc; +} + + +/* API Routines exercised that take /var/lock/LCK..opencryptoki spinlock. + * C_OpenSession + * C_CloseSession + * + * API routines exercised that result in stdll taking + * /var/lock/opencryptoki_stdll spinlock. + * C_FindObjectsInit + * C_FindObjects + * C_CreateObject + * + * 1) Create 3 certificates with different CKA_ID attributes + * 2) Search for a particular CKA_ID. Verify this works. + * 3) Search for a non-existant CKA_ID. Verify this returns nothing. + * 4) Specify an empty template. Verify that all 3 objects are returned. + */ +CK_RV do_FindObjects(void) +{ + CK_SLOT_ID slot_id; + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + CK_BYTE false = FALSE; + + CK_OBJECT_HANDLE h_cert1; + CK_OBJECT_CLASS cert1_class = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE cert1_type = CKC_X_509; + CK_BYTE cert1_subject[] = "Certificate subject #1"; + CK_BYTE cert1_id[] = "Certificate ID #1"; + CK_BYTE cert1_value[] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + + CK_ATTRIBUTE cert1_attribs[] = { + {CKA_CLASS, &cert1_class, sizeof(cert1_class)}, + {CKA_TOKEN, &false, sizeof(false)}, + {CKA_CERTIFICATE_TYPE, &cert1_type, sizeof(cert1_type)}, + {CKA_SUBJECT, &cert1_subject, sizeof(cert1_subject)}, + {CKA_ID, &cert1_id, sizeof(cert1_id)}, + {CKA_VALUE, &cert1_value, sizeof(cert1_value)} + }; + + CK_OBJECT_HANDLE h_cert2; + CK_OBJECT_CLASS cert2_class = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE cert2_type = CKC_X_509; + CK_BYTE cert2_subject[] = "Certificate subject #2"; + CK_BYTE cert2_id[] = "Certificate ID #2"; + CK_BYTE cert2_value[] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + + CK_ATTRIBUTE cert2_attribs[] = { + {CKA_CLASS, &cert2_class, sizeof(cert2_class)}, + {CKA_TOKEN, &false, sizeof(false)}, + {CKA_CERTIFICATE_TYPE, &cert2_type, sizeof(cert2_type)}, + {CKA_SUBJECT, &cert2_subject, sizeof(cert2_subject)}, + {CKA_ID, &cert2_id, sizeof(cert2_id)}, + {CKA_VALUE, &cert2_value, sizeof(cert2_value)} + }; + + CK_OBJECT_HANDLE h_cert3; + CK_OBJECT_CLASS cert3_class = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE cert3_type = CKC_X_509; + CK_BYTE cert3_subject[] = "Certificate subject #3"; + CK_BYTE cert3_id[] = "Certificate ID #3"; + CK_BYTE cert3_value[] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + + CK_ATTRIBUTE cert3_attribs[] = { + {CKA_CLASS, &cert3_class, sizeof(cert3_class)}, + {CKA_TOKEN, &false, sizeof(false)}, + {CKA_CERTIFICATE_TYPE, &cert3_type, sizeof(cert3_type)}, + {CKA_SUBJECT, &cert3_subject, sizeof(cert3_subject)}, + {CKA_ID, &cert3_id, sizeof(cert3_id)}, + {CKA_VALUE, &cert3_value, sizeof(cert3_value)} + }; + + CK_BYTE find1_id[] = "Certificate ID #2"; + CK_ATTRIBUTE find1_attribs[] = { + {CKA_ID, &find1_id, sizeof(find1_id)} + }; + + CK_BYTE find2_id[] = "Certificate ID #12345"; + CK_ATTRIBUTE find2_attribs[] = { + {CKA_ID, &find2_id, sizeof(find2_id)} + }; + + CK_OBJECT_HANDLE obj_list[10]; + CK_ULONG find_count; + CK_ULONG num_existing_objects; + + testcase_begin("starting..."); + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + slot_id = SLOT_ID; + + /* create a USER R/W session */ + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + testcase_fail("C_OpenSession() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + testcase_fail("C_Login() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* Get a count on all currently existing session objects + * If any objects existed before, then after we create three + * new objects. we expect there to be a total of + * current_num_objects+3 tokens. + */ + rc = funcs->C_FindObjectsInit(h_session, NULL, 0); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_FindObjects(h_session, obj_list, 10, &num_existing_objects); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* Since we'll only be checking for max 10 objects... */ + if (num_existing_objects > 7) + num_existing_objects = 7; + + /* create the objects */ + rc = funcs->C_CreateObject(h_session, cert1_attribs, 6, &h_cert1); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_CreateObject(h_session, cert2_attribs, 6, &h_cert2); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_CreateObject(h_session, cert3_attribs, 6, &h_cert3); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* now, search for the 2nd objects */ + rc = funcs->C_FindObjectsInit(h_session, find1_attribs, 1); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_FindObjects(h_session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + return rc; + } + + if (find_count != 1) { + testcase_fail("found %ld instead of just 1 object", find_count); + return -1; + } + + if (obj_list[0] != h_cert2) { + testcase_fail("got the wrong object handle"); + return -1; + } + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* now, search for a non-existant object */ + rc = funcs->C_FindObjectsInit(h_session, find2_attribs, 1); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_FindObjects(h_session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + return rc; + } + + if (find_count != 0) { + testcase_fail("found %ld objects when none where expected", find_count); + return -1; + } + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* now, try to retrieve a list of all the objects */ + rc = funcs->C_FindObjectsInit(h_session, NULL, 0); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_FindObjects(h_session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + return rc; + } + + if (find_count != num_existing_objects + 3) { + testcase_fail("found %ld instead of %ld objects", find_count, + num_existing_objects + 3); + return -1; + } + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* done...close the session and verify the object is deleted */ + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_fail("C_CloseAllSessions() rc = %s", p11_get_ckr(rc)); + return rc; + } + + testcase_pass("Looks okay..."); + + return rc; +} + + +/* API Routines exercised that take /var/lock/LCK..opencryptoki spinlock. + * C_OpenSession + * C_CloseSession + * + * API routines exercised that result in stdll taking + * /var/lock/opencryptoki_stdll spinlock. + * C_FindObjectsInit + * C_FindObjects + * C_CreateObject + * + * 1) Create 3 certificates as PUBLIC token objects + * 2) Search for a particular CKA_ID. Verify that this works. + * 3) Do FindObjects with a NULL template. Verify that all 3 token objects + * are found. + * 4) Search for a particular CKA_ID. Verify it works. + * 5) Search for a non-existant CKA_ID. Verify it returns nothing. + * 6) Close all sessions. Then create a new session. + * 7) Do FindObjects with a NULL template. Verify that all 3 token objects + * are found. + * 8) Search for a particular CKA_ID. Verify it works. + * 9) Search for a non-existant CKA_ID. Verify it returns nothing. + * 10) Destroy all 3 token objects + * 11) Do FindObjects with a NULL template. Verify that nothing is returned. + */ +CK_RV do_CreateTokenObjects(void) +{ + CK_SLOT_ID slot_id; + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + CK_BYTE true = TRUE; + CK_BYTE false = FALSE; + + CK_OBJECT_HANDLE h_cert1; + CK_OBJECT_CLASS cert1_class = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE cert1_type = CKC_X_509; + CK_BYTE cert1_subject[] = "Certificate subject #1"; + CK_BYTE cert1_id[] = "Certificate ID #1"; + CK_BYTE cert1_value[] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + + CK_ATTRIBUTE cert1_attribs[] = { + {CKA_CLASS, &cert1_class, sizeof(cert1_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_CERTIFICATE_TYPE, &cert1_type, sizeof(cert1_type)}, + {CKA_SUBJECT, &cert1_subject, sizeof(cert1_subject)}, + {CKA_ID, &cert1_id, sizeof(cert1_id)}, + {CKA_VALUE, &cert1_value, sizeof(cert1_value)}, + {CKA_PRIVATE, &false, sizeof(false)} + }; + + CK_OBJECT_HANDLE h_cert2; + CK_OBJECT_CLASS cert2_class = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE cert2_type = CKC_X_509; + CK_BYTE cert2_subject[] = "Certificate subject #2"; + CK_BYTE cert2_id[] = "Certificate ID #2"; + CK_BYTE cert2_value[] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + + CK_ATTRIBUTE cert2_attribs[] = { + {CKA_CLASS, &cert2_class, sizeof(cert2_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_CERTIFICATE_TYPE, &cert2_type, sizeof(cert2_type)}, + {CKA_SUBJECT, &cert2_subject, sizeof(cert2_subject)}, + {CKA_ID, &cert2_id, sizeof(cert2_id)}, + {CKA_VALUE, &cert2_value, sizeof(cert2_value)}, + {CKA_PRIVATE, &false, sizeof(false)} + }; + + CK_OBJECT_HANDLE h_cert3; + CK_OBJECT_CLASS cert3_class = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE cert3_type = CKC_X_509; + CK_BYTE cert3_subject[] = "Certificate subject #3"; + CK_BYTE cert3_id[] = "Certificate ID #3"; + CK_BYTE cert3_value[] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + + CK_ATTRIBUTE cert3_attribs[] = { + {CKA_CLASS, &cert3_class, sizeof(cert3_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_CERTIFICATE_TYPE, &cert3_type, sizeof(cert3_type)}, + {CKA_SUBJECT, &cert3_subject, sizeof(cert3_subject)}, + {CKA_ID, &cert3_id, sizeof(cert3_id)}, + {CKA_VALUE, &cert3_value, sizeof(cert3_value)}, + {CKA_PRIVATE, &false, sizeof(false)} + }; + + CK_BYTE find1_id[] = "Certificate ID #2"; + CK_ATTRIBUTE find1_attribs[] = { + {CKA_ID, &find1_id, sizeof(find1_id)} + }; + + CK_BYTE find2_id[] = "Certificate ID #123456"; + CK_ATTRIBUTE find2_attribs[] = { + {CKA_ID, &find2_id, sizeof(find2_id)} + }; + + CK_OBJECT_HANDLE obj_list[10]; + CK_ULONG find_count; + + testcase_begin("starting..."); + + if (skip_token_obj == TRUE) { + testcase_notice("Skipping tests that creates token objects"); + return CKR_OK; + } + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + slot_id = SLOT_ID; + + /* create a USER R/W session */ + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + testcase_fail("C_OpenSession() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + testcase_fail("C_Login() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* create the token objects */ + rc = funcs->C_CreateObject(h_session, cert1_attribs, 7, &h_cert1); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_CreateObject(h_session, cert2_attribs, 7, &h_cert2); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_CreateObject(h_session, cert3_attribs, 7, &h_cert3); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* now, retrieve a list of all object handles */ + rc = funcs->C_FindObjectsInit(h_session, NULL, 0); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_FindObjects(h_session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + return rc; + } + + if (find_count != 3) { + testcase_fail("found %ld objects instead of expected 3", find_count); + return -1; + } + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* now, search for the 2nd object */ + rc = funcs->C_FindObjectsInit(h_session, find1_attribs, 1); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_FindObjects(h_session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + return rc; + } + + if (find_count != 1) { + testcase_fail("found %ld objects instead of expected 1", find_count); + return -1; + } + + if (obj_list[0] != h_cert2) { + testcase_fail("found the wrong object handle"); + return -1; + } + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* now, search for a non-existant attribute */ + rc = funcs->C_FindObjectsInit(h_session, find2_attribs, 1); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_FindObjects(h_session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + return rc; + } + + if (find_count != 0) { + testcase_fail("found %ld objects when none where expected", find_count); + return -1; + } + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* done...close all sessions and open a new one */ + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_fail("C_CloseAllSessions() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* create a USER R/W session */ + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + testcase_fail("C_OpenSession() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + testcase_fail("C_Login() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* now, retrieve a list of all object handles */ + rc = funcs->C_FindObjectsInit(h_session, NULL, 0); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_FindObjects(h_session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + return rc; + } + + if (find_count != 3) { + testcase_fail("found %ld objects instead of expected 3", find_count); + return -1; + } + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* now, search for the 2nd object */ + rc = funcs->C_FindObjectsInit(h_session, find1_attribs, 1); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_FindObjects(h_session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + return rc; + } + + if (find_count != 1) { + testcase_fail("found %ld objects instead of expected 1", find_count); + return -1; + } + + if (obj_list[0] != h_cert2) { + testcase_fail("found the wrong object handle"); + return -1; + } + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* now, search for a non-existant attribute */ + rc = funcs->C_FindObjectsInit(h_session, find2_attribs, 1); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_FindObjects(h_session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + return rc; + } + + if (find_count != 0) { + testcase_fail("found %ld objects when none where expected", find_count); + return -1; + } + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* now, destroy the objects */ + rc = funcs->C_DestroyObject(h_session, h_cert1); + if (rc != CKR_OK) { + testcase_fail("C_DestroyObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_DestroyObject(h_session, h_cert2); + if (rc != CKR_OK) { + testcase_fail("C_DestroyObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_DestroyObject(h_session, h_cert3); + if (rc != CKR_OK) { + testcase_fail("C_DestroyObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* now, retrieve a list of all object handles */ + rc = funcs->C_FindObjectsInit(h_session, NULL, 0); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_FindObjects(h_session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + return rc; + } + + if (find_count != 0) { + testcase_fail("found %ld objects when none where expected", find_count); + return -1; + } + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* done...close the session */ + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_fail("C_CloseAllSessions() rc = %s", p11_get_ckr(rc)); + return rc; + } + + testcase_pass("Looks okay..."); + + return rc; +} + +/* + * do_HWFeatureSearch Test: + * + * 1. Create 4 objects, 2 of which are HW_FEATURE objects (1 of them is a + * monotonic counter). + * 2. Search for objects using a template that does not have its + * HW_FEATURE attribute set. + * 3. Result should be that the other 2 objects are returned, and + * not the HW_FEATURE objects. + * 4. Search for objects using a template that does have its + * HW_FEATURE attribute set. + * 5. Result should be that the only hardware feature objects that is not a + * monotonic counter should be returned. + * + */ +CK_RV do_HWFeatureSearch(void) +{ + unsigned int i; + CK_RV rc, loc_rc; + CK_ULONG find_count; + CK_SLOT_ID slot_id; + CK_BBOOL false = FALSE; + CK_BBOOL true = TRUE; + + CK_SESSION_HANDLE h_session = CK_INVALID_HANDLE; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN] = {0}; + CK_ULONG user_pin_len = 0; + + /* A counter object */ + CK_OBJECT_CLASS counter1_class = CKO_HW_FEATURE; + CK_HW_FEATURE_TYPE feature1_type = CKH_MONOTONIC_COUNTER; + CK_UTF8CHAR counter1_label[] = "Monotonic counter"; + CK_CHAR counter1_value[16] = {0}; + CK_ATTRIBUTE counter1_template[] = { + {CKA_CLASS, &counter1_class, sizeof(counter1_class)}, + {CKA_HW_FEATURE_TYPE, &feature1_type, sizeof(feature1_type)}, + {CKA_LABEL, counter1_label, sizeof(counter1_label) - 1}, + {CKA_VALUE, counter1_value, sizeof(counter1_value)}, + {CKA_RESET_ON_INIT, &true, sizeof(true)}, + {CKA_HAS_RESET, &false, sizeof(false)} + }; + + /* A clock object */ + CK_OBJECT_CLASS clock_class = CKO_HW_FEATURE; + CK_HW_FEATURE_TYPE clock_type = CKH_CLOCK; + CK_UTF8CHAR clock_label[] = "Clock"; + CK_CHAR clock_value[16] = {0}; + CK_ATTRIBUTE clock_template[] = { + {CKA_CLASS, &clock_class, sizeof(clock_class)}, + {CKA_HW_FEATURE_TYPE, &clock_type, sizeof(clock_type)}, + {CKA_LABEL, clock_label, sizeof(clock_label) - 1}, + {CKA_VALUE, clock_value, sizeof(clock_value)} + }; + + /* A data object */ + CK_OBJECT_CLASS obj1_class = CKO_DATA; + CK_UTF8CHAR obj1_label[] = "Object 1"; + CK_BYTE obj1_data[] = "Object 1's data"; + CK_ATTRIBUTE obj1_template[] = { + {CKA_CLASS, &obj1_class, sizeof(obj1_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_LABEL, obj1_label, sizeof(obj1_label) - 1}, + {CKA_VALUE, obj1_data, sizeof(obj1_data)} + }; + + /* A secret key object */ + CK_OBJECT_CLASS obj2_class = CKO_SECRET_KEY; + CK_KEY_TYPE obj2_type = CKK_AES; + CK_UTF8CHAR obj2_label[] = "Object 2"; + CK_BYTE obj2_data[AES_KEY_SIZE_128] = {0}; + CK_ATTRIBUTE obj2_template[] = { + {CKA_CLASS, &obj2_class, sizeof(obj2_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_KEY_TYPE, &obj2_type, sizeof(obj2_type)}, + {CKA_LABEL, obj2_label, sizeof(obj2_label) - 1}, + {CKA_VALUE, obj2_data, sizeof(obj2_data)} + }; + + CK_OBJECT_HANDLE h_counter1 = 0, h_clock = 0, h_obj1 = 0, h_obj2 = 0, + obj_list[10] = {0}; + + CK_ATTRIBUTE find_tmpl[] = { + {CKA_CLASS, &counter1_class, sizeof(counter1_class)} + }; + + if (skip_token_obj == TRUE) { + testcase_notice("Skipping tests that creates token objects"); + return CKR_OK; + } + + slot_id = SLOT_ID; + + testcase_begin("starting..."); + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + /* Open a session with the token */ + rc = funcs->C_OpenSession(slot_id, + (CKF_SERIAL_SESSION | CKF_RW_SESSION), + NULL_PTR, NULL_PTR, &h_session); + if (rc != CKR_OK) { + testcase_fail("C_OpenSession() rc = %s", p11_get_ckr(rc)); + goto done; + } + + // Login correctly + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + testcase_fail("C_Login() rc = %s", p11_get_ckr(rc)); + goto session_close; + } + + /* Create the 4 test objects */ + rc = funcs->C_CreateObject(h_session, obj1_template, 4, &h_obj1); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_CreateObject(h_session, obj2_template, 5, &h_obj2); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto destroy_1; + } + + /* try and create a monotonic object. This should fail + * since it is a read only feature. + */ + rc = funcs->C_CreateObject(h_session, counter1_template, 6, &h_counter1); + if (rc != CKR_ATTRIBUTE_READ_ONLY) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto destroy_2; + } + + rc = funcs->C_CreateObject(h_session, clock_template, 4, &h_clock); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto destroy_2; + } + + /* Search for the 2 objects w/o HW_FEATURE set */ + /* A NULL template here should return all objects in v2.01, but + * in v2.11, it should return all objects *except* HW_FEATURE + * objects. + */ + rc = funcs->C_FindObjectsInit(h_session, NULL, 0); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + rc = funcs->C_FindObjects(h_session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + /* So, we created 4 objects before here, and then searched with a NULL + * template, so that should return all objects except our hardware + * feature object + */ + if (find_count != 2) { + testcase_fail("found %ld objects when expected 2", find_count); + rc = -1; + goto destroy; + } + + if (obj_list[0] != h_obj1 && obj_list[0] != h_obj2) { + testcase_fail("found the wrong object handle"); + rc = -1; + goto destroy; + } + + if (obj_list[1] != h_obj1 && obj_list[1] != h_obj2) { + testcase_fail("found the wrong object handle"); + rc = -1; + goto destroy; + } + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + // Now find the hardware feature objects + rc = funcs->C_FindObjectsInit(h_session, find_tmpl, 1); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + rc = funcs->C_FindObjects(h_session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + if (find_count != 1) { + testcase_fail("found %ld objects when expected 1", find_count); + funcs->C_FindObjectsFinal(h_session); + rc = -1; + goto destroy; + } + + /* Make sure we got the right ones */ + for (i = 0; i < find_count; i++) { + if (obj_list[i] != h_counter1 && obj_list[i] != h_clock) { + testcase_fail("found the wrong object handles"); + rc = -1; + } + } + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + } + + testcase_pass("Looks okay..."); + +destroy: + /* Destroy the created objects, don't clobber the rc */ + loc_rc = funcs->C_DestroyObject(h_session, h_clock); + if (loc_rc != CKR_OK) + testcase_fail("C_DestroyObject() rc = %s", p11_get_ckr(loc_rc)); +destroy_2: + loc_rc = funcs->C_DestroyObject(h_session, h_obj2); + if (loc_rc != CKR_OK) + testcase_fail("C_DestroyObject() rc = %s", p11_get_ckr(loc_rc)); +destroy_1: + loc_rc = funcs->C_DestroyObject(h_session, h_obj1); + if (loc_rc != CKR_OK) + testcase_fail("C_DestroyObject() rc = %s", p11_get_ckr(loc_rc)); + + loc_rc = funcs->C_Logout(h_session); + if (loc_rc != CKR_OK) + testcase_fail("C_Logout() rc = %s", p11_get_ckr(loc_rc)); + +session_close: + /* Close the session */ + loc_rc = funcs->C_CloseSession(h_session); + if (loc_rc != CKR_OK) + testcase_fail("C_CloseSession() rc = %s", p11_get_ckr(loc_rc)); + +done: + return rc; +} + +CK_RV obj_mgmt_functions() +{ + int rc; + + rc = do_CreateSessionObject(); + if (rc && !no_stop) + return rc; + + rc = do_CopyObject(); + if (rc && !no_stop) + return rc; + + rc = do_SetAttributeValues(); + if (rc && !no_stop) + return rc; + + rc = do_FindObjects(); + if (rc && !no_stop) + return rc; + + rc = do_HWFeatureSearch(); + if (rc && !no_stop) + return rc; + + rc = do_CreateTokenObjects(); + if (rc && !no_stop) + return rc; + + return rc; +} + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + int rc; + CK_RV rv; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: no_init: %d, no_stop: %d, skip_token_obj: %d\n", + no_init, no_stop, skip_token_obj); + + rc = do_GetFunctionList(); + if (!rc) { + testcase_error_f("(setup)", "do_GetFunctionList() rc = %s", + p11_get_ckr(rc)); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + // SAB Add calls to ALL functions before the C_Initialize gets hit + + funcs->C_Initialize(&cinit_args); + + { + CK_SESSION_HANDLE hsess = 0; + + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + } + + rv = obj_mgmt_functions(); + + /* make sure we return non-zero if rv is non-zero */ + return ((rv == 0) || (rv % 256) ? (int)rv : -1); +} diff --git a/testcases/misc_tests/obj_mgmt_lock.c b/testcases/misc_tests/obj_mgmt_lock.c new file mode 100644 index 0000000..45b846b --- /dev/null +++ b/testcases/misc_tests/obj_mgmt_lock.c @@ -0,0 +1,1274 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2012-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 + */ + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "common.c" + + +#define AES_KEY_SIZE_128 16 + +/* API Routines exercised that take /var/lock/LCK..opencryptoki spinlock. + * C_OpenSession + * C_CloseSession + * + * API Routines exercised that cause stdll to take /var/lock/opencryptoki_stdll + * spinlock. + * C_CreateObject + * C_Login + * + * 1) create a data object + * 2) create a certificate + */ +CK_RV do_CreateSessionObject(void) +{ + CK_SLOT_ID slot_id; + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + CK_BYTE false = FALSE; + + CK_OBJECT_HANDLE h_data; + CK_OBJECT_CLASS data_class = CKO_DATA; + CK_BYTE data_application[] = "Test Application"; + CK_BYTE data_value[] = "1234567890abcedfghijklmnopqrstuvwxyz"; + CK_ATTRIBUTE data_attribs[] = { + {CKA_CLASS, &data_class, sizeof(data_class)}, + {CKA_TOKEN, &false, sizeof(false)}, + {CKA_APPLICATION, &data_application, sizeof(data_application)}, + {CKA_VALUE, &data_value, sizeof(data_value)} + }; + + CK_OBJECT_HANDLE h_cert; + CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE cert_type = CKC_X_509; + CK_BYTE cert_subject[] = "Certificate subject"; + CK_BYTE cert_id[] = "Certificate ID"; + CK_BYTE cert_value[] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + CK_ATTRIBUTE cert_attribs[] = { + {CKA_CLASS, &cert_class, sizeof(cert_class)}, + {CKA_TOKEN, &false, sizeof(false)}, + {CKA_CERTIFICATE_TYPE, &cert_type, sizeof(cert_type)}, + {CKA_SUBJECT, &cert_subject, sizeof(cert_subject)}, + {CKA_ID, &cert_id, sizeof(cert_id)}, + {CKA_VALUE, &cert_value, sizeof(cert_value)} + }; + + testcase_begin("starting..."); + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + slot_id = SLOT_ID; + + // create a USER R/W session + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + testcase_fail("C_OpenSession() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + testcase_fail("C_Login() rc = %s", p11_get_ckr(rc)); + goto done; + } + + // now, create the objects + rc = funcs->C_CreateObject(h_session, data_attribs, 4, &h_data); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto done; + } + + rc = funcs->C_CreateObject(h_session, cert_attribs, 6, &h_cert); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto done; + } + +done: + // done...close the session and verify the object is deleted + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_fail("C_CloseAllSessions() rc=%s", p11_get_ckr(rc)); + return rc; + } + + testcase_pass("looks okay..."); + + return rc; +} + +/* API Routines exercised that take /var/lock/LCK..opencryptoki spinlock. + * C_OpenSession + * C_CloseSession + * + * API routines exercised that result in stdll taking + * /var/lock/opencryptoki_stdll spinlock. + * C_CreateObject + * C_CopyObject + * C_DestroyObject + * C_GetAttributeValue + * C_GetObjectSize + * + * 1) create a data object with no CKA_APPLICATION attribute + * 2) create a copy of the object specifying the CKA_APPLICATION attribute + * 3) extract the CK_VALUE attribute from the copy. Ensure matches the original + * 4) extract the CKA_APPLICATION attribute from the original. ensure empty. + * 5) extract the CKA_APPLICATION attribute from the copy. ensure is correct. + * 6) attempt to extract CK_PRIME from the original. ensure fails correctly. + * 7) attempt to extract CK_PRIME from a non-existant object. ensure fails + * correctly. + * 8) get the size of the original object and copied objects + * 9) destroy the original object. ensure this succeeds. + * A) destroy a non-existant object. ensure this fails correctly. + * B) get the size of the original object. ensure this fails correctly. + */ +CK_RV do_CopyObject(void) +{ + CK_SLOT_ID slot_id; + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc = 0, loc_rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_ULONG obj_size; + + CK_BYTE true = TRUE; + + CK_OBJECT_HANDLE h_data; + CK_OBJECT_CLASS data_class = CKO_DATA; + CK_BYTE data_application[] = "Test Application"; + CK_BYTE data_value[] = "1234567890abcedfghijklmnopqrstuvwxyz"; + CK_ATTRIBUTE data_attribs[] = { + {CKA_CLASS, &data_class, sizeof(data_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_VALUE, &data_value, sizeof(data_value)} + }; + + CK_OBJECT_HANDLE h_copy; + CK_ATTRIBUTE copy_attribs[] = { + {CKA_APPLICATION, &data_application, sizeof(data_application)} + }; + + CK_BYTE buf1[100]; + CK_ATTRIBUTE verify_attribs[] = { + {CKA_APPLICATION, &buf1, sizeof(buf1)} + }; + + CK_BYTE buf2[100]; + CK_ATTRIBUTE prime_attribs[] = { + {CKA_PRIME, &buf2, sizeof(buf2)} + }; + + testcase_begin("starting..."); + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + slot_id = SLOT_ID; + + /* create a USER R/W session */ + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + testcase_fail("C_OpenSession() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + testcase_fail("C_Login() rc = %s", p11_get_ckr(rc)); + goto done; + } + + /* create the object */ + rc = funcs->C_CreateObject(h_session, data_attribs, 3, &h_data); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto done; + } + + /* create the copy */ + rc = funcs->C_CopyObject(h_session, h_data, copy_attribs, 1, &h_copy); + if (rc != CKR_OK) { + testcase_fail("C_CopyObject() rc = %s", p11_get_ckr(rc)); + goto destroy_1; + } + + /* now, try to extract the CKA_APPLICATION attribute from the original + * this will pull in the token's default value for CKA_APPLICATION which + */ + verify_attribs[0].ulValueLen = sizeof(buf1); + rc = funcs->C_GetAttributeValue(h_session, h_data, verify_attribs, 1); + if (rc != CKR_OK) { + testcase_fail("C_GetAttributeValue() rc=%s", p11_get_ckr(rc)); + goto destroy; + } + + /* now, try to extract the CKA_APPLICATION attribute from the copy */ + verify_attribs[0].ulValueLen = sizeof(buf1); + rc = funcs->C_GetAttributeValue(h_session, h_copy, verify_attribs, 1); + if (rc != CKR_OK) { + testcase_fail("C_GetAttributeValue() rc=%s", p11_get_ckr(rc)); + goto destroy; + } + + if (memcmp(&data_application, + verify_attribs[0].pValue, sizeof(data_application)) != 0) { + testcase_fail("extracted attribute doesn't match"); + rc = -1; + goto destroy; + } + + /* now, try to extract CKA_PRIME from the original. + * this should not exist + */ + prime_attribs[0].ulValueLen = sizeof(buf2); + rc = funcs->C_GetAttributeValue(h_session, h_data, prime_attribs, 1); + if (rc != CKR_ATTRIBUTE_TYPE_INVALID) { + testcase_fail("C_GetAttributeValue() rc = %s (expected " + "CKR_ATTRIBUTE_TYPE_INVALID)", p11_get_ckr(rc)); + goto destroy; + } + + /* now, try to extract CKA_PRIME from a bogus object handle. + * this should not exist + */ + rc = funcs->C_GetAttributeValue(h_session, 98765, prime_attribs, 1); + if (rc != CKR_OBJECT_HANDLE_INVALID) { + testcase_fail("C_GetAttributeValue() rc = %s (expected " + "CKR_OBJECT_HANDLE_INVALID)", p11_get_ckr(rc)); + goto destroy; + } + + /* now, get the size of the original object */ + rc = funcs->C_GetObjectSize(h_session, h_data, &obj_size); + if (rc != CKR_OK) { + testcase_fail("C_GetObjectSize() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + testcase_pass("Looks okay..."); + +destroy: + /* now, destroy the original object and the copy */ + loc_rc = funcs->C_DestroyObject(h_session, h_copy); + if (loc_rc != CKR_OK) + testcase_error("C_DestroyObject() loc_rc = %s", p11_get_ckr(loc_rc)); + +destroy_1: + loc_rc = funcs->C_DestroyObject(h_session, h_data); + if (loc_rc != CKR_OK) + testcase_error("C_DestroyObject() loc_rc = %s", p11_get_ckr(loc_rc)); + +done: + loc_rc = funcs->C_CloseAllSessions(slot_id); + if (loc_rc != CKR_OK) + testcase_error("C_CloseAllSessions() loc_rc=%s", p11_get_ckr(loc_rc)); + + return rc; +} + + +/* API Routines exercised that take /var/lock/LCK..opencryptoki spinlock. + * C_OpenSession + * C_CloseSession + * + * API routines exercised that result in stdll taking + * /var/lock/opencryptoki_stdll spinlock. + * C_CreateObject + * C_GetAttributeValue + * C_SetAttributeValue + * + * 1) create a certificate object with no CKA_SERIAL_NUMBER or CKA_ISSUER + * 2) add CKA_SERIAL_NUMBER and CKA_ISSUER and modify CKA_ID. + * verify this works. + * 3) try to modify CKA_VALUE and CKA_ID in a single call to + * C_SetAttributeValue. verify that this fails correctly and that + * the object is not modified. + */ +CK_RV do_SetAttributeValues(void) +{ + CK_SLOT_ID slot_id; + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc = 0, loc_rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + CK_BYTE true = TRUE; + + CK_OBJECT_HANDLE h_cert; + CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE cert_type = CKC_X_509; + CK_BYTE cert_subject[] = "Certificate subject"; + CK_BYTE cert_id[] = "Certificate ID"; + CK_BYTE cert_value[] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + + CK_ATTRIBUTE cert_attribs[] = { + {CKA_CLASS, &cert_class, sizeof(cert_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_CERTIFICATE_TYPE, &cert_type, sizeof(cert_type)}, + {CKA_SUBJECT, &cert_subject, sizeof(cert_subject)}, + {CKA_ID, &cert_id, sizeof(cert_id)}, + {CKA_VALUE, &cert_value, sizeof(cert_value)} + }; + + CK_BYTE cert_id2[] = "New ID"; + CK_BYTE cert_issuer[] = "Certificate Issuer"; + CK_BYTE cert_ser_no[] = "Serial Number: 12345"; + CK_ATTRIBUTE update_attr[] = { + {CKA_SERIAL_NUMBER, &cert_ser_no, sizeof(cert_ser_no)}, + {CKA_ISSUER, &cert_issuer, sizeof(cert_issuer)}, + {CKA_ID, &cert_id2, sizeof(cert_id2)} + }; + + CK_BYTE cert_value2[] = "Invalid Value"; + CK_BYTE cert_id3[] = "ID #3"; + CK_ATTRIBUTE invalid_attr[] = { + {CKA_VALUE, &cert_value2, sizeof(cert_value2)}, + {CKA_ID, &cert_id3, sizeof(cert_id3)} + }; + + testcase_begin("starting..."); + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + slot_id = SLOT_ID; + + /* create a USER R/W session */ + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + testcase_fail("C_OpenSession() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + testcase_fail("C_Login() rc = %s", p11_get_ckr(rc)); + goto error; + } + + /* create the object */ + rc = funcs->C_CreateObject(h_session, cert_attribs, 6, &h_cert); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto error; + } + + /* Add CKA_SERIAL_NUMBER and CKA_ISSUER and change the + * existing CKA_ID + */ + rc = funcs->C_SetAttributeValue(h_session, h_cert, update_attr, 3); + if (rc != CKR_OK) { + testcase_fail("C_SetAttributeValue() rc = %s", p11_get_ckr(rc)); + goto done; + } else { + CK_BYTE buf1[100]; + CK_BYTE buf2[100]; + CK_BYTE buf3[100]; + CK_ATTRIBUTE check1[] = { + {CKA_ISSUER, &buf1, sizeof(buf1)}, + {CKA_SERIAL_NUMBER, &buf2, sizeof(buf2)}, + {CKA_ID, &buf3, sizeof(buf3)} + }; + + rc = funcs->C_GetAttributeValue(h_session, h_cert, + (CK_ATTRIBUTE *) & check1, 3); + if (rc != CKR_OK) { + testcase_fail("C_GetAttributeValue() rc = %s", p11_get_ckr(rc)); + goto done; + } + + if (memcmp(check1[0].pValue, cert_issuer, check1[0].ulValueLen) != 0) { + testcase_fail("CKA_ISSUER mismatch"); + rc = -1; + goto done; + } + + if (memcmp(check1[1].pValue, cert_ser_no, check1[1].ulValueLen) != 0) { + testcase_fail("CKA_SERIAL_NUMBER mismatch"); + rc = -1; + goto done; + } + + if (memcmp(check1[2].pValue, cert_id2, check1[2].ulValueLen) != 0) { + testcase_fail("CKA_ID mismatch"); + rc = -1; + goto done; + } + } + + /* the next template tries to update a CK_ID (valid) and + * CKA_VALUE (read-only). the entire operation should fail -- no + * attributes should get modified + */ + rc = funcs->C_SetAttributeValue(h_session, h_cert, invalid_attr, 2); + if (rc != CKR_ATTRIBUTE_READ_ONLY) { + testcase_fail + ("C_SetAttributeValue() rc = %s (expected CKR_ATTRIBUTE_READ_ONLY)", + p11_get_ckr(rc)); + goto done; + } else { + CK_BYTE buf1[100]; + CK_ATTRIBUTE check1[] = { + {CKA_ID, &buf1, sizeof(buf1)} + }; + + rc = funcs->C_GetAttributeValue(h_session, h_cert, check1, 1); + if (rc != CKR_OK) { + testcase_fail("C_GetAttributeValue() rc = %s", p11_get_ckr(rc)); + goto done; + } + + if (memcmp(check1[0].pValue, cert_id2, check1[0].ulValueLen) != 0) { + testcase_fail("CKA_ID mismatch"); + rc = -1; + goto done; + } + } + + testcase_pass("Looks okay..."); + +done: + /* now destroy the objects but don't clobber rc */ + loc_rc = funcs->C_DestroyObject(h_session, h_cert); + if (loc_rc != CKR_OK) + testcase_error("C_DestroyObject() loc_rc = %s", p11_get_ckr(loc_rc)); + +error: + /* done...close the session */ + loc_rc = funcs->C_CloseAllSessions(slot_id); + if (loc_rc != CKR_OK) + testcase_error("C_CloseAllSessions() loc_rc = %s", p11_get_ckr(loc_rc)); + + return rc; +} + +/* API Routines exercised that take /var/lock/LCK..opencryptoki spinlock. + * C_OpenSession + * C_CloseSession + * + * API routines exercised that result in stdll taking + * /var/lock/opencryptoki_stdll spinlock. + * C_FindObjectsInit + * C_FindObjects + * C_CreateObject + * + * 1) Create 3 certificates with different CKA_ID attributes + * 2) Search for a particular CKA_ID. Verify this works. + * 3) Search for a non-existant CKA_ID. Verify this returns nothing. + * 4) Specify an empty template. Verify that all 3 objects are returned. + */ +CK_RV do_FindObjects(void) +{ + CK_SLOT_ID slot_id; + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc = 0, loc_rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + CK_BYTE true = TRUE; + + CK_OBJECT_HANDLE h_cert1; + CK_OBJECT_CLASS cert1_class = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE cert1_type = CKC_X_509; + CK_BYTE cert1_subject[] = "Certificate subject #1"; + CK_BYTE cert1_id[] = "Certificate ID #1"; + CK_BYTE cert1_value[] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + + CK_ATTRIBUTE cert1_attribs[] = { + {CKA_CLASS, &cert1_class, sizeof(cert1_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_CERTIFICATE_TYPE, &cert1_type, sizeof(cert1_type)}, + {CKA_SUBJECT, &cert1_subject, sizeof(cert1_subject)}, + {CKA_ID, &cert1_id, sizeof(cert1_id)}, + {CKA_VALUE, &cert1_value, sizeof(cert1_value)} + }; + + CK_OBJECT_HANDLE h_cert2; + CK_OBJECT_CLASS cert2_class = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE cert2_type = CKC_X_509; + CK_BYTE cert2_subject[] = "Certificate subject #2"; + CK_BYTE cert2_id[] = "Certificate ID #2"; + CK_BYTE cert2_value[] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + + CK_ATTRIBUTE cert2_attribs[] = { + {CKA_CLASS, &cert2_class, sizeof(cert2_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_CERTIFICATE_TYPE, &cert2_type, sizeof(cert2_type)}, + {CKA_SUBJECT, &cert2_subject, sizeof(cert2_subject)}, + {CKA_ID, &cert2_id, sizeof(cert2_id)}, + {CKA_VALUE, &cert2_value, sizeof(cert2_value)} + }; + + CK_OBJECT_HANDLE h_cert3; + CK_OBJECT_CLASS cert3_class = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE cert3_type = CKC_X_509; + CK_BYTE cert3_subject[] = "Certificate subject #3"; + CK_BYTE cert3_id[] = "Certificate ID #3"; + CK_BYTE cert3_value[] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + + CK_ATTRIBUTE cert3_attribs[] = { + {CKA_CLASS, &cert3_class, sizeof(cert3_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_CERTIFICATE_TYPE, &cert3_type, sizeof(cert3_type)}, + {CKA_SUBJECT, &cert3_subject, sizeof(cert3_subject)}, + {CKA_ID, &cert3_id, sizeof(cert3_id)}, + {CKA_VALUE, &cert3_value, sizeof(cert3_value)} + }; + + CK_BYTE find1_id[] = "Certificate ID #2"; + CK_ATTRIBUTE find1_attribs[] = { + {CKA_ID, &find1_id, sizeof(find1_id)} + }; + + CK_BYTE find2_id[] = "Certificate ID #12345"; + CK_ATTRIBUTE find2_attribs[] = { + {CKA_ID, &find2_id, sizeof(find2_id)} + }; + + CK_OBJECT_HANDLE obj_list[10]; + CK_ULONG find_count; + unsigned int i; + int got_it = 0; + + testcase_begin("starting..."); + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + slot_id = SLOT_ID; + + /* create a USER R/W session */ + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + testcase_fail("C_OpenSession() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + testcase_fail("C_Login() rc = %s", p11_get_ckr(rc)); + goto done; + } + + /* create the objects */ + rc = funcs->C_CreateObject(h_session, cert1_attribs, 6, &h_cert1); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto done; + } + + rc = funcs->C_CreateObject(h_session, cert2_attribs, 6, &h_cert2); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto destroy_1; + } + + rc = funcs->C_CreateObject(h_session, cert3_attribs, 6, &h_cert3); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto destroy_2; + } + + /* now, search for the 2nd objects */ + rc = funcs->C_FindObjectsInit(h_session, find1_attribs, 1); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + do { + rc = funcs->C_FindObjects(h_session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + /* step through list and find our object handle */ + for (i = 0; i < find_count; i++) { + if (obj_list[i] == h_cert2) + got_it++; + } + } while (got_it == 0 && find_count != 0); + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + if (got_it == 0) { + testcase_fail("could not find object handle"); + rc = -1; + goto destroy; + } + + /* now, search for a non-existant object */ + rc = funcs->C_FindObjectsInit(h_session, find2_attribs, 1); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + rc = funcs->C_FindObjects(h_session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + if (find_count != 0) { + testcase_fail("found %ld objects when none where expected", find_count); + rc = -1; + goto destroy; + } + + testcase_pass("Looks okay..."); + +destroy: + /* now destroy the objects that were created */ + loc_rc = funcs->C_DestroyObject(h_session, h_cert3); + if (loc_rc != CKR_OK) + testcase_error("C_DestroyObject() loc_rc = %s", p11_get_ckr(loc_rc)); + +destroy_2: + loc_rc = funcs->C_DestroyObject(h_session, h_cert2); + if (loc_rc != CKR_OK) + testcase_error("C_DestroyObject() loc_rc = %s", p11_get_ckr(loc_rc)); + +destroy_1: + loc_rc = funcs->C_DestroyObject(h_session, h_cert1); + if (loc_rc != CKR_OK) + testcase_error("C_DestroyObject() loc_rc = %s", p11_get_ckr(loc_rc)); + +done: + /* done...close the session */ + loc_rc = funcs->C_CloseAllSessions(slot_id); + if (loc_rc != CKR_OK) + testcase_error("C_CloseAllSessions() loc_rc = %s", p11_get_ckr(loc_rc)); + + return rc; +} + +/* API Routines exercised that take /var/lock/LCK..opencryptoki spinlock. + * C_OpenSession + * C_CloseSession + * + * API routines exercised that result in stdll taking + * /var/lock/opencryptoki_stdll spinlock. + * C_FindObjectsInit + * C_FindObjects + * C_CreateObject + * + * 1) Create 3 certificates as PUBLIC token objects + * 2) Search for a particular CKA_ID. Verify that this works. + * 3) Do FindObjects with a NULL template. Verify that all 3 token objects + * are found. + * 4) Search for a particular CKA_ID. Verify it works. + * 5) Search for a non-existant CKA_ID. Verify it returns nothing. + * 6) Close all sessions. Then create a new session. + * 7) Search for a particular CKA_ID. Verify it works. + * 8) Search for a non-existant CKA_ID. Verify it returns nothing. + * 9) Destroy all 3 token objects + */ +CK_RV do_CreateTokenObjects(void) +{ + unsigned int i; + int got_it = 0; + CK_SLOT_ID slot_id; + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc = 0, loc_rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + CK_BYTE true = TRUE; + CK_BYTE false = FALSE; + + CK_OBJECT_HANDLE h_cert1; + CK_OBJECT_CLASS cert1_class = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE cert1_type = CKC_X_509; + CK_BYTE cert1_subject[] = "Certificate subject #1"; + CK_BYTE cert1_id[] = "Certificate ID #1"; + CK_BYTE cert1_value[] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + + CK_ATTRIBUTE cert1_attribs[] = { + {CKA_CLASS, &cert1_class, sizeof(cert1_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_CERTIFICATE_TYPE, &cert1_type, sizeof(cert1_type)}, + {CKA_SUBJECT, &cert1_subject, sizeof(cert1_subject)}, + {CKA_ID, &cert1_id, sizeof(cert1_id)}, + {CKA_VALUE, &cert1_value, sizeof(cert1_value)}, + {CKA_PRIVATE, &false, sizeof(false)} + }; + + CK_OBJECT_HANDLE h_cert2; + CK_OBJECT_CLASS cert2_class = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE cert2_type = CKC_X_509; + CK_BYTE cert2_subject[] = "Certificate subject #2"; + CK_BYTE cert2_id[] = "Certificate ID #2"; + CK_BYTE cert2_value[] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + + CK_ATTRIBUTE cert2_attribs[] = { + {CKA_CLASS, &cert2_class, sizeof(cert2_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_CERTIFICATE_TYPE, &cert2_type, sizeof(cert2_type)}, + {CKA_SUBJECT, &cert2_subject, sizeof(cert2_subject)}, + {CKA_ID, &cert2_id, sizeof(cert2_id)}, + {CKA_VALUE, &cert2_value, sizeof(cert2_value)}, + {CKA_PRIVATE, &false, sizeof(false)} + }; + + CK_OBJECT_HANDLE h_cert3; + CK_OBJECT_CLASS cert3_class = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE cert3_type = CKC_X_509; + CK_BYTE cert3_subject[] = "Certificate subject #3"; + CK_BYTE cert3_id[] = "Certificate ID #3"; + CK_BYTE cert3_value[] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + + CK_ATTRIBUTE cert3_attribs[] = { + {CKA_CLASS, &cert3_class, sizeof(cert3_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_CERTIFICATE_TYPE, &cert3_type, sizeof(cert3_type)}, + {CKA_SUBJECT, &cert3_subject, sizeof(cert3_subject)}, + {CKA_ID, &cert3_id, sizeof(cert3_id)}, + {CKA_VALUE, &cert3_value, sizeof(cert3_value)}, + {CKA_PRIVATE, &false, sizeof(false)} + }; + + CK_BYTE find1_id[] = "Certificate ID #2"; + CK_ATTRIBUTE find1_attribs[] = { + {CKA_ID, &find1_id, sizeof(find1_id)} + }; + + CK_BYTE find2_id[] = "Certificate ID #123456"; + CK_ATTRIBUTE find2_attribs[] = { + {CKA_ID, &find2_id, sizeof(find2_id)} + }; + + CK_OBJECT_HANDLE obj_list[10]; + CK_ULONG find_count; + + testcase_begin("starting..."); + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + slot_id = SLOT_ID; + + /* create a USER R/W session */ + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + testcase_fail("C_OpenSession() rc = %s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + testcase_fail("C_Login() rc = %s", p11_get_ckr(rc)); + goto done; + } + + /* create the token objects */ + rc = funcs->C_CreateObject(h_session, cert1_attribs, 7, &h_cert1); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto done; + } + + rc = funcs->C_CreateObject(h_session, cert2_attribs, 7, &h_cert2); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto destroy_1; + } + + rc = funcs->C_CreateObject(h_session, cert3_attribs, 7, &h_cert3); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto destroy_2; + } + + /* now, search for the 2nd object */ + rc = funcs->C_FindObjectsInit(h_session, find1_attribs, 1); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + do { + rc = funcs->C_FindObjects(h_session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + /* step through list and find 2nd object's handle */ + for (i = 0; i < find_count; i++) { + if (obj_list[i] == h_cert2) + got_it++; + } + } while (got_it == 0 && find_count != 0); + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + if (got_it == 0) { + testcase_fail("could not find 2nd object's handle"); + rc = -1; + goto destroy; + } + + /* now, search for a non-existant attribute */ + rc = funcs->C_FindObjectsInit(h_session, find2_attribs, 1); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + rc = funcs->C_FindObjects(h_session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + if (find_count != 0) { + testcase_fail("found %ld objects when none where expected", find_count); + rc = -1; + goto destroy; + } + + /* done...close all sessions and open a new one */ + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + testcase_fail("C_CloseAllSessions() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + /* create a USER R/W session */ + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + testcase_fail("C_OpenSession() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + testcase_fail("C_Login() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + /* now, search for the 2nd object */ + rc = funcs->C_FindObjectsInit(h_session, find1_attribs, 1); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + do { + rc = funcs->C_FindObjects(h_session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + /* step through list and find 2nd object's handle */ + got_it = 0; + for (i = 0; i < find_count; i++) { + if (obj_list[i] == h_cert2) + got_it++; + } + } while (got_it == 0 && find_count != 0); + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + if (got_it == 0) { + testcase_fail("could not find 2nd object's handle in new session"); + rc = -1; + goto destroy; + } + + /* now, search for a non-existant attribute */ + rc = funcs->C_FindObjectsInit(h_session, find2_attribs, 1); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + rc = funcs->C_FindObjects(h_session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + if (find_count != 0) { + testcase_fail("found %ld objects when none where expected", find_count); + rc = -1; + goto destroy; + } + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + testcase_pass("Looks okay..."); + + /* Destroy the created objects, don't clobber the rc */ +destroy: + loc_rc = funcs->C_DestroyObject(h_session, h_cert3); + if (loc_rc != CKR_OK) + testcase_error("C_DestroyObject() loc_rc = %s", p11_get_ckr(loc_rc)); + +destroy_2: + loc_rc = funcs->C_DestroyObject(h_session, h_cert2); + if (loc_rc != CKR_OK) + testcase_error("C_DestroyObject() loc_rc = %s", p11_get_ckr(loc_rc)); + +destroy_1: + loc_rc = funcs->C_DestroyObject(h_session, h_cert1); + if (loc_rc != CKR_OK) + testcase_error("C_DestroyObject() loc_rc = %s", p11_get_ckr(loc_rc)); + +done: + /* done...close the session */ + loc_rc = funcs->C_CloseAllSessions(slot_id); + if (loc_rc != CKR_OK) + testcase_error("C_CloseAllSessions() loc_rc = %s", p11_get_ckr(loc_rc)); + + return rc; +} + +/* + * do_HW_Feature_Search Test: + * + * 1. Create 5 objects, 3 of which are HW_FEATURE objects. + * 2. Search for objects using a template that does have its + * HW_FEATURE attribute set. + * 3. Result should be that the hardware feature object is returned. + * + */ + +CK_RV do_HWFeatureSearch(void) +{ + unsigned int i, got_it = 0; + CK_RV rc, loc_rc; + CK_ULONG find_count; + CK_SLOT_ID slot_id; + CK_BBOOL false = FALSE; + CK_BBOOL true = TRUE; + + CK_SESSION_HANDLE h_session = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN] = {0}; + CK_ULONG user_pin_len = 0; + + /* A counter object */ + CK_OBJECT_CLASS counter1_class = CKO_HW_FEATURE; + CK_HW_FEATURE_TYPE feature1_type = CKH_MONOTONIC_COUNTER; + CK_UTF8CHAR counter1_label[] = "Monotonic counter"; + CK_CHAR counter1_value[16]; + CK_ATTRIBUTE counter1_template[] = { + {CKA_CLASS, &counter1_class, sizeof(counter1_class)}, + {CKA_HW_FEATURE_TYPE, &feature1_type, sizeof(feature1_type)}, + {CKA_LABEL, counter1_label, sizeof(counter1_label) - 1}, + {CKA_VALUE, counter1_value, sizeof(counter1_value)}, + {CKA_RESET_ON_INIT, &true, sizeof(true)}, + {CKA_HAS_RESET, &false, sizeof(false)} + }; + + /* A clock object */ + CK_OBJECT_CLASS clock_class = CKO_HW_FEATURE; + CK_HW_FEATURE_TYPE clock_type = CKH_CLOCK; + CK_UTF8CHAR clock_label[] = "Clock"; + CK_CHAR clock_value[16] = {0}; + CK_ATTRIBUTE clock_template[] = { + {CKA_CLASS, &clock_class, sizeof(clock_class)}, + {CKA_HW_FEATURE_TYPE, &clock_type, sizeof(clock_type)}, + {CKA_LABEL, clock_label, sizeof(clock_label) - 1}, + {CKA_VALUE, clock_value, sizeof(clock_value)} + }; + + /* A data object */ + CK_OBJECT_CLASS obj1_class = CKO_DATA; + CK_UTF8CHAR obj1_label[] = "Object 1"; + CK_BYTE obj1_data[] = "Object 1's data"; + CK_ATTRIBUTE obj1_template[] = { + {CKA_CLASS, &obj1_class, sizeof(obj1_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_LABEL, obj1_label, sizeof(obj1_label) - 1}, + {CKA_VALUE, obj1_data, sizeof(obj1_data)} + }; + + /* A secret key object */ + CK_OBJECT_CLASS obj2_class = CKO_SECRET_KEY; + CK_KEY_TYPE obj2_type = CKK_AES; + CK_UTF8CHAR obj2_label[] = "Object 2"; + CK_BYTE obj2_data[AES_KEY_SIZE_128] = {0}; + CK_ATTRIBUTE obj2_template[] = { + {CKA_CLASS, &obj2_class, sizeof(obj2_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_KEY_TYPE, &obj2_type, sizeof(obj2_type)}, + {CKA_LABEL, obj2_label, sizeof(obj2_label) - 1}, + {CKA_VALUE, obj2_data, sizeof(obj2_data)} + }; + + CK_OBJECT_HANDLE h_counter1 = 0, h_clock = 0, h_obj1 = 0, h_obj2 = 0, + obj_list[10] = {0}; + CK_ATTRIBUTE find_tmpl[] = { + {CKA_CLASS, &counter1_class, sizeof(counter1_class)} + }; + + slot_id = SLOT_ID; + + testcase_begin("starting..."); + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + /* Open a session with the token */ + if ((rc = funcs->C_OpenSession(slot_id, + (CKF_SERIAL_SESSION | CKF_RW_SESSION), + NULL_PTR, NULL_PTR, &h_session)) != CKR_OK) { + testcase_fail("C_OpenSession() rc = %s", p11_get_ckr(rc)); + return rc; + } + + // Login correctly + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + testcase_fail("C_Login() rc = %s", p11_get_ckr(rc)); + goto session_close; + } + + /* Create the 3 test objects */ + if ((rc = funcs->C_CreateObject(h_session, obj1_template, + 4, &h_obj1)) != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto session_close; + } + + if ((rc = funcs->C_CreateObject(h_session, obj2_template, + 5, &h_obj2)) != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto destroy_1; + } + + /* try and create a monotonic object. This should fail + * since it is a read only feature. + */ + if ((rc = funcs->C_CreateObject(h_session, counter1_template, 6, + &h_counter1)) != CKR_ATTRIBUTE_READ_ONLY) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto destroy_2; + } + + if ((rc = funcs->C_CreateObject(h_session, clock_template, + 4, &h_clock)) != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto destroy_2; + } + + /* Now find the hardware feature objects */ + rc = funcs->C_FindObjectsInit(h_session, find_tmpl, 1); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + do { + rc = funcs->C_FindObjects(h_session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + goto destroy; + } + + got_it = 0; + /* Make sure we got the right ones */ + for (i = 0; i < find_count; i++) { + if (obj_list[i] == h_clock) { + got_it++; + } + } + } while (got_it == 0 && find_count != 0); + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + } + + if (got_it != 1) { + testcase_fail("could not find the corect object handle"); + rc = -1; + goto destroy; + } + + testcase_pass("Looks okay..."); + +destroy: + /* Destroy the created objects, don't clobber the rc */ + loc_rc = funcs->C_DestroyObject(h_session, h_clock); + if (loc_rc != CKR_OK) + testcase_error("C_DestroyObject() rc = %s", p11_get_ckr(loc_rc)); +destroy_2: + loc_rc = funcs->C_DestroyObject(h_session, h_obj2); + if (loc_rc != CKR_OK) + testcase_error("C_DestroyObject() rc = %s", p11_get_ckr(loc_rc)); +destroy_1: + loc_rc = funcs->C_DestroyObject(h_session, h_obj1); + if (loc_rc != CKR_OK) + testcase_error("C_DestroyObject() rc = %s", p11_get_ckr(loc_rc)); + + loc_rc = funcs->C_Logout(h_session); + if (loc_rc != CKR_OK) + testcase_error("C_Logout() rc = %s", p11_get_ckr(loc_rc)); + +session_close: + /* Close the session */ + if ((loc_rc = funcs->C_CloseSession(h_session)) != CKR_OK) + testcase_error("C_CloseSession() rc = %s", p11_get_ckr(loc_rc)); + + return rc; +} + +CK_RV obj_mgmt_functions() +{ + int rc, errors = 0; + + rc = do_CreateSessionObject(); + if (rc) + errors++; + + rc = do_CopyObject(); + if (rc) + errors++; + + rc = do_SetAttributeValues(); + if (rc) + errors++; + + rc = do_FindObjects(); + if (rc) + errors++; + + rc = do_HWFeatureSearch(); + if (rc) + errors++; + + rc = do_CreateTokenObjects(); + if (rc) + errors++; + + return errors++; +} + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + int rc; + CK_RV rv; + + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: no_init: %d, no_stop: %d, skip_token_obj: %d\n", + no_init, no_stop, skip_token_obj); + + rc = do_GetFunctionList(); + if (!rc) { + testcase_error_f("(setup)", "do_GetFunctionList() rc = %s", + p11_get_ckr(rc)); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + // SAB Add calls to ALL functions before the C_Initialize gets hit + + funcs->C_Initialize(&cinit_args); + + { + CK_SESSION_HANDLE hsess = 0; + + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + } + + rv = obj_mgmt_functions(); + + /* make sure we return non-zero if rv is non-zero */ + return ((rv == 0) || (rv % 256) ? (int)rv : -1); +} diff --git a/testcases/misc_tests/speed.c b/testcases/misc_tests/speed.c new file mode 100644 index 0000000..39fdca0 --- /dev/null +++ b/testcases/misc_tests/speed.c @@ -0,0 +1,1138 @@ +/* + * 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 + */ + +/* File: speed.c + * + * Performance tests for Opencryptoki + * + * RSA keygen (with keylength 1024, 2048, 4096) + * RSA sign and verify (with keylength 1024, 2048, 4096) + * RSA encrypt and decrypt (with keylength 1024, 2048, 4096) + * DES3 encrypt and decrypt (with modes ECB and CBC) + * AES encrypt and decrypt (with modes ECB and CBC, with keylength 128, 192, + * 256), SHA1, SHA256, SHA512 + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "common.c" + +#define SHA1_HASH_LEN 20 +#define SHA256_HASH_LEN 32 +#define SHA512_HASH_LEN 64 +#define MAX_HASH_LEN SHA512_HASH_LEN + + +// the GetSystemTime and SYSTEMTIME implementation +// from regress.h only has a ms resolution +// and produces absolut inacceptable measurements. +// So we use gettimeofday() and struct timeval +// with us resolution instead. +#ifdef SYSTEMTIME +#undef SYSTEMTIME +#endif +#define SYSTEMTIME struct timeval +#ifdef GetSystemTime +#undef GetSystemTime +#endif +#define GetSystemTime(x) gettimeofday((x),NULL) +static inline unsigned long delta_time_us(struct timeval *t1, + struct timeval *t2) +{ + unsigned long d; + struct timeval td; + + timersub(t2, t1, &td); + d = td.tv_sec * 1000 * 1000 + td.tv_usec; + + return (d ? d : 1); // return 1us if delta is 0 +} + + +int do_GetFunctionList(void); + +// keylength: 512, 1024, 2048, 4096 +int do_RSA_PKCS_EncryptDecrypt(int keylength) +{ + CK_SLOT_ID slot_id; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rv, rc; + + CK_OBJECT_HANDLE publ_key, priv_key; + CK_BYTE data1[100]; + CK_BYTE data2[512]; + CK_BYTE encdata[512]; + CK_ULONG len1, len2, encdata_len; + + CK_ULONG i; + CK_ULONG iterations = 2000; + SYSTEMTIME t1, t2; + CK_ULONG diff, avg_time, min_time, max_time, tot_time; + + CK_ULONG bits = keylength; + CK_BYTE pub_exp[] = { 0x01, 0x00, 0x01 }; + + CK_ATTRIBUTE pub_tmpl[] = { + {CKA_MODULUS_BITS, &bits, sizeof(bits)}, + {CKA_PUBLIC_EXPONENT, &pub_exp, sizeof(pub_exp)} + }; + + testcase_begin("RSA PKCS Encrypt with keylen=%d datalen=%d", + keylength, (int) sizeof(data1)); + + slot_id = SLOT_ID; + + testcase_rw_session(); + testcase_user_login(); + + mech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rc = funcs->C_GenerateKeyPair(session, &mech, pub_tmpl, 2, NULL, 0, + &publ_key, &priv_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKeyPair rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + len1 = sizeof(data1); + encdata_len = sizeof(encdata); + for (i = 0; i < len1; i++) + data1[i] = (unsigned char) i; + + mech.mechanism = CKM_RSA_PKCS; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + tot_time = 0; + max_time = 0; + min_time = 0xFFFFFFFF; + + for (i = 0; i < iterations + 2; i++) { + GetSystemTime(&t1); + + rc = funcs->C_EncryptInit(session, &mech, publ_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + encdata_len = sizeof(encdata); + rc = funcs->C_Encrypt(session, data1, len1, encdata, &encdata_len); + if (rc != CKR_OK) { + testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + GetSystemTime(&t2); + + diff = delta_time_us(&t1, &t2); + + tot_time += diff; + + if (diff < min_time) + min_time = diff; + + if (diff > max_time) + max_time = diff; + } + + tot_time -= min_time; + tot_time -= max_time; + avg_time = tot_time / iterations; + + // us -> ms + tot_time /= 1000; + min_time /= 1000; + max_time /= 1000; + avg_time /= 1000; + + printf("%ld iterations: total=%ldms min=%ldms max=%ldms avg=%ldms " + "op/s=%.3f\n\n", iterations, tot_time, min_time, max_time, + avg_time, (double) (iterations * 1000) / (double) tot_time); + + printf("RSA PKCS Decrypt with keylen=%d datalen=%d\n", + keylength, (int) encdata_len); + + tot_time = 0; + max_time = 0; + min_time = 0xFFFFFFFF; + + for (i = 0; i < iterations + 2; i++) { + GetSystemTime(&t1); + + rc = funcs->C_DecryptInit(session, &mech, priv_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + len2 = sizeof(data2); + rc = funcs->C_Decrypt(session, encdata, encdata_len, data2, &len2); + if (rc != CKR_OK) { + testcase_error("C_Decrypt rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + if (len2 != len1) { + testcase_error("len1=%lu and len2=%lu do not match ?!?", + len1, len2); + rc = CKR_FUNCTION_FAILED;; + goto testcase_cleanup; + } + + GetSystemTime(&t2); + + diff = delta_time_us(&t1, &t2); + + tot_time += diff; + + if (diff < min_time) + min_time = diff; + + if (diff > max_time) + max_time = diff; + + } + + tot_time -= min_time; + tot_time -= max_time; + avg_time = tot_time / iterations; + + // us -> ms + tot_time /= 1000; + min_time /= 1000; + max_time /= 1000; + avg_time /= 1000; + + printf("%ld iterations: total=%ldms min=%ldms max=%ldms avg=%ldms " + "op/s=%.3f\n\n", iterations, tot_time, min_time, max_time, + avg_time, (double) (iterations * 1000) / (double) tot_time); + +testcase_cleanup: + rv = funcs->C_CloseAllSessions(slot_id); + if (rv != CKR_OK) { + testcase_error("C_CloseAllSessions rv=%s", p11_get_ckr(rv)); + return FALSE; + } + + return TRUE; +} + +// keylength: 512, 1024, 2048, 4096 +int do_RSA_KeyGen(int keylength) +{ + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rv, rc; + + CK_ULONG iterations = 10; + SYSTEMTIME t1, t2; + CK_ULONG diff, avg_time, max_time, min_time, tot_time, i; + CK_ULONG bits = 2048; + + CK_OBJECT_HANDLE publ_key, priv_key; + CK_BYTE pub_exp[] = { 0x01, 0x00, 0x01 }; + CK_ATTRIBUTE pub_tmpl[] = { + {CKA_MODULUS_BITS, &bits, sizeof(bits)}, + {CKA_PUBLIC_EXPONENT, &pub_exp, sizeof(pub_exp)} + }; + + testcase_begin("RSA KeyGen with keylen=%d", keylength); + + testcase_rw_session(); + testcase_user_login(); + + mech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rc = funcs->C_GenerateKeyPair(session, &mech, pub_tmpl, 2, NULL, 0, + &publ_key, &priv_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKeyPair rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + min_time = 0xFFFFFFFF; + max_time = 0x00000000; + tot_time = 0x00000000; + + for (i = 0; i < iterations + 2; i++) { + GetSystemTime(&t1); + rc = funcs->C_GenerateKeyPair(session, &mech, pub_tmpl, 2, + NULL, 0, &publ_key, &priv_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKeyPair rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + GetSystemTime(&t2); + diff = delta_time_us(&t1, &t2); + tot_time += diff; + if (diff < min_time) + min_time = diff; + if (diff > max_time) + max_time = diff; + } + + tot_time -= min_time; + tot_time -= max_time; + avg_time = tot_time / iterations; + + // us -> ms + tot_time /= 1000; + min_time /= 1000; + max_time /= 1000; + avg_time /= 1000; + + printf("%ld iterations: total=%ldms min=%ldms max=%ldms avg=%ldms " + "op/s=%.3f\n\n", iterations, tot_time, min_time, max_time, + avg_time, (double) (iterations * 1000) / (double) tot_time); + +testcase_cleanup: + rv = funcs->C_CloseSession(session); + if (rv != CKR_OK) { + testcase_error("C_CloseSession rv=%s", p11_get_ckr(rv)); + return FALSE; + } + + return TRUE; +} + +// keylength: 512, 1024, 2048, 4096 +int do_RSA_PKCS_SignVerify(int keylength) +{ + CK_SLOT_ID slot_id; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rv, rc; + + CK_ULONG i, len1, sig_len; + CK_BYTE signature[512]; + CK_BYTE data1[100]; + CK_OBJECT_HANDLE publ_key, priv_key; + + SYSTEMTIME t1, t2; + CK_ULONG diff, avg_time, min_time, max_time, tot_time; + CK_ULONG iterations = 1000; + + CK_ULONG bits = keylength; + CK_BYTE pub_exp[] = { 0x01, 0x00, 0x01 }; + CK_ATTRIBUTE pub_tmpl[] = { + {CKA_MODULUS_BITS, &bits, sizeof(bits)}, + {CKA_PUBLIC_EXPONENT, &pub_exp, sizeof(pub_exp)} + }; + + slot_id = SLOT_ID; + + testcase_begin("RSA PKCS Sign with keylen=%d datalen=%d", + keylength, (int) sizeof(data1)); + + testcase_rw_session(); + testcase_user_login(); + + mech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rc = funcs->C_GenerateKeyPair(session, &mech, pub_tmpl, 2, NULL, 0, + &publ_key, &priv_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKeyPair rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // sign some data + len1 = sizeof(data1); + sig_len = sizeof(signature); + + for (i = 0; i < len1; i++) + data1[i] = (unsigned char) i; + + mech.mechanism = CKM_RSA_PKCS; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + tot_time = 0; + max_time = 0; + min_time = 0xFFFFFFFF; + + for (i = 0; i < iterations + 2; i++) { + GetSystemTime(&t1); + + rc = funcs->C_SignInit(session, &mech, priv_key); + if (rc != CKR_OK) { + testcase_error("C_SignInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + sig_len = sizeof(signature); + rc = funcs->C_Sign(session, data1, len1, signature, &sig_len); + if (rc != CKR_OK) { + testcase_error("C_Sign rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + GetSystemTime(&t2); + diff = delta_time_us(&t1, &t2); + tot_time += diff; + if (diff < min_time) + min_time = diff; + if (diff > max_time) + max_time = diff; + } + + tot_time -= min_time; + tot_time -= max_time; + avg_time = tot_time / iterations; + + // us -> ms + tot_time /= 1000; + min_time /= 1000; + max_time /= 1000; + avg_time /= 1000; + + printf("%ld iterations: total=%ldms min=%ldms max=%ldms avg=%ldms " + "op/s=%.3f\n\n", iterations, tot_time, min_time, max_time, + avg_time, (double) (iterations * 1000) / (double) tot_time); + + printf("RSA PKCS Verify with keylen=%d datalen=%d\n", + keylength, (int) sizeof(data1)); + + tot_time = 0; + max_time = 0; + min_time = 0xFFFFFFFF; + + for (i = 0; i < iterations + 2; i++) { + GetSystemTime(&t1); + rc = funcs->C_VerifyInit(session, &mech, publ_key); + if (rc != CKR_OK) { + testcase_error("C_VerifyInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_Verify(session, data1, len1, signature, sig_len); + if (rc != CKR_OK) { + testcase_error("C_Verify rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + GetSystemTime(&t2); + diff = delta_time_us(&t1, &t2); + tot_time += diff; + if (diff < min_time) + min_time = diff; + if (diff > max_time) + max_time = diff; + } + + tot_time -= min_time; + tot_time -= max_time; + avg_time = tot_time / iterations; + + // us -> ms + tot_time /= 1000; + min_time /= 1000; + max_time /= 1000; + avg_time /= 1000; + + printf("%ld iterations: total=%ldms min=%ldms max=%ldms avg=%ldms " + "op/s=%.3f\n\n", iterations, tot_time, min_time, max_time, + avg_time, (double) (iterations * 1000) / (double) tot_time); + +testcase_cleanup: + rv = funcs->C_CloseAllSessions(slot_id); + if (rv != CKR_OK) { + testcase_error("C_CloseAllSession rv=%s", p11_get_ckr(rv)); + return FALSE; + } + + return TRUE; +} + +// mode: ECB CBC +int do_DES3_EncrDecr(const char *mode) +{ + CK_SLOT_ID slot_id; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rv, rc; + + CK_OBJECT_HANDLE h_key; + CK_BYTE original[BIG_REQUEST]; + CK_BYTE cipher[BIG_REQUEST]; + CK_BYTE clear[BIG_REQUEST]; + CK_ULONG orig_len, cipher_len, clear_len; + CK_BYTE init_v[8] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; + + SYSTEMTIME t1, t2; + CK_ULONG i, iterations = 10000; + CK_ULONG avg_time, tot_time, min_time, max_time, diff; + + slot_id = SLOT_ID; + + testcase_begin("DES3 Encrypt with mode=%s datalen=%d\n", mode, BIG_REQUEST); + + if (is_cca_token(SLOT_ID) && strcmp(mode, "ECB") == 0) { + testcase_skip("Slot %u doesn't support DES3 ECB En/Decrypt\n", + (unsigned) SLOT_ID); + return TRUE; + } + + testcase_rw_session(); + testcase_user_login(); + + mech.mechanism = CKM_DES3_KEY_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + // generate a DES3 key + 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 testcase_cleanup; + } + // clear buffers + memset(clear, 0, BIG_REQUEST); + memset(original, 0, BIG_REQUEST); + memset(cipher, 0, BIG_REQUEST); + + // encrypt some data + orig_len = BIG_REQUEST; + for (i = 0; i < orig_len; i++) + original[i] = i % 255; + + if (strcmp(mode, "ECB") == 0) { + mech.mechanism = CKM_DES3_ECB; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + } else if (strcmp(mode, "CBC") == 0) { + mech.mechanism = CKM_DES3_CBC; + mech.ulParameterLen = 8; + mech.pParameter = init_v; + } else { + testcase_error("unknown mode %s in do_DES3_EncrDecr()", mode); + rc = CKR_MECHANISM_INVALID; + goto testcase_cleanup; + } + + tot_time = 0; + max_time = 0; + min_time = 0xFFFFFFFF; + + for (i = 0; i < iterations + 2; i++) { + GetSystemTime(&t1); + rc = funcs->C_EncryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + cipher_len = BIG_REQUEST; + rc = funcs->C_Encrypt(session, original, orig_len, cipher, &cipher_len); + if (rc != CKR_OK) { + testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + GetSystemTime(&t2); + + diff = delta_time_us(&t1, &t2); + + tot_time += diff; + + if (diff < min_time) + min_time = diff; + + if (diff > max_time) + max_time = diff; + } + + tot_time -= min_time; + tot_time -= max_time; + avg_time = tot_time / iterations; + + // us -> ms + tot_time /= 1000; + + printf("%ld iterations: total=%ldms min=%ldus max=%ldus avg=%ldus " + "op/s=%.3f %.3fMB/s\n\n", iterations, tot_time, min_time, max_time, + avg_time, (double) (iterations * 1000) / (double) tot_time, + (((double) (iterations * 1000) / (double) (1024 * 1024)) * + BIG_REQUEST) / (double) tot_time); + + printf("DES3 Decrypt with mode=%s datalen=%d\n", mode, BIG_REQUEST); + + tot_time = 0; + max_time = 0; + min_time = 0xFFFFFFFF; + + for (i = 0; i < iterations + 2; i++) { + GetSystemTime(&t1); + + rc = funcs->C_DecryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + clear_len = BIG_REQUEST; + rc = funcs->C_Decrypt(session, cipher, cipher_len, clear, &clear_len); + if (rc != CKR_OK) { + testcase_error("C_Decrypt rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + GetSystemTime(&t2); + + diff = delta_time_us(&t1, &t2); + + tot_time += diff; + + if (diff < min_time) + min_time = diff; + + if (diff > max_time) + max_time = diff; + } + + tot_time -= min_time; + tot_time -= max_time; + avg_time = tot_time / iterations; + + // us -> ms + tot_time /= 1000; + + printf("%ld iterations: total=%ldms min=%ldus max=%ldus avg=%ldus " + "op/s=%.3f %.3fMB/s\n\n", iterations, tot_time, min_time, max_time, + avg_time, (double) (iterations * 1000) / (double) tot_time, + (((double) (iterations * 1000) / (double) (1024 * 1024)) * + BIG_REQUEST) / (double) tot_time); + +testcase_cleanup: + rv = funcs->C_CloseAllSessions(slot_id); + if (rv != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rv)); + return FALSE; + } + + return TRUE; +} + +// keylength: 128...256 +// mode: ECB CBC +int do_AES_EncrDecr(int keylength, const char *mode) +{ + CK_SLOT_ID slot_id; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rv, rc; + + CK_OBJECT_HANDLE h_key; + CK_BYTE original[BIG_REQUEST]; + CK_BYTE cipher[BIG_REQUEST]; + CK_BYTE clear[BIG_REQUEST]; + CK_ULONG orig_len, cipher_len, clear_len; + CK_ULONG key_len = keylength / 8; + + CK_BYTE init_v[16] = { + 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0A, + 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10 + }; + + CK_ULONG i, iterations = 50000; + SYSTEMTIME t1, t2; + CK_ULONG avg_time, tot_time, min_time, max_time, diff; + + testcase_begin("AES Encrypt with mode=%s keylen=%ld datalen=%d\n", + mode, key_len * 8, BIG_REQUEST); + + slot_id = SLOT_ID; + + testcase_rw_session(); + testcase_user_login(); + + mech.mechanism = CKM_AES_KEY_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rc = generate_AESKey(session, key_len, &mech, &h_key); + if (rc != CKR_OK) { + testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + // clear buffers + memset(original, 0, BIG_REQUEST); + memset(clear, 0, BIG_REQUEST); + memset(cipher, 0, BIG_REQUEST); + + // encrypt some data + orig_len = BIG_REQUEST; + for (i = 0; i < orig_len; i++) + original[i] = i % 255; + + if (strcmp(mode, "ECB") == 0) { + mech.mechanism = CKM_AES_ECB; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + } else if (strcmp(mode, "CBC") == 0) { + mech.mechanism = CKM_AES_CBC; + mech.ulParameterLen = 16; + mech.pParameter = init_v; + } else { + testcase_error("unknown mode %s in do_AES_EncrDecr()", mode); + rc = CKR_MECHANISM_INVALID; + goto testcase_cleanup; + } + + tot_time = 0; + max_time = 0; + min_time = 0xFFFFFFFF; + + for (i = 0; i < iterations + 2; i++) { + GetSystemTime(&t1); + rc = funcs->C_EncryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_EncryptInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + cipher_len = BIG_REQUEST; + rc = funcs->C_Encrypt(session, original, orig_len, cipher, &cipher_len); + if (rc != CKR_OK) { + testcase_error("C_Encrypt rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + GetSystemTime(&t2); + diff = delta_time_us(&t1, &t2); + tot_time += diff; + if (diff < min_time) + min_time = diff; + + if (diff > max_time) + max_time = diff; + } + + tot_time -= min_time; + tot_time -= max_time; + avg_time = tot_time / iterations; + + // us -> ms + tot_time /= 1000; + + printf("%ld iterations: total=%ldms min=%ldus max=%ldus avg=%ldus " + "op/s=%.3f %.3fMB/s\n\n", iterations, tot_time, min_time, max_time, + avg_time, (double) (iterations * 1000) / (double) tot_time, + (((double) (iterations * 1000) / (double) (1024 * 1024)) * + BIG_REQUEST) / (double) tot_time); + + printf("AES Decrypt with mode=%s keylen=%ld datalen=%d\n", + mode, key_len * 8, BIG_REQUEST); + + tot_time = 0; + max_time = 0; + min_time = 0xFFFFFFFF; + + for (i = 0; i < iterations + 2; i++) { + GetSystemTime(&t1); + rc = funcs->C_DecryptInit(session, &mech, h_key); + if (rc != CKR_OK) { + testcase_error("C_DecryptInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + clear_len = BIG_REQUEST; + rc = funcs->C_Decrypt(session, cipher, cipher_len, clear, &clear_len); + if (rc != CKR_OK) { + testcase_error("C_Decrypt rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + GetSystemTime(&t2); + diff = delta_time_us(&t1, &t2); + tot_time += diff; + if (diff < min_time) + min_time = diff; + + if (diff > max_time) + max_time = diff; + + } + + tot_time -= min_time; + tot_time -= max_time; + avg_time = tot_time / iterations; + + // us -> ms + tot_time /= 1000; + + printf("%ld iterations: total=%ldms min=%ldus max=%ldus avg=%ldus " + "op/s=%.3f %.3fMB/s\n\n", iterations, tot_time, min_time, max_time, + avg_time, (double) (iterations * 1000) / (double) tot_time, + (((double) (iterations * 1000) / (double) (1024 * 1024)) * + BIG_REQUEST) / (double) tot_time); + + +testcase_cleanup: + rv = funcs->C_CloseAllSessions(slot_id); + if (rv != CKR_OK) { + testcase_error("C_CloseAllSessions rc=%s", p11_get_ckr(rv)); + return FALSE; + } + + return TRUE; +} + +int do_SHA(const char *mode) +{ + CK_SLOT_ID slot_id; + CK_SESSION_HANDLE session; + CK_MECHANISM mech; + CK_FLAGS flags; + CK_RV rc, rv; + + CK_BYTE data[BIG_REQUEST]; + CK_BYTE hash[MAX_HASH_LEN]; + CK_ULONG data_len, hash_len, h_len; + + SYSTEMTIME t1, t2; + CK_ULONG diff, avg_time, tot_time, min_time, max_time; + CK_ULONG i, iterations = 20000; + + printf("SHA (%s) with datalen=%d\n", mode, BIG_REQUEST); + + slot_id = SLOT_ID; + + testcase_rw_session(); + + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + if (strcmp(mode, "SHA1") == 0) { + mech.mechanism = CKM_SHA_1; + hash_len = SHA1_HASH_LEN; + } else if (strcmp(mode, "SHA256") == 0) { + mech.mechanism = CKM_SHA256; + hash_len = SHA256_HASH_LEN; + } else if (strcmp(mode, "SHA512") == 0) { + mech.mechanism = CKM_SHA512; + hash_len = SHA512_HASH_LEN; + } else { + testcase_error("unknown mode %s in do_SHA()", mode); + rc = CKR_MECHANISM_INVALID; + goto testcase_cleanup; + } + + // generate some data to hash + // + data_len = BIG_REQUEST; + memset(data, 0, data_len); + for (i = 0; i < data_len; i++) + data[i] = i % 255; + + tot_time = 0; + max_time = 0; + min_time = 0xFFFFFFFF; + + for (i = 0; i < iterations + 2; i++) { + GetSystemTime(&t1); + + rc = funcs->C_DigestInit(session, &mech); + if (rc != CKR_OK) { + testcase_error("C_DigestInit rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + h_len = sizeof(hash); + rc = funcs->C_Digest(session, data, data_len, hash, &h_len); + if (rc != CKR_OK) { + testcase_error("C_Digest rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + if (h_len != hash_len) { + testcase_error + ("returned hashlen %ld doesn't match to expected len %ld\n", + h_len, hash_len); + rc = CKR_FUNCTION_FAILED; + goto testcase_cleanup; + } + + GetSystemTime(&t2); + diff = delta_time_us(&t1, &t2); + tot_time += diff; + if (diff < min_time) + min_time = diff; + + if (diff > max_time) + max_time = diff; + } + + tot_time -= min_time; + tot_time -= max_time; + avg_time = tot_time / iterations; + + // us -> ms + tot_time /= 1000; + + printf("%ld iterations: total=%ldms min=%ldus max=%ldus avg=%ldus " + "op/s=%.3f %.3fMB/s\n\n", iterations, tot_time, min_time, max_time, + avg_time, (double) (iterations * 1000) / (double) tot_time, + (((double) (iterations * 1000) / (double) (1024 * 1024)) * + BIG_REQUEST) / (double) tot_time); + +testcase_cleanup: + rv = funcs->C_CloseAllSessions(slot_id); + if (rv != CKR_OK) { + testcase_error("C_CloseAllSessions rv=%s", p11_get_ckr(rv)); + return FALSE; + } + + return TRUE; +} + + +int do_DummyFunction(void) +{ +#if DUMMY + CK_SLOT_ID slot_id; + CK_ULONG i, diff, avg_time, min_time, max_time; + CK_ULONG iterations = 1000; + SYSTEMTIME t1, t2; + + testcase_begin("do_DummyFunction..."); + + slot_id = SLOT_ID; + + tot_time = 0; + max_time = 0; + min_time = 0xFFFFFFFF; + + for (i = 0; i < iterations + 2; i++) { + GetSystemTime(&t1); + DummyFunction(slot_id); + + GetSystemTime(&t2); + + diff = delta_time_us(&t1, &t2); + tot_time += diff; + + if (diff < min_time) + min_time = diff; + + if (diff > max_time) + max_time = diff; + } + + tot_time -= min_time; + tot_time -= max_time; + avg_time = tot_time / iterations; + + // us -> ms + tot_time /= 1000; + min_time /= 1000; + max_time /= 1000; + + printf("%ld iterations: total=%ldms min=%ldms max=%ldms avg=%ldms " + "op/s=%.3f\n\n", iterations, tot_time, min_time, max_time, + avg_time, (double) (iterations * 1000) / (double) tot_time); +#endif + + return TRUE; +} + +void speed_usage(char *fct) +{ + printf("usage: %s -slot ", fct); + printf(" [-rsa_keygen] [-rsa_signverify]"); + printf(" [-rsa_endecrypt] [-des3] [-aes] [-sha]"); + printf(" [-h] \n\n"); + + return; +} + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + int rc, i; + int do_rsa_keygen = 0; + int do_rsa_signverify = 0; + int do_rsa_endecrypt = 0; + int do_des3_endecrypt = 0; + int do_aes_endecrypt = 0; + int do_sha = 0; + + SLOT_ID = 1000; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-slot") == 0) { + SLOT_ID = atoi(argv[i + 1]); + i++; + continue; + } + if (strcmp(argv[i], "-rsa_keygen") == 0) { + do_rsa_keygen = 1; + } else if (strcmp(argv[i], "-rsa_signverify") == 0) { + do_rsa_signverify = 1; + } else if (strcmp(argv[i], "-rsa_endecrypt") == 0) { + do_rsa_endecrypt = 1; + } else if (strcmp(argv[i], "-des3") == 0) { + do_des3_endecrypt = 1; + } else if (strcmp(argv[i], "-aes") == 0) { + do_aes_endecrypt = 1; + } else if (strcmp(argv[i], "-sha") == 0) { + do_sha = 1; + } else if (strcmp(argv[i], "-h") == 0) { + speed_usage(argv[0]); + return 0; + } else { + printf("unknown option '%s'\n", argv[i]); + speed_usage(argv[0]); + return 1; + } + } + + // error if slot has not been identified. + if (SLOT_ID == 1000) { + printf("Please specify the slot to be tested.\n"); + speed_usage(argv[0]); + return 1; + } + + if (do_rsa_keygen + do_rsa_signverify + do_rsa_endecrypt + + do_des3_endecrypt + do_aes_endecrypt + do_sha == 0) { + do_rsa_keygen = 1; + do_rsa_signverify = 1; + do_rsa_endecrypt = 1; + do_des3_endecrypt = 1; + do_aes_endecrypt = 1; + do_sha = 1; + } + + printf("Using slot #%lu...\n\n", SLOT_ID); + + rc = do_GetFunctionList(); + if (!rc) + return rc; + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + funcs->C_Initialize(&cinit_args); + + if (do_rsa_keygen) { + rc = do_RSA_KeyGen(1024); + if (!rc) + return rc; + rc = do_RSA_KeyGen(2048); + if (!rc) + return rc; + rc = do_RSA_KeyGen(4096); + if (!rc) + return rc; + } + + if (do_rsa_signverify) { + rc = do_RSA_PKCS_SignVerify(1024); + if (!rc) + return rc; + rc = do_RSA_PKCS_SignVerify(2048); + if (!rc) + return rc; + rc = do_RSA_PKCS_SignVerify(4096); + if (!rc) + return rc; + } + + if (do_rsa_endecrypt) { + rc = do_RSA_PKCS_EncryptDecrypt(1024); + if (!rc) + return rc; + rc = do_RSA_PKCS_EncryptDecrypt(2048); + if (!rc) + return rc; + rc = do_RSA_PKCS_EncryptDecrypt(4096); + if (!rc) + return rc; + } + + if (do_des3_endecrypt) { + rc = do_DES3_EncrDecr("ECB"); + if (!rc) + return rc; + rc = do_DES3_EncrDecr("CBC"); + if (!rc) + return rc; + } + + if (do_aes_endecrypt) { + rc = do_AES_EncrDecr(128, "ECB"); + if (!rc) + return rc; + rc = do_AES_EncrDecr(128, "CBC"); + if (!rc) + return rc; + rc = do_AES_EncrDecr(192, "ECB"); + if (!rc) + return rc; + rc = do_AES_EncrDecr(192, "CBC"); + if (!rc) + return rc; + rc = do_AES_EncrDecr(256, "ECB"); + if (!rc) + return rc; + rc = do_AES_EncrDecr(256, "CBC"); + if (!rc) + return rc; + } + + if (do_sha) { + rc = do_SHA("SHA1"); + if (!rc) + return rc; + rc = do_SHA("SHA256"); + if (!rc) + return rc; + rc = do_SHA("SHA512"); + if (!rc) + return rc; + } + + funcs->C_Finalize(NULL); + + return 0; +} diff --git a/testcases/misc_tests/spinlock_child.sh b/testcases/misc_tests/spinlock_child.sh new file mode 100755 index 0000000..fb8f87e --- /dev/null +++ b/testcases/misc_tests/spinlock_child.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# +# COPYRIGHT (c) International Business Machines Corp. 2012-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 +# + +while getopts ":s:l:" option +do + case $option in +"s") + slotid="$OPTARG" + ;; +"l") + loopcount="$OPTARG" + ;; +[?]) + echo "Usage: -s -l loopcount" + ;; +esac +done + +i="0" +echo $$ +while [ $i -lt $loopcount ] +do + ./obj_mgmt_lock_tests -slot $slotid + i=$[$i+1] +done diff --git a/testcases/misc_tests/spinlock_tests.sh b/testcases/misc_tests/spinlock_tests.sh new file mode 100755 index 0000000..3d6d305 --- /dev/null +++ b/testcases/misc_tests/spinlock_tests.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# +# COPYRIGHT (c) International Business Machines Corp. 2012-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 +# + +while getopts "s:p:l:" option +do + case $option in +"s") + slotid="$OPTARG" + ;; +"p") + procnum="$OPTARG" + ;; +"l") + loopcount="$OPTARG" + ;; +[?]) + echo "Usage: -s -p -l " + exit + ;; +esac +done + +if [ -z $slotid ] || [ -z $procnum ] || [ -z $loopcount ]; then + echo "Usage: -s -p -l " + exit +fi + +while [ $procnum -gt 0 ] +do + echo "Starting child process #$procnum" + (./spinlock_child.sh -s $slotid -l $loopcount;) & + let procnum=procnum-1 +done + +wait +echo "Exiting parent loop" diff --git a/testcases/misc_tests/threadmkobj.c b/testcases/misc_tests/threadmkobj.c new file mode 100644 index 0000000..f61bbd0 --- /dev/null +++ b/testcases/misc_tests/threadmkobj.c @@ -0,0 +1,182 @@ +/* + * 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 + */ + +/* File: tok_obj.c + * + * Test driver for testing the proper storage of token objects +*/ +#ifndef _REENTRANT +#define _REENTRANT +#endif + +#include + +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "defs.h" + +int do_GetInfo(void); +int do_GetFunctionList(void); + +void init_coprocessor(void); + +CK_RV _C_GetFunctionList(CK_FUNCTION_LIST **); + +CK_RV open_session_and_login(void) +{ + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + // create a USER R/W session + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(SLOT_ID, flags, NULL, NULL, &h_session); + + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + + return rc; +} + +// do_create_token_object() +int do_create_token_object(void) +{ + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc; + + CK_BYTE true = TRUE; + CK_BYTE false = FALSE; + + CK_OBJECT_HANDLE h_cert1; + CK_OBJECT_CLASS cert1_class = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE cert1_type = CKC_X_509; + CK_BYTE cert1_subject[] = "Certificate subject #1"; + CK_BYTE cert1_value[] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + + CK_ATTRIBUTE cert1_attribs[] = { + {CKA_CLASS, &cert1_class, sizeof(cert1_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_CERTIFICATE_TYPE, &cert1_type, sizeof(cert1_type)}, + {CKA_SUBJECT, &cert1_subject, sizeof(cert1_subject)}, + {CKA_VALUE, &cert1_value, sizeof(cert1_value)}, + {CKA_PRIVATE, &true, sizeof(false)} + }; + + // create a USER R/W session + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(SLOT_ID, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + show_error(" C_OpenSession #1", rc); + rc = FALSE; + goto done; + } + + // create the token objects + rc = funcs->C_CreateObject(h_session, cert1_attribs, 6, &h_cert1); + if (rc != CKR_OK) { + show_error(" C_CreateObject #1", rc); + rc = FALSE; + goto done; + } + + rc = TRUE; + +done: + funcs->C_CloseSession(h_session); + + return rc; +} + +#define NUMOBJS 10 + +void *thread_func(void *thid) +{ + int i = 0; + CK_RV rv; + + UNUSED(thid); + + do { + rv = do_create_token_object(); + if (rv != 1) + return NULL; + } while (++i < NUMOBJS); + + return thid; +} + +#define THREADCNT 5 + +int main(int argc, char **argv) +{ + int i, rc; + pthread_t id[100]; + int thid[100]; + + + SLOT_ID = 0; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-slot") == 0) { + SLOT_ID = atoi(argv[i + 1]); + i++; + } + + if (strcmp(argv[i], "-h") == 0) { + printf("usage: %s [-slot ] [-h]\n\n", argv[0]); + printf("By default, Slot #1 is used\n\n"); + return 0; + } + } + + printf("Using slot #%lu...\n\n", SLOT_ID); + + rc = do_GetFunctionList(); + if (!rc) + return -1; + + funcs->C_Initialize(NULL); + + + if ((rc = open_session_and_login()) != CKR_OK) + return rc; + + for (i = 0; i < THREADCNT; i++) { + thid[i] = i; + printf("Creating thread %d \n", thid[i]); + pthread_create(&id[i], NULL, (void *(*)(void *)) thread_func, + (void *) &(thid[i])); + } + + for (i = 0; i < THREADCNT; i++) { + printf("Joining thread %ld\n", id[i]); + pthread_join(id[i], NULL); + } + + rc = funcs->C_Finalize(NULL); + if (rc != CKR_OK) + return -1; + + return 0; +} diff --git a/testcases/misc_tests/tok_des.c b/testcases/misc_tests/tok_des.c new file mode 100644 index 0000000..4e7f81d --- /dev/null +++ b/testcases/misc_tests/tok_des.c @@ -0,0 +1,311 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2006-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: driver.c + * + * Test driver. In-depth regression test for PKCS #11 + */ + +#include +#include +#include +#include + +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "common.c" + +int do_GetFunctionList(void); + +CK_RV do_VerifyTokenSymKey(CK_SESSION_HANDLE sess, CK_BYTE * label) +{ + CK_OBJECT_HANDLE obj_handles[20]; + CK_ULONG pulCount = 0, obj_class = CKO_SECRET_KEY, i; + CK_RV rv; + CK_BBOOL true = 1; + + printf("do_VerifyTokenSymKey...\n"); + + /* Find token objects based on the label */ + { + CK_ATTRIBUTE tmpl[] = { + {CKA_LABEL, label, (CK_ULONG) strlen((char *) label) + 1}, + {CKA_TOKEN, &true, sizeof(CK_BBOOL)}, + {CKA_CLASS, &obj_class, sizeof(obj_class)} + }; + + rv = funcs->C_FindObjectsInit(sess, tmpl, 3); + if (rv != CKR_OK) { + show_error(" C_FindObjectsInit #1", rv); + return rv; + } + + rv = funcs->C_FindObjects(sess, obj_handles, 20, &pulCount); + if (rv != CKR_OK) { + show_error(" C_FindObjects #1", rv); + return rv; + } + + rv = funcs->C_FindObjectsFinal(sess); + if (rv != CKR_OK) { + show_error(" C_FindObjectsFinal #1", rv); + return rv; + } + } + + for (i = 0; i < pulCount; i++) { + CK_ULONG valueLen = 0; + CK_BYTE value[256] = { 0, }; + CK_ATTRIBUTE tmpl[] = { + {CKA_VALUE, NULL, valueLen} + }; + + rv = funcs->C_GetAttributeValue(sess, obj_handles[i], tmpl, 1); + if (rv != CKR_OK) { + show_error(" C_GetAttributeValue #1", rv); + return rv; + } + + tmpl[0].pValue = value; + + if (is_ep11_token(SLOT_ID) || is_cca_token(SLOT_ID)) { + /* + * Secure key, there is no value or just a dummy + * value attribute. So skip processing the value. + */ + } else { + rv = funcs->C_GetAttributeValue(sess, obj_handles[i], tmpl, 1); + if (rv != CKR_OK) { + show_error(" C_GetAttributeValue", rv); + return rv; + } + /* The public exponent is element 0 and modulus is element 1 */ + if (tmpl[0].ulValueLen > 256 || tmpl[0].ulValueLen < 8) { + PRINT_ERR("secret key value (%lu) OOB!", tmpl[0].ulValueLen); + return CKR_FUNCTION_FAILED; + } + printf("%lu byte secret key found.\nValue:\n", tmpl[0].ulValueLen); + print_hex(tmpl[0].pValue, tmpl[0].ulValueLen); + } + + + rv = funcs->C_DestroyObject(sess, obj_handles[i]); + if (rv != CKR_OK) { + show_error(" C_DestroyObject", rv); + } else { + printf("Object destroyed.\n"); + } + } + + printf("%s: Success\n", __func__); + + return CKR_OK; +} + +CK_RV do_GenerateTokenSymKey(CK_SESSION_HANDLE sess, CK_BYTE * label, + CK_ULONG type) +{ + CK_MECHANISM mech; + CK_OBJECT_HANDLE key; + CK_RV rv; + CK_BBOOL true = 1; + CK_ULONG key_len = 16; + CK_ATTRIBUTE tmpl[] = { + {CKA_LABEL, label, (CK_ULONG) strlen((char *) label) + 1}, + {CKA_TOKEN, &true, sizeof(CK_BBOOL)}, + {CKA_VALUE_LEN, &key_len, sizeof(CK_ULONG)} + }; + int attr = (type == CKM_AES_KEY_GEN ? 3 : 2); + + printf("do_GenerateTokenSymKey...\n"); + + mech.mechanism = type; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rv = funcs->C_GenerateKey(sess, &mech, tmpl, attr, &key); + if (rv != CKR_OK) { + show_error(" C_GenerateKey #1", rv); + return rv; + } + + printf("Success\n"); + + return CKR_OK; +} + + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + int i, nodelete = 0; + CK_RV rv; + SLOT_ID = 0; + CK_BYTE user_pin[128]; + CK_ULONG user_pin_len; + CK_SLOT_ID slot_id; + CK_SESSION_HANDLE session; + CK_FLAGS flags; + CK_BYTE tdes_label[] = "XXX DELETE ME TEST 3DES KEY"; + CK_BYTE aes_label[] = "XXX DELETE ME TEST AES KEY"; + + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-slot") == 0) { + ++i; + SLOT_ID = atoi(argv[i]); + } + + if (strcmp(argv[i], "-nodelete") == 0) { + nodelete = 1; + } + + if (strcmp(argv[i], "-h") == 0) { + printf("usage: %s [-noskip] [-slot ] [-h]\n\n", argv[0]); + printf("By default, Slot #1 is used\n\n"); + printf("By default we skip anything that creates or modifies\n"); + printf("token objects to preserve flash lifetime.\n"); + return -1; + } + } + + printf("Using slot #%lu...\n\n", SLOT_ID); + + slot_id = SLOT_ID; + + rv = do_GetFunctionList(); + if (rv != TRUE) { + show_error("do_GetFunctionList", rv); + return -1; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + // SAB Add calls to ALL functions before the C_Initialize gets hit + + if ((rv = funcs->C_Initialize(&cinit_args))) { + show_error("C_Initialize", rv); + return -1; + } + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rv = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session); + if (rv != CKR_OK) { + show_error(" C_OpenSession #1", rv); + return rv; + } + + rv = funcs->C_Login(session, CKU_USER, user_pin, user_pin_len); + if (rv != CKR_OK) { + show_error(" C_Login #1", rv); + return rv; + } + + if (mech_supported(slot_id, CKM_DES3_KEY_GEN)) { + rv = do_GenerateTokenSymKey(session, tdes_label, CKM_DES3_KEY_GEN); + if (rv != CKR_OK) { + show_error("do_GenerateTokenSymKey(...DES3_KEY)", rv); + return -1; + } + } else { + testcase_skip("GenerateTokenSymKey(...DES3_KEY)"); + tdes_label[0] = 0; + } + + if (mech_supported(slot_id, CKM_AES_KEY_GEN)) { + rv = do_GenerateTokenSymKey(session, aes_label, CKM_AES_KEY_GEN); + if (rv != CKR_OK) { + show_error("do_GenerateTokenSymKey(...AES_KEY)", rv); + return -1; + } + } else { + testcase_skip("GenerateTokenSymKey(...AES_KEY)"); + aes_label[0] = 0; + } + + rv = funcs->C_CloseSession(session); + if (rv != CKR_OK) { + show_error(" C_CloseSession #3", rv); + return rv; + } + + rv = funcs->C_Finalize(NULL); + if (rv != CKR_OK) { + show_error("C_Finalize", rv); + return -1; + } + + if (nodelete) + return 0; + + /* Open a new session and re-login */ + if ((rv = funcs->C_Initialize(&cinit_args))) { + show_error("C_Initialize", rv); + return -1; + } + + rv = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session); + if (rv != CKR_OK) { + show_error(" C_OpenSession #2", rv); + goto finalize; + } + + rv = funcs->C_Login(session, CKU_USER, user_pin, user_pin_len); + if (rv != CKR_OK) { + show_error(" C_Login #2", rv); + goto close_session; + } + + if (tdes_label[0]) { + rv = do_VerifyTokenSymKey(session, tdes_label); + if (rv != CKR_OK) { + show_error("do_VerifyTokenSymKey(...DES3_KEY...)", rv); + goto close_session; + } + } else { + testcase_skip("VerifyTokenSymKey(...DES3_KEY...)"); + } + + if (aes_label[0]) { + rv = do_VerifyTokenSymKey(session, aes_label); + if (rv != CKR_OK) { + show_error("do_VerifyTokenSymKey(...AES_KEY...)", rv); + goto close_session; + } + } else { + testcase_skip("VerifyTokenSymKey(...AES_KEY...)"); + } + +close_session: + rv = funcs->C_CloseSession(session); + if (rv != CKR_OK) { + show_error(" C_CloseSession #3", rv); + return rv; + } +finalize: + rv = funcs->C_Finalize(NULL); + if (rv != CKR_OK) { + show_error("C_Finalize", rv); + return -1; + } + + printf("%s: Success\n", argv[0]); + + return 0; +} diff --git a/testcases/misc_tests/tok_obj.c b/testcases/misc_tests/tok_obj.c new file mode 100644 index 0000000..c6272cc --- /dev/null +++ b/testcases/misc_tests/tok_obj.c @@ -0,0 +1,608 @@ +/* + * 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 + */ + +/* File: tok_obj.c + * + * Test driver for testing the proper storage of token objects + */ + +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" + +int do_GetInfo(void); +int do_GetFunctionList(void); + +void init_coprocessor(void); + +CK_RV C_GetFunctionList(CK_FUNCTION_LIST **); + +// do_create_token_object() +int do_create_token_object(void) +{ + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + CK_BYTE true = TRUE; + CK_BYTE false = FALSE; + + CK_OBJECT_HANDLE h_cert1; + CK_OBJECT_CLASS cert1_class = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE cert1_type = CKC_X_509; + CK_BYTE cert1_subject[] = "Certificate subject #1"; + CK_BYTE cert1_id[] = "Certificate ID #1"; + CK_BYTE cert1_value[] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + + CK_ATTRIBUTE cert1_attribs[] = { + {CKA_CLASS, &cert1_class, sizeof(cert1_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_CERTIFICATE_TYPE, &cert1_type, sizeof(cert1_type)}, + {CKA_SUBJECT, &cert1_subject, sizeof(cert1_subject)}, + {CKA_VALUE, &cert1_value, sizeof(cert1_value)}, + {CKA_PRIVATE, &true, sizeof(false)} + }; + CK_ATTRIBUTE cert_id_attr[] = { + {CKA_ID, &cert1_id, sizeof(cert1_id)} + }; + CK_OBJECT_HANDLE obj_list[20]; + CK_ULONG objcount; + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + // create a USER R/W session + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + printf("open ing session \n"); + rc = funcs->C_OpenSession(SLOT_ID, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + show_error(" C_OpenSession #1", rc); + rc = FALSE; + goto done; + } + + printf("login ing session \n"); + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + show_error(" C_Login #1", rc); + rc = FALSE; + goto done; + } + // create the token objects + printf("create ing session \n"); + rc = funcs->C_CreateObject(h_session, cert1_attribs, 6, &h_cert1); + if (rc != CKR_OK) { + show_error(" C_CreateObject #1", rc); + rc = FALSE; + goto done; + } + + printf("set ing session \n"); + rc = funcs->C_SetAttributeValue(h_session, h_cert1, cert_id_attr, 1); + if (rc != CKR_OK) { + show_error(" C_SetAttribute #1", rc); + rc = FALSE; + goto done; + } + + // now, retrieve a list of all object handles + printf("find init ing session \n"); + rc = funcs->C_FindObjectsInit(h_session, cert_id_attr, 1); + if (rc != CKR_OK) { + show_error(" C_FindObjectsInit #1", rc); + rc = FALSE; + goto done; + } + + printf("find session \n"); + rc = funcs->C_FindObjects(h_session, obj_list, 20, &objcount); + if (rc != CKR_OK) { + show_error(" C_FindObjects #1", rc); + rc = FALSE; + goto done; + } + + printf("find final session \n"); + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + show_error(" C_FindObjectsFinal #1", rc); + rc = FALSE; + goto done; + } + + rc = TRUE; + +done: + printf("close all session \n"); + funcs->C_CloseAllSessions(SLOT_ID); + + return rc; +} + +// do_count_token_objects() +int do_count_token_objects(void) +{ + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_OBJECT_HANDLE obj_list[20]; + CK_ULONG find_count; + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + // create a USER R/W session + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(SLOT_ID, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + show_error(" C_OpenSession #1", rc); + rc = FALSE; + goto done; + } + + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + show_error(" C_Login #1", rc); + rc = FALSE; + goto done; + } + // + //--------------------------------------------------------------------- + // + + // now, retrieve a list of all object handles + rc = funcs->C_FindObjectsInit(h_session, NULL, 0); + if (rc != CKR_OK) { + show_error(" C_FindObjectsInit #1", rc); + rc = FALSE; + goto done; + } + + rc = funcs->C_FindObjects(h_session, obj_list, 20, &find_count); + if (rc != CKR_OK) { + show_error(" C_FindObjects #1", rc); + rc = FALSE; + goto done; + } + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + show_error(" C_FindObjectsFinal #1", rc); + rc = FALSE; + goto done; + } + + printf("Found: %ld objects\n", find_count); + rc = TRUE; + +done: + funcs->C_CloseAllSessions(SLOT_ID); + + return rc; +} + + +// do_verify_token_object() +int do_verify_token_object(void) +{ + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_OBJECT_HANDLE obj_list[20]; + CK_ULONG find_count; + + CK_BYTE cert1_id[] = "Certificate ID #1"; + + CK_BYTE buf1[100]; + CK_ATTRIBUTE verify_attribs[] = { + {CKA_ID, &buf1, sizeof(buf1)} + }; + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + // create a USER R/W session + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(SLOT_ID, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + show_error(" C_OpenSession #1", rc); + rc = FALSE; + goto done; + } + + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + show_error(" C_Login #1", rc); + rc = FALSE; + goto done; + } + // + //--------------------------------------------------------------------- + // + + // now, retrieve a list of all object handles + rc = funcs->C_FindObjectsInit(h_session, NULL, 0); + if (rc != CKR_OK) { + show_error(" C_FindObjectsInit #1", rc); + rc = FALSE; + goto done; + } + + rc = funcs->C_FindObjects(h_session, obj_list, 20, &find_count); + if (rc != CKR_OK) { + show_error(" C_FindObjects #1", rc); + rc = FALSE; + goto done; + } + + if (find_count == 0) { + printf("ERROR: no objects to examine\n"); + rc = FALSE; + goto done; + } + // now, try to extract the CKA_APPLICATION attribute from the original + // this will pull in the token's default value for CKA_APPLICATION which + verify_attribs[0].ulValueLen = sizeof(buf1); + rc = funcs->C_GetAttributeValue(h_session, obj_list[0], verify_attribs, 1); + if (rc != CKR_OK) { + show_error(" C_GetAttributeValue #1", rc); + rc = FALSE; + goto done; + } + + if (memcmp(&cert1_id, verify_attribs[0].pValue, sizeof(cert1_id)) != 0) { + printf(" ERROR: extracted attribute doesn't match\n"); + rc = FALSE; + goto done; + } + + printf("Attribute matches! Good.\n"); + rc = TRUE; + +done: + funcs->C_CloseAllSessions(SLOT_ID); + + return rc; +} + +int do_destroy_all_token_objects(void) +{ + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + CK_OBJECT_HANDLE obj_list[20]; + CK_ULONG find_count; + CK_ULONG i; + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + // create a USER R/W session + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(SLOT_ID, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + show_error(" C_OpenSession #1", rc); + rc = FALSE; + goto done; + } + + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + show_error(" C_Login #1", rc); + rc = FALSE; + goto done; + } + // + //--------------------------------------------------------------------- + // + + // now, retrieve a list of all object handles + rc = funcs->C_FindObjectsInit(h_session, NULL, 0); + if (rc != CKR_OK) { + show_error(" C_FindObjectsInit #1", rc); + rc = FALSE; + goto done; + } + + do { + rc = funcs->C_FindObjects(h_session, obj_list, 20, &find_count); + if (rc != CKR_OK) { + show_error(" C_FindObjects #1", rc); + rc = FALSE; + goto done; + } + + for (i = 0; i < find_count; i++) { + rc = funcs->C_DestroyObject(h_session, obj_list[i]); + if (rc != CKR_OK) { + printf(" C_DestroyObject #%ld returned", i); + show_error(" ", rc); + rc = FALSE; + goto done; + } + } + } while (find_count != 0); + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + show_error(" C_FindObjectsFinal #1", rc); + rc = FALSE; + goto done; + } + + rc = TRUE; + +done: + funcs->C_CloseAllSessions(SLOT_ID); + + return rc; +} + + +int do_inittoken(void) +{ + CK_BYTE label[32]; + CK_BYTE so_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG so_pin_len; + int len; + CK_RV rc; + + if (get_so_pin(so_pin)) + return CKR_FUNCTION_FAILED; + + so_pin_len = (CK_ULONG) strlen((char *) so_pin); + + // memcpy( label, "A new label ", 32 ); + memcpy(label, " ", 32); + + printf("Enter Token Label:"); + if (!fgets((char *)label, 32, stdin)) { + show_error("fgets failed", (unsigned long)CKR_FUNCTION_FAILED); + rc = FALSE; + goto done; + } + printf("\nLabel is: %s", label); + + for (len = 0; len < 31; len++) { + if (label[len] == '\0') { + label[len] = ' '; + break; + } + } + printf("\n"); + + // memcpy( label, "RemoteLeeds ", 32 ); + + rc = funcs->C_InitToken(SLOT_ID, NULL, so_pin_len, label); + if (rc != CKR_ARGUMENTS_BAD) { + show_error(" C_InitToken Fail #1", rc); + rc = FALSE; + goto done; + } + + rc = funcs->C_InitToken(SLOT_ID, so_pin, so_pin_len, NULL); + if (rc != CKR_ARGUMENTS_BAD) { + show_error(" C_InitToken Fail #2", rc); + rc = FALSE; + goto done; + } + + rc = funcs->C_InitToken(SLOT_ID, so_pin, so_pin_len, label); + if (rc != CKR_OK) { + show_error(" C_InitToken #1", rc); + rc = FALSE; + goto done; + } + + rc = TRUE; + +done: + return rc; +} + + +int do_setUserPIN(void) +{ + CK_BYTE so_pin[PKCS11_MAX_PIN_LEN]; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len, so_pin_len; + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_ULONG rc; + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + if (get_so_pin(so_pin)) + return CKR_FUNCTION_FAILED; + + so_pin_len = (CK_ULONG) strlen((char *) so_pin); + + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(SLOT_ID, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + show_error(" C_OpenSession #1", rc); + rc = FALSE; + goto done; + } + + rc = funcs->C_Login(h_session, CKU_SO, so_pin, so_pin_len); + if (rc != CKR_OK) { + show_error(" C_Login #1", rc); + rc = FALSE; + goto done; + } + + rc = funcs->C_InitPIN(h_session, user_pin, user_pin_len); + if (rc != CKR_OK) { + show_error(" C_InitPIN #1", rc); + rc = FALSE; + goto done; + } + + rc = TRUE; + +done: + funcs->C_CloseAllSessions(SLOT_ID); + + return rc; +} + + +int do_GetTokenInfo(void) +{ + CK_SLOT_ID slot_id; + CK_TOKEN_INFO info; + CK_RV rc; + + printf("do_GetTokenInfo...\n"); + + slot_id = SLOT_ID; + + rc = funcs->C_GetTokenInfo(slot_id, &info); + if (rc != CKR_OK) { + show_error(" C_GetTokenInfo", rc); + return FALSE; + } + + printf(" CK_TOKEN_INFO for slot #1: \n"); + printf(" label: %32.32s\n", info.label); + printf(" manufacturerID: %32.32s\n", info.manufacturerID); + printf(" model: %16.16s\n", info.model); + printf(" serialNumber: %16.16s\n", info.serialNumber); + printf(" flags: %p\n", (void *) info.flags); + printf(" ulMaxSessionCount: %ld\n", info.ulMaxSessionCount); + printf(" ulSessionCount: %ld\n", info.ulSessionCount); + printf(" ulMaxRwSessionCount: %ld\n", info.ulMaxRwSessionCount); + printf(" ulRwSessionCount: %ld\n", info.ulRwSessionCount); + printf(" ulMaxPinLen: %ld\n", info.ulMaxPinLen); + printf(" ulMinPinLen: %ld\n", info.ulMinPinLen); + printf(" ulTotalPublicMemory: %ld\n", info.ulTotalPublicMemory); + printf(" ulFreePublicMemory: %ld\n", info.ulFreePublicMemory); + printf(" ulTotalPrivateMemory: %ld\n", info.ulTotalPrivateMemory); + printf(" ulFreePrivateMemory: %ld\n", info.ulFreePrivateMemory); + printf(" hardwareVersion: %d.%d\n", info.hardwareVersion.major, + info.hardwareVersion.minor); + printf(" firmwareVersion: %d.%d\n", info.firmwareVersion.major, + info.firmwareVersion.minor); + printf(" time: %16.16s\n", info.utcTime); + + printf("Looks okay...\n"); + + return TRUE; +} + +void menu(void) +{ + printf("\n1. Create a token object\n"); + printf("2. Count token objects\n"); + printf("3. Verify contents of the first token object\n"); + printf("4. Destroy all token objects\n"); + printf("5. Initialize Token\n"); + printf("6. Set USER PIN\n"); + printf("7. Get Token Info\n"); + printf("9. Exit\n"); + printf("Selection: "); + fflush(stdout); +} + +int main(int argc, char **argv) +{ + CK_BYTE line[20]; + CK_ULONG val; + int i, rc; + + SLOT_ID = 0; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-slot") == 0) { + SLOT_ID = atoi(argv[i + 1]); + i++; + } + + if (strcmp(argv[i], "-h") == 0) { + printf("usage: %s [-slot ] [-h]\n\n", argv[0]); + printf("By default, Slot #1 is used\n\n"); + return -1; + } + } + + printf("Using slot #%lu...\n\n", SLOT_ID); + + rc = do_GetFunctionList(); + if (!rc) + return rc; + + funcs->C_Initialize(NULL); + + menu(); + + while (fgets((char *) line, 10, stdin)) { + val = atoi((char *) line); + + switch (val) { + case 1: + do_create_token_object(); + break; + case 2: + do_count_token_objects(); + break; + case 3: + do_verify_token_object(); + break; + case 4: + do_destroy_all_token_objects(); + break; + case 5: + do_inittoken(); + break; + case 6: + do_setUserPIN(); + break; + case 7: + do_GetTokenInfo(); + break; + case 9: + goto done; + break; + } + menu(); + } + +done: + rc = funcs->C_Finalize(NULL); + + return rc; +} diff --git a/testcases/misc_tests/tok_obj2.c b/testcases/misc_tests/tok_obj2.c new file mode 100644 index 0000000..caf2433 --- /dev/null +++ b/testcases/misc_tests/tok_obj2.c @@ -0,0 +1,621 @@ +/* + * 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 + */ + +/* File: tok_obj.c + * + * Test driver for testing the proper storage of token objects + */ + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "p11util.h" + + +int do_GetInfo(void); + +void init_coprocessor(void); + +CK_RV C_GetFunctionList(CK_FUNCTION_LIST **); + +void show_error(CK_BYTE * str, CK_RV rc) +{ + printf("%s returned: %ld - %s\n", str, rc, p11_get_ckr(rc)); +} + +int do_GetFunctionList(void) +{ + CK_RV rc; + + printf("do_GetFunctionList...\n"); + + rc = C_GetFunctionList(&funcs); + + if (rc != CKR_OK) { + show_error(" C_GetFunctionList", rc); + return FALSE; + } + + printf("Looks okay...\n"); + + return TRUE; +} + +// do_create_token_object() +int do_create_token_object(void) +{ + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc; + CK_BYTE user_pin[DEFAULT_USER_PIN_LEN]; + CK_ULONG user_pin_len; + + CK_BYTE true = TRUE; + CK_BYTE false = FALSE; + + CK_OBJECT_HANDLE h_cert1; + CK_OBJECT_CLASS cert1_class = CKO_CERTIFICATE; + CK_CERTIFICATE_TYPE cert1_type = CKC_X_509; + CK_BYTE cert1_subject[] = "Certificate subject #1"; + CK_BYTE cert1_id[] = "Certificate ID #1"; + CK_BYTE cert1_value[] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + + CK_ATTRIBUTE cert1_attribs[] = { + {CKA_CLASS, &cert1_class, sizeof(cert1_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_CERTIFICATE_TYPE, &cert1_type, sizeof(cert1_type)}, + {CKA_SUBJECT, &cert1_subject, sizeof(cert1_subject)}, + {CKA_VALUE, &cert1_value, sizeof(cert1_value)}, + {CKA_PRIVATE, &true, sizeof(false)} + //{CKA_PRIVATE, &false, sizeof(false) } + }; + CK_ATTRIBUTE cert_id_attr[] = { + {CKA_ID, &cert1_id, sizeof(cert1_id)} + }; + CK_OBJECT_HANDLE obj_list[20]; + CK_ULONG objcount; + + memcpy(user_pin, DEFAULT_USER_PIN, DEFAULT_USER_PIN_LEN); + user_pin_len = DEFAULT_USER_PIN_LEN; + + // create a USER R/W session + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + printf("open ing session \n"); + rc = funcs->C_OpenSession(SLOT_ID, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + show_error(" C_OpenSession #1", rc); + rc = FALSE; + goto done; + } + + printf("login ing session \n"); + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + show_error(" C_Login #1", rc); + rc = FALSE; + goto done; + } + + // create the token objects + printf("create ing session \n"); + rc = funcs->C_CreateObject(h_session, cert1_attribs, 7, &h_cert1); + if (rc != CKR_OK) { + show_error(" C_CreateObject #1", rc); + rc = FALSE; + goto done; + } + + printf("set ing session \n"); + rc = funcs->C_SetAttributeValue(h_session, h_cert1, cert_id_attr, 1); + if (rc != CKR_OK) { + show_error(" C_SetAttribute #1", rc); + rc = FALSE; + goto done; + } + + // now, retrieve a list of all object handles + printf("find init ing session \n"); + rc = funcs->C_FindObjectsInit(h_session, cert_id_attr, 1); + if (rc != CKR_OK) { + show_error(" C_FindObjectsInit #1", rc); + rc = FALSE; + goto done; + } + + printf("find session \n"); + rc = funcs->C_FindObjects(h_session, obj_list, 20, &objcount); + if (rc != CKR_OK) { + show_error(" C_FindObjects #1", rc); + rc = FALSE; + goto done; + } + + printf("find final session \n"); + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + show_error(" C_FindObjectsFinal #1", rc); + rc = FALSE; + goto done; + } + + rc = TRUE; + +done: + printf("close all session \n"); + funcs->C_CloseAllSessions(SLOT_ID); + + return rc; +} + + +// do_count_token_objects() +// +int do_count_token_objects(void) +{ + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc; + CK_BYTE user_pin[DEFAULT_USER_PIN_LEN]; + CK_ULONG user_pin_len; + CK_OBJECT_HANDLE obj_list[20]; + CK_ULONG find_count; + + memcpy(user_pin, DEFAULT_USER_PIN, DEFAULT_USER_PIN_LEN); + user_pin_len = DEFAULT_USER_PIN_LEN; + + // create a USER R/W session + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(SLOT_ID, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + show_error(" C_OpenSession #1", rc); + rc = FALSE; + goto done; + } + + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + show_error(" C_Login #1", rc); + rc = FALSE; + goto done; + } + // + //--------------------------------------------------------------------- + // + + // now, retrieve a list of all object handles + // + rc = funcs->C_FindObjectsInit(h_session, NULL, 0); + if (rc != CKR_OK) { + show_error(" C_FindObjectsInit #1", rc); + rc = FALSE; + goto done; + } + + do { + rc = funcs->C_FindObjects(h_session, obj_list, 1, &find_count); + if (rc != CKR_OK) { + show_error(" C_FindObjects #1", rc); + rc = FALSE; + goto done; + } + printf("Found: %d objects\n", find_count); + } while (find_count != 0); + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + show_error(" C_FindObjectsFinal #1", rc); + rc = FALSE; + goto done; + } + + rc = TRUE; + +done: + funcs->C_CloseAllSessions(SLOT_ID); + + return rc; +} + + +// do_verify_token_object() +int do_verify_token_object(void) +{ + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc; + CK_BYTE user_pin[DEFAULT_USER_PIN_LEN]; + CK_ULONG user_pin_len; + CK_OBJECT_HANDLE obj_list[20]; + CK_ULONG find_count; + + CK_BYTE cert1_id[] = "Certificate ID #1"; + + CK_BYTE buf1[100]; + CK_ATTRIBUTE verify_attribs[] = { + {CKA_ID, &buf1, sizeof(buf1)} + }; + + memcpy(user_pin, DEFAULT_USER_PIN, DEFAULT_USER_PIN_LEN); + user_pin_len = DEFAULT_USER_PIN_LEN; + + // create a USER R/W session + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(SLOT_ID, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + show_error(" C_OpenSession #1", rc); + rc = FALSE; + goto done; + } + + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + show_error(" C_Login #1", rc); + rc = FALSE; + goto done; + } + // + //--------------------------------------------------------------------- + // + + // now, retrieve a list of all object handles + // + rc = funcs->C_FindObjectsInit(h_session, NULL, 0); + if (rc != CKR_OK) { + show_error(" C_FindObjectsInit #1", rc); + rc = FALSE; + goto done; + } + + rc = funcs->C_FindObjects(h_session, obj_list, 20, &find_count); + if (rc != CKR_OK) { + show_error(" C_FindObjects #1", rc); + rc = FALSE; + goto done; + } + + if (find_count == 0) { + printf("ERROR: no objects to examine\n"); + rc = FALSE; + goto done; + } + + // now, try to extract the CKA_APPLICATION attribute from the original + // this will pull in the token's default value for CKA_APPLICATION which + verify_attribs[0].ulValueLen = sizeof(buf1); + rc = funcs->C_GetAttributeValue(h_session, obj_list[0], verify_attribs, 1); + if (rc != CKR_OK) { + show_error(" C_GetAttributeValue #1", rc); + rc = FALSE; + goto done; + } + + if (memcmp(&cert1_id, verify_attribs[0].pValue, sizeof(cert1_id)) != 0) { + printf(" ERROR: extracted attribute doesn't match\n"); + rc = FALSE; + goto done; + } + + printf("Attribute matches! Good.\n"); + rc = TRUE; + +done: + funcs->C_CloseAllSessions(SLOT_ID); + + return rc; +} + +int do_destroy_all_token_objects(void) +{ + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_RV rc; + CK_BYTE user_pin[DEFAULT_USER_PIN_LEN]; + CK_ULONG user_pin_len; + + CK_OBJECT_HANDLE obj_list[20]; + CK_ULONG find_count; + CK_ULONG i; + + memcpy(user_pin, DEFAULT_USER_PIN, DEFAULT_USER_PIN_LEN); + user_pin_len = DEFAULT_USER_PIN_LEN; + + // create a USER R/W session + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(SLOT_ID, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + show_error(" C_OpenSession #1", rc); + rc = FALSE; + goto done; + } + + rc = funcs->C_Login(h_session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + show_error(" C_Login #1", rc); + rc = FALSE; + goto done; + } + // + //--------------------------------------------------------------------- + // + + // now, retrieve a list of all object handles + // + rc = funcs->C_FindObjectsInit(h_session, NULL, 0); + if (rc != CKR_OK) { + show_error(" C_FindObjectsInit #1", rc); + rc = FALSE; + goto done; + } + + do { + rc = funcs->C_FindObjects(h_session, obj_list, 20, &find_count); + if (rc != CKR_OK) { + show_error(" C_FindObjects #1", rc); + rc = FALSE; + goto done; + } + + for (i = 0; i < find_count; i++) { + rc = funcs->C_DestroyObject(h_session, obj_list[i]); + if (rc != CKR_OK) { + printf(" C_DestroyObject #%d returned", i); + show_error(" ", rc); + rc = FALSE; + goto done; + } + } + } while (find_count != 0); + + rc = funcs->C_FindObjectsFinal(h_session); + if (rc != CKR_OK) { + show_error(" C_FindObjectsFinal #1", rc); + rc = FALSE; + goto done; + } + + rc = TRUE; + +done: + funcs->C_CloseAllSessions(SLOT_ID); + + return rc; +} + + +int do_inittoken(void) +{ + CK_BYTE label[32]; + CK_BYTE so_pin[DEFAULT_SO_PIN_LEN]; + CK_ULONG so_pin_len; + int len; + CK_RV rc; + + memcpy(so_pin, DEFAULT_SO_PIN, DEFAULT_SO_PIN_LEN); + so_pin_len = DEFAULT_SO_PIN_LEN; + + //memcpy( label, "A new label ", 32 ); + memcpy(label, " ", 32); + + printf("Enter Token Label:"); + scanf("%32s", label); + printf("\nLabel is %s:", label); + + for (len = 0; len < 31; len++) { + if (label[len] == '\0') { + label[len] = ' '; + break; + } + } + printf("\n"); + + // memcpy( label, "RemoteLeeds ", 32 ); + + rc = funcs->C_InitToken(SLOT_ID, NULL, so_pin_len, label); + if (rc != CKR_ARGUMENTS_BAD) { + show_error(" C_InitToken Fail #1", rc); + rc = FALSE; + goto done; + } + + rc = funcs->C_InitToken(SLOT_ID, so_pin, so_pin_len, NULL); + if (rc != CKR_ARGUMENTS_BAD) { + show_error(" C_InitToken Fail #2", rc); + rc = FALSE; + goto done; + } + + rc = funcs->C_InitToken(SLOT_ID, so_pin, so_pin_len, label); + if (rc != CKR_OK) { + show_error(" C_InitToken #1", rc); + rc = FALSE; + goto done; + } + + rc = TRUE; + +done: + return rc; +} + + +int do_setUserPIN(void) +{ + CK_BYTE so_pin[DEFAULT_SO_PIN_LEN]; + CK_BYTE user_pin[DEFAULT_USER_PIN_LEN]; + CK_ULONG user_pin_len, so_pin_len; + CK_FLAGS flags; + CK_SESSION_HANDLE h_session; + CK_ULONG rc; + + memcpy(so_pin, DEFAULT_SO_PIN, DEFAULT_SO_PIN_LEN); + memcpy(user_pin, DEFAULT_USER_PIN, DEFAULT_USER_PIN_LEN); + + so_pin_len = DEFAULT_SO_PIN_LEN; + user_pin_len = DEFAULT_USER_PIN_LEN; + + + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(SLOT_ID, flags, NULL, NULL, &h_session); + if (rc != CKR_OK) { + show_error(" C_OpenSession #1", rc); + rc = FALSE; + goto done; + } + + rc = funcs->C_Login(h_session, CKU_SO, so_pin, so_pin_len); + if (rc != CKR_OK) { + show_error(" C_Login #1", rc); + rc = FALSE; + goto done; + } + + rc = funcs->C_InitPIN(h_session, user_pin, user_pin_len); + if (rc != CKR_OK) { + show_error(" C_InitPIN #1", rc); + rc = FALSE; + goto done; + } + + rc = TRUE; + +done: + funcs->C_CloseAllSessions(SLOT_ID); + + return rc; +} + + +int do_GetTokenInfo(void) +{ + CK_SLOT_ID slot_id; + CK_TOKEN_INFO info; + CK_RV rc; + + printf("do_GetTokenInfo...\n"); + + slot_id = SLOT_ID; + + rc = funcs->C_GetTokenInfo(slot_id, &info); + if (rc != CKR_OK) { + show_error(" C_GetTokenInfo", rc); + return FALSE; + } + + printf(" CK_TOKEN_INFO for slot #1: \n"); + printf(" label: %32.32s\n", info.label); + printf(" manufacturerID: %32.32s\n", info.manufacturerID); + printf(" model: %16.16s\n", info.model); + printf(" serialNumber: %16.16s\n", info.serialNumber); + printf(" flags: %0x\n", info.flags); + printf(" ulMaxSessionCount: %d\n", info.ulMaxSessionCount); + printf(" ulSessionCount: %d\n", info.ulSessionCount); + printf(" ulMaxRwSessionCount: %d\n", info.ulMaxRwSessionCount); + printf(" ulRwSessionCount: %d\n", info.ulRwSessionCount); + printf(" ulMaxPinLen: %d\n", info.ulMaxPinLen); + printf(" ulMinPinLen: %d\n", info.ulMinPinLen); + printf(" ulTotalPublicMemory: %d\n", info.ulTotalPublicMemory); + printf(" ulFreePublicMemory: %d\n", info.ulFreePublicMemory); + printf(" ulTotalPrivateMemory: %d\n", info.ulTotalPrivateMemory); + printf(" ulFreePrivateMemory: %d\n", info.ulFreePrivateMemory); + printf(" hardwareVersion: %d.%d\n", info.hardwareVersion.major, + info.hardwareVersion.minor); + printf(" firmwareVersion: %d.%d\n", info.firmwareVersion.major, + info.firmwareVersion.minor); + printf(" time: %16.16s\n", info.utcTime); + + printf("Looks okay...\n"); + + return TRUE; +} + + +int main(int argc, char **argv) +{ + CK_BYTE line[20]; + CK_ULONG val, i; + int rc; + + SLOT_ID = 0; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-slot") == 0) { + SLOT_ID = atoi(argv[i + 1]); + i++; + } + + if (strcmp(argv[i], "-h") == 0) { + printf("usage: %s [-slot ] [-h]\n\n", argv[0]); + printf("By default, Slot #1 is used\n\n"); + return -1; + } + } + + printf("Using slot #%lu...\n\n", SLOT_ID); + + rc = do_GetFunctionList(); + if (!rc) + return rc; + + funcs->C_Initialize(NULL); + + + while (1) { + printf("\n1. Create a token object\n"); + printf("2. Count token objects\n"); + printf("3. Verify contents of the first token object\n"); + printf("4. Destroy all token objects\n"); + printf("5. Initialize Token\n"); + printf("6. Set USER PIN\n"); + printf("7. Get Token Info\n"); + printf("9. Exit\n"); + printf("Selection: "); + fflush(stdout); + + fgets(line, 10, stdin); + + val = atoi(line); + + switch (val) { + case 1: + do_create_token_object(); + break; + case 2: + do_count_token_objects(); + break; + case 3: + do_verify_token_object(); + break; + case 4: + do_destroy_all_token_objects(); + break; + case 5: + do_inittoken(); + break; + case 6: + do_setUserPIN(); + break; + case 7: + do_GetTokenInfo(); + break; + case 9: + goto done; + break; + } + } + +done: + rc = funcs->C_Finalize(NULL); + + return rc; +} diff --git a/testcases/misc_tests/tok_rsa.c b/testcases/misc_tests/tok_rsa.c new file mode 100644 index 0000000..b9d34f8 --- /dev/null +++ b/testcases/misc_tests/tok_rsa.c @@ -0,0 +1,457 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2006-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: driver.c + * + * Test driver. In-depth regression test for PKCS #11 + */ + +#include +#include +#include +#include + +#include +#include + +#include "pkcs11types.h" +#include "regress.h" + +int do_GetFunctionList(void); + +CK_RV do_Cleanup(CK_SESSION_HANDLE sess) +{ + CK_RV rv; + CK_ULONG count = 0; + CK_OBJECT_HANDLE handle = 0; + CK_CHAR label[128] = {0}; + CK_ATTRIBUTE tlabel = { CKA_LABEL, label, sizeof(label) }; + + rv = funcs->C_FindObjectsInit(sess, NULL, 0); + if (rv != CKR_OK) { + show_error(" C_FindObjectsInit #1", rv); + return rv; + } + + while (1) { + rv = funcs->C_FindObjects(sess, &handle, 1, &count); + if (rv != CKR_OK) { + show_error(" C_FindObjects #1", rv); + return rv; + } + + if (count < 1) + break; + + rv = funcs->C_GetAttributeValue(sess, handle, &tlabel, 1); + if (rv != CKR_OK) + continue; + + if (strncmp((char *)label, "XXX DELETE ME", 13) == 0) { + rv = funcs->C_DestroyObject(sess, handle); + if (rv != CKR_OK) { + show_error(" C_DestroyObject", rv); + } + } + } + + rv = funcs->C_FindObjectsFinal(sess); + if (rv != CKR_OK) { + show_error(" C_FindObjectsFinal #1", rv); + return rv; + } + + return rv; +} + + +CK_RV do_VerifyTokenRSAKeyPair(CK_SESSION_HANDLE sess, CK_BYTE * label, + CK_ULONG bits) +{ + CK_OBJECT_HANDLE obj_handles[20]; + CK_ULONG pulCount = 0, obj_class, i; + CK_RV rv; + CK_BBOOL true = 1; + + printf("do_VerifyTokenRSAKeyPair...\n"); + + /* Find token objects based on the label */ + { + CK_ATTRIBUTE tmpl[] = { + {CKA_LABEL, label, (CK_ULONG) strlen((char *) label) + 1}, + {CKA_TOKEN, &true, sizeof(CK_BBOOL)} + }; + + rv = funcs->C_FindObjectsInit(sess, tmpl, 2); + if (rv != CKR_OK) { + show_error(" C_FindObjectsInit #1", rv); + return rv; + } + + rv = funcs->C_FindObjects(sess, obj_handles, 2, &pulCount); + if (rv != CKR_OK) { + show_error(" C_FindObjects #1", rv); + return rv; + } + + rv = funcs->C_FindObjectsFinal(sess); + if (rv != CKR_OK) { + show_error(" C_FindObjectsFinal #1", rv); + return rv; + } + } + + for (i = 0; i < pulCount; i++) { + CK_ATTRIBUTE tmpl[] = { + {CKA_CLASS, &obj_class, sizeof(obj_class)} + }; + + rv = funcs->C_GetAttributeValue(sess, obj_handles[i], tmpl, 1); + if (rv != CKR_OK) { + show_error(" C_GetAttributeValue #1", rv); + return rv; + } + + if (obj_class == CKO_PUBLIC_KEY) { + CK_BYTE n[514], e[514]; + CK_ULONG exp_size = 0, mod_size = 0; + CK_ATTRIBUTE pub_attrs[] = { + {CKA_PUBLIC_EXPONENT, NULL, exp_size}, + {CKA_MODULUS, NULL, mod_size} + }; + + rv = funcs->C_GetAttributeValue(sess, obj_handles[i], pub_attrs, 2); + if (rv != CKR_OK) { + show_error(" C_GetAttributeValue", rv); + return rv; + } + + /* The public exponent is element 0 and modulus is element 1 */ + if (pub_attrs[0].ulValueLen > (bits / 8) + || pub_attrs[1].ulValueLen > (bits / 8)) { + PRINT_ERR("RSA public key '%s' e_size (%lu) or n_size (%lu) " + "too big!", label, pub_attrs[0].ulValueLen, + pub_attrs[1].ulValueLen); + return CKR_FUNCTION_FAILED; + } + + pub_attrs[0].pValue = e; + pub_attrs[1].pValue = n; + + rv = funcs->C_GetAttributeValue(sess, obj_handles[i], pub_attrs, 2); + if (rv != CKR_OK) { + show_error(" C_GetAttributeValue", rv); + return rv; + } + + printf("Found public key with %lu bit modulus and %lu byte public " + "exponent.\n", pub_attrs[1].ulValueLen, + pub_attrs[0].ulValueLen); + + printf("Public exponent:\n"); + print_hex(pub_attrs[0].pValue, pub_attrs[0].ulValueLen); + + printf("Public modulus:\n"); + print_hex(pub_attrs[1].pValue, pub_attrs[1].ulValueLen); + + } else if (obj_class == CKO_PRIVATE_KEY) { + printf("Found a matching private key.\n"); + } else { + fprintf(stderr, "Found an object that's not what we're" + " looking for, skipping it...\n"); + continue; + } + + rv = funcs->C_DestroyObject(sess, obj_handles[i]); + if (rv != CKR_OK) { + show_error(" C_DestroyObject", rv); + } else { + printf("Object destroyed.\n"); + } + } + + printf("%s: Success\n", __func__); + + return CKR_OK; +} + +CK_RV do_GenerateTokenRSAKeyPair(CK_SESSION_HANDLE sess, CK_BYTE * label, + CK_ULONG bits) +{ + CK_MECHANISM mech; + CK_OBJECT_HANDLE publ_key, priv_key; + CK_RV rv; + CK_BBOOL true = 1; + + printf("do_TokenGenerateRSAKey(%lu)...\n", bits); + + mech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + // Use 65537 as pub exp + { + CK_BYTE pub_exp[] = { 0x1, 0x0, 0x1 }; + + CK_ATTRIBUTE pub_tmpl[] = { + {CKA_MODULUS_BITS, &bits, sizeof(bits)}, + {CKA_PUBLIC_EXPONENT, &pub_exp, sizeof(pub_exp)}, + {CKA_LABEL, label, (CK_ULONG) strlen((char *) label) + 1}, + {CKA_TOKEN, &true, sizeof(CK_BBOOL)} + }; + CK_ATTRIBUTE priv_tmpl[] = { + {CKA_LABEL, label, (CK_ULONG) strlen((char *) label) + 1}, + {CKA_TOKEN, &true, sizeof(CK_BBOOL)} + }; + + rv = funcs->C_GenerateKeyPair(sess, &mech, + pub_tmpl, 4, + priv_tmpl, 2, &publ_key, &priv_key); + if (rv != CKR_OK) { + show_error(" C_GenerateKeyPair #2", rv); + return rv; + } + } + + printf("%s: Success\n", __func__); + + return CKR_OK; +} + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + unsigned int bits; + int i, ret = 1; + CK_RV rv; + CK_BYTE user_pin[128]; + CK_ULONG user_pin_len; + CK_SLOT_ID slot_id = 0; + CK_SESSION_HANDLE session; + CK_FLAGS flags; + CK_MECHANISM_INFO rsakeygeninfo; + CK_BYTE label[256]; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-slot") == 0) { + ++i; + slot_id = atoi(argv[i]); + } + + if (strcmp(argv[i], "-h") == 0) { + printf("usage: %s [-noskip] [-slot ] [-h]\n\n", argv[0]); + printf("By default, Slot #1 is used\n\n"); + printf("By default we skip anything that creates or modifies\n"); + printf("token objects to preserve flash lifetime.\n"); + return -1; + } + } + + printf("Using slot #%lu...\n\n", slot_id); + + rv = do_GetFunctionList(); + if (rv != TRUE) { + show_error("do_GetFunctionList", rv); + goto out; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + // SAB Add calls to ALL functions before the C_Initialize gets hit + + if ((rv = funcs->C_Initialize(&cinit_args))) { + show_error("C_Initialize", rv); + goto out; + } + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rv = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session); + if (rv != CKR_OK) { + show_error(" C_OpenSession #1", rv); + goto finalize; + } + + rv = funcs->C_Login(session, CKU_USER, user_pin, user_pin_len); + if (rv != CKR_OK) { + show_error(" C_Login #1", rv); + goto close_session; + } + + rv = do_Cleanup(session); + if (rv != CKR_OK) { + show_error("do_Cleanup()", rv); + goto close_session; + } + + rv = funcs->C_GetMechanismInfo(slot_id, CKM_RSA_PKCS_KEY_PAIR_GEN, + &rsakeygeninfo); + if (rv != CKR_OK) { + show_error("C_GetMechanismInfo(CKM_RSA_PKCS_KEY_PAIR_GEN)", rv); + goto close_session; + } + + bits = 512; + if (bits >= rsakeygeninfo.ulMinKeySize + && bits <= rsakeygeninfo.ulMaxKeySize) { + sprintf((char *)label, "XXX DELETE ME TEST LABEL %dbit", bits); + rv = do_GenerateTokenRSAKeyPair(session, label, bits); + if (rv != CKR_OK) { + show_error("do_GenerateTokenRSAKeyPair(512)", rv); + goto close_session; + } + } else { + testcase_skip("do_GenerateTokenRSAKeyPair(512)"); + } + + bits = 1024; + if (bits >= rsakeygeninfo.ulMinKeySize + && bits <= rsakeygeninfo.ulMaxKeySize) { + sprintf((char *)label, "XXX DELETE ME TEST LABEL %dbit", bits); + rv = do_GenerateTokenRSAKeyPair(session, label, bits); + if (rv != CKR_OK) { + show_error("do_GenerateTokenRSAKeyPair(1024)", rv); + goto close_session; + } + } else { + testcase_skip("do_GenerateTokenRSAKeyPair(1024)"); + } + + bits = 2048; + if (bits >= rsakeygeninfo.ulMinKeySize + && bits <= rsakeygeninfo.ulMaxKeySize) { + sprintf((char *)label, "XXX DELETE ME TEST LABEL %dbit", bits); + rv = do_GenerateTokenRSAKeyPair(session, label, bits); + if (rv != CKR_OK) { + show_error("do_GenerateTokenRSAKeyPair(2048)", rv); + goto close_session; + } + } else { + testcase_skip("do_GenerateTokenRSAKeyPair(2048)"); + } + + bits = 4096; + if (bits >= rsakeygeninfo.ulMinKeySize + && bits <= rsakeygeninfo.ulMaxKeySize) { + sprintf((char *)label, "XXX DELETE ME TEST LABEL %dbit", bits); + rv = do_GenerateTokenRSAKeyPair(session, label, bits); + if (rv != CKR_OK) { + show_error("do_GenerateTokenRSAKeyPair(4096)", rv); + goto close_session; + } + } else { + testcase_skip("do_GenerateTokenRSAKeyPair(4096)"); + } + + rv = funcs->C_CloseSession(session); + if (rv != CKR_OK) { + show_error(" C_CloseSession #3", rv); + goto finalize; + } + + rv = funcs->C_Finalize(NULL); + if (rv != CKR_OK) { + show_error("C_Finalize", rv); + goto out; + } + + /* Open a new session and re-login */ + if ((rv = funcs->C_Initialize(&cinit_args))) { + show_error("C_Initialize", rv); + goto out; + } + + rv = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session); + if (rv != CKR_OK) { + show_error(" C_OpenSession #2", rv); + goto finalize; + } + + rv = funcs->C_Login(session, CKU_USER, user_pin, user_pin_len); + if (rv != CKR_OK) { + show_error(" C_Login #2", rv); + goto close_session; + } + + bits = 512; + if (bits >= rsakeygeninfo.ulMinKeySize + && bits <= rsakeygeninfo.ulMaxKeySize) { + sprintf((char *)label, "XXX DELETE ME TEST LABEL %dbit", bits); + rv = do_VerifyTokenRSAKeyPair(session, label, bits); + if (rv != CKR_OK) { + show_error("do_VerifyTokenRSAKeyPair(512)", rv); + goto close_session; + } + } + + bits = 1024; + if (bits >= rsakeygeninfo.ulMinKeySize + && bits <= rsakeygeninfo.ulMaxKeySize) { + sprintf((char *)label, "XXX DELETE ME TEST LABEL %dbit", bits); + rv = do_VerifyTokenRSAKeyPair(session, label, 1024); + if (rv != CKR_OK) { + show_error("do_VerifyTokenRSAKeyPair(1024)", rv); + goto close_session; + } + } + + bits = 2048; + if (bits >= rsakeygeninfo.ulMinKeySize + && bits <= rsakeygeninfo.ulMaxKeySize) { + sprintf((char *)label, "XXX DELETE ME TEST LABEL %dbit", bits); + rv = do_VerifyTokenRSAKeyPair(session, label, bits); + if (rv != CKR_OK) { + show_error("do_VerifyTokenRSAKeyPair(2048)", rv); + goto close_session; + } + } + + bits = 4096; + if (bits >= rsakeygeninfo.ulMinKeySize + && bits <= rsakeygeninfo.ulMaxKeySize) { + sprintf((char *)label, "XXX DELETE ME TEST LABEL %dbit", bits); + rv = do_VerifyTokenRSAKeyPair(session, label, bits); + if (rv != CKR_OK) { + show_error("do_VerifyTokenRSAKeyPair(4096)", rv); + goto close_session; + } + } + + rv = do_Cleanup(session); + if (rv != CKR_OK) { + show_error("do_Cleanup()", rv); + goto close_session; + } + + ret = 0; +close_session: + rv = funcs->C_CloseSession(session); + if (rv != CKR_OK) { + show_error(" C_CloseSession #3", rv); + ret = 1; + } +finalize: + rv = funcs->C_Finalize(NULL); + if (rv != CKR_OK) { + show_error("C_Finalize", rv); + ret = 1; + } +out: + if (ret == 0) + printf("%s: Success\n", argv[0]); + else + printf("%s: Failure\n", argv[0]); + + return ret; +} diff --git a/testcases/ock_tests.sh.in b/testcases/ock_tests.sh.in new file mode 100755 index 0000000..1df8f84 --- /dev/null +++ b/testcases/ock_tests.sh.in @@ -0,0 +1,345 @@ +#!/bin/bash +# +# COPYRIGHT (c) International Business Machines Corp. 2008-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 +# +# +# NAME +# ocktests.sh +# +# DESCRIPTION +# Simple Bash script that checks the enviroment in which the ock-tests will run +# and starts them. +# +# ALGORITHM +# None. +# +# USAGE +# +# HISTORY +# Rajiv Andrade +# +# RESTRICTIONS +# None. +## + +LOGGING=0 +TESTDIR=`dirname $0` +LOGFILE="$TESTDIR/ock-tests.log" +ERR_SUMMARY="$TESTDIR/ock-tests.err" +PKCONF="@sysconfdir@/opencryptoki/opencryptoki.conf" +PKCSCONFBIN="@sbindir@/pkcsconf" +TESTCONF="$TESTDIR/ock-tests.config" +TOKTYPE="" +NONEED_TOKEN_INIT=0 + +# +# This is the list of the tests we'll be running once everything is initialized +# +# The order of these tests matters. login/login leaves the token with its USER +# PIN locked, leaving the token unusable until someone manually deletes +# $OCKDIR/$TOKEN/*. Manually deleting this dir is pre-req for starting the +# automated tests anyway, so this is OK. +# +# login/login MUST come last if it appears in this list +# +OCK_TESTS="crypto/*tests" +OCK_TEST="" +OCK_BENCHS="pkcs11/*bench" + +usage() +{ + echo -e " usage: ./ock_tests.sh [-s ] [-f ]" \ + "[-l ] [-n] [-h]" + echo -e " -l redirect output to logfile" \ + "(default is command line)" + echo -e " -h display this help" + echo -e " -q run quietly - display only total number" \ + "of tests passed/failed" + echo -e " -s slot against which the testcases will run" \ + "(omit it to test all available tokens)" + echo -e " -f path to test that will be run" + echo -e " -n don't stop in case one of the testcases fail" + echo -e " -b also run benchmarks or performance tests" + exit -1 +} + +### +## check_tpmtok() - Check if stuff needed by tpm token are +## present +### +check_tpmtok() +{ + # Check for tpmtoken_init + if ! which tpmtoken_init; then + echo "Error: tpmtoken_init could not be found on PATH" + return 1 + fi + + # Check if tcsd is running + if ! pgrep tcsd; then + echo "Error: TCSD daemon not running" + return 1 + fi +} + +### +## check_ccatok() - Check if stuff needed by the CCA token +## are present +### +check_ccatok() +{ + # Check if catcher.exe is running + if ! pgrep catcher.exe; then + echo "Error: catcher.exe daemon not running" + return 1 + fi +} + +### +## init_slot() - Initialize a specific slot +## $1 - The slot number to initialize +## +### +init_slot() +{ + case $TOKTYPE in + TPM) + echo "Initializing TPM token using init_tpmtoken.sh" + if ! $TESTDIR/init_tpmtoken.sh; then + echo "Error initializing TPM token" + return 1 + fi + ;; + CCA | EP11 | ICA | Software) + echo "Initializing $TOKTYPE using init_token.sh" + if ! $TESTDIR/init_token.sh $1; then + echo "Error initializing $TOKTYPE token" + return 1 + fi + ;; + *) + echo "FATAL: Token type not recognized: $TOKTYPE" + exit 1 + esac +} + + +### +## check_slot() - Checks if we have everything needed to test +## this specific slot number +## $1 - The slot number to check +### +check_slot() +{ + # Check if the Slot exists, and what it actually is + TOKDESCR=`$PKCSCONFBIN -c $1 -t` + TOKMODEL=`echo "$TOKDESCR" | grep "Model:"` + + case $TOKMODEL in + *TPM*) + echo "TPM Token type detected" + check_tpmtok || return + TOKTYPE="TPM" + ;; + *CCA*) + echo "CCA Token type detected" + check_ccatok || return + TOKTYPE="CCA" + ;; + *ICA*) + echo "ICA Token type detected" + TOKTYPE="ICA" + ;; + *SoftTok*) + echo "Software Token type detected" + TOKTYPE="Software" + ;; + *EP11*) + echo "EP11 Token type detected" + TOKTYPE="EP11" + ;; + *) + echo "Error: unsupported or undetermined token type" + echo " wrong Slot $1?" + return 1 + esac + + # Check if Tokem is initialized and set $NONEED_TOKEN_INIT if so + NONEED_TOKEN_INIT=`echo "$TOKDESCR" | grep "Flags:" | grep TOKEN_INITIALIZED | wc -l` +} + +## +## check_env() - Check if we have everything we need +## +check_env() +{ + ## Check env vars first + if [ -z $PKCS11_SO_PIN ]; then + echo "FATAL: Must set PKCS11_SO_PIN" + exit 1 + fi + + if [ -z $PKCS11_USER_PIN ]; then + echo "FATAL: Must set PKCS11_USER_PIN" + exit 1 + fi + + if [ -z $PKCSLIB ]; then + echo "FATAL: Must set PKCSLIB" + exit 1 + fi + + if [ ! -f $PKCSLIB ]; then + echo "FATAL: PKCSLIB=$PKCSLIB is invalid" + exit 1 + fi + + if [ ! -f $PKCONF ]; then + echo "FATAL: Can't find configuration data ($PKCONF)" + exit 1 + fi + + # if user is not root + if [ $EUID -ne 0 ]; then + ## Check if the pkcs11 group 'exists' + P11GROUP=`getent group pkcs11 | cut -d ":" -f 3` + if [ -z $P11GROUP ]; then + echo "FATAL: Can't find pkcs11 group" + exit 1 + fi + ## Check if we're part of it + if ! id -G | grep $P11GROUP; then + echo "FATAL: Must be part of the pkcs11 group" + exit 1 + fi + fi + + ## Make sure we have the slot daemon running + if ! pgrep pkcsslotd; then + echo "FATAL: The slot daemon (pkcsslotd) must be running" + exit 1 + fi + + ## We also need pkcsconf + if [ ! -x $PKCSCONFBIN ]; then + echo "FATAL: Invalid pkcsconf utility ($PKCSCONFBIN)" + exit 1 + fi +} + +### +## run_tests() - run tests for a specific slot, +## following $OCK_TEST order +## $1 - the slot +### +run_tests() +{ + if [ -n "$OCK_TEST" ]; then + OCK_TESTS="$OCK_TEST" + fi + echo "***** Will run the following tests for slot $1: $(ls -U $OCK_TESTS)" + for j in $( ls -U $OCK_TESTS ); do + echo "** Now executing '$j'" + $j -slot $1 $NO_STOP 2>&1 + RES=$? + if [ $RES -ne 0 ]; then + echo "ERROR: Testcase $i failed to execute." + exit $RES + fi + done +} + +### +## run_benchs() - run benchmarks for a specific slot, +## following $OCK_BENCH order +## $1 - the slot +### +run_benchs() +{ + echo "***** Will run the following benchmarks for slot $1: $(ls -U $OCK_BENCHS)" + for i in $( ls -U $OCK_BENCHS ); do + echo "** Now executing '$i" + $i -slot $1 $NO_STOP 2>&1 + done +} + + +main_script() +{ + LOGFILE=0 + + # check generic stuff first + check_env + + # where to run + if [ -z $SLOT ]; then + NUMSLOT=$(grep '^slot' $PKCONF | wc -l) + for ((i=0; i<$NUMSLOT; i++)); do + SLOT="$SLOT $i" + LOGFILE=1 + done + fi + + for i in $SLOT; do ( + echo "********** Testing Slot $i **********" + check_slot $i || { echo "SKIPPING slot $i"; continue; } + if [ $NONEED_TOKEN_INIT -eq 0 ]; then + init_slot $i || { echo "SKIPPING slot $i"; continue; } + fi + if [ "$LOGFILE" = "1" ]; then + echo "test output for slot $i stored in log-slot_$i.txt" + run_tests $i > "log-slot_$i.txt" 2>&1 + else + run_tests $i + fi + [ -n "$BENCHMARK" ] && run_benchs $i + echo "********** Finished Testing Slot $i **********" + ) & + done + wait +} + +while getopts s:f:l:hc:n arg; do + case $arg in + h) + usage + ;; + l) + LOGGING=1 + if [ -n $OPTARG ]; then + LOGFILE="$OPTARG" + fi + touch $LOGFILE + ;; + c) + TESTCONF="$OPTARG" + touch $TESTCONF + ;; + n) + NO_STOP="-nostop" + ;; + s) + SLOT="$OPTARG" + ;; + f) + OCK_TEST="$OPTARG" + ;; + b) + BENCHMARK="yes" + ;; + esac +done + + +if [ "$LOGGING" = "1" ]; then + main_script >>$LOGFILE 2>&1 +else + main_script +fi + +exit 0 diff --git a/testcases/pkcs11/README b/testcases/pkcs11/README new file mode 100644 index 0000000..a09a6b3 --- /dev/null +++ b/testcases/pkcs11/README @@ -0,0 +1,13 @@ +PKCS11 Testcases + +generate_keypair + Note: Currently does not work on secure key tokens, cca and ep11. + +hw_fn + TODO - Not tested; Needs to be refactored and tested. + +misc_tests + TODO - Not tested; Needs to be refactored and tested. + +sess_mgmt_tests + TODO - Not tested; Needs to be refactored and tested. diff --git a/testcases/pkcs11/attribute.c b/testcases/pkcs11/attribute.c new file mode 100644 index 0000000..a51d8be --- /dev/null +++ b/testcases/pkcs11/attribute.c @@ -0,0 +1,198 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2013-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 + */ + +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "common.c" + +CK_RV do_TestAttributes(void) +{ + CK_OBJECT_HANDLE obj_handle = CK_INVALID_HANDLE; + CK_SESSION_HANDLE session; + CK_RV rc = 0, rv = 0; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + CK_BYTE modulus[] = { + 0xa5, 0x6e, 0x4a, 0x0e, 0x70, 0x10, 0x17, 0x58, + 0x9a, 0x51, 0x87, 0xdc, 0x7e, 0xa8, 0x41, 0xd1, + 0x56, 0xf2, 0xec, 0x0e, 0x36, 0xad, 0x52, 0xa4, + 0x4d, 0xfe, 0xb1, 0xe6, 0x1f, 0x7a, 0xd9, 0x91, + 0xd8, 0xc5, 0x10, 0x56, 0xff, 0xed, 0xb1, 0x62, + 0xb4, 0xc0, 0xf2, 0x83, 0xa1, 0x2a, 0x88, 0xa3, + 0x94, 0xdf, 0xf5, 0x26, 0xab, 0x72, 0x91, 0xcb, + 0xb3, 0x07, 0xce, 0xab, 0xfc, 0xe0, 0xb1, 0xdf, + 0xd5, 0xcd, 0x95, 0x08, 0x09, 0x6d, 0x5b, 0x2b, + 0x8b, 0x6d, 0xf5, 0xd6, 0x71, 0xef, 0x63, 0x77, + 0xc0, 0x92, 0x1c, 0xb2, 0x3c, 0x27, 0x0a, 0x70, + 0xe2, 0x59, 0x8e, 0x6f, 0xf8, 0x9d, 0x19, 0xf1, + 0x05, 0xac, 0xc2, 0xd3, 0xf0, 0xcb, 0x35, 0xf2, + 0x92, 0x80, 0xe1, 0x38, 0x6b, 0x6f, 0x64, 0xc4, + 0xef, 0x22, 0xe1, 0xe1, 0xf2, 0x0d, 0x0c, 0xe8, + 0xcf, 0xfb, 0x22, 0x49, 0xbd, 0x9a, 0x21, 0x37 + }; + + CK_BYTE publicExponent[] = { 0x01, 0x00, 0x01 }; + int modulus_len = 128; + int publicExponent_len = 3; + + CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; + CK_KEY_TYPE keyType = CKK_RSA; + CK_CHAR label[] = "An RSA public key object"; + CK_CHAR newlabel[] = "Updated RSA public key object"; + CK_CHAR labelbuf[100]; + CK_BBOOL false = FALSE; + CK_BBOOL boolval; + + CK_ATTRIBUTE pub_template[] = { + {CKA_CLASS, &class, sizeof(class)}, + {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, + {CKA_TOKEN, &false, sizeof(false)}, + {CKA_LABEL, label, sizeof(label) - 1}, + {CKA_MODULUS, modulus, modulus_len}, + {CKA_PUBLIC_EXPONENT, publicExponent, publicExponent_len} + }; + + CK_ATTRIBUTE new_attrs[] = { + {CKA_ENCRYPT, &false, sizeof(false)}, + {CKA_WRAP, &false, sizeof(false)}, + }; + + CK_ATTRIBUTE update_label[] = { + {CKA_LABEL, newlabel, sizeof(newlabel) - 1}, + }; + + CK_ATTRIBUTE verify_attrs[] = { + {CKA_ENCRYPT, &boolval, sizeof(boolval)}, + {CKA_WRAP, &boolval, sizeof(boolval)}, + {CKA_LABEL, labelbuf, sizeof(labelbuf)}, + }; + + testcase_begin("starting..."); + testcase_rw_session(); + testcase_user_login(); + + /* create a public key object */ + rc = funcs->C_CreateObject(session, pub_template, 6, &obj_handle); + if (rc != CKR_OK) { + testcase_fail("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /* Now add new attributes */ + testcase_new_assertion(); + rc = funcs->C_SetAttributeValue(session, obj_handle, new_attrs, 2); + if (rc != CKR_OK) { + testcase_fail("C_SetAttributeValue() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + testcase_pass("Successfully added new attributes."); + + /* Now update an existing attribute */ + testcase_new_assertion(); + rc = funcs->C_SetAttributeValue(session, obj_handle, update_label, 1); + if (rc != CKR_OK) { + testcase_fail("C_SetAttributeValue() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + testcase_pass("Successfully updated existing attribute."); + + /* Now get the attributes that were updated */ + testcase_new_assertion(); + rc = funcs->C_GetAttributeValue(session, obj_handle, verify_attrs, 3); + if (rc != CKR_OK) { + testcase_fail("C_GetAttributeValue() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /* verify the attribute values retrieved */ + if (*(CK_BBOOL *) verify_attrs[0].pValue != false) { + testcase_fail("CKA_ENCRYPT mismatch"); + goto testcase_cleanup; + } + + if (*(CK_BBOOL *) verify_attrs[1].pValue != false) { + testcase_fail("CKA_WRAP mismatch"); + goto testcase_cleanup; + } + + if (memcmp(verify_attrs[2].pValue, + newlabel, verify_attrs[2].ulValueLen) != 0) + testcase_fail("CKA_LABEL mismatch"); + else + testcase_pass("Successfully verified updated attributes."); + +testcase_cleanup: + rv = funcs->C_DestroyObject(session, obj_handle); + if (rv != CKR_OK) + testcase_error("C_DestroyObject rv=%s", p11_get_ckr(rv)); + + testcase_user_logout(); + rv = funcs->C_CloseSession(session); + if (rv != CKR_OK) + testcase_error("C_CloseSessions rv=%s", p11_get_ckr(rv)); + + return rc; +} + +int main(int argc, char **argv) +{ + int rc; + CK_C_INITIALIZE_ARGS cinit_args; + CK_RV rv = 0; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: nostop: %d\n", no_stop); + + rc = do_GetFunctionList(); + if (!rc) { + testcase_error("do_getFunctionList(), rc=%s", p11_get_ckr(rc)); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + funcs->C_Initialize(&cinit_args); + + { + CK_SESSION_HANDLE hsess = 0; + + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + } + + testcase_setup(0); + rc = do_TestAttributes(); + testcase_print_result(); + + funcs->C_Finalize(NULL); + + /* make sure we return non-zero if rv is non-zero */ + return ((rv == 0) || (rv % 256) ? (int)rv : -1); +} diff --git a/testcases/pkcs11/copyobjects.c b/testcases/pkcs11/copyobjects.c new file mode 100644 index 0000000..ce1e835 --- /dev/null +++ b/testcases/pkcs11/copyobjects.c @@ -0,0 +1,321 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2013-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 + */ + +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "common.c" + +/* API Routines exercised: + * C_CreateObject + * C_CopyObject + * C_DestroyObject + * + * 3 TestCases + * Setup: Create a key object. + * Testcase 1: Make an exact copy of the object with empty attribute list. + * Testcase 2: make an exact copy of the object with one additional attribute. + */ +CK_RV do_CopyObjects(void) +{ + CK_FLAGS flags; + CK_SESSION_HANDLE session; + CK_RV rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_ATTRIBUTE empty_tmpl; + + CK_OBJECT_HANDLE keyobj = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE firstobj = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE secondobj = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE thirdobj = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE fourthobj = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE fifthobj = CK_INVALID_HANDLE; + + CK_BBOOL true = TRUE; + CK_BBOOL false = FALSE; + CK_KEY_TYPE aes_type = CKK_AES; + CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; + CK_CHAR aes_value[] = "This is a fake aes key."; + CK_ATTRIBUTE aes_tmpl[] = { + {CKA_CLASS, &key_class, sizeof(key_class)}, + {CKA_KEY_TYPE, &aes_type, sizeof(aes_type)}, + {CKA_VALUE, &aes_value, sizeof(aes_value)}, + {CKA_SENSITIVE, &false, sizeof(false)} + }; + + CK_KEY_TYPE new_aes_type; + CK_OBJECT_CLASS new_key_class; + CK_CHAR new_aes_value[50]; + CK_BBOOL sensitive; + CK_ATTRIBUTE test_tmpl[] = { + {CKA_CLASS, &new_key_class, sizeof(new_key_class)}, + {CKA_KEY_TYPE, &new_aes_type, sizeof(new_aes_type)}, + {CKA_VALUE, &new_aes_value, sizeof(new_aes_value)}, + {CKA_SENSITIVE, &sensitive, sizeof(sensitive)} + }; + + CK_ATTRIBUTE copy_tmpl[] = { + {CKA_TOKEN, &true, sizeof(true)} + }; + + CK_ATTRIBUTE true_sensitive_tmpl[] = { + {CKA_SENSITIVE, &true, sizeof(true)} + }; + + CK_ATTRIBUTE false_sensitive_tmpl[] = { + {CKA_SENSITIVE, &false, sizeof(false)} + }; + + CK_ATTRIBUTE test_sensitive_tmpl[] = { + {CKA_SENSITIVE, &sensitive, sizeof(sensitive)} + }; + + memset(&empty_tmpl, 0, sizeof(empty_tmpl)); + + CK_ATTRIBUTE *null_tmpl = NULL; + + // Do some setup and login to the token + testcase_begin("starting..."); + testcase_rw_session(); + testcase_user_login(); + + // Create an AES Key Object. + rc = funcs->C_CreateObject(session, aes_tmpl, 4, &keyobj); + if (rc != CKR_OK) { + testcase_error("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // Testcase #1 - Copy object exactly with no additional attributes, by + // passing a null object + testcase_new_assertion(); + + rc = funcs->C_CopyObject(session, keyobj, null_tmpl, 0, &firstobj); + if (rc != CKR_OK) { + testcase_fail("C_CopyObject() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // Pull up some attributes and verify that new object has + // same attribute values as original. + rc = funcs->C_GetAttributeValue(session, firstobj, test_tmpl, 4); + if (rc != CKR_OK) { + testcase_error("C_GetAttributeValue() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // Step thru template to see if new object matches original... + if ((memcmp(test_tmpl[0].pValue, aes_tmpl[0].pValue, + aes_tmpl[0].ulValueLen) == 0) && + (memcmp(test_tmpl[1].pValue, aes_tmpl[1].pValue, + aes_tmpl[1].ulValueLen) == 0) && + (memcmp(test_tmpl[3].pValue, aes_tmpl[3].pValue, + aes_tmpl[3].ulValueLen) == 0)) { + + /* CKA_VALUE is suppose to be zeroed out for + * secure key tokens after importing the key. + */ + if ((is_cca_token(SLOT_ID)) || (is_ep11_token(SLOT_ID))) { + if (*(CK_BYTE *) test_tmpl[2].pValue == 0) + testcase_pass("Copied object's attributes are correct"); + else + testcase_fail("Copied object's attributes are incorrect."); + } else { + if (memcmp(test_tmpl[2].pValue, aes_tmpl[2].pValue, + aes_tmpl[2].ulValueLen) == 0) + testcase_pass("Copied object's attributes are the same."); + else + testcase_fail("Copied object's attributes are different."); + } + } else { + testcase_fail("Copied object's attributes are different."); + } + + + + // Testcase #2 - Copy object exactly with no additional attributes, by + // passing an empty template. + testcase_new_assertion(); + + rc = funcs->C_CopyObject(session, keyobj, &empty_tmpl, 0, &secondobj); + if (rc != CKR_OK) { + testcase_fail("C_CopyObject() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // Pull up some attributes and verify that new object has + // same attribute values as original. + rc = funcs->C_GetAttributeValue(session, secondobj, test_tmpl, 4); + if (rc != CKR_OK) { + testcase_error("C_GetAttributeValue() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // Step thru template to see if new object matches original... + if ((memcmp(test_tmpl[0].pValue, aes_tmpl[0].pValue, + aes_tmpl[0].ulValueLen) == 0) && + (memcmp(test_tmpl[1].pValue, aes_tmpl[1].pValue, + aes_tmpl[1].ulValueLen) == 0) && + (memcmp(test_tmpl[3].pValue, aes_tmpl[3].pValue, + aes_tmpl[3].ulValueLen) == 0)) { + + /* CKA_VALUE is suppose to be zeroed out for + * secure key tokens after importing the key. + */ + if ((is_cca_token(SLOT_ID)) || (is_ep11_token(SLOT_ID))) { + if (*(CK_BYTE *)test_tmpl[2].pValue == 0) + testcase_pass("Copied object's attributes are correct"); + else + testcase_fail("Copied object's attributes are incorrect."); + } else { + if (memcmp(test_tmpl[2].pValue, aes_tmpl[2].pValue, + aes_tmpl[2].ulValueLen) == 0) + testcase_pass("Copied object's attributes are the same."); + else + testcase_fail("Copied object's attributes are different."); + } + } else { + testcase_fail("Copied object's attributes are different."); + } + + + + // Testcase #3 - Copy an object and include one additional attribute. + testcase_new_assertion(); + + rc = funcs->C_CopyObject(session, keyobj, copy_tmpl, 1, &thirdobj); + if (rc != CKR_OK) { + testcase_fail("C_CopyObject() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // Verify that new object has the new attribute and value (CKA_TOKEN). + // NOTE: Since passing in same template, original value will be + // over-written. + rc = funcs->C_GetAttributeValue(session, thirdobj, copy_tmpl, 1); + if (rc != CKR_OK) { + testcase_fail("C_GetAttributeValue() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + if (*(CK_BBOOL *) copy_tmpl[0].pValue == TRUE) + testcase_pass("Copied object's attributes are the same."); + else + testcase_fail("Copied object's attributes are different."); + + + + // Testcase #4 - Copy object changing the value of CKA_SENSITIVE + // from true to false. This should be allowed on copy. + testcase_new_assertion(); + + rc = funcs->C_CopyObject(session, keyobj, + true_sensitive_tmpl, 1, &fourthobj); + if (rc != CKR_OK) { + testcase_fail("C_CopyObject() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + // Verify that new object has CKA_SENSITIVE == true; + rc = funcs->C_GetAttributeValue(session, fourthobj, + test_sensitive_tmpl, 1); + if (rc != CKR_OK) { + testcase_fail("C_GetAttributeValue() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + if (*(CK_BBOOL *) test_sensitive_tmpl[0].pValue == TRUE) + testcase_pass("Copied object's CKA_SENSITIVE == TRUE."); + else + testcase_fail("Copied object's CKA_SENSITIVE != TRUE."); + + + // Testcase #5 - Now try changing CKA_SENSITIVE from TRUE to False. + // This should not be allowed. + testcase_new_assertion(); + + rc = funcs->C_CopyObject(session, fourthobj, + false_sensitive_tmpl, 1, &fifthobj); + if (rc != CKR_OK) + testcase_pass("C_CopyObject) did not copy the object. rc = %s", + p11_get_ckr(rc)); + else + testcase_fail("C_CopyObject() should have failed."); + + +testcase_cleanup: + funcs->C_DestroyObject(session, keyobj); + funcs->C_DestroyObject(session, firstobj); + funcs->C_DestroyObject(session, secondobj); + funcs->C_DestroyObject(session, thirdobj); + funcs->C_DestroyObject(session, fourthobj); + funcs->C_DestroyObject(session, fifthobj); + + + testcase_user_logout(); + rc = funcs->C_CloseSession(session); + if (rc != CKR_OK) { + testcase_error("C_CloseSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +int main(int argc, char **argv) +{ + int rc; + CK_C_INITIALIZE_ARGS cinit_args; + CK_RV rv = 0; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: nostop: %d\n", no_stop); + + rc = do_GetFunctionList(); + if (!rc) { + testcase_error("do_getFunctionList(), rc=%s", p11_get_ckr(rc)); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + funcs->C_Initialize(&cinit_args); + + { + CK_SESSION_HANDLE hsess = 0; + + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + } + + testcase_setup(0); + rc = do_CopyObjects(); + testcase_print_result(); + + funcs->C_Finalize(NULL); + + /* make sure we return non-zero if rv is non-zero */ + return ((rv == 0) || (rv % 256) ? (int)rv : -1); +} diff --git a/testcases/pkcs11/destroyobjects.c b/testcases/pkcs11/destroyobjects.c new file mode 100644 index 0000000..ab7a8b4 --- /dev/null +++ b/testcases/pkcs11/destroyobjects.c @@ -0,0 +1,259 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2013-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 + */ + +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "common.c" + + +/* API Routines exercised: + * C_DestroyObject + * + * TestCases + * Setup: Create several key objects and generate several key objects. + * Testcase 1: Destroy only a few objects. Verify they were deleted. + * Testcase 2: Verify the other objects were not deleted. + * Testcase 3: Destroy all objects and verify all were removed. + */ +CK_RV do_DestroyObjects(void) +{ + CK_FLAGS flags; + CK_SESSION_HANDLE session; + CK_RV rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_OBJECT_HANDLE keyobj[8]; + CK_OBJECT_HANDLE obj_list[10]; + CK_ULONG i, num_objs = 0, find_count, found = 0; + CK_MECHANISM mech; + + CK_BBOOL true = TRUE; + CK_KEY_TYPE aes_type = CKK_AES; + CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; + CK_CHAR aes_value[] = "This is a fake aes key."; + CK_CHAR test_id[5] = "abcde"; + CK_ULONG aesgen_keylen = 32; + + CK_ATTRIBUTE aes_tmpl[] = { + {CKA_CLASS, &key_class, sizeof(key_class)}, + {CKA_KEY_TYPE, &aes_type, sizeof(aes_type)}, + {CKA_ID, &test_id, sizeof(test_id)}, + {CKA_VALUE, &aes_value, sizeof(aes_value)} + }; + + CK_ATTRIBUTE aesgen_tmpl[] = { + {CKA_CLASS, &key_class, sizeof(key_class)}, + {CKA_KEY_TYPE, &aes_type, sizeof(aes_type)}, + {CKA_ID, &test_id, sizeof(test_id)}, + {CKA_VALUE_LEN, &aesgen_keylen, sizeof(aesgen_keylen)}, + {CKA_TOKEN, &true, sizeof(true)} + }; + + CK_ATTRIBUTE find_tmpl[] = { + {CKA_KEY_TYPE, &aes_type, sizeof(aes_type)}, + {CKA_ID, &test_id, sizeof(test_id)} + }; + + testcase_begin("starting..."); + testcase_rw_session(); + testcase_user_login(); + + /* Create a few session key objects */ + for (i = 0; i < 4; i++) { + rc = funcs->C_CreateObject(session, aes_tmpl, 4, &keyobj[num_objs]); + if (rc != CKR_OK) { + testcase_error("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + num_objs++; + } + + /* Generate a few token key objects */ + mech.mechanism = CKM_AES_KEY_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + for (i = 4; i < 8; i++) { + rc = funcs->C_GenerateKey(session, &mech, aesgen_tmpl, 5, + &keyobj[num_objs]); + if (rc != CKR_OK) { + testcase_error("C_GenerateObject() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + num_objs++; + } + + /* Now delete 2 session key objects */ + rc = funcs->C_DestroyObject(session, keyobj[7]); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + num_objs--; + + rc = funcs->C_DestroyObject(session, keyobj[6]); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + num_objs--; + + /* Now see if only 2 session key objects were destroyed */ + rc = funcs->C_FindObjectsInit(session, find_tmpl, 2); + if (rc != CKR_OK) { + testcase_error("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_FindObjects(session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_error("C_FindObjects() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_FindObjectsFinal(session); + if (rc != CKR_OK) { + testcase_error("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /* Testcase 1: step thru and see if objects were deleted. */ + if (find_count != 6) { + testcase_fail("Did not find 6 objects!"); + goto testcase_cleanup; + } + + for (i = 0; i < find_count; i++) { + if ((obj_list[i] == keyobj[6]) || (obj_list[i] == keyobj[7])) + found++; + } + + if (found) { + testcase_fail("Objects were not deleted."); + goto testcase_cleanup; + } + + testcase_pass("The 2 objects were successfully deleted."); + + /* Testcase 2: Now make sure the other objects are still there */ + + for (i = 0; i < find_count; i++) { + if ((obj_list[i] == keyobj[0]) || (obj_list[i] == keyobj[1]) || + (obj_list[i] == keyobj[2]) || (obj_list[i] == keyobj[3]) || + (obj_list[i] == keyobj[4]) || (obj_list[i] == keyobj[5])) + found++; + } + + if (found != 6) { + testcase_fail("Some Objects were not found!"); + goto testcase_cleanup; + } + + testcase_pass("The other objects are intact."); + + /* Testcase 3: Remove all the objects */ + find_count = 0; + + /* Now delete the rest of the objects */ + for (i = 0; i < num_objs; i++) + funcs->C_DestroyObject(session, keyobj[i]); + + /* Now see if all the objects were deleted. */ + rc = funcs->C_FindObjectsInit(session, find_tmpl, 2); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_FindObjects(session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_FindObjectsFinal(session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + if (find_count) { + testcase_fail("The remaining objects were not deleted."); + goto testcase_cleanup; + } + + testcase_pass("All objects were deleted."); + +testcase_cleanup: + if (num_objs) { + for (i = 0; i < num_objs; i++) + funcs->C_DestroyObject(session, keyobj[i]); + } + + testcase_user_logout(); + rc = funcs->C_CloseSession(session); + if (rc != CKR_OK) { + testcase_error("C_CloseSession rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +int main(int argc, char **argv) +{ + int rc; + CK_C_INITIALIZE_ARGS cinit_args; + CK_RV rv = 0; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: nostop: %d\n", no_stop); + + rc = do_GetFunctionList(); + if (!rc) { + testcase_error("do_getFunctionList(), rc=%s", p11_get_ckr(rc)); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + funcs->C_Initialize(&cinit_args); + + { + CK_SESSION_HANDLE hsess = 0; + + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + } + + testcase_setup(0); + rc = do_DestroyObjects(); + testcase_print_result(); + + funcs->C_Finalize(NULL); + + /* make sure we return non-zero if rv is non-zero */ + return ((rv == 0) || (rv % 256) ? (int)rv : -1); +} diff --git a/testcases/pkcs11/findobjects.c b/testcases/pkcs11/findobjects.c new file mode 100644 index 0000000..aaa284c --- /dev/null +++ b/testcases/pkcs11/findobjects.c @@ -0,0 +1,295 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2013-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 + */ + +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "common.c" + +/* API Routines exercised: + * C_FindObjectsInit + * C_FindObjects + * C_CreateObject + * + * 3 TestCases + * Setup: Create 2 3des objects and 2 aes private objects + * Testcase 1: Find only the 3des key objects. + * Testcase 2: Find only the aes session objects that were created. + * Testcase 3: Find all the objects. + */ +CK_RV do_FindObjects(void) +{ + CK_FLAGS flags; + CK_SESSION_HANDLE session; + CK_RV rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + CK_ULONG find_count; + CK_OBJECT_HANDLE keyobj[4]; + CK_OBJECT_HANDLE obj_list[10]; + + CK_ULONG not_found = 0; + CK_ULONG num_objs = 0; + CK_ULONG i; + + CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; + CK_KEY_TYPE aes_type = CKK_AES; + CK_KEY_TYPE des3_type = CKK_DES3; + CK_BBOOL false = FALSE; + CK_CHAR aes_value[] = "This is a fake aes key."; + CK_CHAR des3_value[] = "This is a fake des key."; + CK_CHAR test1_id[] = "My Testcase 1 keys."; + CK_CHAR test2_id[] = "My Testcase 2 keys."; + + CK_ATTRIBUTE des3_tmpl[] = { + {CKA_CLASS, &key_class, sizeof(key_class)}, + {CKA_KEY_TYPE, &des3_type, sizeof(des3_type)}, + {CKA_ID, &test1_id, sizeof(test1_id)}, + {CKA_VALUE, &des3_value, sizeof(des3_value)} + }; + + CK_ATTRIBUTE aes_tmpl[] = { + {CKA_CLASS, &key_class, sizeof(key_class)}, + {CKA_KEY_TYPE, &aes_type, sizeof(aes_type)}, + {CKA_PRIVATE, &false, sizeof(false)}, + {CKA_ID, &test2_id, sizeof(test2_id)}, + {CKA_VALUE, &aes_value, sizeof(aes_value)} + }; + + CK_ATTRIBUTE search_des3_tmpl[] = { + {CKA_KEY_TYPE, &des3_type, sizeof(des3_type)}, + {CKA_ID, &test1_id, sizeof(test1_id)} + }; + + CK_ATTRIBUTE search_tmpl[] = { + {CKA_KEY_TYPE, &aes_type, sizeof(aes_type)}, + {CKA_ID, &test2_id, sizeof(test2_id)}, + }; + + testcase_begin("starting..."); + testcase_rw_session(); + testcase_user_login(); + + /* Create 2 des3 session key objects */ + rc = funcs->C_CreateObject(session, des3_tmpl, 4, &keyobj[num_objs]); + if (rc != CKR_OK) { + testcase_error("C_CreateObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + num_objs++; + + rc = funcs->C_CreateObject(session, des3_tmpl, 4, &keyobj[num_objs]); + if (rc != CKR_OK) { + testcase_error("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + num_objs++; + + /* Create 2 aes private session key objects */ + rc = funcs->C_CreateObject(session, aes_tmpl, 5, &keyobj[num_objs]); + if (rc != CKR_OK) { + testcase_error("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + num_objs++; + + rc = funcs->C_CreateObject(session, aes_tmpl, 5, &keyobj[num_objs]); + if (rc != CKR_OK) { + testcase_error("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /* Testcase 1: Now find the the 2 des3 key objects */ + testcase_new_assertion(); + + rc = funcs->C_FindObjectsInit(session, search_des3_tmpl, 2); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_FindObjects(session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /* We should have gotten back 2 des3 key objects */ + if (find_count != 2) { + testcase_fail("Should have found 2 des3 key objects, found %d", + (int) find_count); + goto testcase_cleanup; + } + + /* Examine the 2 objects... */ + for (i = 0; i < find_count; i++) { + if ((obj_list[i] != keyobj[0]) && (obj_list[i] != keyobj[1])) + not_found++; + } + + rc = funcs->C_FindObjectsFinal(session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + if (not_found) { + testcase_fail("Wrong objects found!"); + goto testcase_cleanup; + } + + testcase_pass("Found the 2 des3 key objects."); + + /* Testcase 2: Now find 2 aes keys with aes_id. */ + /* Note in ICSF, all secret keys are marked private by default. */ + testcase_new_assertion(); + + not_found = 0; + find_count = 0; + + rc = funcs->C_FindObjectsInit(session, search_tmpl, 2); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_FindObjects(session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /* We should have gotten back 2 key objects */ + if (find_count != 2) { + testcase_fail("Should have found 2 key objects, found %d", + (int) find_count); + goto testcase_cleanup; + } + + /* Examine the 2 objects... */ + for (i = 0; i < find_count; i++) { + if ((obj_list[i] != keyobj[2]) && (obj_list[i] != keyobj[3])) + not_found++; + } + + rc = funcs->C_FindObjectsFinal(session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + if (not_found) { + testcase_fail("Wrong objects found!"); + goto testcase_cleanup; + } + + testcase_pass("Found the 2 non-private objects."); + + /* Testcase 3: Find all the objects */ + testcase_new_assertion(); + + not_found = 0; + find_count = 0; + + rc = funcs->C_FindObjectsInit(session, NULL, 0); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsInit() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_FindObjects(session, obj_list, 10, &find_count); + if (rc != CKR_OK) { + testcase_fail("C_FindObjects() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_FindObjectsFinal(session); + if (rc != CKR_OK) { + testcase_fail("C_FindObjectsFinal() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /* We should have gotten back 4 key objects + * testing for more than 4 just in case some other pkcs#11 app is + * running. + */ + if (find_count < 4) { + testcase_fail("Should have found at least 6 objects, found %d", + (int) find_count); + goto testcase_cleanup; + } + + testcase_pass("Found all the objects."); + +testcase_cleanup: +/* for (i=0; iC_DestroyObject(session, keyobj[i]); +*/ + + testcase_user_logout(); + rc = funcs->C_CloseSession(session); + if (rc != CKR_OK) { + testcase_error("C_CloseSession rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +int main(int argc, char **argv) +{ + int rc; + CK_C_INITIALIZE_ARGS cinit_args; + CK_RV rv = 0; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: nostop: %d\n", no_stop); + + rc = do_GetFunctionList(); + if (!rc) { + testcase_error("do_getFunctionList(), rc=%s", p11_get_ckr(rc)); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + funcs->C_Initialize(&cinit_args); + + { + CK_SESSION_HANDLE hsess = 0; + + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + } + + testcase_setup(0); + rc = do_FindObjects(); + testcase_print_result(); + + funcs->C_Finalize(NULL); + + /* make sure we return non-zero if rv is non-zero */ + return ((rv == 0) || (rv % 256) ? (int)rv : -1); +} diff --git a/testcases/pkcs11/gen_purpose.c b/testcases/pkcs11/gen_purpose.c new file mode 100644 index 0000000..1846a00 --- /dev/null +++ b/testcases/pkcs11/gen_purpose.c @@ -0,0 +1,760 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2015-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 + */ + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "common.c" + +CK_RV do_GetInfo(void) +{ + CK_FLAGS flags; + CK_SESSION_HANDLE session; + CK_RV rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_INFO info; + + // Do some setup and login to the token + testcase_begin("C_GetInfo function check"); + testcase_rw_session(); + testcase_user_login(); + + testcase_new_assertion(); + + rc = funcs->C_GetInfo(&info); + if (rc != CKR_OK) { + testcase_fail("C_GetInfo() rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + testcase_pass("Library info successfully sourced"); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseSession(session); + if (rc != CKR_OK) + testcase_error("C_CloseSession() failed."); + + return rc; +} + +CK_RV do_GetSlotList(void) +{ + CK_FLAGS flags; + CK_SESSION_HANDLE session; + CK_RV rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + CK_BBOOL tokenPresent; + CK_SLOT_ID_PTR pSlotList = NULL; + CK_ULONG ulCount = 0; + + tokenPresent = TRUE; + + testcase_begin("testing C_GetSlotList"); + testcase_rw_session(); + testcase_user_login(); + + testcase_new_assertion(); + + /* pkcs#11v2.20, Section 11.5 + * If pSlotList is NULL_PTR, then all that C_GetSlotList does is + * return (in *pulCount) the number of slots, without actually + * returning a list of slots. + */ + rc = funcs->C_GetSlotList(tokenPresent, NULL, &ulCount); + if (rc != CKR_OK) { + testcase_fail("C_GetSlotList rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + if (ulCount) + testcase_pass("C_GetSlotList received slot count."); + else + testcase_fail("C_GetSlotList did not receive slot count."); + + pSlotList = (CK_SLOT_ID *) malloc(ulCount * sizeof(CK_SLOT_ID)); + if (!pSlotList) { + testcase_error("malloc failed to allocate memory for list\n"); + rc = CKR_HOST_MEMORY; + goto testcase_cleanup; + } + + testcase_new_assertion(); + + /* Get the slots */ + rc = funcs->C_GetSlotList(tokenPresent, pSlotList, &ulCount); + if (rc != CKR_OK) { + testcase_fail("C_GetSlotList rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + testcase_pass("Slot list returned successfully"); + +testcase_cleanup: + if (pSlotList) + free(pSlotList); + + testcase_user_logout(); + rc = funcs->C_CloseSession(session); + if (rc != CKR_OK) + testcase_error("C_CloseSession failed."); + + return rc; +} + +CK_RV do_GetSlotInfo(void) +{ + CK_FLAGS flags; + CK_SESSION_HANDLE session; + CK_RV rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + CK_SLOT_ID slot_id = SLOT_ID; + CK_SLOT_INFO info; + + testcase_begin("testing C_GetSlotInfo"); + testcase_rw_session(); + testcase_user_login(); + + /* Test expected values */ + testcase_new_assertion(); + + rc = funcs->C_GetSlotInfo(slot_id, &info); + if (rc != CKR_OK) { + testcase_fail("C_GetSlotInfo() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + testcase_pass("Slot info of in-use slot received successfully"); + + /* Test for invalid slot */ + testcase_new_assertion(); + + rc = funcs->C_GetSlotInfo(9999, &info); + if (rc != CKR_SLOT_ID_INVALID) { + testcase_fail("C_GetSlotInfo returned %s instead of" + " CKR_SLOT_ID_INVALID.", p11_get_ckr(rc)); + rc = CKR_FUNCTION_FAILED; // dont confuse loop in main + goto testcase_cleanup; + } + + testcase_pass("C_GetSlotInfo correctly returned " "CKR_SLOT_ID_INVALID."); + rc = 0; // don't confuse loop in main + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseSession(session); + if (rc != CKR_OK) + testcase_error("C_CloseSessions failed."); + + return rc; +} + +CK_RV do_GetTokenInfo(void) +{ + CK_FLAGS flags; + CK_SESSION_HANDLE session; + CK_RV rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_SLOT_ID slot_id = SLOT_ID; + CK_TOKEN_INFO info; + + testcase_begin("testing C_GetTokenInfo()"); + testcase_rw_session(); + testcase_user_login(); + + testcase_new_assertion(); + + rc = funcs->C_GetTokenInfo(slot_id, &info); + if (rc != CKR_OK) { + testcase_fail("C_GetTokenInfo rc=%s", p11_get_ckr(rc)); + return rc; + } + + testcase_pass("C_GetTokenInfo returned successfully"); + + /* Test with an invalid slot id */ + testcase_new_assertion(); + + rc = funcs->C_GetTokenInfo(9999, &info); + if (rc != CKR_SLOT_ID_INVALID) { + testcase_fail("C_GetTokenInfo() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + testcase_pass("C_GetTokenInfo returned error when given invalid slot."); + +testcase_cleanup: + testcase_user_logout(); + rc = funcs->C_CloseSession(session); + if (rc != CKR_OK) + testcase_error("C_CloseSessions failed."); + + return rc; +} + +CK_RV do_GetMechanismList(void) +{ + CK_FLAGS flags = 0; + CK_SESSION_HANDLE session = 0; + CK_RV rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN] = {0}; + CK_ULONG user_pin_len = 0; + CK_SLOT_ID slot_id = SLOT_ID; + CK_ULONG count = 0; + CK_MECHANISM_TYPE *mech_list = NULL; + + testcase_begin("testing C_GetMechanismList"); + testcase_rw_session(); + testcase_user_login(); + + /* pkcs11v2.20, page 111 + * If pMechanismList is NULL_PTR, then all that C_GetMechanismList + * does is return (in *pulCount) the number of mechanisms, without + * actually returning a list of mechanisms. The contents of + * *pulCount on entry to C_GetMechanismList has no meaning in this + * case, and the call returns the value CKR_OK. + */ + testcase_new_assertion(); + + rc = funcs->C_GetMechanismList(slot_id, NULL, &count); + if (rc != CKR_OK) { + testcase_fail("C_GetMechanismList 1 rc=%s", p11_get_ckr(rc)); + return rc; + } + + if (count) + testcase_pass("C_GetMechanismList returned mechanism count."); + else + testcase_fail("C_GetMechanismList did not not return " + "mechanism count."); + + mech_list = (CK_MECHANISM_TYPE *) calloc(1, count * sizeof(CK_MECHANISM_TYPE)); + if (!mech_list) { + testcase_fail(); + rc = CKR_HOST_MEMORY; + goto testcase_cleanup; + } + + testcase_new_assertion(); + rc = funcs->C_GetMechanismList(slot_id, mech_list, &count); + if (rc != CKR_OK) { + testcase_fail("C_GetMechanismList 2 rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + testcase_pass("Mechanism listing from current slot"); + + /* Test for invalid slot */ + testcase_new_assertion(); + + rc = funcs->C_GetMechanismList(9999, NULL, &count); + if (rc != CKR_SLOT_ID_INVALID) { + testcase_fail("C_GetMechanismList() returned %s instead of" + " CKR_SLOT_ID_INVALID.", p11_get_ckr(rc)); + rc = CKR_FUNCTION_FAILED; + goto testcase_cleanup; + } + + testcase_pass("C_GetMechanismList correctly returned " + "CKR_SLOT_ID_INVALID."); + rc = CKR_OK; + +testcase_cleanup: + if (mech_list) + free(mech_list); + + testcase_user_logout(); + rc = funcs->C_CloseSession(session); + if (rc != CKR_OK) + testcase_error("C_CloseSessions failed."); + + return rc; +} + +CK_RV do_GetMechanismInfo(void) +{ + CK_FLAGS flags = 0; + CK_SESSION_HANDLE session = 0; + CK_RV rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN] = {0}; + CK_ULONG user_pin_len = 0; + CK_SLOT_ID slot_id = SLOT_ID; + CK_MECHANISM_INFO info; + CK_ULONG i = 0, count = 0; + CK_MECHANISM_TYPE *mech_list = NULL; + + memset(&info, 0, sizeof(info)); + + testcase_begin("testing C_GetMechanismInfo"); + testcase_rw_session(); + testcase_user_login(); + + testcase_new_assertion(); + + rc = funcs->C_GetMechanismList(slot_id, NULL, &count); + if (rc != CKR_OK) { + testcase_error("C_GetMechanismList #1 rc=%s", p11_get_ckr(rc)); + return rc; + } + + mech_list = (CK_MECHANISM_TYPE *) calloc(1, count * sizeof(CK_MECHANISM_TYPE)); + if (!mech_list) { + rc = CKR_HOST_MEMORY; + goto testcase_cleanup; + } + + rc = funcs->C_GetMechanismList(slot_id, mech_list, &count); + if (rc != CKR_OK) { + testcase_error("C_GetMechanismList #2 rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + for (i = 0; i < count; i++) { + rc = funcs->C_GetMechanismInfo(slot_id, mech_list[i], &info); + if (rc != CKR_OK) + break; + } + + if (rc != CKR_OK) + testcase_fail("C_GetMechanismInfo rc=%s", p11_get_ckr(rc)); + else + testcase_pass("C_GetMechanismInfo was successful."); + + testcase_new_assertion(); + + rc = funcs->C_GetMechanismInfo(slot_id, 0x12345678, &info); + + if (rc != CKR_MECHANISM_INVALID) + testcase_fail("C_GetMechanismInfo returned rc=%s instead " + "of CKR_MECHANISM_INVALID", p11_get_ckr(rc)); + else + testcase_pass("C_GetMechanismInfo correctly returned CKR_MECHANISM_INVALID."); + +testcase_cleanup: + if (mech_list) + free(mech_list); + + testcase_user_logout(); + rc = funcs->C_CloseSession(session); + if (rc != CKR_OK) + testcase_error("C_CloseSessions rc=%s", p11_get_ckr(rc)); + + return rc; +} + +CK_RV do_InitToken(void) +{ + CK_BYTE label[32] = {0}; + int len = 0; + CK_CHAR so_pin[PKCS11_MAX_PIN_LEN] = {0}; + CK_RV rc = 0; + + testcase_begin("testing C_InitToken"); + + memcpy(label, "L13 ", 32); + for (len = 0; len < 31; len++) { + if (label[len] == '\0') { + label[len] = ' '; + break; + } + } + + testcase_new_assertion(); + /* test with invalid SO PIN */ + rc = funcs->C_InitToken(SLOT_ID, NULL, strlen((char *) so_pin), label); + if (rc != CKR_ARGUMENTS_BAD) { + testcase_fail("C_InitToken returned %s instead of " + "CKR_ARGUMENTS_BAD", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + testcase_pass("C_InitToken correctly return CKR_ARGUMENS_BAD."); + + /* test with invalid slot id */ + testcase_new_assertion(); + rc = funcs->C_InitToken(9999, so_pin, strlen((char *) so_pin), label); + if (rc != CKR_SLOT_ID_INVALID) { + testcase_fail("C_InitToken returned %s instead of " + "CKR_SLOT_ID_INVALID.", p11_get_ckr(rc)); + rc = CKR_FUNCTION_FAILED; + } else { + testcase_pass("C_InitToken correctly returned CKR_SLOT_ID_INVALID."); + rc = CKR_OK; + } + +testcase_cleanup: + return rc; +} + +CK_RV do_InitPIN(void) +{ + CK_SLOT_ID slot_id; + CK_FLAGS flags; + CK_SESSION_HANDLE session; + CK_CHAR so_pin[PKCS11_MAX_PIN_LEN]; + CK_CHAR user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG so_pin_len; + CK_ULONG user_pin_len; + CK_RV rc; + + testcase_begin("Testing C_InitPIN"); + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + if (get_so_pin(so_pin)) + return CKR_FUNCTION_FAILED; + + so_pin_len = (CK_ULONG) strlen((char *) so_pin); + + slot_id = SLOT_ID; + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + + // try to call C_InitPIN from a public session + testcase_new_assertion(); + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session); + if (rc != CKR_OK) { + testcase_error("C_OpenSession rc=%s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_InitPIN(session, user_pin, user_pin_len); + if (rc != CKR_USER_NOT_LOGGED_IN) { + testcase_fail("C_InitPIN returned %s instead of " + "CKR_USER_NOT_LOGGED_IN", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + testcase_pass("C_InitPin correctly returned CKR_USER_NOT_LOGGED_IN."); + + // try to call C_InitPIN from an SO session + testcase_new_assertion(); + rc = funcs->C_Login(session, CKU_SO, so_pin, so_pin_len); + if (rc != CKR_OK) { + testcase_error("C_Login #1 failed: rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_InitPIN(session, user_pin, user_pin_len); + if (rc != CKR_OK) + testcase_fail("C_InitPIN failed: rc=%s", p11_get_ckr(rc)); + else + testcase_pass("C_InitPIN #1 was successful."); + + rc = funcs->C_Logout(session); + if (rc != CKR_OK) { + testcase_error("C_Logout #1 failed."); + goto testcase_cleanup; + } + // try to call C_InitPIN from a normal user session + testcase_new_assertion(); + rc = funcs->C_Login(session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + testcase_error("C_Login failed: rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + rc = funcs->C_InitPIN(session, user_pin, user_pin_len); + if (rc != CKR_USER_NOT_LOGGED_IN) { + testcase_fail("C_InitPIN returned %s instead of " + "CKR_USER_NOT_LOGGED_IN.", p11_get_ckr(rc)); + rc = CKR_FUNCTION_FAILED; + } else { + testcase_pass("C_InitPIN #2 was successful."); + rc = CKR_OK; + } + + rc = funcs->C_Logout(session); + if (rc != CKR_OK) + testcase_error("C_Logout #2 rc=%s", p11_get_ckr(rc)); + +testcase_cleanup: + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) + testcase_error("C_CloseAllSessions #1 rc=%s", p11_get_ckr(rc)); + + return rc; +} + +CK_RV do_SetPIN(void) +{ + CK_SLOT_ID slot_id; + CK_FLAGS flags; + CK_SESSION_HANDLE session; + CK_CHAR old_pin[PKCS11_MAX_PIN_LEN]; + CK_CHAR new_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG old_len; + CK_ULONG new_len; + CK_RV rc; + + testcase_begin("Testing C_SetPIN"); + + // first, try to get the user PIN + if (get_user_pin(old_pin)) + return CKR_FUNCTION_FAILED; + + old_len = (CK_ULONG) strlen((char *) old_pin); + + memcpy(new_pin, "ABCDEF", 6); + new_len = 6; + + slot_id = SLOT_ID; + + /* try to call C_SetPIN from a R/O public session, it should fail. + */ + flags = CKF_SERIAL_SESSION; + testcase_new_assertion(); + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session); + if (rc != CKR_OK) { + testcase_error("C_OpenSession #1 rc=%s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_SetPIN(session, old_pin, old_len, new_pin, new_len); + if (rc != CKR_SESSION_READ_ONLY) { + testcase_fail("C_SetPIN #1 returned %s instead of " + "CKR_SESSION_READ_ONLY.", p11_get_ckr(rc)); + rc = CKR_FUNCTION_FAILED; + goto testcase_cleanup; + } + + testcase_pass("C_SetPIN successful in pubic session."); + + rc = funcs->C_CloseSession(session); + if (rc != CKR_OK) { + testcase_error("C_CloseSession #1 failed."); + goto testcase_cleanup; + } + + /* try to call C_SetPIN from a R/W public session, it should work. + */ + testcase_new_assertion(); + + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session); + if (rc != CKR_OK) { + testcase_error("C_OpenSession #1 rc=%s", p11_get_ckr(rc)); + return rc; + } + + rc = funcs->C_SetPIN(session, old_pin, old_len, new_pin, new_len); + if (rc != CKR_OK) { + testcase_fail("C_SetPIN failed: rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + testcase_pass("C_SetPIN successful in r/w pubic session."); + + rc = funcs->C_CloseSession(session); + if (rc != CKR_OK) { + testcase_error("C_CloseSession #1 failed."); + goto testcase_cleanup; + } + + /* open a new session and try logging in with new pin */ + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session); + if (rc != CKR_OK) { + testcase_error("C_OpenSession #1 rc=%s", p11_get_ckr(rc)); + return rc; + } + + testcase_new_assertion(); + + rc = funcs->C_Login(session, CKU_USER, new_pin, new_len); + if (rc != CKR_OK) { + testcase_fail("C_Login #1 failed: rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + testcase_pass("Successfully logged in with new pin."); + + /* try to call C_SetPIN from a normal user session, r/w user. + * set back to original user pin. this should work. + */ + testcase_new_assertion(); + + rc = funcs->C_SetPIN(session, new_pin, new_len, old_pin, old_len); + if (rc != CKR_OK) { + testcase_fail("C_SetPIN #2 rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + testcase_pass("C_SetPIN successful."); + + rc = funcs->C_Logout(session); + if (rc != CKR_OK) { + testcase_error("C_Logout #1 falied: rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /* + * done with user tests...now try with the SO + */ + + if (get_so_pin(old_pin)) + return CKR_FUNCTION_FAILED; + + /* try to call C_SetPIN from a normal user session */ + testcase_new_assertion(); + + 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)); + goto testcase_cleanup; + } + + rc = funcs->C_SetPIN(session, old_pin, old_len, new_pin, new_len); + if (rc != CKR_OK) { + testcase_fail("C_SetPIN #4 failed: rc=%s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + testcase_pass("C_SetPIN successfully set SO PIN."); + + rc = funcs->C_Logout(session); + if (rc != CKR_OK) { + testcase_error("C_Logout #3 failed."); + goto testcase_cleanup; + } + + /* now login with new pin. should work. */ + testcase_new_assertion(); + + rc = funcs->C_Login(session, CKU_SO, new_pin, new_len); + if (rc != CKR_OK) + testcase_fail("C_Login #5 failed: rc=%s", p11_get_ckr(rc)); + else + testcase_pass("C_Login #5 was successful."); + + /* change the PIN back to the original so the rest of this program + * doesn't break + */ + rc = funcs->C_SetPIN(session, new_pin, new_len, old_pin, old_len); + if (rc != CKR_OK) + testcase_error("C_SetPIN #5 failed to set back to the original " + "SO PIN, rc=%s", p11_get_ckr(rc)); + + rc = funcs->C_Logout(session); + if (rc != CKR_OK) + testcase_error("C_Logout #4 failed."); + +testcase_cleanup: + rc = funcs->C_CloseSession(session); + if (rc != CKR_OK) + testcase_error("C_CloseSession #1 failed."); + + return rc; +} + + +CK_RV api_driver(void) +{ + CK_RV rc; + + rc = do_GetInfo(); + if (rc && !no_stop) + return rc; + + rc = do_GetSlotList(); + if (rc && !no_stop) + return rc; + + rc = do_GetSlotInfo(); + if (rc && !no_stop) + return rc; + + rc = do_GetTokenInfo(); + if (rc && !no_stop) + return rc; + + rc = do_GetMechanismList(); + if (rc && !no_stop) + return rc; + + rc = do_GetMechanismInfo(); + if (rc && !no_stop) + return rc; + + /* do not run on icsf token */ + if (!is_icsf_token(SLOT_ID)) { + rc = do_InitToken(); + if (rc && !no_stop) + return rc; + } + + rc = do_InitPIN(); + if (rc && !no_stop) + return rc; + + rc = do_SetPIN(); + if (rc && !no_stop) + return rc; + + return rc; +} + +int main(int argc, char **argv) +{ + int rc; + CK_C_INITIALIZE_ARGS cinit_args; + CK_RV rv = 0; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: nostop: %d\n", no_stop); + + rc = do_GetFunctionList(); + if (!rc) { + testcase_error("do_getFunctionList(), rc=%s", p11_get_ckr(rc)); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + funcs->C_Initialize(&cinit_args); + + { + CK_SESSION_HANDLE hsess = 0; + + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + } + + testcase_setup(0); + rv = api_driver(); + testcase_print_result(); + + funcs->C_Finalize(NULL_PTR); + + /* make sure we return non-zero if rv is non-zero */ + return ((rv == 0) || (rv % 256) ? (int)rv : -1); +} diff --git a/testcases/pkcs11/generate_keypair.c b/testcases/pkcs11/generate_keypair.c new file mode 100644 index 0000000..4b47127 --- /dev/null +++ b/testcases/pkcs11/generate_keypair.c @@ -0,0 +1,254 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2015-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 + */ + +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "common.c" + +/* API Routines exercised: + * C_GenerateKeyPair + */ +CK_RV do_GenerateKeyPairRSA(void) +{ + CK_FLAGS flags; + CK_SESSION_HANDLE session; + CK_RV rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + CK_OBJECT_HANDLE priv_key = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE publ_key = CK_INVALID_HANDLE; + CK_MECHANISM mech; + + CK_KEY_TYPE keytype = CKK_RSA; + CK_ULONG modbits = 2048; + unsigned int modbytes = modbits / 8; + CK_BYTE pubExp[3] = { 0x01, 0x00, 0x01 }; + CK_ATTRIBUTE publ_tmpl[] = { + {CKA_KEY_TYPE, &keytype, sizeof(keytype)}, + {CKA_MODULUS_BITS, &modbits, sizeof(modbits)}, + {CKA_PUBLIC_EXPONENT, pubExp, sizeof(pubExp)} + }; + + CK_OBJECT_CLASS class; + CK_BYTE publicExponent[4]; + CK_BYTE modulus[512]; + CK_BYTE subject[20], id[20];; + CK_BYTE start_date[20], end_date[20]; + CK_BBOOL encrypt, decrypt, sign, sign_recover, verify, verify_recover; + CK_BBOOL wrap, unwrap, derive, local, extractable, never; + CK_BBOOL sensitive, always; + + CK_ATTRIBUTE publ_def[] = { + {CKA_KEY_TYPE, &keytype, sizeof(keytype)}, + {CKA_CLASS, &class, sizeof(class)}, + {CKA_PUBLIC_EXPONENT, publicExponent, sizeof(publicExponent)}, + {CKA_MODULUS, modulus, sizeof(modulus)}, + {CKA_SUBJECT, subject, sizeof(subject)}, + {CKA_ENCRYPT, &encrypt, sizeof(encrypt)}, + {CKA_VERIFY, &verify, sizeof(verify)}, + {CKA_VERIFY_RECOVER, &verify_recover, sizeof(verify_recover)}, + {CKA_WRAP, &wrap, sizeof(wrap)}, + {CKA_ID, &id, sizeof(id)}, + {CKA_START_DATE, &start_date, sizeof(start_date)}, + {CKA_END_DATE, &end_date, sizeof(end_date)}, + {CKA_DERIVE, &derive, sizeof(derive)}, + {CKA_LOCAL, &local, sizeof(local)} + }; + + /* According to pkcs#11v2.20, Section 12.1.4, the implementation + * MAY contribute some of the CRT attributes. So, dont look for these. + * Only check for the common defaults for the private key. + */ + CK_ATTRIBUTE priv_def[] = { + {CKA_KEY_TYPE, &keytype, sizeof(keytype)}, + {CKA_CLASS, &class, sizeof(class)}, + {CKA_SUBJECT, subject, sizeof(subject)}, + {CKA_SENSITIVE, &sensitive, sizeof(sensitive)}, + {CKA_DECRYPT, &decrypt, sizeof(decrypt)}, + {CKA_SIGN, &sign, sizeof(sign)}, + {CKA_SIGN_RECOVER, &sign_recover, sizeof(sign_recover)}, + {CKA_UNWRAP, &unwrap, sizeof(unwrap)}, + {CKA_EXTRACTABLE, &extractable, sizeof(extractable)}, + {CKA_ALWAYS_SENSITIVE, &always, sizeof(always)}, + {CKA_NEVER_EXTRACTABLE, &never, sizeof(never)}, + {CKA_ID, &id, sizeof(id)}, + {CKA_START_DATE, start_date, sizeof(start_date)}, + {CKA_END_DATE, end_date, sizeof(end_date)}, + {CKA_DERIVE, &derive, sizeof(derive)}, + {CKA_LOCAL, &local, sizeof(local)} + }; + + /* Do some setup and login to the token */ + testcase_begin("starting..."); + testcase_rw_session(); + testcase_user_login(); + + mech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + /* Assertion #1: generate an RSA key pair. */ + testcase_new_assertion(); + + rc = funcs->C_GenerateKeyPair(session, &mech, publ_tmpl, 3, NULL, + 0, &publ_key, &priv_key); + if (rc != CKR_OK) { + testcase_fail("C_GenerateKeyPair() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + testcase_pass("C_GenerateKeypair was successful\n"); + + /* Assertion #2: Ensure public key contains the default attributes + * and those the implementation should have contributed for RSA PKCS#1 + * key pairs. (Section 12.1.4 of pkcs#11v2.20) + */ + testcase_new_assertion(); + + rc = funcs->C_GetAttributeValue(session, publ_key, publ_def, 14); + if (rc == CKR_ATTRIBUTE_TYPE_INVALID) { + testcase_fail("Some of the default attributes were missing.\n"); + goto testcase_cleanup; + } + if (rc != CKR_OK) { + testcase_error("C_GetAttributeValue: rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + if (*(CK_ULONG *) publ_def[0].pValue != CKK_RSA) { + testcase_fail("Public RSA key was not generated correctly" + " (wrong CKA_KEY_TYPE).\n"); + } + if (*(CK_ULONG *) publ_def[1].pValue != CKO_PUBLIC_KEY) { + testcase_fail("Public RSA key was not generated correctly" + " (wrong CKA_CLASS).\n"); + } + if (publ_def[2].ulValueLen != sizeof(pubExp)) { + /* some tokens add an leading 0x00 to the exponent value */ + unsigned char *pv = (unsigned char *) publ_def[2].pValue; + if (publ_def[2].ulValueLen == sizeof(pubExp) + 1 + && pv[0] == 0x00 && memcmp(pv + 1, pubExp, sizeof(pubExp)) == 0) { + /* len is just +1, first byte is 0, rest matches to pubExp */ + } else { + testcase_fail("Public RSA key was not generated correctly" + " (pub exp mismatch).\n"); + } + } else { + /* same length, check value */ + if (memcmp(publ_def[2].pValue, pubExp, sizeof(pubExp)) != 0) { + testcase_fail("Public RSA key was not generated correctly" + " (pub exp mismatch).\n"); + } + } + if (publ_def[3].ulValueLen != modbytes) { + /* some tokens add an leading 0x00 to the modulus value */ + unsigned char *pv = (unsigned char *) publ_def[3].pValue; + if (publ_def[3].ulValueLen == modbytes + 1 && pv[0] == 0x00) { + /* len is just +1, first byte is 0, all fine */ + } else { + testcase_fail("Public RSA key was not generated correctly" + " (modulus length mismatch).\n"); + } + } + testcase_pass("Public RSA key generated correctly.\n"); + + testcase_new_assertion(); + + rc = funcs->C_GetAttributeValue(session, priv_key, priv_def, 16); + if (rc != CKR_OK) { + testcase_error("C_GetAttributeValue: rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + if (rc == CKR_ATTRIBUTE_TYPE_INVALID) { + testcase_fail("Some of the default attributes were missing.\n"); + goto testcase_cleanup; + } + if (rc != CKR_OK) { + testcase_error("C_GetAttributeValue: rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /* Assertion #3: Ensure private key contains the default attributes + * and those the implementation should have contributed for RSA PKCS#1 + * key pairs. (Section 12.1.4 of pkcs#11v2.20) + */ + if (*(CK_ULONG *) priv_def[0].pValue != CKK_RSA) { + testcase_fail("Private RSA key was not generated correctly" + " (wrong CKA_KEY_TYPE).\n"); + } + if (*(CK_ULONG *) priv_def[1].pValue != CKO_PRIVATE_KEY) { + testcase_fail("Private RSA key was not generated correctly" + " (wrong CKA_CLASS).\n"); + } + testcase_pass("Private RSA key generated correctly.\n"); + +testcase_cleanup: + funcs->C_DestroyObject(session, priv_key); + funcs->C_DestroyObject(session, publ_key); + + testcase_user_logout(); + rc = funcs->C_CloseSession(session); + if (rc != CKR_OK) { + testcase_error("C_CloseSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +int main(int argc, char **argv) +{ + int rc; + CK_C_INITIALIZE_ARGS cinit_args; + CK_RV rv = 0; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: nostop: %d\n", no_stop); + + rc = do_GetFunctionList(); + if (!rc) { + testcase_error("do_getFunctionList(), rc=%s", p11_get_ckr(rc)); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + funcs->C_Initialize(&cinit_args); + + { + CK_SESSION_HANDLE hsess = 0; + + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + } + + testcase_setup(0); + rc = do_GenerateKeyPairRSA(); + testcase_print_result(); + + /* make sure we return non-zero if rv is non-zero */ + return ((rv == 0) || (rv % 256) ? (int)rv : -1); +} diff --git a/testcases/pkcs11/getobjectsize.c b/testcases/pkcs11/getobjectsize.c new file mode 100644 index 0000000..49cfa8c --- /dev/null +++ b/testcases/pkcs11/getobjectsize.c @@ -0,0 +1,147 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2016-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 + */ + +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "common.c" + + +/* API Routines exercised: + * C_CreateObject + * C_GetObjectSize + * C_DestroyObject + * + * 2 TestCases + * Setup: Create a key object. + * Get the object size + * Destroy the object + * Get the object size + */ +CK_RV do_GetObjectSize(void) +{ + CK_FLAGS flags; + CK_SESSION_HANDLE session; + CK_RV rc = 0; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + CK_OBJECT_HANDLE keyobj = CK_INVALID_HANDLE; + + CK_BBOOL false = FALSE; + CK_KEY_TYPE aes_type = CKK_AES; + CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; + CK_CHAR aes_value[] = "This is a fake aes key."; + CK_ATTRIBUTE aes_tmpl[] = { + {CKA_CLASS, &key_class, sizeof(key_class)}, + {CKA_KEY_TYPE, &aes_type, sizeof(aes_type)}, + {CKA_VALUE, &aes_value, sizeof(aes_value)}, + {CKA_SENSITIVE, &false, sizeof(false)} + }; + + CK_ULONG obj_size = 0; + + // Do some setup and login to the token + testcase_begin("starting..."); + testcase_rw_session(); + testcase_user_login(); + + // Create an AES Key Object. + rc = funcs->C_CreateObject(session, aes_tmpl, 4, &keyobj); + if (rc != CKR_OK) { + testcase_error("C_CreateObject() rc = %s", p11_get_ckr(rc)); + goto testcase_cleanup; + } + + /* now, get the size of the object */ + rc = funcs->C_GetObjectSize(session, keyobj, &obj_size); + if (rc != CKR_OK) { + testcase_fail("C_GetObjectSize() rc = %s", p11_get_ckr(rc)); + return rc; + } + + printf("\nSize of object = %lu\n", obj_size); + + /** Destroy the object */ + rc = funcs->C_DestroyObject(session, keyobj); + if (rc != CKR_OK) { + testcase_fail("C_DestroyObject() rc = %s", p11_get_ckr(rc)); + return rc; + } + + /* now, get the size of a non-existent object */ + rc = funcs->C_GetObjectSize(session, keyobj, &obj_size); + if (rc != CKR_OBJECT_HANDLE_INVALID) { + testcase_fail("C_GetObjectSize () rc = %s (expected " + "CKR_OBJECT_HANDLE_INVALID)", p11_get_ckr(rc)); + return rc; + } + + printf("C_GetObjectSize test passed\n"); + +testcase_cleanup: + funcs->C_DestroyObject(session, keyobj); + + testcase_user_logout(); + rc = funcs->C_CloseSession(session); + if (rc != CKR_OK) { + testcase_error("C_CloseSessions rc=%s", p11_get_ckr(rc)); + } + + return rc; +} + +int main(int argc, char **argv) +{ + int rc; + CK_C_INITIALIZE_ARGS cinit_args; + CK_RV rv = 0; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + + rc = do_GetFunctionList(); + if (!rc) { + testcase_error("do_getFunctionList(), rc=%s", p11_get_ckr(rc)); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + funcs->C_Initialize(&cinit_args); + + { + CK_SESSION_HANDLE hsess = 0; + + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + } + + rc = do_GetObjectSize(); + + funcs->C_Finalize(NULL); + + /* make sure we return non-zero if rv is non-zero */ + return ((rv == 0) || (rv % 256) ? (int)rv : -1); +} diff --git a/testcases/pkcs11/hw_fn.c b/testcases/pkcs11/hw_fn.c new file mode 100644 index 0000000..b6a79c9 --- /dev/null +++ b/testcases/pkcs11/hw_fn.c @@ -0,0 +1,359 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2003-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 + */ + +/* + * openCryptoki testcase + * + * Mar 14, 2003 + * Kent Yoder + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" + +#define AES_KEY_SIZE_128 16 + +int do_GetFunctionList(void); +int clean_up(void); + +CK_SLOT_ID slot_id; +CK_SESSION_HANDLE sess; + +/* + * do_HW_Feature_Seatch Test: + * + * 1. Create 5 objects, 3 of which are HW_FEATURE objects (2 of them are + * monotonic counters). + * 2. Search for objects using a template that does not have its + * HW_FEATURE attribute set. + * 3. Result should be that the other 2 objects are returned, and + * not the HW_FEATURE objects. + * 4. Search for objects using a template that does have its + * HW_FEATURE attribute set. + * 5. Result should be that the only hardware feature objects that are not + * monotonic counters should be returned. + * + */ +int do_HW_Feature_Search(void) +{ + unsigned int i = 0; + CK_RV rc = 0; + CK_ULONG find_count = 0; + + CK_BBOOL false = FALSE; + CK_BBOOL true = TRUE; + + // A counter object + CK_OBJECT_CLASS counter1_class = CKO_HW_FEATURE; + CK_HW_FEATURE_TYPE feature1_type = CKH_MONOTONIC_COUNTER; + CK_UTF8CHAR counter1_label[] = "Monotonic counter"; + CK_CHAR counter1_value[16] = {0}; + CK_ATTRIBUTE counter1_template[] = { + {CKA_CLASS, &counter1_class, sizeof(counter1_class)}, + {CKA_HW_FEATURE_TYPE, &feature1_type, sizeof(feature1_type)}, + {CKA_LABEL, counter1_label, sizeof(counter1_label) - 1}, + {CKA_VALUE, counter1_value, sizeof(counter1_value)}, + {CKA_RESET_ON_INIT, &true, sizeof(true)}, + {CKA_HAS_RESET, &false, sizeof(false)} + }; + + // Another counter object + CK_OBJECT_CLASS counter2_class = CKO_HW_FEATURE; + CK_HW_FEATURE_TYPE feature2_type = CKH_MONOTONIC_COUNTER; + CK_UTF8CHAR counter2_label[] = "Monotonic counter"; + CK_CHAR counter2_value[16] = {0}; + CK_ATTRIBUTE counter2_template[] = { + {CKA_CLASS, &counter2_class, sizeof(counter2_class)}, + {CKA_HW_FEATURE_TYPE, &feature2_type, sizeof(feature2_type)}, + {CKA_LABEL, counter2_label, sizeof(counter2_label) - 1}, + {CKA_VALUE, counter2_value, sizeof(counter2_value)}, + {CKA_RESET_ON_INIT, &true, sizeof(true)}, + {CKA_HAS_RESET, &false, sizeof(false)} + }; + + // A clock object + CK_OBJECT_CLASS clock_class = CKO_HW_FEATURE; + CK_HW_FEATURE_TYPE clock_type = CKH_CLOCK; + CK_UTF8CHAR clock_label[] = "Clock"; + CK_CHAR clock_value[16] = {0}; + CK_ATTRIBUTE clock_template[] = { + {CKA_CLASS, &clock_class, sizeof(clock_class)}, + {CKA_HW_FEATURE_TYPE, &clock_type, sizeof(clock_type)}, + {CKA_LABEL, clock_label, sizeof(clock_label) - 1}, + {CKA_VALUE, clock_value, sizeof(clock_value)} + }; + + // A data object + CK_OBJECT_CLASS obj1_class = CKO_DATA; + CK_UTF8CHAR obj1_label[] = "Object 1"; + CK_BYTE obj1_data[] = "Object 1's data"; + CK_ATTRIBUTE obj1_template[] = { + {CKA_CLASS, &obj1_class, sizeof(obj1_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_LABEL, obj1_label, sizeof(obj1_label) - 1}, + {CKA_VALUE, obj1_data, sizeof(obj1_data)} + }; + + // A secret key object + CK_OBJECT_CLASS obj2_class = CKO_SECRET_KEY; + CK_KEY_TYPE obj2_type = CKK_AES; + CK_UTF8CHAR obj2_label[] = "Object 2"; + CK_BYTE obj2_data[AES_KEY_SIZE_128] = {0}; + CK_ATTRIBUTE obj2_template[] = { + {CKA_CLASS, &obj2_class, sizeof(obj2_class)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_KEY_TYPE, &obj2_type, sizeof(obj2_type)}, + {CKA_LABEL, obj2_label, sizeof(obj2_label) - 1}, + {CKA_VALUE, obj2_data, sizeof(obj2_data)} + }; + + CK_OBJECT_HANDLE h_counter1 = 0, + h_counter2 = 0, h_clock = 0, h_obj1 = 0, h_obj2 = 0, + obj_list[10] = {0}; + + CK_ATTRIBUTE find_tmpl[] = { + {CKA_CLASS, &counter1_class, sizeof(counter1_class)} + }; + + /* 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); + return rc; + } + + rc = funcs->C_CreateObject(sess, obj2_template, 5, &h_obj2); + if (rc != CKR_OK) { + show_error("C_CreateObject #2", 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); + 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); + goto destroy_3; + } + + rc = funcs->C_CreateObject(sess, clock_template, 4, &h_clock); + if (rc != CKR_OK) { + show_error("C_CreateObject #5", rc); + goto destroy_4; + } + + + /* Search for the 2 objects w/o HW_FEATURE set + * A NULL template here should return all objects in v2.01, but + * in v2.11, it should return all objects *except* HW_FEATURE + * objects. + */ + rc = funcs->C_FindObjectsInit(sess, NULL, 0); + if (rc != CKR_OK) { + show_error(" C_FindObjectsInit #1", rc); + goto done; + } + + rc = funcs->C_FindObjects(sess, obj_list, 10, &find_count); + if (rc != CKR_OK) { + show_error(" C_FindObjects #1", rc); + goto done; + } + + /* So, we created 5 objects before here, and then searched with a NULL + * template, so that should return all objects except our hardware + * feature object. + */ + if (find_count != 2) { + printf("%s:%d ERROR: C_FindObjects #1 should have found 2 objects!\n" + " It found %ld objects\n", __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", + __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", + __FILE__, __LINE__); + rc = -1; + goto done; + } + + rc = funcs->C_FindObjectsFinal(sess); + if (rc != CKR_OK) { + show_error(" C_FindObjectsFinal #1", rc); + goto done; + } + + + /* Now find the hardware feature objects (should find only 1 since monotonic + * counters are read-only + */ + rc = funcs->C_FindObjectsInit(sess, find_tmpl, 1); + if (rc != CKR_OK) { + show_error(" C_FindObjectsInit #2", rc); + goto done; + } + + rc = funcs->C_FindObjects(sess, obj_list, 10, &find_count); + if (rc != CKR_OK) { + show_error(" C_FindObjects #2", rc); + goto done; + } + + if (find_count != 1) { + printf("%s:%d ERROR: C_FindObjects #2 should have found 1 object!\n" + " It found %ld objects\n", __FILE__, __LINE__, + find_count); + funcs->C_FindObjectsFinal(sess); + rc = -1; + goto done; + } + + /* Make sure we got the right ones */ + for (i = 0; i < find_count; i++) { + 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" + " objects!", __FILE__, __LINE__); + rc = -1; + } + } + + rc = funcs->C_FindObjectsFinal(sess); + if (rc != CKR_OK) { + show_error(" C_FindObjectsFinal #2", rc); + } + +done: + /* Destroy the created objects, don't clobber the rc */ + funcs->C_DestroyObject(sess, h_clock); +destroy_4: + funcs->C_DestroyObject(sess, h_counter2); +destroy_3: + funcs->C_DestroyObject(sess, h_counter1); +destroy_2: + funcs->C_DestroyObject(sess, h_obj2); +destroy_1: + funcs->C_DestroyObject(sess, h_obj1); + + return rc; +} + +int main(int argc, char **argv) +{ + int i; + CK_RV rc; + CK_C_INITIALIZE_ARGS initialize_args; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + + /* Set default slot to 0 */ + slot_id = 0; + + /* Parse the command line */ + for (i = 1; i < argc; i++) { + if (strncmp(argv[i], "-slot", 5) == 0) { + slot_id = atoi(argv[i + 1]); + i++; + break; + } + } + + printf("Using slot %ld...\n\n", slot_id); + + if (!do_GetFunctionList()) + return -1; + + /* There will be no multi-threaded Cryptoki access in this app */ + memset(&initialize_args, 0, sizeof(initialize_args)); + + rc = funcs->C_Initialize(&initialize_args); + if (rc != CKR_OK) { + show_error("C_Initialize", rc); + return -1; + } + + rc = funcs->C_OpenSession(slot_id, + (CKF_SERIAL_SESSION | CKF_RW_SESSION), + NULL_PTR, NULL_PTR, &sess); + /* Open a session with the token */ + if (rc != CKR_OK) { + show_error("C_OpenSession #1", rc); + goto done; + } + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + // Login correctly + rc = funcs->C_Login(sess, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + show_error("C_Login #1", rc); + goto session_close; + } + + printf("do_HW_Feature_Search...\n"); + 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); + +session_close: + rc = funcs->C_CloseSession(sess); + /* Close the session */ + if (rc != CKR_OK) + show_error("C_CloseSession", rc); + +done: + /* Call C_Finalize and dlclose the library */ + return clean_up(); +} + +int clean_up(void) +{ + CK_RV rc = 0; + + rc = funcs->C_Finalize(NULL); + if (rc != CKR_OK) + show_error("C_Finalize", rc); + + return rc; +} diff --git a/testcases/pkcs11/pkcs11.mk b/testcases/pkcs11/pkcs11.mk new file mode 100644 index 0000000..eb16d5c --- /dev/null +++ b/testcases/pkcs11/pkcs11.mk @@ -0,0 +1,55 @@ +noinst_PROGRAMS += \ + testcases/pkcs11/hw_fn testcases/pkcs11/sess_mgmt_tests \ + testcases/pkcs11/sess_bench testcases/pkcs11/sess_opstate \ + testcases/pkcs11/attribute testcases/pkcs11/findobjects \ + testcases/pkcs11/destroyobjects testcases/pkcs11/copyobjects \ + testcases/pkcs11/generate_keypair testcases/pkcs11/gen_purpose \ + testcases/pkcs11/getobjectsize + +testcases_pkcs11_hw_fn_CFLAGS = ${testcases_inc} +testcases_pkcs11_hw_fn_LDADD = testcases/common/libcommon.la +testcases_pkcs11_hw_fn_SOURCES = testcases/pkcs11/hw_fn.c + +testcases_pkcs11_sess_mgmt_tests_CFLAGS = ${testcases_inc} +testcases_pkcs11_sess_mgmt_tests_LDADD = \ + testcases/common/libcommon.la +testcases_pkcs11_sess_mgmt_tests_SOURCES = testcases/pkcs11/sess_mgmt.c + +testcases_pkcs11_sess_bench_CFLAGS = ${testcases_inc} +testcases_pkcs11_sess_bench_LDADD = testcases/common/libcommon.la +testcases_pkcs11_sess_bench_SOURCES = testcases/pkcs11/sess_perf.c + +testcases_pkcs11_sess_opstate_CFLAGS = ${testcases_inc} +testcases_pkcs11_sess_opstate_LDADD = testcases/common/libcommon.la +testcases_pkcs11_sess_opstate_SOURCES = testcases/pkcs11/sess_opstate.c + +testcases_pkcs11_attribute_CFLAGS = ${testcases_inc} +testcases_pkcs11_attribute_LDADD = testcases/common/libcommon.la +testcases_pkcs11_attribute_SOURCES = testcases/pkcs11/attribute.c + +testcases_pkcs11_findobjects_CFLAGS = ${testcases_inc} +testcases_pkcs11_findobjects_LDADD = testcases/common/libcommon.la +testcases_pkcs11_findobjects_SOURCES = testcases/pkcs11/findobjects.c + +testcases_pkcs11_destroyobjects_CFLAGS = ${testcases_inc} +testcases_pkcs11_destroyobjects_LDADD = testcases/common/libcommon.la +testcases_pkcs11_destroyobjects_SOURCES = \ + testcases/pkcs11/destroyobjects.c + +testcases_pkcs11_copyobjects_CFLAGS = ${testcases_inc} +testcases_pkcs11_copyobjects_LDADD = testcases/common/libcommon.la +testcases_pkcs11_copyobjects_SOURCES = testcases/pkcs11/copyobjects.c + +testcases_pkcs11_generate_keypair_CFLAGS = ${testcases_inc} +testcases_pkcs11_generate_keypair_LDADD = testcases/common/libcommon.la +testcases_pkcs11_generate_keypair_SOURCES = \ + testcases/pkcs11/generate_keypair.c + +testcases_pkcs11_gen_purpose_CFLAGS = ${testcases_inc} +testcases_pkcs11_gen_purpose_LDADD = testcases/common/libcommon.la +testcases_pkcs11_gen_purpose_SOURCES = testcases/pkcs11/gen_purpose.c + +testcases_pkcs11_getobjectsize_CFLAGS = ${testcases_inc} +testcases_pkcs11_getobjectsize_LDADD = testcases/common/libcommon.la +testcases_pkcs11_getobjectsize_SOURCES = \ + testcases/pkcs11/getobjectsize.c diff --git a/testcases/pkcs11/sess_mgmt.c b/testcases/pkcs11/sess_mgmt.c new file mode 100644 index 0000000..9024e91 --- /dev/null +++ b/testcases/pkcs11/sess_mgmt.c @@ -0,0 +1,1283 @@ +/* + * 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 + */ + +/* File: sess_mgmt.c */ + +#include + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "mech_to_str.h" +#include "common.c" + +void dump_session_info(CK_SESSION_INFO * info) +{ + printf(" CK_SESSION_INFO:\n"); + printf(" slotID: %ld\n", info->slotID); + printf(" state: "); + switch (info->state) { + case CKS_RO_PUBLIC_SESSION: + printf("CKS_RO_PUBLIC_SESSION\n"); + break; + case CKS_RW_PUBLIC_SESSION: + printf("CKS_RW_PUBLIC_SESSION\n"); + break; + case CKS_RO_USER_FUNCTIONS: + printf("CKS_RO_USER_FUNCTIONS\n"); + break; + case CKS_RW_USER_FUNCTIONS: + printf("CKS_RW_USER_FUNCTIONS\n"); + break; + case CKS_RW_SO_FUNCTIONS: + printf("CKS_RW_SO_FUNCTIONS\n"); + break; + } + printf(" flags: %p\n", (void *) info->flags); + printf(" ulDeviceError: %ld\n", info->ulDeviceError); +} + +CK_RV do_OpenSession(void) +{ + CK_SLOT_ID slot_id; + CK_FLAGS flags; + CK_SESSION_HANDLE handle; + CK_RV rc; + + printf("do_OpenSession...\n"); + + 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); + return rc; + } + + rc = funcs->C_CloseSession(handle); + if (rc != CKR_OK) { + show_error(" C_CloseSession #1", rc); + return rc; + } + + printf("Looks okay...\n"); + + return rc; +} + +CK_RV do_OpenSession2(void) +{ + CK_SLOT_ID slot_id; + CK_FLAGS flags; + CK_SESSION_HANDLE h1, h2; + CK_RV rc; + + printf("do_OpenSession2...\n"); + + 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); + 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); + return rc; + } + + rc = funcs->C_CloseSession(h1); + if (rc != CKR_OK) { + show_error(" C_CloseSession #1", rc); + return rc; + } + + rc = funcs->C_CloseSession(h2); + if (rc != CKR_OK) { + show_error(" C_CloseSession #2", rc); + return rc; + } + + printf("Looks okay...\n"); + + return rc; +} + +CK_RV do_CloseAllSessions(void) +{ + CK_SLOT_ID slot_id; + CK_FLAGS flags; + CK_SESSION_HANDLE h1, h2, h3; + CK_RV rc; + + printf("do_CloseAllSessions...\n"); + + 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); + 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); + 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); + return rc; + } + + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + show_error(" C_CloseAllSessions", rc); + return rc; + } + + printf("Looks okay...\n"); + + return rc; +} + +CK_RV do_GetSessionInfo(void) +{ + CK_SLOT_ID slot_id; + CK_FLAGS flags; + CK_SESSION_HANDLE h1, h2, h3; + CK_SESSION_INFO info; + CK_RV rc; + + printf("do_GetSessionInfo...\n"); + + 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); + 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); + 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); + return rc; + } + + rc = funcs->C_GetSessionInfo(h1, &info); + if (rc != CKR_OK) { + show_error(" C_GetSessionInfo #1", rc); + return rc; + } + + dump_session_info(&info); + + rc = funcs->C_GetSessionInfo(h2, &info); + if (rc != CKR_OK) { + show_error(" C_GetSessionInfo #2", rc); + return rc; + } + + dump_session_info(&info); + + rc = funcs->C_GetSessionInfo(h2, &info); + if (rc != CKR_OK) { + show_error(" C_GetSessionInfo #3", rc); + return rc; + } + + dump_session_info(&info); + + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + show_error(" C_CloseAllSessions", rc); + return rc; + } + + printf("Looks okay...\n"); + + return rc; +} + +// This is a messy function but it does alot of tests: +// +// 1) Create 1 RO session and 2 RW sessions +// 2) Log the USER into session #1. Verify that all 3 become USER sessions. +// 3) Try to login again, this time to session #2. Verify that it fails +// 4) Logout session #1 +// 5) Try to logout from session #2. Verify that this fails. +// 6) Try to log the SO into session #1. Verify that it fails (RO session exists) +// 7) Try to log the SO into session #2. Verify that it fails (RO session exists) +// 8) Close all sessions +// 9) Creaate 2 RW sessions +// A) Log the SO into one. Verify that both are now SO sessions. +// B) Create a 3rd RW session. Verify that it immediately becomes an SO session +// C) Try to create a RO session. Verify that it fails (SO session exists) +// D) Close all sessions and return +// +CK_RV do_LoginLogout(void) +{ + CK_SLOT_ID slot_id; + CK_FLAGS flags; + CK_SESSION_HANDLE h1, h2, h3, h4; + CK_SESSION_INFO info; + CK_RV rc; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_BYTE so_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG so_pin_len; + + printf("do_LoginLogout...\n"); + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + if (get_so_pin(so_pin)) + return CKR_FUNCTION_FAILED; + + so_pin_len = (CK_ULONG) strlen((char *) so_pin); + + slot_id = SLOT_ID; + flags = CKF_SERIAL_SESSION; // read-only session + + // 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); + 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); + 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); + 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); + return rc; + } + + rc = funcs->C_GetSessionInfo(h1, &info); + if (rc != CKR_OK) { + show_error(" C_GetSessionInfo #1", rc); + return rc; + } + + dump_session_info(&info); + + rc = funcs->C_GetSessionInfo(h2, &info); + if (rc != CKR_OK) { + show_error(" C_GetSessionInfo #2", rc); + return rc; + } + + dump_session_info(&info); + + rc = funcs->C_GetSessionInfo(h2, &info); + if (rc != CKR_OK) { + show_error(" C_GetSessionInfo #3", rc); + return rc; + } + + dump_session_info(&info); + + // 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); + PRINT_ERR(" Expected CKR_USER_ALREADY_LOGGED_IN\n"); + return -1; + } + + // now, try to logout twice + rc = funcs->C_Logout(h1); + if (rc != CKR_OK) { + show_error(" C_Logout #1", rc); + return rc; + } + + rc = funcs->C_Logout(h2); + if (rc != CKR_USER_NOT_LOGGED_IN) { + show_error(" C_Logout #2", rc); + PRINT_ERR(" Expected CKR_USER_NOT_LOGGED_IN\n"); + return rc; + } + + // 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); + 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); + PRINT_ERR(" Expected CKR_SESSION_READ_ONLY_EXISTS\n"); + return -1; + } + + // log completely out + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + show_error(" C_CloseAllSessions #1", rc); + return rc; + } + + // now, start two RW sessions + 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); + 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); + 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); + return rc; + } + + rc = funcs->C_GetSessionInfo(h1, &info); + if (rc != CKR_OK) { + show_error(" C_GetSessionInfo #4", rc); + return rc; + } + + dump_session_info(&info); + + rc = funcs->C_GetSessionInfo(h2, &info); + if (rc != CKR_OK) { + show_error(" C_GetSessionInfo #5", rc); + return rc; + } + + dump_session_info(&info); + + // now, create a 3rd RW session. + // verify that it is automatically an SO session + 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); + return rc; + } + + rc = funcs->C_GetSessionInfo(h3, &info); + if (rc != CKR_OK) { + show_error(" C_GetSessionInfo #6", rc); + return rc; + } + + dump_session_info(&info); + + // now, try to create a 4th session. RO this time. Should fail + 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); + PRINT_ERR(" Expected CKR_SESSION_READ_WRITE_SO_EXISTS\n"); + return -1; + } + + // we're done...close all sessions + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + show_error(" C_CloseAllSessions #2: %d", rc); + return rc; + } + + printf("Looks okay...\n"); + + return rc; +} + +CK_RV do_OperationState1(void) +{ + CK_SLOT_ID slot_id; + CK_SESSION_HANDLE session1, session2; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rc; + + CK_BYTE original[1024]; + CK_BYTE crypt1[1024]; + CK_BYTE crypt2[1024]; + CK_BYTE trash1[8]; + CK_BYTE trash2[8]; + + CK_BYTE *op_state = NULL; + CK_ULONG op_state_len; + + CK_ULONG orig_len, crypt1_len, crypt2_len, trash1_len, trash2_len; + CK_ULONG i; + + CK_ULONG key_len = 16; + CK_ATTRIBUTE key_gen_tmpl[] = { + {CKA_VALUE_LEN, &key_len, sizeof(CK_ULONG)} + }; + + CK_MECHANISM mech; + CK_OBJECT_HANDLE h_key; + + + printf("do_OperationState1...\n"); + slot_id = SLOT_ID; + + // + // here's the goal: + // + // All the hash values should be the same + // 1) session #1 starts a multi-part encryption + // 2) save session #1 operation state + // 3) session #1 passes garbage to encrypt update + // 4) session #2's operation state is set to what we saved + // 5) sessoin #2 finishes the encryption operation + // + // Session #2's results should be the same as the single-part version + // + + // 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); + return rc; + } + + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session2); + if (rc != CKR_OK) { + show_error(" C_OpenSession #2", rc); + return rc; + } + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + rc = funcs->C_Login(session1, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + show_error(" C_Login #1", rc); + return rc; + } + + orig_len = sizeof(original); + for (i = 0; i < orig_len; i++) + original[i] = i % 255; + + trash1_len = sizeof(trash1); + memcpy(trash1, "asdflkjasdlkjadslkj", trash1_len); + + // first generate a AES key + mech.mechanism = CKM_AES_KEY_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + if (!mech_supported(slot_id, mech.mechanism)) { + printf("Mechanism %s not supported. (skipped)\n", + mech_to_str(mech.mechanism)); + funcs->C_CloseSession(session1); + funcs->C_CloseSession(session2); + return 0; + } + + rc = funcs->C_GenerateKey(session1, &mech, key_gen_tmpl, 1, &h_key); + if (rc != CKR_OK) { + show_error(" C_GenerateKey #1", rc); + return rc; + } + // now encrypt the original data all at once using CBC + mech.mechanism = CKM_AES_CBC; + mech.ulParameterLen = 16; + mech.pParameter = "1234qwerasdfyxcv"; + + rc = funcs->C_EncryptInit(session1, &mech, h_key); + if (rc != CKR_OK) { + show_error(" C_EncryptInit #1", 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); + return rc; + } + + // now, begin encrypting multipart + rc = funcs->C_EncryptInit(session1, &mech, h_key); + if (rc != CKR_OK) { + show_error(" C_EncryptInit #2", rc); + return rc; + } + + crypt2_len = sizeof(crypt2); + rc = funcs->C_EncryptUpdate(session1, original, orig_len / 2, + crypt2, &crypt2_len); + if (rc != CKR_OK) { + show_error(" C_EncryptUpdate #1", rc); + return rc; + } + + // save session #1's operation state + rc = funcs->C_GetOperationState(session1, NULL, &op_state_len); + if (rc != CKR_OK) { + show_error(" C_GetOperationState #1", rc); + return rc; + } + + op_state = (CK_BYTE *) malloc(op_state_len); + if (!op_state) { + show_error(" HOST MEMORY ERROR", (CK_ULONG) CKR_HOST_MEMORY); + return -1; + } + + rc = funcs->C_GetOperationState(session1, op_state, &op_state_len); + if (rc != CKR_OK) { + show_error(" C_GetOperationState #1", rc); + return rc; + } + + // now, encrypt some garbage. this will affect the CBC even if + // we throw the encrypted garbage away + trash2_len = sizeof(trash2); + rc = funcs->C_EncryptUpdate(session1, trash1, trash1_len, + trash2, &trash2_len); + if (rc != CKR_OK) { + show_error(" C_EncryptUpdate #2", rc); + return rc; + } + + // restore session #1's operation state that we just saved back + // 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); + return rc; + } + + free(op_state); + + // now, encrypt the rest of the original data + i = crypt2_len; + crypt2_len = sizeof(crypt2) - crypt2_len; + rc = funcs->C_EncryptUpdate(session2, + original + orig_len / 2, orig_len / 2, + crypt2 + i, &crypt2_len); + if (rc != CKR_OK) { + show_error(" C_EncryptUpdate #3", rc); + return rc; + } + + crypt2_len += i; + + trash2_len = sizeof(trash2); + rc = funcs->C_EncryptFinal(session2, trash2, &trash2_len); + if (rc != CKR_OK) { + show_error(" C_EncryptFinal #1", rc); + return rc; + } + + if (crypt2_len != crypt1_len) { + PRINT_ERR(" ERROR: Lengths don't match\n"); + return -1; + } + + if (memcmp(crypt1, crypt2, crypt1_len) != 0) { + PRINT_ERR(" ERROR: crypt1 != crypt2\n"); + return -1; + } + + rc = funcs->C_CloseSession(session1); + if (rc != CKR_OK) { + show_error(" C_CloseSession #1", rc); + return rc; + } + + rc = funcs->C_CloseSession(session2); + if (rc != CKR_OK) { + show_error(" C_CloseSession #2", rc); + return rc; + } + + printf("Looks okay...\n"); + + return rc; +} + +CK_RV do_OperationState2(void) +{ + CK_SLOT_ID slot_id; + CK_SESSION_HANDLE session1, session2, session3; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rc; + + CK_BYTE original[1024]; + CK_BYTE digest1[16]; + CK_BYTE digest2[16]; + CK_BYTE digest3[16]; + + CK_ULONG orig_len; + CK_ULONG digest1_len, digest2_len, digest3_len; + + CK_BYTE *op_state1 = NULL; + CK_BYTE *op_state2 = NULL; + CK_ULONG op_state1_len; + CK_ULONG op_state2_len; + + CK_ULONG i; + + CK_MECHANISM mech; + + printf("do_OperationState2...\n"); + slot_id = SLOT_ID; + + // + // here's the goal: + // 1) session #1 digests the first 499 bytes + // 2) session #2 digests the first 27 bytes + // 3) session #3 digests the whole thing + // 3) we save both operation states + // 4) we set the operation states to the 'other' session thereby + // switching sessions. Session #2 picks up where session #1 was + // saved, session #1 picks up where session #2 was saved. + // 5) session #1 digests the final (1024 - 27) bytes + // 6) session #2 digests the final (1024 - 499) bytes + // + // All the hash values should be the same + // + + // create three 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); + return rc; + } + + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session2); + if (rc != CKR_OK) { + show_error(" C_OpenSession #2", rc); + return rc; + } + + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session3); + if (rc != CKR_OK) { + show_error(" C_OpenSession #3", rc); + return rc; + } + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + rc = funcs->C_Login(session1, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + show_error(" C_Login #1", rc); + return rc; + } + + orig_len = sizeof(original); + for (i = 0; i < orig_len; i++) + original[i] = i % 255; + + mech.mechanism = CKM_MD5; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + + if (!mech_supported(slot_id, mech.mechanism)) { + printf("Mechanism %s not supported. (skipped)\n", + mech_to_str(mech.mechanism)); + funcs->C_CloseSession(session1); + funcs->C_CloseSession(session2); + funcs->C_CloseSession(session3); + return 0; + } + + rc = funcs->C_DigestInit(session1, &mech); + if (rc != CKR_OK) { + show_error(" C_DigestInit #1", rc); + return rc; + } + + rc = funcs->C_DigestInit(session2, &mech); + if (rc != CKR_OK) { + show_error(" C_DigestInit #2", rc); + return rc; + } + + rc = funcs->C_DigestInit(session3, &mech); + if (rc != CKR_OK) { + show_error(" C_DigestInit #3", rc); + return rc; + } + + rc = funcs->C_DigestUpdate(session1, original, 499); + if (rc != CKR_OK) { + show_error(" C_DigestUpdate #1", rc); + return rc; + } + + rc = funcs->C_DigestUpdate(session2, original, 27); + if (rc != CKR_OK) { + show_error(" C_DigestUpdate #2", rc); + return rc; + } + + orig_len = sizeof(original); + 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); + return rc; + } + + // save the operation states of sessions 1 and 2 + rc = funcs->C_GetOperationState(session1, NULL, &op_state1_len); + if (rc != CKR_OK) { + show_error(" C_GetOperationState #1", rc); + return rc; + } + + op_state1 = (CK_BYTE *) malloc(op_state1_len); + if (!op_state1) { + show_error(" HOST MEMORY ERROR", (CK_ULONG) CKR_HOST_MEMORY); + return -1; + } + + rc = funcs->C_GetOperationState(session1, op_state1, &op_state1_len); + if (rc != CKR_OK) { + show_error(" C_GetOperationState #2", rc); + return rc; + } + + rc = funcs->C_GetOperationState(session2, NULL, &op_state2_len); + if (rc != CKR_OK) { + show_error(" C_GetOperationState #3", rc); + return rc; + } + + op_state2 = (CK_BYTE *) malloc(op_state2_len); + if (!op_state2) { + show_error(" HOST MEMORY ERROR", (CK_ULONG) CKR_HOST_MEMORY); + return -1; + } + + rc = funcs->C_GetOperationState(session2, op_state2, &op_state2_len); + if (rc != CKR_OK) { + show_error(" C_GetOperationState #4", 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); + return rc; + } + + rc = funcs->C_SetOperationState(session2, op_state1, op_state1_len, 0, 0); + if (rc != CKR_OK) { + show_error(" C_SetOperationState #3", 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); + return rc; + } + + rc = funcs->C_DigestUpdate(session1, original + 27, orig_len - 27); + if (rc != CKR_OK) { + show_error(" C_DigestUpdate #4", 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); + return rc; + } + + digest2_len = sizeof(digest2); + rc = funcs->C_DigestFinal(session2, digest2, &digest2_len); + if (rc != CKR_OK) { + show_error(" C_DigestFinal #2", rc); + return rc; + } + + if (digest1_len != digest2_len || digest1_len != digest3_len) { + PRINT_ERR(" ERROR: digested lengths don't match\n"); + return -1; + } + + if (memcmp(digest1, digest2, digest1_len) != 0) { + PRINT_ERR(" ERROR: digest1 != digest2\n"); + return -1; + } + + if (memcmp(digest1, digest3, digest1_len) != 0) { + PRINT_ERR(" ERROR: digest1 != digest3\n"); + return -1; + } + + rc = funcs->C_CloseSession(session1); + if (rc != CKR_OK) { + show_error(" C_CloseSession #3", rc); + return rc; + } + + rc = funcs->C_CloseSession(session2); + if (rc != CKR_OK) { + show_error(" C_CloseSession #4", rc); + return rc; + } + + rc = funcs->C_CloseSession(session3); + if (rc != CKR_OK) { + show_error(" C_CloseSession #5", rc); + return rc; + } + + printf("Looks okay...\n"); + + free(op_state1); + free(op_state2); + return rc; +} + +CK_RV do_OperationState3(void) +{ + CK_SLOT_ID slot_id; + CK_SESSION_HANDLE session1, session2, session3; + CK_FLAGS flags; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; + CK_ULONG user_pin_len; + CK_RV rc; + + CK_BYTE original[1024]; + CK_BYTE digest1[16]; + CK_BYTE digest2[16]; + CK_BYTE digest3[16]; + CK_BYTE junk[1024]; + + CK_ULONG orig_len, junk_len; + CK_ULONG digest1_len, digest2_len, digest3_len; + + CK_BYTE *op_state2 = NULL; + CK_ULONG op_state2_len; + + CK_ULONG i; + + CK_ULONG key_len = 16; + CK_ATTRIBUTE key_gen_tmpl[] = { + {CKA_VALUE_LEN, &key_len, sizeof(CK_ULONG)} + }; + + CK_MECHANISM mech1, mech2; + CK_OBJECT_HANDLE key; + + + printf("do_OperationState3...\n"); + slot_id = SLOT_ID; + + // + // here's the goal: + // 1) session #1 starts a multi-part encrypt + // 2) session #2 starts a multi-part digest + // 3) session #3 digests the whole thing + // 4) assign session #2's operating state to session #1 + // 5) session #1 tries C_EncryptUpdate. Should fail. + // 6) session #1 finishes the multi-part digest + // 7) session #2 finishes the multi-part digest + // + // All the hash values should be the same + // + + // create three 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); + return rc; + } + + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session2); + if (rc != CKR_OK) { + show_error(" C_OpenSession #2", rc); + return rc; + } + + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session3); + if (rc != CKR_OK) { + show_error(" C_OpenSession #3", rc); + return rc; + } + + if (get_user_pin(user_pin)) + return CKR_FUNCTION_FAILED; + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + + rc = funcs->C_Login(session1, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + show_error(" C_Login #1", rc); + return rc; + } + + orig_len = sizeof(original); + for (i = 0; i < orig_len; i++) + original[i] = i % 255; + + mech1.mechanism = CKM_AES_KEY_GEN; + mech1.pParameter = NULL; + mech1.ulParameterLen = 0; + + if (!mech_supported(slot_id, mech1.mechanism)) { + printf("Mechanism %s not supported. (skipped)\n", + mech_to_str(mech1.mechanism)); + funcs->C_CloseSession(session1); + funcs->C_CloseSession(session2); + funcs->C_CloseSession(session3); + return 0; + } + + rc = funcs->C_GenerateKey(session1, &mech1, key_gen_tmpl, 1, &key); + if (rc != CKR_OK) { + show_error(" C_GenerateKey #1", rc); + return rc; + } + + mech1.mechanism = CKM_AES_ECB; + mech1.pParameter = NULL; + mech1.ulParameterLen = 0; + + if (!mech_supported(slot_id, mech1.mechanism)) { + printf("Mechanism %s not supported. (skipped)\n", + mech_to_str(mech1.mechanism)); + funcs->C_CloseSession(session1); + funcs->C_CloseSession(session2); + funcs->C_CloseSession(session3); + return 0; + } + + rc = funcs->C_EncryptInit(session1, &mech1, key); + if (rc != CKR_OK) { + show_error(" C_EncryptInit #1", rc); + return rc; + } + + mech2.mechanism = CKM_MD5; + mech2.pParameter = NULL; + mech2.ulParameterLen = 0; + + if (!mech_supported(slot_id, mech2.mechanism)) { + printf("Mechanism %s not supported. (skipped)\n", + mech_to_str(mech2.mechanism)); + funcs->C_CloseSession(session1); + funcs->C_CloseSession(session2); + funcs->C_CloseSession(session3); + return 0; + } + + rc = funcs->C_DigestInit(session2, &mech2); + if (rc != CKR_OK) { + show_error(" C_DigestInit #1", rc); + return rc; + } + + rc = funcs->C_DigestInit(session3, &mech2); + if (rc != CKR_OK) { + show_error(" C_DigestInit #2", rc); + return rc; + } + + rc = funcs->C_DigestUpdate(session2, original, 499); + if (rc != CKR_OK) { + show_error(" C_DigestUpdate #1", rc); + return rc; + } + + orig_len = sizeof(original); + 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); + return rc; + } + + rc = funcs->C_GetOperationState(session2, NULL, &op_state2_len); + if (rc != CKR_OK) { + show_error(" C_GetOperationState #1", 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); + return -1; + } + + rc = funcs->C_GetOperationState(session2, op_state2, &op_state2_len); + if (rc != CKR_OK) { + show_error(" C_GetOperationState #2", 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); + return rc; + } + + // session #1 should not be set to do digest not encryption + 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"); + 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); + return rc; + } + + rc = funcs->C_DigestUpdate(session2, original + 499, (orig_len - 499)); + if (rc != CKR_OK) { + show_error(" C_DigestUpdate #3", 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); + return rc; + } + + digest2_len = sizeof(digest2); + rc = funcs->C_DigestFinal(session2, digest2, &digest2_len); + if (rc != CKR_OK) { + show_error(" C_DigestFinal #2", rc); + return rc; + } + + if (digest1_len != digest2_len || digest1_len != digest3_len) { + PRINT_ERR(" ERROR: digested lengths don't match\n"); + return -1; + } + + if (memcmp(digest1, digest2, digest1_len) != 0) { + PRINT_ERR(" ERROR: digest1 != digest2\n"); + return -1; + } + + if (memcmp(digest1, digest3, digest1_len) != 0) { + PRINT_ERR(" ERROR: digest1 != digest3\n"); + return -1; + } + + rc = funcs->C_CloseSession(session1); + if (rc != CKR_OK) { + show_error(" C_CloseSession #3", rc); + return rc; + } + + rc = funcs->C_CloseSession(session2); + if (rc != CKR_OK) { + show_error(" C_CloseSession #4", rc); + return rc; + } + + rc = funcs->C_CloseSession(session3); + if (rc != CKR_OK) { + show_error(" C_CloseSession #5", rc); + return rc; + } + + printf("Looks okay...\n"); + + free(op_state2); + return rc; +} + +CK_RV sess_mgmt_functions() +{ + SYSTEMTIME t1, t2; + CK_RV rc; + + GetSystemTime(&t1); + rc = do_OpenSession(); + if (rc && !no_stop) + return rc; + GetSystemTime(&t2); + process_time(t1, t2); + + + GetSystemTime(&t1); + rc = do_OpenSession2(); + if (rc && !no_stop) + return rc; + GetSystemTime(&t2); + process_time(t1, t2); + + + GetSystemTime(&t1); + rc = do_CloseAllSessions(); + if (rc && !no_stop) + return rc; + GetSystemTime(&t2); + process_time(t1, t2); + + + GetSystemTime(&t1); + rc = do_GetSessionInfo(); + if (rc && !no_stop) + return rc; + GetSystemTime(&t2); + process_time(t1, t2); + + + GetSystemTime(&t1); + rc = do_LoginLogout(); + if (rc && !no_stop) + return rc; + GetSystemTime(&t2); + process_time(t1, t2); + + + GetSystemTime(&t1); + rc = do_OperationState1(); + if (rc && !no_stop) + return rc; + GetSystemTime(&t2); + process_time(t1, t2); + + + GetSystemTime(&t1); + rc = do_OperationState2(); + if (rc && !no_stop) + return rc; + GetSystemTime(&t2); + process_time(t1, t2); + + + GetSystemTime(&t1); + rc = do_OperationState3(); + if (rc && !no_stop) + return rc; + GetSystemTime(&t2); + process_time(t1, t2); + + return rc; +} + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + int rc; + CK_RV rv; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: no_init: %d\n", no_init); + + rc = do_GetFunctionList(); + if (!rc) { + PRINT_ERR("ERROR do_GetFunctionList() Failed , rc = 0x%0x\n", rc); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + // SAB Add calls to ALL functions before the C_Initialize gets hit + + funcs->C_Initialize(&cinit_args); + + { + CK_SESSION_HANDLE hsess = 0; + + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + } + + rv = sess_mgmt_functions(); + + /* make sure we return non-zero if rv is non-zero */ + return ((rv == 0) || (rv % 256) ? (int)rv : -1); +} diff --git a/testcases/pkcs11/sess_opstate.c b/testcases/pkcs11/sess_opstate.c new file mode 100644 index 0000000..3235b45 --- /dev/null +++ b/testcases/pkcs11/sess_opstate.c @@ -0,0 +1,287 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 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 + */ + +/* + * Testcase for + * C_GetOperationState / C_SetOperationState + */ + +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "common.c" + + +CK_BYTE_PTR alloc_random_buf(CK_SESSION_HANDLE sess, CK_LONG nbytes) +{ + CK_RV rc; + CK_BYTE_PTR ptr = malloc(nbytes); + if (ptr == NULL) { + testcase_error("malloc(%lu) failed", nbytes); + return NULL; + } + + rc = funcs->C_GenerateRandom(sess, ptr, nbytes); + if (rc != CKR_OK) { + testcase_error("C_GenerateRandom() rc=%s", p11_get_ckr(rc)); + free(ptr); + return NULL; + } + + return ptr; +} + +int sess_opstate_funcs(int loops) +{ + CK_SESSION_HANDLE s1, s2; + CK_SLOT_ID slot_id = SLOT_ID; + CK_ULONG flags; + CK_RV rc; + unsigned int i; + int counter, rbytes; + CK_BYTE *rdata = NULL; + CK_MECHANISM mech1 = { CKM_SHA256, 0, 0 }; + CK_MECHANISM mech2 = { CKM_SHA_1, 0, 0 }; + CK_ULONG r1hlen, r2hlen, hlen; + CK_BYTE r1hash[32], r2hash[32], hash[32]; + CK_ULONG opstatelen; + CK_BYTE *opstate = NULL; + + // open 2 sessions + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &s1); + if (rc != CKR_OK) { + testcase_error("C_OpenSession() rc=%s", p11_get_ckr(rc)); + goto out; + } + + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &s2); + if (rc != CKR_OK) { + testcase_error("C_OpenSession() rc=%s", p11_get_ckr(rc)); + goto out; + } + + // init digest for both sessions + rc = funcs->C_DigestInit(s1, &mech1); + if (rc != CKR_OK) { + testcase_error("C_DigestInit rc=%s", p11_get_ckr(rc)); + goto out; + } + + rc = funcs->C_DigestInit(s2, &mech1); + if (rc != CKR_OK) { + testcase_error("C_DigestInit rc=%s", p11_get_ckr(rc)); + goto out; + } + + // now loop over some digest updates + for (counter = 0; counter < loops; counter++) { + // create some random data + rbytes = random() % sizeof(rdata); + rdata = alloc_random_buf(s1, rbytes); + if (!rdata) + goto out; + + // digest update on session 1 + rc = funcs->C_DigestUpdate(s1, rdata, rbytes); + if (rc != CKR_OK) { + testcase_error("C_DigestUpdate rc=%s", p11_get_ckr(rc)); + goto out; + } + + // restore op state on session 2 + if (opstate != NULL) { + rc = funcs->C_SetOperationState(s2, opstate, opstatelen, 0, 0); + if (rc != CKR_OK) { + testcase_error("C_SetOperationState rc=%s", p11_get_ckr(rc)); + goto out; + } + free(opstate); + opstate = NULL; + } + + // digest update on session 2 + rc = funcs->C_DigestUpdate(s2, rdata, rbytes); + if (rc != CKR_OK) { + testcase_error("C_DigestUpdate rc=%s", p11_get_ckr(rc)); + goto out; + } + + // fetch op state on session 2 + opstatelen = 0; + rc = funcs->C_GetOperationState(s2, NULL, &opstatelen); + if (rc != CKR_OK) { + testcase_error("C_GetOperationState rc=%s", p11_get_ckr(rc)); + goto out; + } + + opstate = malloc(opstatelen); + if (opstate == NULL) { + testcase_error("malloc(%lu) failed", opstatelen); + goto out; + } + + rc = funcs->C_GetOperationState(s2, opstate, &opstatelen); + if (rc != CKR_OK) { + testcase_error("C_GetOperationState rc=%s", p11_get_ckr(rc)); + goto out; + } + + free(rdata); + rdata = NULL; + + // now do something different on session 2, but first + // we have to wipe out the started digest operation + hlen = sizeof(hash); + rc = funcs->C_DigestFinal(s2, hash, &hlen); + if (rc != CKR_OK) { + testcase_error("C_DigestFinal rc=%s", p11_get_ckr(rc)); + goto out; + } + + // so now let's do a digest init/update/finish + // to randomize the memory a little + rc = funcs->C_DigestInit(s2, &mech2); + if (rc != CKR_OK) { + testcase_error("C_DigestInit rc=%s", p11_get_ckr(rc)); + goto out; + } + + for (i = 0; i < (unsigned int)loops; i++) { + rbytes = random() % sizeof(rdata); + rdata = alloc_random_buf(s1, rbytes); + if (!rdata) + goto out; + + rc = funcs->C_DigestUpdate(s2, rdata, rbytes); + if (rc != CKR_OK) { + testcase_error("C_DigestUpdate rc=%s", p11_get_ckr(rc)); + goto out; + } + free(rdata); + rdata = NULL; + } + hlen = sizeof(hash); + + rc = funcs->C_DigestFinal(s2, hash, &hlen); + if (rc != CKR_OK) { + testcase_error("C_DigestFinal rc=%s", p11_get_ckr(rc)); + goto out; + } + } + + // restore op state on session 2 + rc = funcs->C_SetOperationState(s2, opstate, opstatelen, 0, 0); + if (rc != CKR_OK) { + testcase_error("C_SetOperationState rc=%s", p11_get_ckr(rc)); + goto out; + } + + // digest finish + r1hlen = sizeof(r1hash); + rc = funcs->C_DigestFinal(s1, r1hash, &r1hlen); + if (rc != CKR_OK) { + testcase_error("C_DigestFinal rc=%s", p11_get_ckr(rc)); + goto out; + } + + r2hlen = sizeof(r2hash); + rc = funcs->C_DigestFinal(s2, r2hash, &r2hlen); + if (rc != CKR_OK) { + testcase_error("C_DigestFinal rc=%s", p11_get_ckr(rc)); + goto out; + } + + // check both hashes + if (r1hlen != r2hlen) { + testcase_fail("hash length differ"); + goto out; + } + if (memcmp(r1hash, r2hash, r1hlen) != 0) { + testcase_fail("hash values differs"); + goto out; + } + + testcase_pass("Get/SetOperationState digest test"); + +out: + if (opstate) + free(opstate); + if (rdata) + free(rdata); + funcs->C_CloseAllSessions(slot_id); + + return rc; +} + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + int rc, i, j, loops = 0; + CK_RV rv; + + SLOT_ID = 0; + no_init = FALSE; + + srandom(time(0)); + + for (i = 0; i < argc; i++) { + if (strncmp(argv[i], "loops=", 6) == 0) { + sscanf(argv[i] + 6, "%i", &loops); + for (j = i; j < argc; j++) + argv[j] = argv[j + 1]; + argc--; + } + } + + if (loops < 1) + loops = 100; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: no_init: %d\n", no_init); + printf("Running %d loops...\n", loops); + + rc = do_GetFunctionList(); + if (!rc) { + PRINT_ERR("ERROR do_GetFunctionList() Failed , rc = 0x%0x\n", rc); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + funcs->C_Initialize(&cinit_args); + + { + CK_SESSION_HANDLE hsess = 0; + + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + } + + rv = sess_opstate_funcs(loops); + + /* make sure we return non-zero if rv is non-zero */ + return ((rv == 0) || (rv % 256) ? (int)rv : -1); +} diff --git a/testcases/pkcs11/sess_perf.c b/testcases/pkcs11/sess_perf.c new file mode 100644 index 0000000..dc35369 --- /dev/null +++ b/testcases/pkcs11/sess_perf.c @@ -0,0 +1,266 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2010-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: sess_perf.c */ + +#include + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "regress.h" +#include "defs.h" + +#define DATALEN 1024 +CK_BYTE DATA[DATALEN]; +CK_BYTE DUMP[DATALEN]; + +typedef struct _context_table { + CK_SESSION_HANDLE hsess; + CK_OBJECT_HANDLE hkey; +} context_table_t; + +void dump_session_info(CK_SESSION_INFO * info) +{ + printf(" CK_SESSION_INFO:\n"); + printf(" slotID: %ld\n", info->slotID); + printf(" state: "); + switch (info->state) { + case CKS_RO_PUBLIC_SESSION: + printf("CKS_RO_PUBLIC_SESSION\n"); + break; + case CKS_RW_PUBLIC_SESSION: + printf("CKS_RW_PUBLIC_SESSION\n"); + break; + case CKS_RO_USER_FUNCTIONS: + printf("CKS_RO_USER_FUNCTIONS\n"); + break; + case CKS_RW_USER_FUNCTIONS: + printf("CKS_RW_USER_FUNCTIONS\n"); + break; + case CKS_RW_SO_FUNCTIONS: + printf("CKS_RW_SO_FUNCTIONS\n"); + break; + } + printf(" flags: %p\n", (void *) info->flags); + printf(" ulDeviceError: %ld\n", info->ulDeviceError); +} + +int create_des_encrypt_context(CK_SESSION_HANDLE_PTR hsess, + CK_OBJECT_HANDLE_PTR hkey) +{ + CK_SLOT_ID slot_id; + CK_FLAGS flags; + CK_RV rc; + CK_MECHANISM mech; + CK_ULONG key_len = 16; + CK_ATTRIBUTE tkey = { CKA_VALUE_LEN, &key_len, sizeof(CK_ULONG) }; + + /* create session */ + slot_id = SLOT_ID; + flags = CKF_SERIAL_SESSION; // read-only session + + rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, hsess); + if (rc != CKR_OK) { + show_error(" C_OpenSession #1", rc); + return FALSE; + } + + /* generate key in this specific session */ + mech.mechanism = CKM_AES_KEY_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rc = funcs->C_GenerateKey(*hsess, &mech, &tkey, 1, hkey); + if (rc != CKR_OK) { + show_error(" C_GenerateKey #1", rc); + return FALSE; + } + + /* Get Random for Initialization Vector */ + mech.mechanism = CKM_AES_CBC; + mech.ulParameterLen = 16; + mech.pParameter = "1234567890123456"; + + /* 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); + return FALSE; + } + + return TRUE; +} + +int encrypt_DATA(CK_SESSION_HANDLE hsess, CK_OBJECT_HANDLE hkey, + CK_ULONG blocklen) +{ + CK_RV rc; + CK_ULONG outlen = 16; + unsigned long int i; + + UNUSED(hkey); + + for (i = 0; i < DATALEN; i += outlen) { + 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); + return FALSE; + } + } + + return TRUE; +} + + +int finalize_des_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); + return FALSE; + } + + rc = funcs->C_CloseSession(hsess); + if (rc != CKR_OK) { + show_error("C_CloseSession #1", rc); + return FALSE; + } + + return TRUE; +} + +int close_all_sess(void) +{ + CK_SLOT_ID slot_id; + CK_RV rc; + + slot_id = SLOT_ID; + + rc = funcs->C_CloseAllSessions(slot_id); + if (rc != CKR_OK) { + show_error("C_CloseAllSessions #1", rc); + return FALSE; + } + + return TRUE; +} + +int do_SessionPerformance(unsigned int count) +{ + SYSTEMTIME t1, t2; + int rc; + unsigned int i; + context_table_t *t = NULL; + + if (count == 0) { + show_error("do_SessionPerformance: zero session count", (CK_RV) 0); + return FALSE; + } + + t = (context_table_t *) calloc(count, sizeof(context_table_t)); + if (t == NULL) { + show_error("do_SessionPerformance: insuficient memory", (CK_RV) 0); + return FALSE; + } + + /* create encryption contexts */ + for (i = 0; i < count; i++) { + rc = create_des_encrypt_context(&(t[i].hsess), &(t[i].hkey)); + if (rc == FALSE) { + show_error("create_aes_encrypt_context", (CK_RV) 0); + goto ret; + } + } + + /* Time encrypt operation in the first and last session */ + GetSystemTime(&t1); + rc = encrypt_DATA(t[0].hsess, t[0].hkey, 16); + if (rc == FALSE) { + show_error("encrypt_DATA #1", (CK_RV) 0); + 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); + goto ret; + } + GetSystemTime(&t2); + process_time(t1, t2); + + for (i = 0; i < count; i++) { + rc = finalize_des_encrypt_context(t[i].hsess); + if (rc == FALSE) { + show_error("finalize_aes_encrypt_context", (CK_RV) 0); + goto ret; + } + } + + rc = TRUE; +ret: + if (t != NULL) + free(t); + return rc; +} + +int main(int argc, char **argv) +{ + CK_C_INITIALIZE_ARGS cinit_args; + int rc, i; + + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + printf("With option: no_init: %d\n", no_init); + + rc = do_GetFunctionList(); + if (!rc) { + PRINT_ERR("ERROR do_GetFunctionList() Failed , rc = 0x%0x\n", rc); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + // SAB Add calls to ALL functions before the C_Initialize gets hit + + funcs->C_Initialize(&cinit_args); + + { + CK_SESSION_HANDLE hsess = 0; + + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + } + + for (i = 100; i < 50000; i = 1.2 * i) { + printf("timing do_SessionPerformance(%d)\n", i); + do_SessionPerformance(i); + } + + return 0; +} diff --git a/testcases/testcases.mk b/testcases/testcases.mk new file mode 100644 index 0000000..d38b6a8 --- /dev/null +++ b/testcases/testcases.mk @@ -0,0 +1,30 @@ +testcases_inc = \ + -I${srcdir}/usr/include -I${srcdir}/usr/lib/common \ + -I${srcdir}/testcases/include -I${srcdir}/testcases/common \ + -I${srcdir}/testcases/login -I${srcdir}/testcases/crypto \ + -I${srcdir}/testcases/misc_tests -I${srcdir}/testcases/pkcs11 + +include testcases/include/include.mk +include testcases/common/common.mk +include testcases/crypto/crypto.mk +include testcases/login/login.mk +include testcases/misc_tests/misc_tests.mk +include testcases/pkcs11/pkcs11.mk + +noinst_SCRIPTS += testcases/ock_tests.sh testcases/init_token.sh +CLEANFILES += testcases/ock_tests.sh testcases/init_token.sh +EXTRA_DIST += testcases/ock_tests.sh.in testcases/init_token.sh.in + +testcases/ock_tests.sh: testcases/ock_tests.sh.in + @SED@ -e s!\@sysconfdir\@!"@sysconfdir@"!g \ + -e s!\@sbindir\@!"@sbindir@"!g \ + -e s!\@libdir\@!"@libdir@"!g < $< > $@-t + @CHMOD@ a+x $@-t + mv $@-t $@ + +testcases/init_token.sh: testcases/init_token.sh.in + @SED@ -e s!\@localstatedir\@!"@localstatedir@"!g \ + -e s!\@sbindir\@!"@sbindir@"!g \ + -e s!\@libdir\@!"@libdir@"!g < $< > $@-t + @CHMOD@ a+x $@-t + mv $@-t $@ diff --git a/usr/include/apiclient.h b/usr/include/apiclient.h new file mode 100644 index 0000000..9c1a0bc --- /dev/null +++ b/usr/include/apiclient.h @@ -0,0 +1,196 @@ +/* + * 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 + */ + +#ifndef _APICLIENT_H +#define _APICLIENT_H + + +#include "pkcs11types.h" + + +#define VERSION_MAJOR 2 // Version 2 of the PKCS library +#define VERSION_MINOR 01 // minor revision .10 of PKCS11 + +#ifdef __cplusplus +extern "C" { +#endif + + CK_RV C_CancelFunction(CK_SESSION_HANDLE); + + CK_RV C_CloseAllSessions(CK_SLOT_ID); + + CK_RV C_CloseSession(CK_SESSION_HANDLE); + + CK_RV C_CopyObject(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, + CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR); + + CK_RV C_CreateObject(CK_SESSION_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG, + CK_OBJECT_HANDLE_PTR); + + CK_RV C_Decrypt(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, + CK_ULONG_PTR); + + CK_RV C_DecryptDigestUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, + CK_BYTE_PTR, CK_ULONG_PTR); + + CK_RV C_DecryptFinal(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR); + + CK_RV C_DecryptInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE); + + CK_RV C_DecryptUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, + CK_ULONG_PTR); + + CK_RV C_DecryptVerifyUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, + CK_BYTE_PTR, CK_ULONG_PTR); + + CK_RV C_DeriveKey(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, + CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR); + + CK_RV C_DestroyObject(CK_SESSION_HANDLE, CK_OBJECT_HANDLE); + + CK_RV C_Digest(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, + CK_ULONG_PTR); + + CK_RV C_DigestEncryptUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, + CK_BYTE_PTR, CK_ULONG_PTR); + + CK_RV C_DigestFinal(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR); + + CK_RV C_DigestInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR); + + CK_RV C_DigestKey(CK_SESSION_HANDLE, CK_OBJECT_HANDLE); + + CK_RV C_DigestUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG); + + CK_RV C_Encrypt(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, + CK_ULONG_PTR); + + CK_RV C_EncryptFinal(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR); + + CK_RV C_EncryptInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE); + + CK_RV C_EncryptUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, + CK_ULONG_PTR); + + CK_RV C_Finalize(CK_VOID_PTR); + + CK_RV C_FindObjects(CK_SESSION_HANDLE, CK_OBJECT_HANDLE_PTR, CK_ULONG, + CK_ULONG_PTR); + + CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE); + + CK_RV C_FindObjectsInit(CK_SESSION_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG); + + CK_RV C_GenerateKey(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, + CK_ULONG, CK_OBJECT_HANDLE_PTR); + + CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE, CK_MECHANISM_PTR, + CK_ATTRIBUTE_PTR, CK_ULONG, CK_ATTRIBUTE_PTR, + CK_ULONG, CK_OBJECT_HANDLE_PTR, + CK_OBJECT_HANDLE_PTR); + + CK_RV C_GenerateRandom(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG); + + CK_RV C_GetAttributeValue(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, + CK_ATTRIBUTE_PTR, CK_ULONG); + + CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR); + + CK_RV C_GetFunctionStatus(CK_SESSION_HANDLE); + + CK_RV C_GetInfo(CK_INFO_PTR); + + CK_RV C_GetMechanismInfo(CK_SLOT_ID, CK_MECHANISM_TYPE, + CK_MECHANISM_INFO_PTR); + + CK_RV C_GetMechanismList(CK_SLOT_ID, CK_MECHANISM_TYPE_PTR, CK_ULONG_PTR); + + CK_RV C_GetObjectSize(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_ULONG_PTR); + + CK_RV C_GetOperationState(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR); + + CK_RV C_GetSessionInfo(CK_SESSION_HANDLE, CK_SESSION_INFO_PTR); + + CK_RV C_GetSlotInfo(CK_SLOT_ID, CK_SLOT_INFO_PTR); + + CK_RV C_GetSlotList(CK_BBOOL, CK_SLOT_ID_PTR, CK_ULONG_PTR); + + CK_RV C_GetTokenInfo(CK_SLOT_ID, CK_TOKEN_INFO_PTR); + + CK_RV C_Initialize(CK_VOID_PTR); + + CK_RV C_InitPIN(CK_SESSION_HANDLE, CK_CHAR_PTR, CK_ULONG); + + CK_RV C_InitToken(CK_SLOT_ID, CK_CHAR_PTR, CK_ULONG, CK_CHAR_PTR); + + CK_RV C_Login(CK_SESSION_HANDLE, CK_USER_TYPE, CK_CHAR_PTR, CK_ULONG); + + CK_RV C_Logout(CK_SESSION_HANDLE); + + CK_RV C_OpenSession(CK_SLOT_ID, CK_FLAGS, CK_VOID_PTR, CK_NOTIFY, + CK_SESSION_HANDLE_PTR); + + CK_RV C_SeedRandom(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG); + + CK_RV C_SetAttributeValue(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, + CK_ATTRIBUTE_PTR, CK_ULONG); + + CK_RV C_SetOperationState(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, + CK_OBJECT_HANDLE, CK_OBJECT_HANDLE); + + CK_RV C_SetPIN(CK_SESSION_HANDLE, CK_CHAR_PTR, CK_ULONG, CK_CHAR_PTR, + CK_ULONG); + + CK_RV C_Sign(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, + CK_ULONG_PTR); + + CK_RV C_SignEncryptUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, + CK_BYTE_PTR, CK_ULONG_PTR); + + CK_RV C_SignFinal(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR); + + CK_RV C_SignInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE); + + CK_RV C_SignRecover(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, + CK_ULONG_PTR); + + CK_RV C_SignRecoverInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR, + CK_OBJECT_HANDLE); + + CK_RV C_SignUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG); + + CK_RV C_UnwrapKey(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, + CK_BYTE_PTR, CK_ULONG, CK_ATTRIBUTE_PTR, CK_ULONG, + CK_OBJECT_HANDLE_PTR); + + CK_RV C_Verify(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, + CK_ULONG); + + CK_RV C_VerifyFinal(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG); + + CK_RV C_VerifyInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE); + + CK_RV C_VerifyRecover(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, + CK_ULONG_PTR); + + CK_RV C_VerifyRecoverInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR, + CK_OBJECT_HANDLE); + + CK_RV C_VerifyUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG); + + CK_RV C_WaitForSlotEvent(CK_FLAGS, CK_SLOT_ID_PTR, CK_VOID_PTR); + + CK_RV C_WrapKey(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, + CK_OBJECT_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR); + +#ifdef __cplusplus +} +#endif +#endif // _APICLIENT_H diff --git a/usr/include/apictl.h b/usr/include/apictl.h new file mode 100644 index 0000000..8898cae --- /dev/null +++ b/usr/include/apictl.h @@ -0,0 +1,62 @@ +/* + * 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 + */ + +#include +#include +#include +#include +#include + +#include "local_types.h" + +#ifndef _APILOCAL_H +#define _APILOCAL_H + +// SAB Add a linked list of STDLL's loaded to +// only load and get list once, but let multiple slots us it. + +typedef struct { + CK_BOOL DLLoaded; // Flag to indicate if the STDDL has been loaded + char *dll_name; // Malloced space to copy the name. + void *dlop_p; + int dll_load_count; +// STDLL_FcnList_t *FcnList; // Function list pointer for the STDLL +} DLL_Load_t; + +struct API_Slot { + CK_BOOL DLLoaded; // Flag to indicate if the STDDL has been loaded + void *dlop_p; // Pointer to the value returned from the DL open + STDLL_FcnList_t *FcnList; // Function list pointer for the STDLL + STDLL_TokData_t *TokData; // Pointer to Token specific data + DLL_Load_t *dll_information; + CK_RV (*pSTfini)(STDLL_TokData_t *, CK_SLOT_ID, SLOT_INFO *, + struct trace_handle_t *, CK_BBOOL); + CK_RV(*pSTcloseall)(STDLL_TokData_t *, CK_SLOT_ID); +}; + + +// Per process API structure. +// Allocate one per process on the C_Initialize. This will be +// a global type for the API and will be used through out. +// +typedef struct { + pid_t Pid; + key_t shm_tok; + + struct btree sess_btree; + void *SharedMemP; + Slot_Mgr_Socket_t SocketDataP; + uint16 MgrProcIndex; // Index into shared memory for This process ctl block + API_Slot_t SltList[NUMBER_SLOTS_MANAGED]; + DLL_Load_t DLLs[NUMBER_SLOTS_MANAGED]; // worst case we have a separate DLL + // per slot +} API_Proc_Struct_t; + +#endif diff --git a/usr/include/ec_curves.h b/usr/include/ec_curves.h new file mode 100644 index 0000000..77005f5 --- /dev/null +++ b/usr/include/ec_curves.h @@ -0,0 +1,107 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2019 + * + * 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 _EC_CURVES_H_ +#define _EC_CURVES_H_ + +/* + * OIDs and their DER encoding for the EC curves supported by OpenCryptoki: + */ + +/* brainpoolP160r1: 1.3.36.3.3.2.8.1.1.1 */ +#define OCK_BRAINPOOL_P160R1 { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, \ + 0x02, 0x08, 0x01, 0x01, 0x01 } + +/* brainpoolP160t1: 1.3.36.3.3.2.8.1.1.2 */ +#define OCK_BRAINPOOL_P160T1 { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, \ + 0x02, 0x08, 0x01, 0x01, 0x02 } + +/* brainpoolP192r1: 1.3.36.3.3.2.8.1.1.3 */ +#define OCK_BRAINPOOL_P192R1 { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, \ + 0x02, 0x08, 0x01, 0x01, 0x03 } + +/* brainpoolP192t1: 1.3.36.3.3.2.8.1.1.4 */ +#define OCK_BRAINPOOL_P192T1 { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, \ + 0x02, 0x08, 0x01, 0x01, 0x04 } + +/* brainpoolP224r1: 1.3.36.3.3.2.8.1.1.5 */ +#define OCK_BRAINPOOL_P224R1 { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, \ + 0x02, 0x08, 0x01, 0x01, 0x05 } + +/* brainpoolP224t1: 1.3.36.3.3.2.8.1.1.6 */ +#define OCK_BRAINPOOL_P224T1 { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, \ + 0x02, 0x08, 0x01, 0x01, 0x06 } + +/* brainpoolP256r1: 1.3.36.3.3.2.8.1.1.7 */ +#define OCK_BRAINPOOL_P256R1 { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, \ + 0x02, 0x08, 0x01, 0x01, 0x07 } + +/* brainpoolP256t1: 1.3.36.3.3.2.8.1.1.8 */ +#define OCK_BRAINPOOL_P256T1 { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, \ + 0x02, 0x08, 0x01, 0x01, 0x08 } + +/* brainpoolP320r1: 1.3.36.3.3.2.8.1.1.9 */ +#define OCK_BRAINPOOL_P320R1 { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, \ + 0x02, 0x08, 0x01, 0x01, 0x09 } + +/* brainpoolP320t1: 1.3.36.3.3.2.8.1.1.10 */ +#define OCK_BRAINPOOL_P320T1 { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, \ + 0x02, 0x08, 0x01, 0x01, 0x0A } + +/* brainpoolP384r1: 1.3.36.3.3.2.8.1.1.11 */ +#define OCK_BRAINPOOL_P384R1 { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, \ + 0x02, 0x08, 0x01, 0x01, 0x0B } + +/* brainpoolP384t1: 1.3.36.3.3.2.8.1.1.12 */ +#define OCK_BRAINPOOL_P384T1 { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, \ + 0x02, 0x08, 0x01, 0x01, 0x0C } + +/* brainpoolP512r1: 1.3.36.3.3.2.8.1.1.13 */ +#define OCK_BRAINPOOL_P512R1 { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, \ + 0x02, 0x08, 0x01, 0x01, 0x0D } + +/* brainpoolP512t1: 1.3.36.3.3.2.8.1.1.14 */ +#define OCK_BRAINPOOL_P512T1 { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, \ + 0x02, 0x08, 0x01, 0x01, 0x0E } + +/* prime192: 1.2.840.10045.3.1.1 */ +#define OCK_PRIME192V1 { 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, \ + 0x3D, 0x03, 0x01, 0x01 } + + /* secp224: 1.3.132.0.33 */ +#define OCK_SECP224R1 { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x21 } + + /* prime256: 1.2.840.10045.3.1.7 */ +#define OCK_PRIME256V1 { 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, \ + 0x3D, 0x03, 0x01, 0x07 } + + /* secp384: 1.3.132.0.34 */ +#define OCK_SECP384R1 { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22 } + +/* secp521: 1.3.132.0.35 */ +#define OCK_SECP521R1 { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23 } + +/* secp256k1: 1.3.132.0.10 */ +#define OCK_SECP256K1 { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x0A } + +/* Curve25519 (also called X25519): 1.3.101.110 */ +#define OCK_CURVE25519 { 0x06, 0x03, 0x2B, 0x65, 0x6E } + +/* Curve448 (also called X448):1.3.101.111 */ +#define OCK_CURVE448 { 0x06, 0x03, 0x2B, 0x65, 0x6F } + +/* Ed25519: 1.3.101.112 */ +#define OCK_ED25519 { 0x06, 0x03, 0x2B, 0x65, 0x70 } + +/* Ed448: 1.3.101.113 */ +#define OCK_ED448 { 0x06, 0x03, 0x2B, 0x65, 0x71 } + +#endif // _EC_CURVES_H_ diff --git a/usr/include/include.mk b/usr/include/include.mk new file mode 100644 index 0000000..a36afb2 --- /dev/null +++ b/usr/include/include.mk @@ -0,0 +1,10 @@ +opencryptokiincludedir = ${includedir}/opencryptoki + +opencryptokiinclude_HEADERS = \ + usr/include/apiclient.h usr/include/pkcs11types.h \ + usr/include/pkcs11.h \ + usr/include/ec_curves.h + +noinst_HEADERS += \ + usr/include/apictl.h usr/include/local_types.h \ + usr/include/pkcs32.h usr/include/slotmgr.h usr/include/stdll.h diff --git a/usr/include/local_types.h b/usr/include/local_types.h new file mode 100644 index 0000000..f03c662 --- /dev/null +++ b/usr/include/local_types.h @@ -0,0 +1,76 @@ +/* + * 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 + */ + +#ifndef __LOCAL_TYPES +#define __LOCAL_TYPES + +typedef unsigned char uint8; + +typedef unsigned short uint16; +// typedef short int16; + +typedef unsigned int uint32; +// typedef int int32; + + +/* 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 + +/* Binary tree node + * - 20 bytes on 32bit platform + * - 40 bytes on 64bit platform + */ +struct btnode { + struct btnode *left; + struct btnode *right; + struct btnode *parent; + unsigned long flags; + void *value; +}; + +/* Binary tree root */ +struct btree { + struct btnode *free_list; + struct btnode *top; + unsigned long size; + unsigned long free_nodes; +#ifdef ENABLE_LOCKS + pthread_mutex_t mutex; +#endif + void (*delete_func)(void *); +}; + +typedef struct _STDLL_TokData_t STDLL_TokData_t; +typedef struct _LW_SHM_TYPE LW_SHM_TYPE; +typedef struct API_Slot API_Slot_t; + +struct btnode *bt_get_node(struct btree *t, unsigned long node_num); +void *bt_get_node_value(struct btree *t, unsigned long node_num); +int bt_put_node_value(struct btree *t, void *value); +int bt_is_empty(struct btree *t); +void bt_for_each_node(STDLL_TokData_t *, struct btree *t, + void (*)(STDLL_TokData_t *, void *, unsigned long, + void *), void *); +unsigned long bt_nodes_in_use(struct btree *t); +unsigned long bt_node_add(struct btree *t, void *value); +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 *)); + +#endif diff --git a/usr/include/pkcs11.h b/usr/include/pkcs11.h new file mode 100644 index 0000000..f3d81f9 --- /dev/null +++ b/usr/include/pkcs11.h @@ -0,0 +1,17 @@ +/* + * 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 + */ + +#ifndef OPENCRYPTOKI_PKCS11_H +#define OPENCRYPTOKI_PKCS11_H + +#include +#include + +#endif diff --git a/usr/include/pkcs11types.h b/usr/include/pkcs11types.h new file mode 100644 index 0000000..a0e7a50 --- /dev/null +++ b/usr/include/pkcs11types.h @@ -0,0 +1,1775 @@ +/* + * 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: PKCS11Types.h +// +// +//---------------------------------------------------------------------------- + + +#ifndef _PKCS11TYPES_H_ +#define _PKCS11TYPES_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + +#define CK_TRUE 1 +#define CK_FALSE 0 + +#ifndef CK_DISABLE_TRUE_FALSE +#ifndef FALSE +#define FALSE CK_FALSE +#endif + +#ifndef TRUE +#define TRUE CK_TRUE +#endif +#endif + +// AIX Addition for 64Bit work. +// All types are 32bit types, therefore the longs have to be +// typedefed to be 32bit values. +typedef unsigned int uint_32; +typedef int int_32; + +#define CK_PTR * + +#define CK_CALLBACK_FUNCTION(returnType, name) \ + returnType (* name) + +#ifndef NULL_PTR +#define NULL_PTR NULL +#endif /* NULL_PTR */ + +/* an unsigned 8-bit value */ +typedef unsigned char CK_BYTE; + +/* an unsigned 8-bit character */ +typedef CK_BYTE CK_CHAR; + +/* an 8-bit UTF-8 character */ +typedef CK_BYTE CK_UTF8CHAR; + +/* a BYTE-sized Boolean flag */ +typedef CK_BYTE CK_BBOOL; + +/* an unsigned value, at least 32 bits long */ +typedef unsigned long int CK_ULONG; + +/* a signed value, the same size as a CK_ULONG */ +/* CK_LONG is new for v2.0 */ +typedef long int CK_LONG; + +/* at least 32 bits; each bit is a Boolean flag */ +typedef CK_ULONG CK_FLAGS; + + +/* some special values for certain CK_ULONG variables */ +#define CK_UNAVAILABLE_INFORMATION (~0UL) +#define CK_EFFECTIVELY_INFINITE 0 + + +typedef CK_BYTE CK_PTR CK_BYTE_PTR; +typedef CK_CHAR CK_PTR CK_CHAR_PTR; +typedef CK_UTF8CHAR CK_PTR CK_UTF8CHAR_PTR; +typedef CK_ULONG CK_PTR CK_ULONG_PTR; +typedef void CK_PTR CK_VOID_PTR; + +/* Pointer to a CK_VOID_PTR-- i.e., pointer to pointer to void */ +typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR; + + +/* The following value is always invalid if used as a session */ +/* handle or object handle */ +#define CK_INVALID_HANDLE 0 + + +typedef struct CK_VERSION { + CK_BYTE major; /* integer portion of version number */ + CK_BYTE minor; /* 1/100ths portion of version number */ +} CK_VERSION; + +typedef CK_VERSION CK_PTR CK_VERSION_PTR; + + +typedef struct CK_INFO { + CK_VERSION cryptokiVersion; /* Cryptoki interface ver */ + CK_CHAR manufacturerID[32]; /* blank padded */ + CK_FLAGS flags; /* must be zero */ + + /* libraryDescription and libraryVersion are new for v2.0 */ + CK_CHAR libraryDescription[32]; /* blank padded */ + CK_VERSION libraryVersion; /* version of library */ +} CK_INFO; + +typedef CK_INFO CK_PTR CK_INFO_PTR; + + +/* CK_NOTIFICATION enumerates the types of notifications that + * Cryptoki provides to an application */ +/* CK_NOTIFICATION has been changed from an enum to a CK_ULONG + * for v2.0 */ +typedef CK_ULONG CK_NOTIFICATION; +#define CKN_SURRENDER 0 + + +typedef CK_ULONG CK_SLOT_ID; + +typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR; + + +/* CK_SLOT_INFO provides information about a slot */ +typedef struct CK_SLOT_INFO { + CK_CHAR slotDescription[64]; /* blank padded */ + CK_CHAR manufacturerID[32]; /* blank padded */ + CK_FLAGS flags; + + /* hardwareVersion and firmwareVersion are new for v2.0 */ + CK_VERSION hardwareVersion; /* version of hardware */ + CK_VERSION firmwareVersion; /* version of firmware */ +} CK_SLOT_INFO; + +/* flags: bit flags that provide capabilities of the slot + * Bit Flag Mask Meaning + */ +#define CKF_TOKEN_PRESENT 0x00000001 /* a token is there */ +#define CKF_REMOVABLE_DEVICE 0x00000002 /* removable devices */ +#define CKF_HW_SLOT 0x00000004 /* hardware slot */ + +typedef CK_SLOT_INFO CK_PTR CK_SLOT_INFO_PTR; + + +/* CK_TOKEN_INFO provides information about a token */ +typedef struct CK_TOKEN_INFO { + CK_CHAR label[32]; /* blank padded */ + CK_CHAR manufacturerID[32]; /* blank padded */ + CK_CHAR model[16]; /* blank padded */ + CK_CHAR serialNumber[16]; /* blank padded */ + CK_FLAGS flags; /* see below */ + + /* ulMaxSessionCount, ulSessionCount, ulMaxRwSessionCount, + * ulRwSessionCount, ulMaxPinLen, and ulMinPinLen have all been + * changed from CK_USHORT to CK_ULONG for v2.0 */ + CK_ULONG ulMaxSessionCount; /* max open sessions */ + CK_ULONG ulSessionCount; /* sess. now open */ + CK_ULONG ulMaxRwSessionCount; /* max R/W sessions */ + CK_ULONG ulRwSessionCount; /* R/W sess. now open */ + CK_ULONG ulMaxPinLen; /* in bytes */ + CK_ULONG ulMinPinLen; /* in bytes */ + CK_ULONG ulTotalPublicMemory; /* in bytes */ + CK_ULONG ulFreePublicMemory; /* in bytes */ + CK_ULONG ulTotalPrivateMemory; /* in bytes */ + CK_ULONG ulFreePrivateMemory; /* in bytes */ + + /* hardwareVersion, firmwareVersion, and time are new for + * v2.0 */ + CK_VERSION hardwareVersion; /* version of hardware */ + CK_VERSION firmwareVersion; /* version of firmware */ + CK_CHAR utcTime[16]; /* time */ +} CK_TOKEN_INFO; + +/* The flags parameter is defined as follows: + * Bit Flag Mask Meaning + */ +#define CKF_RNG 0x00000001 /* has random # + * generator */ +#define CKF_WRITE_PROTECTED 0x00000002 /* token is + * write- + * protected */ +#define CKF_LOGIN_REQUIRED 0x00000004 /* user must + * login */ +#define CKF_USER_PIN_INITIALIZED 0x00000008 /* normal user's + * PIN is set */ + +/* CKF_RESTORE_KEY_NOT_NEEDED is new for v2.0. If it is set, + * that means that *every* time the state of cryptographic + * operations of a session is successfully saved, all keys + * needed to continue those operations are stored in the state */ +#define CKF_RESTORE_KEY_NOT_NEEDED 0x00000020 + +/* CKF_CLOCK_ON_TOKEN is new for v2.0. If it is set, that means + * that the token has some sort of clock. The time on that + * clock is returned in the token info structure */ +#define CKF_CLOCK_ON_TOKEN 0x00000040 + +/* CKF_PROTECTED_AUTHENTICATION_PATH is new for v2.0. If it is + * set, that means that there is some way for the user to login + * without sending a PIN through the Cryptoki library itself */ +#define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100 + +/* CKF_DUAL_CRYPTO_OPERATIONS is new for v2.0. If it is true, + * that means that a single session with the token can perform + * dual simultaneous cryptographic operations (digest and + * encrypt; decrypt and digest; sign and encrypt; and decrypt + * and sign) */ +#define CKF_DUAL_CRYPTO_OPERATIONS 0x00000200 + +/* CKF_TOKEN_INITIALIZED is new for v2.11. If it is true, the + * token has been initialized using C_InitializeToken or an + * equivalent mechanism outside the scope of this standard. + * Calling C_InitializeToken when this flag is set will cause + * the token to be reinitialized. */ +#define CKF_TOKEN_INITIALIZED 0x00000400 + +/* CKF_SECONDARY_AUTHENTICATION is new for v2.11. If it is + * true, the token supports secondary authentication for private + * key objects. According to the 2.11 spec pg. 45, this flag + * is deprecated and this flags should never be true. */ +#define CKF_SECONDARY_AUTHENTICATION 0x00000800 + +/* CKF_USER_PIN_COUNT_LOW is new in v2.11. This flag is true + * is an incorrect user PIN has been entered at least once + * since the last successful authentication. */ +#define CKF_USER_PIN_COUNT_LOW 0x00010000 + +/* CKF_USER_PIN_FINAL_TRY is new in v2.11. This flag is true if + * supplying an incorrect user PIN will cause it to become + * locked. */ +#define CKF_USER_PIN_FINAL_TRY 0x00020000 + +/* CKF_USER_PIN_LOCKED is new in v2.11. This is true if the + * user PIN has been locked. User login to the token is not + * possible. */ +#define CKF_USER_PIN_LOCKED 0x00040000 + +/* CKF_USER_PIN_TO_BE_CHANGED is new in v2.11. This flag is + * true if the user PIN value is the default value set by + * token initialization of manufacturing, or the PIN has + * been expired by the card. */ +#define CKF_USER_PIN_TO_BE_CHANGED 0x00080000 + +/* CKF_SO_PIN_COUNT_LOW is new in v2.11. This flag is true if + * and incorrect SO login PIN has been entered at least once + * since the last successful authentication. */ +#define CKF_SO_PIN_COUNT_LOW 0x00100000 + +/* CKF_SO_PIN_FINAL_TRY is new in v2.11. This flag is true if + * supplying an incorrect SO PIN will cause it to become + * locked. */ +#define CKF_SO_PIN_FINAL_TRY 0x00200000 + +/* CKF_SO_PIN_LOCKED is new in v2.11. This flag is true if + * the SO PIN has been locked. User login to the token is not + * possible. */ +#define CKF_SO_PIN_LOCKED 0x00400000 + +/* CKF_SO_PIN_TO_BE_CHANGED is new in v2.11. This flag is true + * if the SO PIN calue is the default value set by token init- + * ialization of manufacturing, or the PIN has been expired by + * the card. */ +#define CKF_SO_PIN_TO_BE_CHANGED 0x00800000 + +#if 0 +/* IBM extended Token Info Flags - defined by Michael Hamann */ +/* These Flags are not part of PKCS#11 Version 2.01 */ + +/* This will be used to track the state of login retries */ +#define CKF_USER_PIN_COUNT_LOW 0x00010000 +#define CKF_USER_PIN_FINAL_TRY 0x00020000 +#define CKF_USER_PIN_LOCKED 0x00040000 +#define CKF_USER_PIN_MANUFACT_VALUE 0x00080000 + +#define CKF_SO_PIN_COUNT_LOW 0x00100000 +#define CKF_SO_PIN_FINAL_TRY 0x00200000 +#define CKF_SO_PIN_LOCKED 0x00400000 +#define CKF_SO_PIN_MANUFACT_VALUE 0x00800000 +#endif + +/* other IBM extended Token info Flags 05/29/99 */ +// Sec Officer pin on card is derived from card id +#define CKF_SO_PIN_DERIVED 0x01000000 +// Security Officer Card +#define CKF_SO_CARD 0x02000000 +/* End of IBM extented Token Info Flags */ + + +typedef CK_TOKEN_INFO CK_PTR CK_TOKEN_INFO_PTR; + +/* CK_SESSION_HANDLE is a Cryptoki-assigned value that + * identifies a session */ +typedef CK_ULONG CK_SESSION_HANDLE; + +typedef CK_SESSION_HANDLE CK_PTR CK_SESSION_HANDLE_PTR; + + +/* CK_USER_TYPE enumerates the types of Cryptoki users */ +/* CK_USER_TYPE has been changed from an enum to a CK_ULONG for + * v2.0 */ +typedef CK_ULONG CK_USER_TYPE; +/* Security Officer */ +#define CKU_SO 0 +/* Normal user */ +#define CKU_USER 1 + + +/* CK_STATE enumerates the session states */ +/* CK_STATE has been changed from an enum to a CK_ULONG for + * v2.0 */ +typedef CK_ULONG CK_STATE; +#define CKS_RO_PUBLIC_SESSION 0 +#define CKS_RO_USER_FUNCTIONS 1 +#define CKS_RW_PUBLIC_SESSION 2 +#define CKS_RW_USER_FUNCTIONS 3 +#define CKS_RW_SO_FUNCTIONS 4 + + +/* CK_SESSION_INFO provides information about a session */ +typedef struct CK_SESSION_INFO { + CK_SLOT_ID slotID; + CK_STATE state; + CK_FLAGS flags; /* see below */ + + /* ulDeviceError was changed from CK_USHORT to CK_ULONG for + * v2.0 */ + CK_ULONG ulDeviceError; /* device-dependent error code */ +} CK_SESSION_INFO; + +/* The flags are defined in the following table: + * Bit Flag Mask Meaning + */ +#define CKF_RW_SESSION 0x00000002 /* session is r/w */ +#define CKF_SERIAL_SESSION 0x00000004 /* no parallel */ + +typedef CK_SESSION_INFO CK_PTR CK_SESSION_INFO_PTR; + + +/* CK_OBJECT_HANDLE is a token-specific identifier for an + * object */ +typedef CK_ULONG CK_OBJECT_HANDLE; + +typedef CK_OBJECT_HANDLE CK_PTR CK_OBJECT_HANDLE_PTR; + + +/* CK_OBJECT_CLASS is a value that identifies the classes (or + * types) of objects that Cryptoki recognizes. It is defined + * as follows: */ +/* CK_OBJECT_CLASS was changed from CK_USHORT to CK_ULONG for + * v2.0 */ +typedef CK_ULONG CK_OBJECT_CLASS; + +/* The following classes of objects are defined: */ +#define CKO_DATA 0x00000000 +#define CKO_CERTIFICATE 0x00000001 +#define CKO_PUBLIC_KEY 0x00000002 +#define CKO_PRIVATE_KEY 0x00000003 +#define CKO_SECRET_KEY 0x00000004 +/* CKO_HW_FEATURE and CKO_DOMAIN_PARAMETERS are new for v2.11 */ +#define CKO_HW_FEATURE 0x00000005 +#define CKO_DOMAIN_PARAMETERS 0x00000006 +#define CKO_VENDOR_DEFINED 0x80000000 + +typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR; + +/* CK_HW_FEATURE_TYPE is a value that identifies a hardware + * feature type of a device. This is new for v2.11. + */ +typedef CK_ULONG CK_HW_FEATURE_TYPE; + +/* The following hardware feature types are defined: */ +#define CKH_MONOTONIC_COUNTER 0x00000001 +#define CKH_CLOCK 0x00000002 +#define CKH_VENDOR_DEFINED 0x80000000 + + +/* CK_KEY_TYPE is a value that identifies a key type */ +/* CK_KEY_TYPE was changed from CK_USHORT to CK_ULONG for v2.0 */ +typedef CK_ULONG CK_KEY_TYPE; + +/* the following key types are defined: */ +#define CKK_RSA 0x00000000 +#define CKK_DSA 0x00000001 +#define CKK_DH 0x00000002 + +/* CKK_ECDSA and CKK_KEA are new for v2.0 */ +/* CKK_ECDSA is deprecated in v2.11, CKK_EC is preferred */ +#define CKK_ECDSA 0x00000003 +#define CKK_EC 0x00000003 +#define CKK_X9_42_DH 0x00000004 +#define CKK_KEA 0x00000005 + +#define CKK_GENERIC_SECRET 0x00000010 +#define CKK_RC2 0x00000011 +#define CKK_RC4 0x00000012 +#define CKK_DES 0x00000013 +#define CKK_DES2 0x00000014 +#define CKK_DES3 0x00000015 + +/* all these key types are new for v2.0 */ +#define CKK_CAST 0x00000016 +#define CKK_CAST3 0x00000017 +/* CKK_CAST5 is deprecated in v2.11, CKK_CAST128 is preferred */ +#define CKK_CAST5 0x00000018 +#define CKK_CAST128 0x00000018 /* CAST128=CAST5 */ +#define CKK_RC5 0x00000019 +#define CKK_IDEA 0x0000001A +#define CKK_SKIPJACK 0x0000001B +#define CKK_BATON 0x0000001C +#define CKK_JUNIPER 0x0000001D +#define CKK_CDMF 0x0000001E +/* CKK_AES is new for v2.11 */ +#define CKK_AES 0x0000001F + +#define CKK_VENDOR_DEFINED 0x80000000 + +#define CKK_IBM_PQC_DILITHIUM CKK_VENDOR_DEFINED + 0x10023 + +/* CK_CERTIFICATE_TYPE is a value that identifies a certificate + * type */ +/* CK_CERTIFICATE_TYPE was changed from CK_USHORT to CK_ULONG + * for v2.0 */ +typedef CK_ULONG CK_CERTIFICATE_TYPE; + +/* The following certificate types are defined: */ +#define CKC_X_509 0x00000000 +/* CKC_X_509_ATTR_CERT is new for v2.11 */ +#define CKC_X_509_ATTR_CERT 0x00000001 +#define CKC_VENDOR_DEFINED 0x80000000 + + +/* CK_ATTRIBUTE_TYPE is a value that identifies an attribute + * type */ +/* CK_ATTRIBUTE_TYPE was changed from CK_USHORT to CK_ULONG for + * v2.0 */ +typedef CK_ULONG CK_ATTRIBUTE_TYPE; + +/* The CKF_ARRAY_ATTRIBUTE flag identifies an attribute which + * consists of an array of values. */ +#define CKF_ARRAY_ATTRIBUTE 0x40000000 + +/* The following attribute types are defined: */ +#define CKA_CLASS 0x00000000 +#define CKA_TOKEN 0x00000001 +#define CKA_PRIVATE 0x00000002 +#define CKA_LABEL 0x00000003 +#define CKA_APPLICATION 0x00000010 +#define CKA_VALUE 0x00000011 +/* CKA_OBJECT_ID is new for v2.11 */ +#define CKA_OBJECT_ID 0x00000012 +#define CKA_CERTIFICATE_TYPE 0x00000080 +#define CKA_ISSUER 0x00000081 +#define CKA_SERIAL_NUMBER 0x00000082 +/* CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES and CKA_TRUSTED + * are new for v2.11 */ +#define CKA_AC_ISSUER 0x00000083 +#define CKA_OWNER 0x00000084 +#define CKA_ATTR_TYPES 0x00000085 +#define CKA_TRUSTED 0x00000086 + +#define CKA_KEY_TYPE 0x00000100 +#define CKA_SUBJECT 0x00000101 +#define CKA_ID 0x00000102 +#define CKA_SENSITIVE 0x00000103 +#define CKA_ENCRYPT 0x00000104 +#define CKA_DECRYPT 0x00000105 +#define CKA_WRAP 0x00000106 +#define CKA_UNWRAP 0x00000107 +#define CKA_SIGN 0x00000108 +#define CKA_SIGN_RECOVER 0x00000109 +#define CKA_VERIFY 0x0000010A +#define CKA_VERIFY_RECOVER 0x0000010B +#define CKA_DERIVE 0x0000010C +#define CKA_START_DATE 0x00000110 +#define CKA_END_DATE 0x00000111 +#define CKA_MODULUS 0x00000120 +#define CKA_MODULUS_BITS 0x00000121 +#define CKA_PUBLIC_EXPONENT 0x00000122 +#define CKA_PRIVATE_EXPONENT 0x00000123 +#define CKA_PRIME_1 0x00000124 +#define CKA_PRIME_2 0x00000125 +#define CKA_EXPONENT_1 0x00000126 +#define CKA_EXPONENT_2 0x00000127 +#define CKA_COEFFICIENT 0x00000128 +#define CKA_PRIME 0x00000130 +#define CKA_SUBPRIME 0x00000131 +#define CKA_BASE 0x00000132 +/* CKA_PRIME_BITS and CKA_SUB_PRIME_BITS are new for v2.11 */ +#define CKA_PRIME_BITS 0x00000133 +#define CKA_SUBPRIME_BITS 0x00000134 + +#define CKA_VALUE_BITS 0x00000160 +#define CKA_VALUE_LEN 0x00000161 + +/* CKA_EXTRACTABLE, CKA_LOCAL, CKA_NEVER_EXTRACTABLE, + * CKA_ALWAYS_SENSITIVE, CKA_MODIFIABLE, CKA_ECDSA_PARAMS, + * and CKA_EC_POINT are new for v2.0 */ +#define CKA_EXTRACTABLE 0x00000162 +#define CKA_LOCAL 0x00000163 +#define CKA_NEVER_EXTRACTABLE 0x00000164 +#define CKA_ALWAYS_SENSITIVE 0x00000165 +/* CKA_KEY_GEN_MECHANISM is new for v2.11 */ +#define CKA_KEY_GEN_MECHANISM 0x00000166 +#define CKA_MODIFIABLE 0x00000170 +/* CKA_ECDSA_PARAMS is deprecated in v2.11, CKA_EC_PARAMS is preferred */ +#define CKA_ECDSA_PARAMS 0x00000180 +#define CKA_EC_PARAMS 0x00000180 +#define CKA_EC_POINT 0x00000181 +/* The following are new for v2.11 */ +#define CKA_SECONDARY_AUTH 0x00000200 +#define CKA_AUTH_PIN_FLAGS 0x00000201 +#define CKA_ALWAYS_AUTHENTICATE 0x00000202 +#define CKA_HW_FEATURE_TYPE 0x00000300 +#define CKA_RESET_ON_INIT 0x00000301 +#define CKA_HAS_RESET 0x00000302 + +#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000211UL) +#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000212UL) + +#define CKA_VENDOR_DEFINED 0x80000000 + +/* For use in storing objects that have an encrypted or otherwise + * 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_RESTRICTABLE (CKA_VENDOR_DEFINED +0x10001) +#define CKA_IBM_NEVER_MODIFIABLE (CKA_VENDOR_DEFINED +0x10002) +#define CKA_IBM_RETAINKEY (CKA_VENDOR_DEFINED +0x10003) +#define CKA_IBM_ATTRBOUND (CKA_VENDOR_DEFINED +0x10004) +#define CKA_IBM_KEYTYPE (CKA_VENDOR_DEFINED +0x10005) +#define CKA_IBM_CV (CKA_VENDOR_DEFINED +0x10006) +#define CKA_IBM_MACKEY (CKA_VENDOR_DEFINED +0x10007) +#define CKA_IBM_USE_AS_DATA (CKA_VENDOR_DEFINED +0x10008) +#define CKA_IBM_STRUCT_PARAMS (CKA_VENDOR_DEFINED +0x10009) +#define CKA_IBM_STD_COMPLIANCE1 (CKA_VENDOR_DEFINED +0x1000a) + +/* For Dilithium, oid = 1.3.6.1.4.1.2.267.1.6.5 */ +#define IBM_DILITHIUM_KEYFORM_ROUND2 1 + +#define CKA_IBM_DILITHIUM_KEYFORM (CKA_VENDOR_DEFINED + 0xd0001) +#define CKA_IBM_DILITHIUM_RHO (CKA_VENDOR_DEFINED + 0xd0002) +#define CKA_IBM_DILITHIUM_SEED (CKA_VENDOR_DEFINED + 0xd0003) +#define CKA_IBM_DILITHIUM_TR (CKA_VENDOR_DEFINED + 0xd0004) +#define CKA_IBM_DILITHIUM_S1 (CKA_VENDOR_DEFINED + 0xd0005) +#define CKA_IBM_DILITHIUM_S2 (CKA_VENDOR_DEFINED + 0xd0006) +#define CKA_IBM_DILITHIUM_T0 (CKA_VENDOR_DEFINED + 0xd0007) +#define CKA_IBM_DILITHIUM_T1 (CKA_VENDOR_DEFINED + 0xd0008) + +/* For NSS 3.30: */ +#define NSSCK_VENDOR_NSS 0x4E534350 +#define CKA_NSS (CKA_VENDOR_DEFINED | NSSCK_VENDOR_NSS) +#define CKA_NSS_MOZILLA_CA_POLICY (CKA_NSS + 34) + +/* CK_ATTRIBUTE is a structure that includes the type, length + * and value of an attribute */ +typedef struct CK_ATTRIBUTE { + CK_ATTRIBUTE_TYPE type; + CK_VOID_PTR pValue; + + /* ulValueLen went from CK_USHORT to CK_ULONG for v2.0 */ + CK_ULONG ulValueLen; /* in bytes */ +} CK_ATTRIBUTE; + +typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR; + + +/* CK_DATE is a structure that defines a date */ +typedef struct CK_DATE { + CK_CHAR year[4]; /* the year ("1900" - "9999") */ + CK_CHAR month[2]; /* the month ("01" - "12") */ + CK_CHAR day[2]; /* the day ("01" - "31") */ +} CK_DATE; + + +/* CK_MECHANISM_TYPE is a value that identifies a mechanism + * type */ +/* CK_MECHANISM_TYPE was changed from CK_USHORT to CK_ULONG for + * v2.0 */ +typedef CK_ULONG CK_MECHANISM_TYPE; + +/* the following mechanism types are defined: */ +#define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000 +#define CKM_RSA_PKCS 0x00000001 +#define CKM_RSA_9796 0x00000002 +#define CKM_RSA_X_509 0x00000003 + +/* CKM_MD2_RSA_PKCS, CKM_MD5_RSA_PKCS, and CKM_SHA1_RSA_PKCS + * are new for v2.0. They are mechanisms which hash and sign */ +#define CKM_MD2_RSA_PKCS 0x00000004 +#define CKM_MD5_RSA_PKCS 0x00000005 +#define CKM_SHA1_RSA_PKCS 0x00000006 +/* The following are new for v2.11: */ +#define CKM_RIPEMD128_RSA_PKCS 0x00000007 +#define CKM_RIPEMD160_RSA_PKCS 0x00000008 +#define CKM_RSA_PKCS_OAEP 0x00000009 +#define CKM_RSA_X9_31_KEY_PAIR_GEN 0x0000000A +#define CKM_RSA_X9_31 0x0000000B +#define CKM_SHA1_RSA_X9_31 0x0000000C +#define CKM_RSA_PKCS_PSS 0x0000000D +#define CKM_SHA1_RSA_PKCS_PSS 0x0000000E + +#define CKM_DSA_KEY_PAIR_GEN 0x00000010 +#define CKM_DSA 0x00000011 +#define CKM_DSA_SHA1 0x00000012 +#define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020 +#define CKM_DH_PKCS_DERIVE 0x00000021 +/* The following are new for v2.11 */ +#define CKM_X9_42_DH_KEY_PAIR_GEN 0x00000030 +#define CKM_X9_42_DH_DERIVE 0x00000031 +#define CKM_X9_42_DH_HYBRID_DERIVE 0x00000032 +#define CKM_X9_42_MQV_DERIVE 0x00000033 + +#define CKM_SHA224_RSA_PKCS 0x00000046 +#define CKM_SHA256_RSA_PKCS 0x00000040 +#define CKM_SHA384_RSA_PKCS 0x00000041 +#define CKM_SHA512_RSA_PKCS 0x00000042 + +#define CKM_SHA224_RSA_PKCS_PSS 0x00000047 +#define CKM_SHA256_RSA_PKCS_PSS 0x00000043 +#define CKM_SHA384_RSA_PKCS_PSS 0x00000044 +#define CKM_SHA512_RSA_PKCS_PSS 0x00000045 + +#define CKM_RC2_KEY_GEN 0x00000100 +#define CKM_RC2_ECB 0x00000101 +#define CKM_RC2_CBC 0x00000102 +#define CKM_RC2_MAC 0x00000103 + +/* CKM_RC2_MAC_GENERAL and CKM_RC2_CBC_PAD are new for v2.0 */ +#define CKM_RC2_MAC_GENERAL 0x00000104 +#define CKM_RC2_CBC_PAD 0x00000105 + +#define CKM_RC4_KEY_GEN 0x00000110 +#define CKM_RC4 0x00000111 +#define CKM_DES_KEY_GEN 0x00000120 +#define CKM_DES_ECB 0x00000121 +#define CKM_DES_CBC 0x00000122 +#define CKM_DES_MAC 0x00000123 + +/* CKM_DES_MAC_GENERAL and CKM_DES_CBC_PAD are new for v2.0 */ +#define CKM_DES_MAC_GENERAL 0x00000124 +#define CKM_DES_CBC_PAD 0x00000125 + +#define CKM_DES2_KEY_GEN 0x00000130 +#define CKM_DES3_KEY_GEN 0x00000131 +#define CKM_DES3_ECB 0x00000132 +#define CKM_DES3_CBC 0x00000133 +#define CKM_DES3_MAC 0x00000134 + +/* CKM_DES3_MAC_GENERAL, CKM_DES3_CBC_PAD, CKM_CDMF_KEY_GEN, + * CKM_CDMF_ECB, CKM_CDMF_CBC, CKM_CDMF_MAC, + * CKM_CDMF_MAC_GENERAL, and CKM_CDMF_CBC_PAD are new for v2.0 */ +#define CKM_DES3_MAC_GENERAL 0x00000135 +#define CKM_DES3_CBC_PAD 0x00000136 +#define CKM_DES3_CMAC_GENERAL 0x00000137 +#define CKM_DES3_CMAC 0x00000138 +#define CKM_CDMF_KEY_GEN 0x00000140 +#define CKM_CDMF_ECB 0x00000141 +#define CKM_CDMF_CBC 0x00000142 +#define CKM_CDMF_MAC 0x00000143 +#define CKM_CDMF_MAC_GENERAL 0x00000144 +#define CKM_CDMF_CBC_PAD 0x00000145 + +#define CKM_DES_OFB64 0x00000150 +#define CKM_DES_CFB64 0x00000152 +#define CKM_DES_CFB8 0x00000153 + +#define CKM_MD2 0x00000200 + +/* CKM_MD2_HMAC and CKM_MD2_HMAC_GENERAL are new for v2.0 */ +#define CKM_MD2_HMAC 0x00000201 +#define CKM_MD2_HMAC_GENERAL 0x00000202 + +#define CKM_MD5 0x00000210 + +/* CKM_MD5_HMAC and CKM_MD5_HMAC_GENERAL are new for v2.0 */ +#define CKM_MD5_HMAC 0x00000211 +#define CKM_MD5_HMAC_GENERAL 0x00000212 + +#define CKM_SHA_1 0x00000220 + +/* CKM_SHA_1_HMAC and CKM_SHA_1_HMAC_GENERAL are new for v2.0 */ +#define CKM_SHA_1_HMAC 0x00000221 +#define CKM_SHA_1_HMAC_GENERAL 0x00000222 + +/* The following are new for v2.11 */ +#define CKM_RIPEMD128 0x00000230 +#define CKM_RIPEMD128_HMAC 0x00000231 +#define CKM_RIPEMD128_HMAC_GENERAL 0x00000232 +#define CKM_RIPEMD160 0x00000240 +#define CKM_RIPEMD160_HMAC 0x00000241 +#define CKM_RIPEMD160_HMAC_GENERAL 0x00000242 + +#define CKM_SHA256 0x00000250 +#define CKM_SHA256_HMAC 0x00000251 +#define CKM_SHA256_HMAC_GENERAL 0x00000252 +#define CKM_SHA224 0x00000255 +#define CKM_SHA224_HMAC 0x00000256 +#define CKM_SHA224_HMAC_GENERAL 0x00000257 +#define CKM_SHA384 0x00000260 +#define CKM_SHA384_HMAC 0x00000261 +#define CKM_SHA384_HMAC_GENERAL 0x00000262 +#define CKM_SHA512 0x00000270 +#define CKM_SHA512_HMAC 0x00000271 +#define CKM_SHA512_HMAC_GENERAL 0x00000272 + +#define CKM_SHA512_224 0x00000048 +#define CKM_SHA512_224_HMAC 0x00000049 +#define CKM_SHA512_224_HMAC_GENERAL 0x0000004A +#define CKM_SHA512_256 0x0000004C +#define CKM_SHA512_256_HMAC 0x0000004D +#define CKM_SHA512_256_HMAC_GENERAL 0x0000004E + +/* All of the following mechanisms are new for v2.0 */ +/* Note that CAST128 and CAST5 are the same algorithm */ +#define CKM_CAST_KEY_GEN 0x00000300 +#define CKM_CAST_ECB 0x00000301 +#define CKM_CAST_CBC 0x00000302 +#define CKM_CAST_MAC 0x00000303 +#define CKM_CAST_MAC_GENERAL 0x00000304 +#define CKM_CAST_CBC_PAD 0x00000305 +#define CKM_CAST3_KEY_GEN 0x00000310 +#define CKM_CAST3_ECB 0x00000311 +#define CKM_CAST3_CBC 0x00000312 +#define CKM_CAST3_MAC 0x00000313 +#define CKM_CAST3_MAC_GENERAL 0x00000314 +#define CKM_CAST3_CBC_PAD 0x00000315 +#define CKM_CAST5_KEY_GEN 0x00000320 +#define CKM_CAST128_KEY_GEN 0x00000320 +#define CKM_CAST5_ECB 0x00000321 +#define CKM_CAST128_ECB 0x00000321 +#define CKM_CAST5_CBC 0x00000322 +#define CKM_CAST128_CBC 0x00000322 +#define CKM_CAST5_MAC 0x00000323 +#define CKM_CAST128_MAC 0x00000323 +#define CKM_CAST5_MAC_GENERAL 0x00000324 +#define CKM_CAST128_MAC_GENERAL 0x00000324 +#define CKM_CAST5_CBC_PAD 0x00000325 +#define CKM_CAST128_CBC_PAD 0x00000325 +#define CKM_RC5_KEY_GEN 0x00000330 +#define CKM_RC5_ECB 0x00000331 +#define CKM_RC5_CBC 0x00000332 +#define CKM_RC5_MAC 0x00000333 +#define CKM_RC5_MAC_GENERAL 0x00000334 +#define CKM_RC5_CBC_PAD 0x00000335 +#define CKM_IDEA_KEY_GEN 0x00000340 +#define CKM_IDEA_ECB 0x00000341 +#define CKM_IDEA_CBC 0x00000342 +#define CKM_IDEA_MAC 0x00000343 +#define CKM_IDEA_MAC_GENERAL 0x00000344 +#define CKM_IDEA_CBC_PAD 0x00000345 +#define CKM_GENERIC_SECRET_KEY_GEN 0x00000350 +#define CKM_CONCATENATE_BASE_AND_KEY 0x00000360 +#define CKM_CONCATENATE_BASE_AND_DATA 0x00000362 +#define CKM_CONCATENATE_DATA_AND_BASE 0x00000363 +#define CKM_XOR_BASE_AND_DATA 0x00000364 +#define CKM_EXTRACT_KEY_FROM_KEY 0x00000365 +#define CKM_SSL3_PRE_MASTER_KEY_GEN 0x00000370 +#define CKM_SSL3_MASTER_KEY_DERIVE 0x00000371 +#define CKM_SSL3_KEY_AND_MAC_DERIVE 0x00000372 +/* The following are new for v2.11 */ +#define CKM_SSL3_MASTER_KEY_DERIVE_DH 0x00000373 +#define CKM_TLS_PRE_MASTER_KEY_GEN 0x00000374 +#define CKM_TLS_MASTER_KEY_DERIVE 0x00000375 +#define CKM_TLS_KEY_AND_MAC_DERIVE 0x00000376 +#define CKM_TLS_MASTER_KEY_DERIVE_DH 0x00000377 + +#define CKM_SSL3_MD5_MAC 0x00000380 +#define CKM_SSL3_SHA1_MAC 0x00000381 +#define CKM_MD5_KEY_DERIVATION 0x00000390 +#define CKM_MD2_KEY_DERIVATION 0x00000391 +#define CKM_SHA1_KEY_DERIVATION 0x00000392 +#define CKM_SHA224_KEY_DERIVATION 0x00000396 +#define CKM_SHA256_KEY_DERIVATION 0x00000393 +#define CKM_SHA384_KEY_DERIVATION 0x00000394 +#define CKM_SHA512_KEY_DERIVATION 0x00000395 +#define CKM_PBE_MD2_DES_CBC 0x000003A0 +#define CKM_PBE_MD5_DES_CBC 0x000003A1 +#define CKM_PBE_MD5_CAST_CBC 0x000003A2 +#define CKM_PBE_MD5_CAST3_CBC 0x000003A3 +#define CKM_PBE_MD5_CAST5_CBC 0x000003A4 +#define CKM_PBE_MD5_CAST128_CBC 0x000003A4 +#define CKM_PBE_SHA1_CAST5_CBC 0x000003A5 +#define CKM_PBE_SHA1_CAST128_CBC 0x000003A5 +#define CKM_PBE_SHA1_RC4_128 0x000003A6 +#define CKM_PBE_SHA1_RC4_40 0x000003A7 +#define CKM_PBE_SHA1_DES3_EDE_CBC 0x000003A8 +#define CKM_PBE_SHA1_DES2_EDE_CBC 0x000003A9 +#define CKM_PBE_SHA1_RC2_128_CBC 0x000003AA +#define CKM_PBE_SHA1_RC2_40_CBC 0x000003AB +/* CKM_PKCS5_PBKD2 is new for v2.11 */ +#define CKM_PKCS5_PBKD2 0x000003B0 +#define CKM_PBA_SHA1_WITH_SHA1_HMAC 0x000003C0 +#define CKM_KEY_WRAP_LYNKS 0x00000400 +#define CKM_KEY_WRAP_SET_OAEP 0x00000401 + +/* Fortezza mechanisms */ +#define CKM_SKIPJACK_KEY_GEN 0x00001000 +#define CKM_SKIPJACK_ECB64 0x00001001 +#define CKM_SKIPJACK_CBC64 0x00001002 +#define CKM_SKIPJACK_OFB64 0x00001003 +#define CKM_SKIPJACK_CFB64 0x00001004 +#define CKM_SKIPJACK_CFB32 0x00001005 +#define CKM_SKIPJACK_CFB16 0x00001006 +#define CKM_SKIPJACK_CFB8 0x00001007 +#define CKM_SKIPJACK_WRAP 0x00001008 +#define CKM_SKIPJACK_PRIVATE_WRAP 0x00001009 +#define CKM_SKIPJACK_RELAYX 0x0000100a +#define CKM_KEA_KEY_PAIR_GEN 0x00001010 +#define CKM_KEA_KEY_DERIVE 0x00001011 +#define CKM_FORTEZZA_TIMESTAMP 0x00001020 +#define CKM_BATON_KEY_GEN 0x00001030 +#define CKM_BATON_ECB128 0x00001031 +#define CKM_BATON_ECB96 0x00001032 +#define CKM_BATON_CBC128 0x00001033 +#define CKM_BATON_COUNTER 0x00001034 +#define CKM_BATON_SHUFFLE 0x00001035 +#define CKM_BATON_WRAP 0x00001036 + +/* CKM_ECDSA_KEY_PAIR_GEN is deprecated in v2.11, + * CKM_EC_KEY_PAIR_GEN is preferred. */ +#define CKM_ECDSA_KEY_PAIR_GEN 0x00001040 +#define CKM_EC_KEY_PAIR_GEN 0x00001040 +#define CKM_ECDSA 0x00001041 +#define CKM_ECDSA_SHA1 0x00001042 +/* The following are new for v2.3 */ +#define CKM_ECDSA_SHA224 0x00001043 +#define CKM_ECDSA_SHA256 0x00001044 +#define CKM_ECDSA_SHA384 0x00001045 +#define CKM_ECDSA_SHA512 0x00001046 +/* The following are new for v2.11 */ +#define CKM_ECDH1_DERIVE 0x00001050 +#define CKM_ECDH1_COFACTOR_DERIVE 0x00001051 +#define CKM_ECMQV_DERIVE 0x00001052 + +#define CKM_JUNIPER_KEY_GEN 0x00001060 +#define CKM_JUNIPER_ECB128 0x00001061 +#define CKM_JUNIPER_CBC128 0x00001062 +#define CKM_JUNIPER_COUNTER 0x00001063 +#define CKM_JUNIPER_SHUFFLE 0x00001064 +#define CKM_JUNIPER_WRAP 0x00001065 +#define CKM_FASTHASH 0x00001070 +/* The following are new for v2.11 */ +#define CKM_AES_KEY_GEN 0x00001080 +#define CKM_AES_ECB 0x00001081 +#define CKM_AES_CBC 0x00001082 +#define CKM_AES_MAC 0x00001083 +#define CKM_AES_MAC_GENERAL 0x00001084 +#define CKM_AES_CBC_PAD 0x00001085 +#define CKM_AES_CTR 0x00001086 +#define CKM_AES_GCM 0x00001087 +#define CKM_AES_CMAC_GENERAL 0x00001089 +#define CKM_AES_CMAC 0x0000108A +#define CKM_DSA_PARAMETER_GEN 0x00002000 +#define CKM_DH_PKCS_PARAMETER_GEN 0x00002001 +#define CKM_X9_42_DH_PARAMETER_GEN 0x00002002 + +#define CKM_AES_OFB 0x00002104 +#define CKM_AES_CFB64 0x00002105 +#define CKM_AES_CFB8 0x00002106 +#define CKM_AES_CFB128 0x00002107 + +#define CKM_VENDOR_DEFINED 0x80000000 + +#define CKM_IBM_SHA3_224 CKM_VENDOR_DEFINED + 0x00010001 +#define CKM_IBM_SHA3_256 CKM_VENDOR_DEFINED + 0x00010002 +#define CKM_IBM_SHA3_384 CKM_VENDOR_DEFINED + 0x00010003 +#define CKM_IBM_SHA3_512 CKM_VENDOR_DEFINED + 0x00010004 +#define CKM_IBM_CMAC CKM_VENDOR_DEFINED + 0x00010007 +#define CKM_IBM_DILITHIUM CKM_VENDOR_DEFINED + 0x00010023 +#define CKM_IBM_SHA3_224_HMAC CKM_VENDOR_DEFINED + 0x00010025 +#define CKM_IBM_SHA3_256_HMAC CKM_VENDOR_DEFINED + 0x00010026 +#define CKM_IBM_SHA3_384_HMAC CKM_VENDOR_DEFINED + 0x00010027 +#define CKM_IBM_SHA3_512_HMAC CKM_VENDOR_DEFINED + 0x00010028 + +#define CKM_IBM_EC_C25519 CKM_VENDOR_DEFINED + 0x0001001b +#define CKM_IBM_EDDSA_SHA512 CKM_VENDOR_DEFINED + 0x0001001c +#define CKM_IBM_EC_C448 CKM_VENDOR_DEFINED + 0x0001001e +#define CKM_IBM_ED448_SHA3 CKM_VENDOR_DEFINED + 0x0001001f + +typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR; + + +/* CK_MECHANISM is a structure that specifies a particular + * mechanism */ +typedef struct CK_MECHANISM { + CK_MECHANISM_TYPE mechanism; + CK_VOID_PTR pParameter; + + /* ulParameterLen was changed from CK_USHORT to CK_ULONG for + * v2.0 */ + CK_ULONG ulParameterLen; /* in bytes */ +} CK_MECHANISM; + +typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR; + + +/* CK_MECHANISM_INFO provides information about a particular + * mechanism */ +typedef struct CK_MECHANISM_INFO { + CK_ULONG ulMinKeySize; + CK_ULONG ulMaxKeySize; + CK_FLAGS flags; +} CK_MECHANISM_INFO; + +/* The flags are defined as follows: + * Bit Flag Mask Meaning */ +#define CKF_HW 0x00000001 /* performed by HW */ + +/* The flags CKF_ENCRYPT, CKF_DECRYPT, CKF_DIGEST, CKF_SIGN, + * CKG_SIGN_RECOVER, CKF_VERIFY, CKF_VERIFY_RECOVER, + * CKF_GENERATE, CKF_GENERATE_KEY_PAIR, CKF_WRAP, CKF_UNWRAP, + * and CKF_DERIVE are new for v2.0. They specify whether or not + * a mechanism can be used for a particular task */ +#define CKF_ENCRYPT 0x00000100 +#define CKF_DECRYPT 0x00000200 +#define CKF_DIGEST 0x00000400 +#define CKF_SIGN 0x00000800 +#define CKF_SIGN_RECOVER 0x00001000 +#define CKF_VERIFY 0x00002000 +#define CKF_VERIFY_RECOVER 0x00004000 +#define CKF_GENERATE 0x00008000 +#define CKF_GENERATE_KEY_PAIR 0x00010000 +#define CKF_WRAP 0x00020000 +#define CKF_UNWRAP 0x00040000 +#define CKF_DERIVE 0x00080000 +/* The following are new for v2.11 */ +#define CKF_EC_F_P 0x00100000 +#define CKF_EC_F_2M 0x00200000 +#define CKF_EC_ECPARAMETERS 0x00400000 +#define CKF_EC_NAMEDCURVE 0x00800000 +#define CKF_EC_UNCOMPRESS 0x01000000 +#define CKF_EC_COMPRESS 0x02000000 + +#define CKF_EXTENSION 0x80000000 /* FALSE for 2.01 */ + +typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR; + + +/* CK_RV is a value that identifies the return value of a + * Cryptoki function */ +/* CK_RV was changed from CK_USHORT to CK_ULONG for v2.0 */ +typedef CK_ULONG CK_RV; + +#define CKR_OK 0x00000000 +#define CKR_CANCEL 0x00000001 +#define CKR_HOST_MEMORY 0x00000002 +#define CKR_SLOT_ID_INVALID 0x00000003 + +/* CKR_FLAGS_INVALID was removed for v2.0 */ + +/* CKR_GENERAL_ERROR and CKR_FUNCTION_FAILED are new for v2.0 */ +#define CKR_GENERAL_ERROR 0x00000005 +#define CKR_FUNCTION_FAILED 0x00000006 + +/* CKR_ARGUMENTS_BAD, CKR_NO_EVENT, CKR_NEED_TO_CREATE_THREADS, + * and CKR_CANT_LOCK are new for v2.01 */ +#define CKR_ARGUMENTS_BAD 0x00000007 +#define CKR_NO_EVENT 0x00000008 +#define CKR_NEED_TO_CREATE_THREADS 0x00000009 +#define CKR_CANT_LOCK 0x0000000A + +#define CKR_ATTRIBUTE_READ_ONLY 0x00000010 +#define CKR_ATTRIBUTE_SENSITIVE 0x00000011 +#define CKR_ATTRIBUTE_TYPE_INVALID 0x00000012 +#define CKR_ATTRIBUTE_VALUE_INVALID 0x00000013 +#define CKR_DATA_INVALID 0x00000020 +#define CKR_DATA_LEN_RANGE 0x00000021 +#define CKR_DEVICE_ERROR 0x00000030 +#define CKR_DEVICE_MEMORY 0x00000031 +#define CKR_DEVICE_REMOVED 0x00000032 +#define CKR_ENCRYPTED_DATA_INVALID 0x00000040 +#define CKR_ENCRYPTED_DATA_LEN_RANGE 0x00000041 +#define CKR_FUNCTION_CANCELED 0x00000050 +#define CKR_FUNCTION_NOT_PARALLEL 0x00000051 + +/* CKR_FUNCTION_NOT_SUPPORTED is new for v2.0 */ +#define CKR_FUNCTION_NOT_SUPPORTED 0x00000054 + +#define CKR_KEY_HANDLE_INVALID 0x00000060 + +/* CKR_KEY_SENSITIVE was removed for v2.0 */ + +#define CKR_KEY_SIZE_RANGE 0x00000062 +#define CKR_KEY_TYPE_INCONSISTENT 0x00000063 + +/* CKR_KEY_NOT_NEEDED, CKR_KEY_CHANGED, CKR_KEY_NEEDED, + * CKR_KEY_INDIGESTIBLE, CKR_KEY_FUNCTION_NOT_PERMITTED, + * CKR_KEY_NOT_WRAPPABLE, and CKR_KEY_UNEXTRACTABLE are new for + * v2.0 */ +#define CKR_KEY_NOT_NEEDED 0x00000064 +#define CKR_KEY_CHANGED 0x00000065 +#define CKR_KEY_NEEDED 0x00000066 +#define CKR_KEY_INDIGESTIBLE 0x00000067 +#define CKR_KEY_FUNCTION_NOT_PERMITTED 0x00000068 +#define CKR_KEY_NOT_WRAPPABLE 0x00000069 +#define CKR_KEY_UNEXTRACTABLE 0x0000006A + +#define CKR_MECHANISM_INVALID 0x00000070 +#define CKR_MECHANISM_PARAM_INVALID 0x00000071 + +/* CKR_OBJECT_CLASS_INCONSISTENT and CKR_OBJECT_CLASS_INVALID + * were removed for v2.0 */ +#define CKR_OBJECT_HANDLE_INVALID 0x00000082 +#define CKR_OPERATION_ACTIVE 0x00000090 +#define CKR_OPERATION_NOT_INITIALIZED 0x00000091 +#define CKR_PIN_INCORRECT 0x000000A0 +#define CKR_PIN_INVALID 0x000000A1 +#define CKR_PIN_LEN_RANGE 0x000000A2 + +/* CKR_PIN_EXPIRED and CKR_PIN_LOCKED are new for v2.0 */ +#define CKR_PIN_EXPIRED 0x000000A3 +#define CKR_PIN_LOCKED 0x000000A4 + +#define CKR_SESSION_CLOSED 0x000000B0 +#define CKR_SESSION_COUNT 0x000000B1 +#define CKR_SESSION_HANDLE_INVALID 0x000000B3 +#define CKR_SESSION_PARALLEL_NOT_SUPPORTED 0x000000B4 +#define CKR_SESSION_READ_ONLY 0x000000B5 +#define CKR_SESSION_EXISTS 0x000000B6 + +/* CKR_SESSION_READ_ONLY_EXISTS and + * CKR_SESSION_READ_WRITE_SO_EXISTS are new for v2.0 */ +#define CKR_SESSION_READ_ONLY_EXISTS 0x000000B7 +#define CKR_SESSION_READ_WRITE_SO_EXISTS 0x000000B8 + +#define CKR_SIGNATURE_INVALID 0x000000C0 +#define CKR_SIGNATURE_LEN_RANGE 0x000000C1 +#define CKR_TEMPLATE_INCOMPLETE 0x000000D0 +#define CKR_TEMPLATE_INCONSISTENT 0x000000D1 +#define CKR_TOKEN_NOT_PRESENT 0x000000E0 +#define CKR_TOKEN_NOT_RECOGNIZED 0x000000E1 +#define CKR_TOKEN_WRITE_PROTECTED 0x000000E2 +#define CKR_UNWRAPPING_KEY_HANDLE_INVALID 0x000000F0 +#define CKR_UNWRAPPING_KEY_SIZE_RANGE 0x000000F1 +#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT 0x000000F2 +#define CKR_USER_ALREADY_LOGGED_IN 0x00000100 +#define CKR_USER_NOT_LOGGED_IN 0x00000101 +#define CKR_USER_PIN_NOT_INITIALIZED 0x00000102 +#define CKR_USER_TYPE_INVALID 0x00000103 + +/* CKR_USER_ANOTHER_ALREADY_LOGGED_IN and CKR_USER_TOO_MANY_TYPES + * are new to v2.01 */ +#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN 0x00000104 +#define CKR_USER_TOO_MANY_TYPES 0x00000105 + +#define CKR_WRAPPED_KEY_INVALID 0x00000110 +#define CKR_WRAPPED_KEY_LEN_RANGE 0x00000112 +#define CKR_WRAPPING_KEY_HANDLE_INVALID 0x00000113 +#define CKR_WRAPPING_KEY_SIZE_RANGE 0x00000114 +#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT 0x00000115 +#define CKR_RANDOM_SEED_NOT_SUPPORTED 0x00000120 + +/* These are new to v2.0 */ +#define CKR_RANDOM_NO_RNG 0x00000121 +/* CKR_DOMAIN_PARAMS_INVALID is new for v2.11 */ +#define CKR_DOMAIN_PARAMS_INVALID 0x00000130 +/* CKR_CURVE_NOT_SUPPORTED is new for v2.40 */ +#define CKR_CURVE_NOT_SUPPORTED 0x00000140 +#define CKR_BUFFER_TOO_SMALL 0x00000150 +#define CKR_SAVED_STATE_INVALID 0x00000160 +#define CKR_INFORMATION_SENSITIVE 0x00000170 +#define CKR_STATE_UNSAVEABLE 0x00000180 + +/* These are new to v2.01 */ +#define CKR_CRYPTOKI_NOT_INITIALIZED 0x00000190 +#define CKR_CRYPTOKI_ALREADY_INITIALIZED 0x00000191 +#define CKR_MUTEX_BAD 0x000001A0 +#define CKR_MUTEX_NOT_LOCKED 0x000001A1 + +/* CKR_FUNCTION_REJECTED is new for v2.20 */ +#define CKR_FUNCTION_REJECTED 0x00000200 + +#define CKR_VENDOR_DEFINED 0x80000000 + + +/* CK_NOTIFY is an application callback that processes events */ +typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_NOTIFICATION event, + CK_VOID_PTR pApplication /* passed to C_OpenSession */ + ); + +/* CK_CREATEMUTEX is an application callback for creating a + * mutex object */ +typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)( + CK_VOID_PTR_PTR ppMutex /* location to receive ptr to mutex */ + ); + + +/* CK_DESTROYMUTEX is an application callback for destroying a + * mutex object */ +typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)( + CK_VOID_PTR pMutex /* pointer to mutex */ + ); + + +/* CK_LOCKMUTEX is an application callback for locking a mutex */ +typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)( + CK_VOID_PTR pMutex /* pointer to mutex */ + ); + + +/* CK_UNLOCKMUTEX is an application callback for unlocking a + * mutex */ +typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)( + CK_VOID_PTR pMutex /* pointer to mutex */ + ); + + +/* CK_C_INITIALIZE_ARGS provides the optional arguments to + * C_Initialize */ +// SAB the mutex ones had pf infront previously.. +// The spec says otherwise. +typedef struct CK_C_INITIALIZE_ARGS { + CK_CREATEMUTEX CreateMutex; + CK_DESTROYMUTEX DestroyMutex; + CK_LOCKMUTEX LockMutex; + CK_UNLOCKMUTEX UnlockMutex; + CK_FLAGS flags; + CK_VOID_PTR pReserved; +} CK_C_INITIALIZE_ARGS; + +/* flags: bit flags that provide capabilities of the slot + * Bit Flag Mask Meaning + */ +#define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001 +#define CKF_OS_LOCKING_OK 0x00000002 + +typedef CK_C_INITIALIZE_ARGS CK_PTR CK_C_INITIALIZE_ARGS_PTR; + + +/* additional flags for parameters to functions */ + +/* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */ +#define CKF_DONT_BLOCK 1 + + +/* CK_KEA_DERIVE_PARAMS provides the parameters to the + * CKM_KEA_DERIVE mechanism */ +/* CK_KEA_DERIVE_PARAMS is new for v2.0 */ +typedef struct CK_KEA_DERIVE_PARAMS { + CK_BBOOL isSender; + CK_ULONG ulRandomLen; + CK_BYTE_PTR pRandomA; + CK_BYTE_PTR pRandomB; + CK_ULONG ulPublicDataLen; + CK_BYTE_PTR pPublicData; +} CK_KEA_DERIVE_PARAMS; + +typedef CK_KEA_DERIVE_PARAMS CK_PTR CK_KEA_DERIVE_PARAMS_PTR; + + +/* CK_RC2_PARAMS provides the parameters to the CKM_RC2_ECB and + * CKM_RC2_MAC mechanisms. An instance of CK_RC2_PARAMS just + * holds the effective keysize */ +typedef CK_ULONG CK_RC2_PARAMS; + +typedef CK_RC2_PARAMS CK_PTR CK_RC2_PARAMS_PTR; + + +/* CK_RC2_CBC_PARAMS provides the parameters to the CKM_RC2_CBC + * mechanism */ +typedef struct CK_RC2_CBC_PARAMS { + /* ulEffectiveBits was changed from CK_USHORT to CK_ULONG for + * v2.0 */ + CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */ + + CK_BYTE iv[8]; /* IV for CBC mode */ +} CK_RC2_CBC_PARAMS; + +typedef CK_RC2_CBC_PARAMS CK_PTR CK_RC2_CBC_PARAMS_PTR; + + +/* CK_RC2_MAC_GENERAL_PARAMS provides the parameters for the + * CKM_RC2_MAC_GENERAL mechanism */ +/* CK_RC2_MAC_GENERAL_PARAMS is new for v2.0 */ +typedef struct CK_RC2_MAC_GENERAL_PARAMS { + CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */ + CK_ULONG ulMacLength; /* Length of MAC in bytes */ +} CK_RC2_MAC_GENERAL_PARAMS; + +typedef CK_RC2_MAC_GENERAL_PARAMS CK_PTR CK_RC2_MAC_GENERAL_PARAMS_PTR; + + +/* CK_RC5_PARAMS provides the parameters to the CKM_RC5_ECB and + * CKM_RC5_MAC mechanisms */ +/* CK_RC5_PARAMS is new for v2.0 */ +typedef struct CK_RC5_PARAMS { + CK_ULONG ulWordsize; /* wordsize in bits */ + CK_ULONG ulRounds; /* number of rounds */ +} CK_RC5_PARAMS; + +typedef CK_RC5_PARAMS CK_PTR CK_RC5_PARAMS_PTR; + +/* CK_AES_CTR_PARAMS is new for PKCS #11 v2.20 amendment 3 */ +typedef struct CK_AES_CTR_PARAMS { + CK_ULONG ulCounterBits; + CK_BYTE cb[16]; +} CK_AES_CTR_PARAMS; + +typedef CK_AES_CTR_PARAMS CK_PTR CK_AES_CTR_PARAMS_PTR; + +typedef struct CK_GCM_PARAMS { + CK_BYTE_PTR pIv; + CK_ULONG ulIvLen; + CK_BYTE_PTR pAAD; + CK_ULONG ulAADLen; + CK_ULONG ulTagBits; +} CK_GCM_PARAMS; + +typedef CK_GCM_PARAMS CK_PTR CK_GCM_PARAMS_PTR; + +/* CK_RC5_CBC_PARAMS provides the parameters to the CKM_RC5_CBC + * mechanism */ +/* CK_RC5_CBC_PARAMS is new for v2.0 */ +typedef struct CK_RC5_CBC_PARAMS { + CK_ULONG ulWordsize; /* wordsize in bits */ + CK_ULONG ulRounds; /* number of rounds */ + CK_BYTE_PTR pIv; /* pointer to IV */ + CK_ULONG ulIvLen; /* length of IV in bytes */ +} CK_RC5_CBC_PARAMS; + +typedef CK_RC5_CBC_PARAMS CK_PTR CK_RC5_CBC_PARAMS_PTR; + + +/* CK_RC5_MAC_GENERAL_PARAMS provides the parameters for the + * CKM_RC5_MAC_GENERAL mechanism */ +/* CK_RC5_MAC_GENERAL_PARAMS is new for v2.0 */ +typedef struct CK_RC5_MAC_GENERAL_PARAMS { + CK_ULONG ulWordsize; /* wordsize in bits */ + CK_ULONG ulRounds; /* number of rounds */ + CK_ULONG ulMacLength; /* Length of MAC in bytes */ +} CK_RC5_MAC_GENERAL_PARAMS; + +typedef CK_RC5_MAC_GENERAL_PARAMS CK_PTR CK_RC5_MAC_GENERAL_PARAMS_PTR; + + +/* CK_MAC_GENERAL_PARAMS provides the parameters to most block + * ciphers' MAC_GENERAL mechanisms. Its value is the length of + * the MAC */ +/* CK_MAC_GENERAL_PARAMS is new for v2.0 */ +typedef CK_ULONG CK_MAC_GENERAL_PARAMS; + +typedef CK_MAC_GENERAL_PARAMS CK_PTR CK_MAC_GENERAL_PARAMS_PTR; + + +/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the + * CKM_SKIPJACK_PRIVATE_WRAP mechanism */ +/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS is new for v2.0 */ +typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS { + CK_ULONG ulPasswordLen; + CK_BYTE_PTR pPassword; + CK_ULONG ulPublicDataLen; + CK_BYTE_PTR pPublicData; + CK_ULONG ulPAndGLen; + CK_ULONG ulQLen; + CK_ULONG ulRandomLen; + CK_BYTE_PTR pRandomA; + CK_BYTE_PTR pPrimeP; + CK_BYTE_PTR pBaseG; + CK_BYTE_PTR pSubprimeQ; +} CK_SKIPJACK_PRIVATE_WRAP_PARAMS; + +typedef CK_SKIPJACK_PRIVATE_WRAP_PARAMS CK_PTR CK_SKIPJACK_PRIVATE_WRAP_PTR; + + +/* CK_SKIPJACK_RELAYX_PARAMS provides the parameters to the + * CKM_SKIPJACK_RELAYX mechanism */ +/* CK_SKIPJACK_RELAYX_PARAMS is new for v2.0 */ +typedef struct CK_SKIPJACK_RELAYX_PARAMS { + CK_ULONG ulOldWrappedXLen; + CK_BYTE_PTR pOldWrappedX; + CK_ULONG ulOldPasswordLen; + CK_BYTE_PTR pOldPassword; + CK_ULONG ulOldPublicDataLen; + CK_BYTE_PTR pOldPublicData; + CK_ULONG ulOldRandomLen; + CK_BYTE_PTR pOldRandomA; + CK_ULONG ulNewPasswordLen; + CK_BYTE_PTR pNewPassword; + CK_ULONG ulNewPublicDataLen; + CK_BYTE_PTR pNewPublicData; + CK_ULONG ulNewRandomLen; + CK_BYTE_PTR pNewRandomA; +} CK_SKIPJACK_RELAYX_PARAMS; + +typedef CK_SKIPJACK_RELAYX_PARAMS CK_PTR CK_SKIPJACK_RELAYX_PARAMS_PTR; + + +typedef struct CK_PBE_PARAMS { + CK_CHAR_PTR pInitVector; + CK_CHAR_PTR pPassword; + CK_ULONG ulPasswordLen; + CK_CHAR_PTR pSalt; + CK_ULONG ulSaltLen; + CK_ULONG ulIteration; +} CK_PBE_PARAMS; + +typedef CK_PBE_PARAMS CK_PTR CK_PBE_PARAMS_PTR; + + +/* CK_KEY_WRAP_SET_OAEP_PARAMS provides the parameters to the + * CKM_KEY_WRAP_SET_OAEP mechanism */ +/* CK_KEY_WRAP_SET_OAEP_PARAMS is new for v2.0 */ +typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS { + CK_BYTE bBC; /* block contents byte */ + CK_BYTE_PTR pX; /* extra data */ + CK_ULONG ulXLen; /* length of extra data in bytes */ +} CK_KEY_WRAP_SET_OAEP_PARAMS; + +typedef CK_KEY_WRAP_SET_OAEP_PARAMS CK_PTR CK_KEY_WRAP_SET_OAEP_PARAMS_PTR; + + +typedef struct CK_SSL3_RANDOM_DATA { + CK_BYTE_PTR pClientRandom; + CK_ULONG ulClientRandomLen; + CK_BYTE_PTR pServerRandom; + CK_ULONG ulServerRandomLen; +} CK_SSL3_RANDOM_DATA; + + +typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS { + CK_SSL3_RANDOM_DATA RandomInfo; + CK_VERSION_PTR pVersion; +} CK_SSL3_MASTER_KEY_DERIVE_PARAMS; + +typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS CK_PTR + CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR; + + +typedef struct CK_SSL3_KEY_MAT_OUT { + CK_OBJECT_HANDLE hClientMacSecret; + CK_OBJECT_HANDLE hServerMacSecret; + CK_OBJECT_HANDLE hClientKey; + CK_OBJECT_HANDLE hServerKey; + CK_BYTE_PTR pIVClient; + CK_BYTE_PTR pIVServer; +} CK_SSL3_KEY_MAT_OUT; + +typedef CK_SSL3_KEY_MAT_OUT CK_PTR CK_SSL3_KEY_MAT_OUT_PTR; + + +typedef struct CK_SSL3_KEY_MAT_PARAMS { + CK_ULONG ulMacSizeInBits; + CK_ULONG ulKeySizeInBits; + CK_ULONG ulIVSizeInBits; + CK_BBOOL bIsExport; + CK_SSL3_RANDOM_DATA RandomInfo; + CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial; +} CK_SSL3_KEY_MAT_PARAMS; + +typedef CK_SSL3_KEY_MAT_PARAMS CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR; + + +typedef struct CK_KEY_DERIVATION_STRING_DATA { + CK_BYTE_PTR pData; + CK_ULONG ulLen; +} CK_KEY_DERIVATION_STRING_DATA; + +typedef CK_KEY_DERIVATION_STRING_DATA CK_PTR CK_KEY_DERIVATION_STRING_DATA_PTR; + + +/* The CK_EXTRACT_PARAMS is used for the + * CKM_EXTRACT_KEY_FROM_KEY mechanism. It specifies which bit + * of the base key should be used as the first bit of the + * derived key */ +/* CK_EXTRACT_PARAMS is new for v2.0 */ +typedef CK_ULONG CK_EXTRACT_PARAMS; + +typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR; + +/* RSA mechanism OAEP encoding */ +typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE; +typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE; +typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR; +/* PKCS#1 RSA OAEP Encoding Parameter Sources */ +#define CKZ_DATA_SPECIFIED 0x00000001 + +/* PKCS#1 Mask Generation Functions */ +#define CKG_MGF1_SHA1 0x00000001 +#define CKG_MGF1_SHA224 0x00000005 +#define CKG_MGF1_SHA256 0x00000002 +#define CKG_MGF1_SHA384 0x00000003 +#define CKG_MGF1_SHA512 0x00000004 + +#define CKG_VENDOR_DEFINED 0x80000000UL + +#define CKG_IBM_MGF1_SHA3_224 CKG_VENDOR_DEFINED + 1 +#define CKG_IBM_MGF1_SHA3_256 CKG_VENDOR_DEFINED + 2 +#define CKG_IBM_MGF1_SHA3_384 CKG_VENDOR_DEFINED + 3 +#define CKG_IBM_MGF1_SHA3_512 CKG_VENDOR_DEFINED + 4 + +typedef struct CK_RSA_PKCS_OAEP_PARAMS { + CK_MECHANISM_TYPE hashAlg; + CK_RSA_PKCS_MGF_TYPE mgf; + CK_RSA_PKCS_OAEP_SOURCE_TYPE source; + CK_VOID_PTR pSourceData; + CK_ULONG ulSourceDataLen; +} CK_RSA_PKCS_OAEP_PARAMS; + +typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR; + +typedef struct CK_RSA_PKCS_PSS_PARAMS { + CK_MECHANISM_TYPE hashAlg; + CK_RSA_PKCS_MGF_TYPE mgf; + CK_ULONG sLen; +} CK_RSA_PKCS_PSS_PARAMS; + +typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR; + +/* ECDH mechanisms */ +typedef CK_ULONG CK_EC_KDF_TYPE; + +typedef struct CK_ECDH1_DERIVE_PARAMS { + CK_EC_KDF_TYPE kdf; + CK_ULONG ulSharedDataLen; + CK_BYTE_PTR pSharedData; + CK_ULONG ulPublicDataLen; + CK_BYTE_PTR pPublicData; +} CK_ECDH1_DERIVE_PARAMS; + +/* EC key derivation functions */ +#define CKD_NULL 0x00000001UL +#define CKD_SHA1_KDF 0x00000002UL + +/* X9.42 DH key derivation functions */ +#define CKD_SHA1_KDF_ASN1 0x00000003UL +#define CKD_SHA1_KDF_CONCATENATE 0x00000004UL +#define CKD_SHA224_KDF 0x00000005UL +#define CKD_SHA256_KDF 0x00000006UL +#define CKD_SHA384_KDF 0x00000007UL +#define CKD_SHA512_KDF 0x00000008UL + +/* CK_FUNCTION_LIST is a structure holding a Cryptoki spec + * version and pointers of appropriate types to all the + * Cryptoki functions */ +/* CK_FUNCTION_LIST is new for v2.0 */ +typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST; + +typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR; + +typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR; + +typedef CK_RV (CK_PTR CK_C_Initialize) (CK_VOID_PTR pReserved); +typedef CK_RV (CK_PTR CK_C_Finalize) (CK_VOID_PTR pReserved); +typedef CK_RV (CK_PTR CK_C_Terminate) (void); +typedef CK_RV (CK_PTR CK_C_GetInfo) (CK_INFO_PTR pInfo); +typedef CK_RV (CK_PTR CK_C_GetFunctionList) (CK_FUNCTION_LIST_PTR_PTR + ppFunctionList); +typedef CK_RV (CK_PTR CK_C_GetSlotList) (CK_BBOOL tokenPresent, + CK_SLOT_ID_PTR pSlotList, + CK_ULONG_PTR pusCount); +typedef CK_RV (CK_PTR CK_C_GetSlotInfo) (CK_SLOT_ID slotID, + CK_SLOT_INFO_PTR pInfo); +typedef CK_RV (CK_PTR CK_C_GetTokenInfo) (CK_SLOT_ID slotID, + CK_TOKEN_INFO_PTR pInfo); +typedef CK_RV (CK_PTR CK_C_GetMechanismList) (CK_SLOT_ID slotID, + CK_MECHANISM_TYPE_PTR + pMechanismList, + CK_ULONG_PTR pusCount); +typedef CK_RV (CK_PTR CK_C_GetMechanismInfo) (CK_SLOT_ID slotID, + CK_MECHANISM_TYPE type, + CK_MECHANISM_INFO_PTR pInfo); +typedef CK_RV (CK_PTR CK_C_InitToken) (CK_SLOT_ID slotID, + CK_CHAR_PTR pPin, + CK_ULONG usPinLen, CK_CHAR_PTR pLabel); +typedef CK_RV (CK_PTR CK_C_InitPIN) (CK_SESSION_HANDLE hSession, + CK_CHAR_PTR pPin, CK_ULONG usPinLen); +typedef CK_RV (CK_PTR CK_C_SetPIN) (CK_SESSION_HANDLE hSession, + CK_CHAR_PTR pOldPin, + CK_ULONG usOldLen, + CK_CHAR_PTR pNewPin, CK_ULONG usNewLen); +typedef CK_RV (CK_PTR CK_C_OpenSession) (CK_SLOT_ID slotID, CK_FLAGS flags, + CK_VOID_PTR pApplication, + CK_RV (*Notify) + (CK_SESSION_HANDLE hSession, + CK_NOTIFICATION event, + CK_VOID_PTR pApplication), + CK_SESSION_HANDLE_PTR phSession); +typedef CK_RV (CK_PTR CK_C_CloseSession) (CK_SESSION_HANDLE hSession); +typedef CK_RV (CK_PTR CK_C_CloseAllSessions) (CK_SLOT_ID slotID); +typedef CK_RV (CK_PTR CK_C_GetSessionInfo) (CK_SESSION_HANDLE hSession, + CK_SESSION_INFO_PTR pInfo); +typedef CK_RV (CK_PTR CK_C_GetOperationState) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pOperationState, + CK_ULONG_PTR + pulOperationStateLen); +typedef CK_RV (CK_PTR CK_C_SetOperationState) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pOperationState, + CK_ULONG ulOperationStateLen, + CK_OBJECT_HANDLE hEncryptionKey, + CK_OBJECT_HANDLE + hAuthenticationKey); +typedef CK_RV (CK_PTR CK_C_Login) (CK_SESSION_HANDLE hSession, + CK_USER_TYPE userType, + CK_CHAR_PTR pPin, CK_ULONG usPinLen); +typedef CK_RV (CK_PTR CK_C_Logout) (CK_SESSION_HANDLE hSession); +typedef CK_RV (CK_PTR CK_C_CreateObject) (CK_SESSION_HANDLE hSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG usCount, + CK_OBJECT_HANDLE_PTR phObject); +typedef CK_RV (CK_PTR CK_C_CopyObject) (CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG usCount, + CK_OBJECT_HANDLE_PTR phNewObject); +typedef CK_RV (CK_PTR CK_C_DestroyObject) (CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject); +typedef CK_RV (CK_PTR CK_C_GetObjectSize) (CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, + CK_ULONG_PTR pusSize); +typedef CK_RV (CK_PTR CK_C_GetAttributeValue) (CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG usCount); +typedef CK_RV (CK_PTR CK_C_SetAttributeValue) (CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG usCount); +typedef CK_RV (CK_PTR CK_C_FindObjectsInit) (CK_SESSION_HANDLE hSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG usCount); +typedef CK_RV (CK_PTR CK_C_FindObjects) (CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE_PTR phObject, + CK_ULONG usMaxObjectCount, + CK_ULONG_PTR pusObjectCount); +typedef CK_RV (CK_PTR CK_C_FindObjectsFinal) (CK_SESSION_HANDLE hSession); +typedef CK_RV (CK_PTR CK_C_EncryptInit) (CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); +typedef CK_RV (CK_PTR CK_C_Encrypt) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pData, + CK_ULONG usDataLen, + CK_BYTE_PTR pEncryptedData, + CK_ULONG_PTR pusEncryptedDataLen); +typedef CK_RV (CK_PTR CK_C_EncryptUpdate) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, + CK_ULONG usPartLen, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pusEncryptedPartLen); +typedef CK_RV (CK_PTR CK_C_EncryptFinal) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pLastEncryptedPart, + CK_ULONG_PTR pusLastEncryptedPartLen); +typedef CK_RV (CK_PTR CK_C_DecryptInit) (CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); +typedef CK_RV (CK_PTR CK_C_Decrypt) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedData, + CK_ULONG usEncryptedDataLen, + CK_BYTE_PTR pData, + CK_ULONG_PTR pusDataLen); +typedef CK_RV (CK_PTR CK_C_DecryptUpdate) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG usEncryptedPartLen, + CK_BYTE_PTR pPart, + CK_ULONG_PTR pusPartLen); +typedef CK_RV (CK_PTR CK_C_DecryptFinal) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pLastPart, + CK_ULONG_PTR pusLastPartLen); +typedef CK_RV (CK_PTR CK_C_DigestInit) (CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism); +typedef CK_RV (CK_PTR CK_C_Digest) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pData, + CK_ULONG usDataLen, + CK_BYTE_PTR pDigest, + CK_ULONG_PTR pusDigestLen); +typedef CK_RV (CK_PTR CK_C_DigestUpdate) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, + CK_ULONG usPartLen); +typedef CK_RV (CK_PTR CK_C_DigestKey) (CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hKey); +typedef CK_RV (CK_PTR CK_C_DigestFinal) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pDigest, + CK_ULONG_PTR pusDigestLen); +typedef CK_RV (CK_PTR CK_C_SignInit) (CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); +typedef CK_RV (CK_PTR CK_C_Sign) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pData, + CK_ULONG usDataLen, + CK_BYTE_PTR pSignature, + CK_ULONG_PTR pusSignatureLen); +typedef CK_RV (CK_PTR CK_C_SignUpdate) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, CK_ULONG usPartLen); +typedef CK_RV (CK_PTR CK_C_SignFinal) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pSignature, + CK_ULONG_PTR pusSignatureLen); +typedef CK_RV (CK_PTR CK_C_SignRecoverInit) (CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); +typedef CK_RV (CK_PTR CK_C_SignRecover) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pData, + CK_ULONG usDataLen, + CK_BYTE_PTR pSignature, + CK_ULONG_PTR pusSignatureLen); +typedef CK_RV (CK_PTR CK_C_VerifyInit) (CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); +typedef CK_RV (CK_PTR CK_C_Verify) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pData, + CK_ULONG usDataLen, + CK_BYTE_PTR pSignature, + CK_ULONG usSignatureLen); +typedef CK_RV (CK_PTR CK_C_VerifyUpdate) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, + CK_ULONG usPartLen); +typedef CK_RV (CK_PTR CK_C_VerifyFinal) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pSignature, + CK_ULONG usSignatureLen); +typedef CK_RV (CK_PTR CK_C_VerifyRecoverInit) (CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); +typedef CK_RV (CK_PTR CK_C_VerifyRecover) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pSignature, + CK_ULONG usSignatureLen, + CK_BYTE_PTR pData, + CK_ULONG_PTR pusDataLen); +typedef CK_RV (CK_PTR CK_C_DigestEncryptUpdate) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, + CK_ULONG ulPartLen, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR + pulEncryptedPartLen); +typedef CK_RV (CK_PTR CK_C_DecryptDigestUpdate) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, + CK_BYTE_PTR pPart, + CK_ULONG_PTR pulPartLen); +typedef CK_RV (CK_PTR CK_C_SignEncryptUpdate) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, + CK_ULONG ulPartLen, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR + pulEncryptedPartLen); +typedef CK_RV (CK_PTR CK_C_DecryptVerifyUpdate) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, + CK_BYTE_PTR pPart, + CK_ULONG_PTR pulPartLen); +typedef CK_RV (CK_PTR CK_C_GenerateKey) (CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG usCount, + CK_OBJECT_HANDLE_PTR phKey); +typedef CK_RV (CK_PTR CK_C_GenerateKeyPair) (CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_ATTRIBUTE_PTR + pPublicKeyTemplate, + CK_ULONG usPublicKeyAttributeCount, + CK_ATTRIBUTE_PTR + pPrivateKeyTemplate, + CK_ULONG + usPrivateKeyAttributeCount, + CK_OBJECT_HANDLE_PTR phPrivateKey, + CK_OBJECT_HANDLE_PTR phPublicKey); +typedef CK_RV (CK_PTR CK_C_WrapKey) (CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hWrappingKey, + CK_OBJECT_HANDLE hKey, + CK_BYTE_PTR pWrappedKey, + CK_ULONG_PTR pusWrappedKeyLen); +typedef CK_RV (CK_PTR CK_C_UnwrapKey) (CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hUnwrappingKey, + CK_BYTE_PTR pWrappedKey, + CK_ULONG usWrappedKeyLen, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG usAttributeCount, + CK_OBJECT_HANDLE_PTR phKey); +typedef CK_RV (CK_PTR CK_C_DeriveKey) (CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hBaseKey, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG usAttributeCount, + CK_OBJECT_HANDLE_PTR phKey); +typedef CK_RV (CK_PTR CK_C_SeedRandom) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pSeed, CK_ULONG usSeedLen); +typedef CK_RV (CK_PTR CK_C_GenerateRandom) (CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pRandomData, + CK_ULONG usRandomLen); +typedef CK_RV (CK_PTR CK_C_GetFunctionStatus) (CK_SESSION_HANDLE hSession); +typedef CK_RV (CK_PTR CK_C_CancelFunction) (CK_SESSION_HANDLE hSession); +typedef CK_RV (CK_PTR CK_Notify) (CK_SESSION_HANDLE hSession, + CK_NOTIFICATION event, + CK_VOID_PTR pApplication); +typedef CK_RV (CK_PTR CK_C_WaitForSlotEvent) (CK_FLAGS flags, + CK_SLOT_ID_PTR pSlot, + CK_VOID_PTR pReserved); + +struct CK_FUNCTION_LIST { + CK_VERSION version; + CK_C_Initialize C_Initialize; + CK_C_Finalize C_Finalize; + CK_C_GetInfo C_GetInfo; + CK_C_GetFunctionList C_GetFunctionList; + CK_C_GetSlotList C_GetSlotList; + CK_C_GetSlotInfo C_GetSlotInfo; + CK_C_GetTokenInfo C_GetTokenInfo; + CK_C_GetMechanismList C_GetMechanismList; + CK_C_GetMechanismInfo C_GetMechanismInfo; + CK_C_InitToken C_InitToken; + CK_C_InitPIN C_InitPIN; + CK_C_SetPIN C_SetPIN; + CK_C_OpenSession C_OpenSession; + CK_C_CloseSession C_CloseSession; + CK_C_CloseAllSessions C_CloseAllSessions; + CK_C_GetSessionInfo C_GetSessionInfo; + CK_C_GetOperationState C_GetOperationState; + CK_C_SetOperationState C_SetOperationState; + CK_C_Login C_Login; + CK_C_Logout C_Logout; + CK_C_CreateObject C_CreateObject; + CK_C_CopyObject C_CopyObject; + CK_C_DestroyObject C_DestroyObject; + CK_C_GetObjectSize C_GetObjectSize; + CK_C_GetAttributeValue C_GetAttributeValue; + CK_C_SetAttributeValue C_SetAttributeValue; + CK_C_FindObjectsInit C_FindObjectsInit; + CK_C_FindObjects C_FindObjects; + CK_C_FindObjectsFinal C_FindObjectsFinal; + CK_C_EncryptInit C_EncryptInit; + CK_C_Encrypt C_Encrypt; + CK_C_EncryptUpdate C_EncryptUpdate; + CK_C_EncryptFinal C_EncryptFinal; + CK_C_DecryptInit C_DecryptInit; + CK_C_Decrypt C_Decrypt; + CK_C_DecryptUpdate C_DecryptUpdate; + CK_C_DecryptFinal C_DecryptFinal; + CK_C_DigestInit C_DigestInit; + CK_C_Digest C_Digest; + CK_C_DigestUpdate C_DigestUpdate; + CK_C_DigestKey C_DigestKey; + CK_C_DigestFinal C_DigestFinal; + CK_C_SignInit C_SignInit; + CK_C_Sign C_Sign; + CK_C_SignUpdate C_SignUpdate; + CK_C_SignFinal C_SignFinal; + CK_C_SignRecoverInit C_SignRecoverInit; + CK_C_SignRecover C_SignRecover; + CK_C_VerifyInit C_VerifyInit; + CK_C_Verify C_Verify; + CK_C_VerifyUpdate C_VerifyUpdate; + CK_C_VerifyFinal C_VerifyFinal; + CK_C_VerifyRecoverInit C_VerifyRecoverInit; + CK_C_VerifyRecover C_VerifyRecover; + CK_C_DigestEncryptUpdate C_DigestEncryptUpdate; + CK_C_DecryptDigestUpdate C_DecryptDigestUpdate; + CK_C_SignEncryptUpdate C_SignEncryptUpdate; + CK_C_DecryptVerifyUpdate C_DecryptVerifyUpdate; + CK_C_GenerateKey C_GenerateKey; + CK_C_GenerateKeyPair C_GenerateKeyPair; + CK_C_WrapKey C_WrapKey; + CK_C_UnwrapKey C_UnwrapKey; + CK_C_DeriveKey C_DeriveKey; + CK_C_SeedRandom C_SeedRandom; + CK_C_GenerateRandom C_GenerateRandom; + CK_C_GetFunctionStatus C_GetFunctionStatus; + CK_C_CancelFunction C_CancelFunction; + CK_C_WaitForSlotEvent C_WaitForSlotEvent; +}; + +#ifdef __cplusplus +} +#endif + +#endif // _PKCS11TYPES_H_ diff --git a/usr/include/pkcs32.h b/usr/include/pkcs32.h new file mode 100644 index 0000000..6df37d7 --- /dev/null +++ b/usr/include/pkcs32.h @@ -0,0 +1,181 @@ +/* + * 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: PKCS11Types.h +// +// +//---------------------------------------------------------------------------- + + +#ifndef _PKCS1132_H_ +#define _PKCS1132_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* These are the new definitions need for the structures in + * leeds_stdll largs.h (and elsewhere) + */ + +typedef unsigned int CK_ULONG_32; +typedef int CK_LONG_32; +typedef unsigned int *CK_ULONG_PTR_32; + +typedef CK_ULONG_32 CK_MECHANISM_TYPE_32; +typedef CK_ULONG_32 CK_SESSION_HANDLE_32; +typedef CK_ULONG_32 CK_SLOT_ID_32; +typedef CK_ULONG_32 CK_FLAGS_32; +typedef CK_ULONG_32 CK_USER_TYPE_32; +typedef CK_ULONG_32 CK_OBJECT_HANDLE_32; +typedef CK_OBJECT_HANDLE_32 *CK_OBJECT_HANDLE__PTR_32; +typedef CK_ULONG_32 CK_ATTRIBUTE_TYPE_32; +typedef CK_ULONG_32 CK_STATE_32; +typedef CK_ULONG_32 CK_OBJECT_CLASS_32; + +typedef CK_BYTE CK_PTR CK_BYTE_PTR_32; +typedef CK_CHAR CK_PTR CK_CHAR_PTR_32; + +typedef CK_ULONG_32 CK_MAC_GENERAL_PARAMS_32; + +typedef CK_MAC_GENERAL_PARAMS_32 CK_PTR CK_MAC_GENERAL_PARAMS_PTR_32; + +// SSL 3 Mechanism pointers for the Leeds card. +typedef struct CK_SSL3_RANDOM_DATA_32 { + CK_BYTE_PTR_32 pClientRandom; + CK_ULONG_32 ulClientRandomLen; + CK_BYTE_PTR_32 pServerRandom; + CK_ULONG_32 ulServerRandomLen; +} CK_SSL3_RANDOM_DATA_32; + + +typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS_32 { + CK_SSL3_RANDOM_DATA_32 RandomInfo; + CK_VERSION_PTR pVersion; +} CK_SSL3_MASTER_KEY_DERIVE_PARAMS_32; + +typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS_32 CK_PTR + CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR_32; + + +typedef struct CK_SSL3_KEY_MAT_OUT_32 { + CK_OBJECT_HANDLE_32 hClientMacSecret; + CK_OBJECT_HANDLE_32 hServerMacSecret; + CK_OBJECT_HANDLE_32 hClientKey; + CK_OBJECT_HANDLE_32 hServerKey; + CK_BYTE_PTR_32 pIVClient; + CK_BYTE_PTR_32 pIVServer; +} CK_SSL3_KEY_MAT_OUT_32; + +typedef CK_SSL3_KEY_MAT_OUT_32 CK_PTR CK_SSL3_KEY_MAT_OUT_PTR_32; + + +typedef struct CK_SSL3_KEY_MAT_PARAMS_32 { + CK_ULONG_32 ulMacSizeInBits; + CK_ULONG_32 ulKeySizeInBits; + CK_ULONG_32 ulIVSizeInBits; + CK_BBOOL bIsExport; + CK_SSL3_RANDOM_DATA_32 RandomInfo; + CK_SSL3_KEY_MAT_OUT_PTR_32 pReturnedKeyMaterial; +} CK_SSL3_KEY_MAT_PARAMS_32; + +typedef CK_SSL3_KEY_MAT_PARAMS_32 CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR_32; + + +typedef struct CK_KEY_DERIVATION_STRING_DATA_32 { + CK_BYTE_PTR_32 pData; + CK_ULONG_32 ulLen; +} CK_KEY_DERIVATION_STRING_DATA_32; + +typedef CK_KEY_DERIVATION_STRING_DATA_32 CK_PTR + CK_KEY_DERIVATION_STRING_DATA_PTR_32; + + +typedef struct CK_TOKEN_INFO_32 { + CK_CHAR label[32]; /* blank padded */ + CK_CHAR manufacturerID[32]; /* blank padded */ + CK_CHAR model[16]; /* blank padded */ + CK_CHAR serialNumber[16]; /* blank padded */ + CK_FLAGS_32 flags; /* see below */ + // SAB FIXME needs to be 32 bit + + /* ulMaxSessionCount, ulSessionCount, ulMaxRwSessionCount, + * ulRwSessionCount, ulMaxPinLen, and ulMinPinLen have all been + * changed from CK_USHORT to CK_ULONG for v2.0 */ + CK_ULONG_32 ulMaxSessionCount; /* max open sessions */ + CK_ULONG_32 ulSessionCount; /* sess. now open */ + CK_ULONG_32 ulMaxRwSessionCount; /* max R/W sessions */ + CK_ULONG_32 ulRwSessionCount; /* R/W sess. now open */ + CK_ULONG_32 ulMaxPinLen; /* in bytes */ + CK_ULONG_32 ulMinPinLen; /* in bytes */ + CK_ULONG_32 ulTotalPublicMemory; /* in bytes */ + CK_ULONG_32 ulFreePublicMemory; /* in bytes */ + CK_ULONG_32 ulTotalPrivateMemory; /* in bytes */ + CK_ULONG_32 ulFreePrivateMemory; /* in bytes */ + + /* hardwareVersion, firmwareVersion, and time are new for + * v2.0 */ + CK_VERSION hardwareVersion; /* version of hardware */ + CK_VERSION firmwareVersion; /* version of firmware */ + CK_CHAR utcTime[16]; /* time */ +} CK_TOKEN_INFO_32; + + +typedef struct CK_SESSION_INFO_32 { + CK_SLOT_ID_32 slotID; + CK_STATE_32 state; + CK_FLAGS_32 flags; /* see below */ + + /* ulDeviceError was changed from CK_USHORT to CK_ULONG for + * v2.0 */ + CK_ULONG_32 ulDeviceError; /* device-dependent error code */ +} CK_SESSION_INFO_32; + + +typedef struct CK_MECHANISM_INFO_32 { + CK_ULONG_32 ulMinKeySize; + CK_ULONG_32 ulMaxKeySize; + CK_FLAGS_32 flags; +} CK_MECHANISM_INFO_32; + +/* CK_MECHANISM_32 is a structure that specifies a particular + * mechanism */ +typedef struct CK_MECHANISM_32 { + CK_MECHANISM_TYPE_32 mechanism; + CK_VOID_PTR pParameter; + + /* ulParameterLen was changed from CK_USHORT to CK_ULONG for + * v2.0 */ + CK_ULONG_32 ulParameterLen; /* in bytes */ +} CK_MECHANISM_32; + +/* CK_ATTRIBUTE is a structure that includes the type, length + * and value of an attribute */ +typedef struct CK_ATTRIBUTE_32 { + CK_ATTRIBUTE_TYPE_32 type; + CK_ULONG_32 pValue; // SAB XXX XXX Was CK_VOID_PTR which is 64Bit + + /* ulValueLen went from CK_USHORT to CK_ULONG for v2.0 */ + CK_ULONG_32 ulValueLen; /* in bytes */ +} CK_ATTRIBUTE_32; + + + +#pragma pack() + + +#ifdef __cplusplus +} +#endif + +#endif // _PKCS1132_HS_H_ diff --git a/usr/include/slotmgr.h b/usr/include/slotmgr.h new file mode 100644 index 0000000..0abbdff --- /dev/null +++ b/usr/include/slotmgr.h @@ -0,0 +1,250 @@ +/* + * 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 + */ + +// +//Slot Manager Daemon Constants... +// +// + +#include +#include +#include +#include +#include +#include + +#include "local_types.h" + +#ifndef _SLOTMGR_H +#define _SLOTMGR_H + +#define TOK_PATH SBIN_PATH "/pkcsslotd" +#define OCK_API_LOCK_FILE LOCKDIR_PATH "/LCK..APIlock" + +#define SOCKET_FILE_PATH "/var/run/pkcsslotd.socket" + +#define PID_FILE_PATH "/var/run/pkcsslotd.pid" +#define OCK_CONFIG OCK_CONFDIR "/opencryptoki.conf" + +#ifndef CK_BOOL +#define CK_BOOL CK_BBOOL +#endif /* CK_BOOL */ + +#ifndef TEST_COND_VARS +#define TEST_COND_VARS 0 +#endif /* TEST_COND_VARS */ + +#define NUMBER_SLOTS_MANAGED 1024 +#define NUMBER_PROCESSES_ALLOWED 1000 + +// +// Per Process Data structure +// one entry in the table is grabbed by each process +// when it attaches to the shared memory and released +// when the C_Finalize is called. + +typedef struct { + pthread_mutex_t proc_mutex; + pthread_cond_t proc_slot_cond; + + CK_BOOL inuse; // flag indicating if the entry is in use + pid_t proc_id; /* This could also be used to indicate inuse. + * however we will actualy use it to provide + * a check for a bad process which did not + * C_finalize and remove itself properly. + */ + uint32 slotmap; /* Bit map of the slots with events App uses + * in the C_WaitForSlotEvent call + */ + + uint8 blocking; /* Flag to use if a thread is blocking on the + * condition variable Used by C_Finalize to + * wake up the + */ + + uint8 error; /* indication of an error causing the thread + * sleeping on the condition variable to wakeup. + */ + uint32 slot_session_count[NUMBER_SLOTS_MANAGED]; /* Per process session + * count for garbage + * collection clean up + * of the global + * session count. + */ + time_t reg_time; // Time application registered +} Slot_Mgr_Proc_t; + + +// Slot info structure which contains the PKCS11 CK_SLOT_INFO +// as well as the local information +typedef struct { + CK_SLOT_ID slot_number; + CK_BOOL present; + CK_SLOT_INFO pk_slot; + char dll_location[NAME_MAX + 1]; // location of slot management DLL + char slot_init_fcn[NAME_MAX + 1]; /* function to call to initialize the + * token in the slot + */ + LW_SHM_TYPE *shm_addr; // token specific shm address +} Slot_Info_t; + + +#ifdef PKCS64 + +/* + * Constant size types and structures to allow 32-bit daemon to work with + * 64-bit libraries. + * + * Note - ulong long is 8 bytes for both 32-bit and 64-bit applications. + * + */ + +typedef signed long long pid_t_64; +typedef unsigned long long time_t_64; +typedef unsigned long long CK_SLOT_ID_64; +typedef unsigned long long CK_FLAGS_64; + +typedef struct CK_INFO_64 { + CK_VERSION cryptokiVersion; /* Cryptoki interface ver */ + CK_CHAR manufacturerID[32]; /* blank padded */ + CK_CHAR pad1[6]; /* pad for dword alignment */ + CK_FLAGS_64 flags; /* must be zero */ + + /* libraryDescription and libraryVersion are new for v2.0 */ + CK_CHAR libraryDescription[32]; /* blank padded */ + CK_VERSION libraryVersion; /* version of library */ + CK_CHAR pad2[6]; /* pad for dword alignment */ +} CK_INFO_64; + +typedef CK_INFO_64 CK_PTR CK_INFO_PTR_64; + +typedef struct CK_SLOT_INFO_64 { + CK_CHAR slotDescription[64]; /* blank padded */ + CK_CHAR manufacturerID[32]; /* blank padded */ + CK_FLAGS_64 flags; + + /* hardwareVersion and firmwareVersion are new for v2.0 */ + CK_VERSION hardwareVersion; /* version of hardware */ + CK_VERSION firmwareVersion; /* version of firmware */ + CK_CHAR pad[4]; /* pad for dword alignment */ +} CK_SLOT_INFO_64; + + +typedef struct Slot_Mgr_Proc_t_64 { + // pthread_cond_t proc_slot_cond; + + CK_BOOL inuse; // flag indicating if the entry is in use + pid_t proc_id; /* This could also be used to indicate inuse. + * however we will actualy use it to provide + * a check for a bad process which did not + * C_finalize and remove itself properly. + */ + uint32 slotmap; /* Bit map of the slots with events App uses + * this in the C_WaitForSlotEvent call + */ + + uint8 blocking; /* Flag to use if a thread is blocking on the + * condition variable Used by C_Finalize to + * wake up the + */ + + uint8 error; /* indication of an error causing the thread + * sleeping on the condition variable to wakeup. + */ + uint32 slot_session_count[NUMBER_SLOTS_MANAGED]; /* Per process session + * count for garbage + * collection clean up + * of the global + * session count. + */ + time_t_64 reg_time; // Time application registered +} Slot_Mgr_Proc_t_64; + +// +// Shared Memory Region of Slot information +// + +// Slot info structure which contains the PKCS11 CK_SLOT_INFO +// as well as the local information +typedef struct { + CK_SLOT_ID_64 slot_number; + CK_BOOL present; + char pad1[7]; // pad for dword alignment + CK_SLOT_INFO_64 pk_slot; + char dll_location[NAME_MAX + 1]; // location of slot's DLL + char confname[NAME_MAX + 1]; // token specific config file + char tokname[NAME_MAX + 1]; // token specific directory + LW_SHM_TYPE *shm_addr; // token specific shm address + uint32_t version; // version: major<<16|minor +} Slot_Info_t_64; + +typedef Slot_Info_t_64 SLOT_INFO; + +typedef struct { + + /* Information that the API calls will use. */ + uint32 slot_global_sessions[NUMBER_SLOTS_MANAGED]; + Slot_Mgr_Proc_t_64 proc_table[NUMBER_PROCESSES_ALLOWED]; +} Slot_Mgr_Shr_t; + +typedef struct { + uint8 num_slots; + CK_INFO_64 ck_info; + Slot_Info_t_64 slot_info[NUMBER_SLOTS_MANAGED]; +} Slot_Mgr_Socket_t; + +#else // PKCS64 + +typedef struct { + /* Information that the API calls will use. */ + uint32 slot_global_sessions[NUMBER_SLOTS_MANAGED]; + Slot_Mgr_Proc_t proc_table[NUMBER_PROCESSES_ALLOWED]; +} Slot_Mgr_Shr_t; + +typedef struct { + uint8 num_slots; + CK_INFO ck_info; + Slot_Info_t slot_info[NUMBER_SLOTS_MANAGED]; +} Slot_Mgr_Socket_t; + +typedef Slot_Info_t SLOT_INFO; + +#endif // PKCS64 + + +// Loging type constants +// +#define ERROR 1 +#define INFO 2 + + +// Call to populate the shared memory +#define STR "01234567890123456789012345678901" +#define MFG "IBM " +#define LIB "openCryptoki " + + +#define MAJOR_V 1 +#define MINOR_V 2 + +#ifndef CRYPTOKI_API_MAJOR_V +#define CRYPTOKI_API_MAJOR_V 0x2 +#endif + +#ifndef CRYPTOKI_API_MINOR_V +#define CRYPTOKI_API_MINOR_V 0x14 +#endif + +#define LIB_MAJOR_V 1 +#define LIB_MINOR_V 4 + +#define RESTART_SYS_CALLS 1 + +#endif /* _SLOTMGR_H */ diff --git a/usr/include/stdll.h b/usr/include/stdll.h new file mode 100644 index 0000000..cafdf82 --- /dev/null +++ b/usr/include/stdll.h @@ -0,0 +1,420 @@ +/* + * 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 + */ + +// +// API Local control blocks within the PKCS11 Meta API +// +// + + +#include +#include +#include +#include + +#include "local_types.h" + +#ifndef _STDLL_H +#define _STDLL_H + + +typedef struct { + struct bt_ref_hdr hdr; + CK_SLOT_ID slotID; + CK_SESSION_HANDLE sessionh; +} ST_SESSION_T; + +typedef struct trace_handle_t trace_handle; +typedef ST_SESSION_T ST_SESSION_HANDLE; + +/* CK_FUNCTION_LIST is a structure holding a Cryptoki spec + * version and pointers of appropriate types to all the + * Cryptoki functions + * CK_FUNCTION_LIST is new for v2.0 + */ + +typedef CK_RV (CK_PTR ST_C_Initialize) (API_Slot_t *sltp, CK_SLOT_ID slotID, + SLOT_INFO *sinfp, trace_handle t); + +typedef CK_RV (CK_PTR ST_C_Finalize) (CK_VOID_PTR pReserved); +typedef CK_RV (CK_PTR ST_C_Terminate) (void); +typedef CK_RV (CK_PTR ST_C_GetInfo) (CK_INFO_PTR pInfo); +typedef CK_RV (CK_PTR ST_C_GetFunctionList) (CK_FUNCTION_LIST_PTR_PTR + ppFunctionList); +typedef CK_RV (CK_PTR ST_C_GetSlotList) (CK_BBOOL tokenPresent, + CK_SLOT_ID_PTR pSlotList, + CK_ULONG_PTR pusCount); +typedef CK_RV (CK_PTR ST_C_GetSlotInfo) (CK_SLOT_ID slotID, + CK_SLOT_INFO_PTR pInfo); +typedef CK_RV (CK_PTR ST_C_GetTokenInfo) (STDLL_TokData_t *tokdata, + CK_SLOT_ID slotID, + CK_TOKEN_INFO_PTR pInfo); +typedef CK_RV (CK_PTR ST_C_GetMechanismList) (STDLL_TokData_t *tokdata, + CK_SLOT_ID slotID, + CK_MECHANISM_TYPE_PTR + pMechanismList, + CK_ULONG_PTR pusCount); +typedef CK_RV (CK_PTR ST_C_GetMechanismInfo) (STDLL_TokData_t *tokdata, + CK_SLOT_ID slotID, + CK_MECHANISM_TYPE type, + CK_MECHANISM_INFO_PTR pInfo); +typedef CK_RV (CK_PTR ST_C_InitToken) (STDLL_TokData_t *tokdata, + CK_SLOT_ID slotID, CK_CHAR_PTR pPin, + CK_ULONG usPinLen, CK_CHAR_PTR pLabel); +typedef CK_RV (CK_PTR ST_C_InitPIN) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, CK_CHAR_PTR pPin, + CK_ULONG usPinLen); +typedef CK_RV (CK_PTR ST_C_SetPIN) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, CK_CHAR_PTR pOldPin, + CK_ULONG usOldLen, CK_CHAR_PTR pNewPin, + CK_ULONG usNewLen); + +// typedef CK_RV (CK_PTR ST_C_OpenSession) +// (CK_SLOT_ID slotID, CK_FLAGS flags, +// CK_VOID_PTR pApplication, +// CK_RV (*Notify) (CK_SESSION_HANDLE hSession, +// CK_NOTIFICATION event, CK_VOID_PTR pApplication), +// CK_SESSION_HANDLE_PTR phSession); + +typedef CK_RV (CK_PTR ST_C_OpenSession) (STDLL_TokData_t *tokdata, + CK_SLOT_ID slotID, CK_FLAGS flags, + CK_SESSION_HANDLE_PTR phSession); + +typedef CK_RV (CK_PTR ST_C_CloseSession) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BBOOL in_fork_initializer); +typedef CK_RV (CK_PTR ST_C_CloseAllSessions) (STDLL_TokData_t *tokdata, + CK_SLOT_ID slotID); +typedef CK_RV (CK_PTR ST_C_GetSessionInfo) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_SESSION_INFO_PTR pInfo); +typedef CK_RV (CK_PTR ST_C_GetOperationState) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pOperationState, + CK_ULONG_PTR + pulOperationStateLen); +typedef CK_RV (CK_PTR ST_C_SetOperationState) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pOperationState, + CK_ULONG ulOperationStateLen, + CK_OBJECT_HANDLE hEncryptionKey, + CK_OBJECT_HANDLE + hAuthenticationKey); +typedef CK_RV (CK_PTR ST_C_Login) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_USER_TYPE userType, CK_CHAR_PTR pPin, + CK_ULONG usPinLen); +typedef CK_RV (CK_PTR ST_C_Logout) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession); +typedef CK_RV (CK_PTR ST_C_CreateObject) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG usCount, + CK_OBJECT_HANDLE_PTR phObject); + +typedef CK_RV (CK_PTR ST_C_CopyObject) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG usCount, + CK_OBJECT_HANDLE_PTR phNewObject); +typedef CK_RV (CK_PTR ST_C_DestroyObject) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_OBJECT_HANDLE hObject); +typedef CK_RV (CK_PTR ST_C_GetObjectSize) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_OBJECT_HANDLE hObject, + CK_ULONG_PTR pusSize); +typedef CK_RV (CK_PTR ST_C_GetAttributeValue) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG usCount); +typedef CK_RV (CK_PTR ST_C_SetAttributeValue) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG usCount); +typedef CK_RV (CK_PTR ST_C_FindObjectsInit) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG usCount); +typedef CK_RV (CK_PTR ST_C_FindObjects) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_OBJECT_HANDLE_PTR phObject, + CK_ULONG usMaxObjectCount, + CK_ULONG_PTR pusObjectCount); +typedef CK_RV (CK_PTR ST_C_FindObjectsFinal) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession); +typedef CK_RV (CK_PTR ST_C_EncryptInit) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); +typedef CK_RV (CK_PTR ST_C_Encrypt) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, CK_BYTE_PTR pData, + CK_ULONG usDataLen, + CK_BYTE_PTR pEncryptedData, + CK_ULONG_PTR pusEncryptedDataLen); +typedef CK_RV (CK_PTR ST_C_EncryptUpdate) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pPart, CK_ULONG usPartLen, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pusEncryptedPartLen); +typedef CK_RV (CK_PTR ST_C_EncryptFinal) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pLastEncryptedPart, + CK_ULONG_PTR pusLastEncryptedPartLen); +typedef CK_RV (CK_PTR ST_C_DecryptInit) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); +typedef CK_RV (CK_PTR ST_C_Decrypt) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pEncryptedData, + CK_ULONG usEncryptedDataLen, + CK_BYTE_PTR pData, CK_ULONG_PTR pusDataLen); +typedef CK_RV (CK_PTR ST_C_DecryptUpdate) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG usEncryptedPartLen, + CK_BYTE_PTR pPart, + CK_ULONG_PTR pusPartLen); +typedef CK_RV (CK_PTR ST_C_DecryptFinal) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pLastPart, + CK_ULONG_PTR pusLastPartLen); +typedef CK_RV (CK_PTR ST_C_DigestInit) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_MECHANISM_PTR pMechanism); +typedef CK_RV (CK_PTR ST_C_Digest) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, CK_BYTE_PTR pData, + CK_ULONG usDataLen, CK_BYTE_PTR pDigest, + CK_ULONG_PTR pusDigestLen); +typedef CK_RV (CK_PTR ST_C_DigestUpdate) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pPart, CK_ULONG usPartLen); +typedef CK_RV (CK_PTR ST_C_DigestKey) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_OBJECT_HANDLE hKey); +typedef CK_RV (CK_PTR ST_C_DigestFinal) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pDigest, + CK_ULONG_PTR pusDigestLen); +typedef CK_RV (CK_PTR ST_C_SignInit) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); +typedef CK_RV (CK_PTR ST_C_Sign) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, CK_BYTE_PTR pData, + CK_ULONG usDataLen, CK_BYTE_PTR pSignature, + CK_ULONG_PTR pusSignatureLen); +typedef CK_RV (CK_PTR ST_C_SignUpdate) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pPart, CK_ULONG usPartLen); +typedef CK_RV (CK_PTR ST_C_SignFinal) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pSignature, + CK_ULONG_PTR pusSignatureLen); +typedef CK_RV (CK_PTR ST_C_SignRecoverInit) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); +typedef CK_RV (CK_PTR ST_C_SignRecover) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pData, CK_ULONG usDataLen, + CK_BYTE_PTR pSignature, + CK_ULONG_PTR pusSignatureLen); +typedef CK_RV (CK_PTR ST_C_VerifyInit) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); +typedef CK_RV (CK_PTR ST_C_Verify) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, CK_BYTE_PTR pData, + CK_ULONG usDataLen, CK_BYTE_PTR pSignature, + CK_ULONG usSignatureLen); +typedef CK_RV (CK_PTR ST_C_VerifyUpdate) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pPart, CK_ULONG usPartLen); +typedef CK_RV (CK_PTR ST_C_VerifyFinal) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pSignature, + CK_ULONG usSignatureLen); +typedef CK_RV (CK_PTR ST_C_VerifyRecoverInit) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hKey); +typedef CK_RV (CK_PTR ST_C_VerifyRecover) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pSignature, + CK_ULONG usSignatureLen, + CK_BYTE_PTR pData, + CK_ULONG_PTR pusDataLen); +typedef CK_RV (CK_PTR ST_C_DigestEncryptUpdate) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pPart, + CK_ULONG ulPartLen, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR + pulEncryptedPartLen); +typedef CK_RV (CK_PTR ST_C_DecryptDigestUpdate) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, + CK_BYTE_PTR pPart, + CK_ULONG_PTR pulPartLen); +typedef CK_RV (CK_PTR ST_C_SignEncryptUpdate) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pPart, + CK_ULONG ulPartLen, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen); +typedef CK_RV (CK_PTR ST_C_DecryptVerifyUpdate) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, + CK_BYTE_PTR pPart, + CK_ULONG_PTR pulPartLen); +typedef CK_RV (CK_PTR ST_C_GenerateKey) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_MECHANISM_PTR pMechanism, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG usCount, + CK_OBJECT_HANDLE_PTR phKey); +typedef CK_RV (CK_PTR ST_C_GenerateKeyPair) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_MECHANISM_PTR pMechanism, + CK_ATTRIBUTE_PTR pPublicKeyTemplate, + CK_ULONG usPublicKeyAttributeCount, + CK_ATTRIBUTE_PTR + pPrivateKeyTemplate, + CK_ULONG usPrivateKeyAttributeCount, + CK_OBJECT_HANDLE_PTR phPrivateKey, + CK_OBJECT_HANDLE_PTR phPublicKey); +typedef CK_RV (CK_PTR ST_C_WrapKey) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hWrappingKey, + CK_OBJECT_HANDLE hKey, + CK_BYTE_PTR pWrappedKey, + CK_ULONG_PTR pusWrappedKeyLen); +typedef CK_RV (CK_PTR ST_C_UnwrapKey) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hUnwrappingKey, + CK_BYTE_PTR pWrappedKey, + CK_ULONG usWrappedKeyLen, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG usAttributeCount, + CK_OBJECT_HANDLE_PTR phKey); +typedef CK_RV (CK_PTR ST_C_DeriveKey) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hBaseKey, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG usAttributeCount, + CK_OBJECT_HANDLE_PTR phKey); +typedef CK_RV (CK_PTR ST_C_SeedRandom) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pSeed, CK_ULONG usSeedLen); +typedef CK_RV (CK_PTR ST_C_GenerateRandom) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession, + CK_BYTE_PTR pRandomData, + CK_ULONG usRandomLen); +typedef CK_RV (CK_PTR ST_C_GetFunctionStatus) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession); +typedef CK_RV (CK_PTR ST_C_CancelFunction) (STDLL_TokData_t *tokdata, + ST_SESSION_T *hSession); +typedef CK_RV (CK_PTR ST_Notify) (ST_SESSION_T *hSession, + CK_NOTIFICATION event, + CK_VOID_PTR pApplication); +typedef CK_RV (CK_PTR ST_C_WaitForSlotEvent) (STDLL_TokData_t *tokdata, + CK_FLAGS flags, + CK_SLOT_ID_PTR pSlot, + CK_VOID_PTR pReserved); + + + +struct ST_FCN_LIST { + + // Need initialization function But it is different than + // the C_Initialize + ST_C_Initialize ST_Initialize; + + ST_C_GetTokenInfo ST_GetTokenInfo; + ST_C_GetMechanismList ST_GetMechanismList; + ST_C_GetMechanismInfo ST_GetMechanismInfo; + ST_C_InitToken ST_InitToken; + ST_C_InitPIN ST_InitPIN; + ST_C_SetPIN ST_SetPIN; + + ST_C_OpenSession ST_OpenSession; + ST_C_CloseSession ST_CloseSession; + ST_C_GetSessionInfo ST_GetSessionInfo; + ST_C_GetOperationState ST_GetOperationState; // Not used by Netscape + ST_C_SetOperationState ST_SetOperationState; // Not used by Netscape + ST_C_Login ST_Login; + ST_C_Logout ST_Logout; + + ST_C_CreateObject ST_CreateObject; + ST_C_CopyObject ST_CopyObject; + ST_C_DestroyObject ST_DestroyObject; + ST_C_GetObjectSize ST_GetObjectSize; + ST_C_GetAttributeValue ST_GetAttributeValue; + ST_C_SetAttributeValue ST_SetAttributeValue; + ST_C_FindObjectsInit ST_FindObjectsInit; + ST_C_FindObjects ST_FindObjects; + ST_C_FindObjectsFinal ST_FindObjectsFinal; + + + ST_C_EncryptInit ST_EncryptInit; + ST_C_Encrypt ST_Encrypt; + ST_C_EncryptUpdate ST_EncryptUpdate; // Not used by Netscape + ST_C_EncryptFinal ST_EncryptFinal; // Not used by Netscape + ST_C_DecryptInit ST_DecryptInit; + ST_C_Decrypt ST_Decrypt; + ST_C_DecryptUpdate ST_DecryptUpdate; // Not used by Netscape + ST_C_DecryptFinal ST_DecryptFinal; // Not used by Netscape + ST_C_DigestInit ST_DigestInit; + ST_C_Digest ST_Digest; + ST_C_DigestUpdate ST_DigestUpdate; + ST_C_DigestKey ST_DigestKey; + ST_C_DigestFinal ST_DigestFinal; + ST_C_SignInit ST_SignInit; + ST_C_Sign ST_Sign; + ST_C_SignUpdate ST_SignUpdate; + ST_C_SignFinal ST_SignFinal; + ST_C_SignRecoverInit ST_SignRecoverInit; + ST_C_SignRecover ST_SignRecover; + ST_C_VerifyInit ST_VerifyInit; + ST_C_Verify ST_Verify; + ST_C_VerifyUpdate ST_VerifyUpdate; + ST_C_VerifyFinal ST_VerifyFinal; + ST_C_VerifyRecoverInit ST_VerifyRecoverInit; + ST_C_VerifyRecover ST_VerifyRecover; + ST_C_DigestEncryptUpdate ST_DigestEncryptUpdate; + ST_C_DecryptDigestUpdate ST_DecryptDigestUpdate; + ST_C_SignEncryptUpdate ST_SignEncryptUpdate; + ST_C_DecryptVerifyUpdate ST_DecryptVerifyUpdate; + ST_C_GenerateKey ST_GenerateKey; + ST_C_GenerateKeyPair ST_GenerateKeyPair; + ST_C_WrapKey ST_WrapKey; // Netscape optionsl will use En/Decrypt + ST_C_UnwrapKey ST_UnwrapKey; + ST_C_DeriveKey ST_DeriveKey; + ST_C_SeedRandom ST_SeedRandom; + ST_C_GenerateRandom ST_GenerateRandom; + // Question if these have to be implemented for Netscape support + ST_C_GetFunctionStatus ST_GetFunctionStatus; + ST_C_CancelFunction ST_CancelFunction; + +}; + +typedef struct ST_FCN_LIST STDLL_FcnList_t; + +#endif diff --git a/usr/lib/api/api.mk b/usr/lib/api/api.mk new file mode 100644 index 0000000..630a43b --- /dev/null +++ b/usr/lib/api/api.mk @@ -0,0 +1,30 @@ +nobase_lib_LTLIBRARIES += opencryptoki/libopencryptoki.la + +noinst_HEADERS += usr/lib/api/apiproto.h + +SO_CURRENT=0 +SO_REVISION=0 +SO_AGE=0 + +opencryptoki_libopencryptoki_la_CFLAGS = \ + -DAPI -DDEV -D_THREAD_SAFE -fPIC -I${srcdir}/usr/include \ + -I${srcdir}/usr/lib/common -I${srcdir}/usr/lib/api \ + -DSTDLL_NAME=\"api\" + +opencryptoki_libopencryptoki_la_LDFLAGS = \ + -shared -Wl,-z,defs,-Bsymbolic -lc -ldl -lpthread \ + -version-info $(SO_CURRENT):$(SO_REVISION):$(SO_AGE) \ + -Wl,--version-script=${srcdir}/opencryptoki.map + +opencryptoki_libopencryptoki_la_SOURCES = \ + usr/lib/api/api_interface.c usr/lib/api/shrd_mem.c \ + usr/lib/api/socket_client.c usr/lib/api/apiutil.c \ + usr/lib/common/trace.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 diff --git a/usr/lib/api/api_interface.c b/usr/lib/api/api_interface.c new file mode 100644 index 0000000..51ab30f --- /dev/null +++ b/usr/lib/api/api_interface.c @@ -0,0 +1,4278 @@ +/* + * 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 + */ + +#if NGPTH +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include "trace.h" +#include "ock_syslog.h" + +void api_init(); + +// NOTES: +// In many cases the specificaiton does not allow returns +// of CKR_ARGUMENTSB_BAD. We break the spec, since validation of parameters +// to the function are best represented by this return code (where +// specific RC's such as CKR_INVALID_SESSION do not exist). +// NOTE NOTE NOTE NOTE +// The parameter checking on the update operations may need to be +// modified (as well as the encrypt/decrypt) to call the stdll +// anyway with sanatized parameters since on error, the encrypt/decrypt +// sign operations are all supposed to complete. +// Therefor the parameter checking here might need to be done in +// the STDLL instead of the API. +// This would affect ALL the Multipart operations which have +// an init followed by one or more operations. + +// Globals for the API + +API_Proc_Struct_t *Anchor = NULL; // Initialized to NULL +unsigned int Initialized = 0; // Initialized flag +pthread_mutex_t GlobMutex = PTHREAD_MUTEX_INITIALIZER; // Global Mutex +CK_FUNCTION_LIST FuncList; + +int slot_loaded[NUMBER_SLOTS_MANAGED]; // Array of flags to indicate + // if the STDLL loaded + +CK_BBOOL in_child_fork_initializer = FALSE; + +void child_fork_initializer() +{ + /* + * Reinitialize trace so that the trace output appears under the new + * process's trace file, and not in the parent process's once. + * C_Finalize will pass the new trace handle to the tokens, so that their + * finalization code will also trace into the new trace file. + */ + trace_finalize(); + trace_initialize(); + /* + * Terminate all slots by calling C_Finalize(). This will also free the + * Anchor and set it to NULL. + * A forked child is no PKCS11 application after fork. Thus it needs to + * call C_Initialize again to become a PKC11 application and be able to + * use Opencryptoki. + * Indicate that we are in the fork initializer. + * A forked child process has the same mapped memory as the parent, but + * since client is no PKCS11 application after fork, it must not update + * (i.e decrease) the reference count during C_Finalize. + * If the client calls C_Initialize to become a PKCS11 application, it + * will then increase the reference count. + */ + in_child_fork_initializer = TRUE; + if (Anchor != NULL) + C_Finalize(NULL); + in_child_fork_initializer = FALSE; + } + +//------------------------------------------------------------------------ +// API function C_CancelFunction +//------------------------------------------------------------------------ +// This is a legacy function and performs no operations per the +// specification. +CK_RV C_CancelFunction(CK_SESSION_HANDLE hSession) +{ + UNUSED(hSession); + + TRACE_INFO("C_CancelFunction\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_PARALLEL)); + + return CKR_FUNCTION_NOT_PARALLEL; // PER PKCS#11v2.20,Sec 11.16 +} + +//------------------------------------------------------------------------ +// API function C_CloseAllSessions +//------------------------------------------------------------------------ +// Netscape Required +// +// This is a special one since the API can do this by removing +// all active sessions on the slot... The STDLL does not have to implement +// this. however this function will fail if any Session removal fails +// in the walk. Which could lead to undetermined results. +// +//------------------------------------------------------------------------ + +CK_RV C_CloseAllSessions(CK_SLOT_ID slotID) +{ + // Although why does modutil do a close all sessions. It is a single + // application it can only close its sessions... + // And all sessions should be closed anyhow. + + TRACE_INFO("CloseAllSessions\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (slotID >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + return CKR_SLOT_ID_INVALID; + } + + /* for every node in the API-level session tree, if the session's slot + * matches slotID, close it + */ + CloseAllSessions(slotID, FALSE); + + return CKR_OK; +} // end of C_CloseAllSessions + +//------------------------------------------------------------------------ +// API function C_CloseSession +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_CloseSession(CK_SESSION_HANDLE hSession) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_CloseSession\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_CloseSession) { + // Map the Session to the slot session + rv = fcn->ST_CloseSession(sltp->TokData, &rSession, FALSE); + TRACE_DEVEL("Called STDLL rv = 0x%lx\n", rv); + // If the STDLL successfully closed the session + // we can free it.. Otherwise we will have to leave it + // lying arround. + if (rv == CKR_OK) { + RemoveFromSessionList(hSession); + // Need to decrement the global slot session count as well + // as the per process slot session count to allow for + // proper tracking of the number of sessions on a slot. + // This allows things like InitToken to properly work in case + // other applications have the token active. + decr_sess_counts(rSession.slotID); + } else { + TRACE_DEVEL("fcn->ST_CloseSession failed:0x%lx\n", rv); + } + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_CloseSession + +//------------------------------------------------------------------------ +// API function C_CopyObject +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_CopyObject\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + if (!phNewObject) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + // null template with a count... will cause the lower layer + // to have problems + // Template with 0 count is not a problem. we can let + // the STDLL handle that... + if (!pTemplate && ulCount) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_CopyObject) { + // Map the Session to the slot session + rv = fcn->ST_CopyObject(sltp->TokData, &rSession, hObject, + pTemplate, ulCount, phNewObject); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_CopyObject + +//------------------------------------------------------------------------ +// API function C_CreateObject +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_CreateObject(CK_SESSION_HANDLE hSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_CreateObject\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + // Null template is invalid... An object needs a minimal + // template for creation. + if (!pTemplate) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + // A 0 count for the template is bad + if (ulCount == 0) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + // A Null pointer to return the handle in is also bad + // since we could de-reference incorrectly. + if (!phObject) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_CreateObject) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_CreateObject + +//------------------------------------------------------------------------ +// API function C_Decrypt +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ +CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedData, + CK_ULONG ulEncryptedDataLen, + CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_Decrypt\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_Decrypt) { + // Map the Session to the slot session + rv = fcn->ST_Decrypt(sltp->TokData, &rSession, pEncryptedData, + ulEncryptedDataLen, pData, pulDataLen); + TRACE_DEVEL("fcn->ST_Decrypt returned:0x%lx\n", rv); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_Decrypt + +//------------------------------------------------------------------------ +// API function C_DecryptDigestUpdate +//------------------------------------------------------------------------ +// Netscape Required + +CK_RV C_DecryptDigestUpdate(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, + CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_DecryptDigestUpdate\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + // This may have to go to the STDLL for validation + if (!pEncryptedPart || !pulPartLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_DecryptDigestUpdate) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_DecryptFinal +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_DecryptFinal(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_DecryptFinal\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_DecryptFinal) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_DecryptFinal + +//------------------------------------------------------------------------ +// API function C_DecryptInit +//------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_DecryptInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_DecryptInit\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + // Null mechanism pointer is not good + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_DecryptInit) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_DecryptInit + +//------------------------------------------------------------------------ +// API function C_DecryptUpdate +//------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_DecryptUpdate(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, + CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_DecryptUpdate\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_DecryptUpdate) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_DecryptUpdate + +//------------------------------------------------------------------------ +// API function C_DecryptVerifyUpdate +//------------------------------------------------------------------------ + +CK_RV C_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, + CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_DecryptVerifyUpdate\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + // May have to let these go through and let the STDLL handle them + if (!pEncryptedPart || !pulPartLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_DecryptVerifyUpdate) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_DeriveKey +//------------------------------------------------------------------------ + +CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hBaseKey, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_DeriveKey\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + // Null phKey is invalid + // Null mechanism pointer is invalid + // This is allowed for some SSL3 mechs. the STDLL has to catch this + // condition since it validates the mechanism + //if (!phKey ) return CKR_ARGUMENTS_BAD; + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + // Null template with attribute count is bad + // but we will let a template with len 0 pass through + if (!pTemplate && ulAttributeCount) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_DeriveKey) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_DestroyObject +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_DestroyObject\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_DestroyObject) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_DestroyObject + +//------------------------------------------------------------------------ +// API function C_Digest +//------------------------------------------------------------------------ + +CK_RV C_Digest(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, + CK_ULONG_PTR pulDigestLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_Digest\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_Digest) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_DigestEncryptUpdate +//------------------------------------------------------------------------ + +CK_RV C_DigestEncryptUpdate(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, + CK_ULONG ulPartLen, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_DigestEncryptUpdate\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + // May have to pass on through to the STDLL + if (!pPart || !pulEncryptedPartLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_DigestEncryptUpdate) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_DigestFinal +//------------------------------------------------------------------------ + +CK_RV C_DigestFinal(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_DigestFinal\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_DigestFinal) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_DigestInit +//------------------------------------------------------------------------ + +CK_RV C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_DigestInit\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_DigestInit) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_DigestKey +//------------------------------------------------------------------------ + +CK_RV C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_DigestKey\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_DigestKey) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_DigestUpdate +//------------------------------------------------------------------------ + +CK_RV C_DigestUpdate(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_DigestUpdate\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_DigestUpdate) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_Encrypt +//------------------------------------------------------------------------ + +CK_RV C_Encrypt(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pData, + CK_ULONG ulDataLen, + CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_Encrypt\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_Encrypt) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_EncryptFinal +//------------------------------------------------------------------------ + +CK_RV C_EncryptFinal(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pLastEncryptedPart, + CK_ULONG_PTR pulLastEncryptedPartLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_EncryptFinal\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_EncryptFinal) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_EncryptInit +//------------------------------------------------------------------------ + +CK_RV C_EncryptInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_EncryptInit\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_EncryptInit) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_EncryptUpdate +//------------------------------------------------------------------------ + +CK_RV C_EncryptUpdate(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, + CK_ULONG ulPartLen, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_EncryptUpdate\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_EncryptUpdate) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_Finalize +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_Finalize(CK_VOID_PTR pReserved) +{ + API_Slot_t *sltp; + CK_SLOT_ID slotID; + Slot_Mgr_Socket_t *shData; + SLOT_INFO *sinfp; + CK_RV rc = CKR_OK; + + if (pReserved != NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + /* + * Lock so that only one thread can run C_Initialize or C_Finalize at + * a time + */ + pthread_mutex_lock(&GlobMutex); // Grab Process level Global MUTEX + + TRACE_INFO("C_Finalize\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + shData = &(Anchor->SocketDataP); + + // unload all the STDLL's from the application + // This is in case the APP decides to do the re-initialize and + // continue on + for (slotID = 0; slotID < NUMBER_SLOTS_MANAGED; slotID++) { + sltp = &(Anchor->SltList[slotID]); + if (slot_loaded[slotID]) { + CloseAllSessions(slotID, in_child_fork_initializer); + if (sltp->pSTfini) { + sinfp = &(shData->slot_info[slotID]); + // call the terminate function.. + sltp->pSTfini(sltp->TokData, slotID, sinfp, &trace, + in_child_fork_initializer); + } + } + + DL_UnLoad(sltp, slotID); + } + + // Un register from Slot D + API_UnRegister(); + + bt_destroy(&Anchor->sess_btree); + + detach_shared_memory(Anchor->SharedMemP); + free(Anchor); // Free API Proc Struct + Anchor = NULL; + + trace_finalize(); + + //close the lock file descriptor here to avoid memory leak + ProcClose(); + +done: + // Unlock + pthread_mutex_unlock(&GlobMutex); + + return rc; +} // end of C_Finalize + +//------------------------------------------------------------------------ +// API function C_FindObjects +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_FindObjects(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE_PTR phObject, + CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_FindObjects\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!phObject || !pulObjectCount) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_FindObjects) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_FindObjects + +//------------------------------------------------------------------------ +// API function C_FindObjectsFinal +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE hSession) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_FindObjectsFinal\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_FindObjectsFinal) { + // Map the Session to the slot session + rv = fcn->ST_FindObjectsFinal(sltp->TokData, &rSession); + TRACE_DEVEL("fcn->ST_FindObjectsFinal returned: 0x%lx\n", rv); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_FindObjectsFinal + +//------------------------------------------------------------------------ +// API function +// C_FindObjectsInit +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_FindObjectsInit\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + // What does a NULL template really mean + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_FindObjectsInit) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_FindObjectsInit + +//------------------------------------------------------------------------ +// API function C_GenerateKey +//------------------------------------------------------------------------ +// Netscape Required + +CK_RV C_GenerateKey(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_GenerateKey\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + if (!phKey) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_GenerateKey) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_GenerateKeyPair +//------------------------------------------------------------------------ +// Netscape Required + +CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_ATTRIBUTE_PTR pPublicKeyTemplate, + CK_ULONG ulPublicKeyAttributeCount, + CK_ATTRIBUTE_PTR pPrivateKeyTemplate, + CK_ULONG ulPrivateKeyAttributeCount, + CK_OBJECT_HANDLE_PTR phPublicKey, + CK_OBJECT_HANDLE_PTR phPrivateKey) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_GenerateKeyPair\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + if (!phPublicKey || !phPrivateKey) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + // what other validation of parameters ... What about + // template pointers is a Null template pointer valid in generate + // key... Are there defaults. + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_GenerateKeyPair) { + // Map the Session to the slot session + rv = fcn->ST_GenerateKeyPair(sltp->TokData, &rSession, + pMechanism, + pPublicKeyTemplate, + ulPublicKeyAttributeCount, + pPrivateKeyTemplate, + ulPrivateKeyAttributeCount, + phPublicKey, phPrivateKey); + TRACE_DEVEL("fcn->ST_GenerateKeyPair returned:0x%lx\n", rv); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_GenerateRandom +//------------------------------------------------------------------------ +// Netscape Required + +CK_RV C_GenerateRandom(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR RandomData, CK_ULONG ulRandomLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_GenerateRandom\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!RandomData) + return CKR_ARGUMENTS_BAD; + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_GenerateRandom) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_GetAttributeValue +//------------------------------------------------------------------------ +// Netscape Required +// +// +//------------------------------------------------------------------------ + +CK_RV C_GetAttributeValue(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_GetAttributeValue\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pTemplate) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + if (ulCount == 0) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_GetAttributeValue) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_GetAttributeValue + +//------------------------------------------------------------------------ +// API function C_GetFunctionList +//------------------------------------------------------------------------ +// Netscape Required + +CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) +{ + api_init(); + + TRACE_INFO("C_GetFunctionList\n"); + FuncList.version.major = VERSION_MAJOR; + FuncList.version.minor = VERSION_MINOR; + FuncList.C_Initialize = C_Initialize; + FuncList.C_Finalize = C_Finalize; + FuncList.C_GetInfo = C_GetInfo; + FuncList.C_GetFunctionList = C_GetFunctionList; + FuncList.C_GetSlotList = C_GetSlotList; + FuncList.C_GetSlotInfo = C_GetSlotInfo; + FuncList.C_GetTokenInfo = C_GetTokenInfo; + FuncList.C_GetMechanismList = C_GetMechanismList; + FuncList.C_GetMechanismInfo = C_GetMechanismInfo; + FuncList.C_InitToken = C_InitToken; + FuncList.C_InitPIN = C_InitPIN; + FuncList.C_SetPIN = C_SetPIN; + FuncList.C_OpenSession = C_OpenSession; + FuncList.C_CloseSession = C_CloseSession; + FuncList.C_CloseAllSessions = C_CloseAllSessions; + FuncList.C_GetSessionInfo = C_GetSessionInfo; + FuncList.C_GetOperationState = C_GetOperationState; + FuncList.C_SetOperationState = C_SetOperationState; + FuncList.C_Login = C_Login; + FuncList.C_Logout = C_Logout; + FuncList.C_CreateObject = C_CreateObject; + FuncList.C_CopyObject = C_CopyObject; + FuncList.C_DestroyObject = C_DestroyObject; + FuncList.C_GetObjectSize = C_GetObjectSize; + FuncList.C_GetAttributeValue = C_GetAttributeValue; + FuncList.C_SetAttributeValue = C_SetAttributeValue; + FuncList.C_FindObjectsInit = C_FindObjectsInit; + FuncList.C_FindObjects = C_FindObjects; + FuncList.C_FindObjectsFinal = C_FindObjectsFinal; + FuncList.C_EncryptInit = C_EncryptInit; + FuncList.C_Encrypt = C_Encrypt; + FuncList.C_EncryptUpdate = C_EncryptUpdate; + FuncList.C_EncryptFinal = C_EncryptFinal; + FuncList.C_DecryptInit = C_DecryptInit; + FuncList.C_Decrypt = C_Decrypt; + FuncList.C_DecryptUpdate = C_DecryptUpdate; + FuncList.C_DecryptFinal = C_DecryptFinal; + FuncList.C_DigestInit = C_DigestInit; + FuncList.C_Digest = C_Digest; + FuncList.C_DigestUpdate = C_DigestUpdate; + FuncList.C_DigestKey = C_DigestKey; + FuncList.C_DigestFinal = C_DigestFinal; + FuncList.C_SignInit = C_SignInit; + FuncList.C_Sign = C_Sign; + FuncList.C_SignUpdate = C_SignUpdate; + FuncList.C_SignFinal = C_SignFinal; + FuncList.C_SignRecoverInit = C_SignRecoverInit; + FuncList.C_SignRecover = C_SignRecover; + FuncList.C_VerifyInit = C_VerifyInit; + FuncList.C_Verify = C_Verify; + FuncList.C_VerifyUpdate = C_VerifyUpdate; + FuncList.C_VerifyFinal = C_VerifyFinal; + FuncList.C_VerifyRecoverInit = C_VerifyRecoverInit; + FuncList.C_VerifyRecover = C_VerifyRecover; + FuncList.C_DigestEncryptUpdate = C_DigestEncryptUpdate; + FuncList.C_DecryptDigestUpdate = C_DecryptDigestUpdate; + FuncList.C_SignEncryptUpdate = C_SignEncryptUpdate; + FuncList.C_DecryptVerifyUpdate = C_DecryptVerifyUpdate; + FuncList.C_GenerateKey = C_GenerateKey; + FuncList.C_GenerateKeyPair = C_GenerateKeyPair; + FuncList.C_WrapKey = C_WrapKey; + FuncList.C_UnwrapKey = C_UnwrapKey; + FuncList.C_DeriveKey = C_DeriveKey; + FuncList.C_SeedRandom = C_SeedRandom; + FuncList.C_GenerateRandom = C_GenerateRandom; + FuncList.C_GetFunctionStatus = C_GetFunctionStatus; + FuncList.C_CancelFunction = C_CancelFunction; + FuncList.C_WaitForSlotEvent = C_WaitForSlotEvent; + + if (ppFunctionList) { + (*ppFunctionList) = &FuncList; + return CKR_OK; + } + + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + + return CKR_ARGUMENTS_BAD; +} + +//------------------------------------------------------------------------ +// API function C_GetFunctionStatus +//------------------------------------------------------------------------ + +CK_RV C_GetFunctionStatus(CK_SESSION_HANDLE hSession) +{ + UNUSED(hSession); + + TRACE_INFO("C_GetFunctionStatus\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_PARALLEL)); + + return CKR_FUNCTION_NOT_PARALLEL; // PER Specification PG 170 +} + +//------------------------------------------------------------------------ +// API function C_GetInfo +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_GetInfo(CK_INFO_PTR pInfo) +{ + Slot_Mgr_Socket_t *shData; + + TRACE_INFO("C_GetInfo\n"); + if (!API_Initialized()) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + shData = &(Anchor->SocketDataP); + + if (!pInfo) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + CK_Info_From_Internal(pInfo, &(shData->ck_info)); + + return CKR_OK; +} // end of C_GetInfo + + +//------------------------------------------------------------------------ +// API function C_GetMechanismInfo +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID, + CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + + TRACE_INFO("C_GetMechansimInfo %lu %lx %p\n", slotID, type, + (void *)pInfo); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (slotID >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + return CKR_SLOT_ID_INVALID; + } + + sltp = &(Anchor->SltList[slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_GetMechanismInfo) { + rv = fcn->ST_GetMechanismInfo(sltp->TokData, slotID, type, pInfo); + TRACE_DEVEL("fcn->ST_GetMechanismInfo returned:0x%lx\n", rv); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_GetMechanismInfo + +//------------------------------------------------------------------------ +// API function C_GetMechanismList +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_GetMechanismList(CK_SLOT_ID slotID, + CK_MECHANISM_TYPE_PTR pMechanismList, + CK_ULONG_PTR pulCount) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + + TRACE_INFO("C_GetMechanismList\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + // Always have to have a pulCount + if (!pulCount) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + TRACE_DEVEL("Slot %lu MechList %p Count %lu\n", + slotID, (void *)pMechanismList, *pulCount); + + // Null PMechanism is valid to get a count of mechanisms + + if (slotID >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + return CKR_SLOT_ID_INVALID; + } + + sltp = &(Anchor->SltList[slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_GetMechanismList) { + rv = fcn->ST_GetMechanismList(sltp->TokData, slotID, + pMechanismList, pulCount); + TRACE_DEVEL("fcn->ST_GetMechanismList returned: 0x%lx\n", rv); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + if (rv == CKR_OK) { + if (pMechanismList) { + unsigned long i; + for (i = 0; i < *pulCount; i++) { + TRACE_DEVEL("Mechanism[%lu] 0x%08lX \n", i, pMechanismList[i]); + } + } + } + + return rv; +} // end of C_GetMechanismList + +//------------------------------------------------------------------------ +// API function C_GetObjectSize +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_GetObjectSize(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_GetObjectSize\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pulSize) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_GetObjectSize) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_GetObjectSize + +//------------------------------------------------------------------------ +// API function C_GetOperationState +//------------------------------------------------------------------------ + +CK_RV C_GetOperationState(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pOperationState, + CK_ULONG_PTR pulOperationStateLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_GetOperateionState\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + // NULL pOperationState is valid to get buffer + // size + if (!pulOperationStateLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_GetOperationState) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_GetSessionInfo +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_GetSessionInfo %lx %p\n", hSession, (void *)pInfo); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pInfo) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_GetSessionInfo) { + // Map the Session to the slot session + rv = fcn->ST_GetSessionInfo(sltp->TokData, &rSession, pInfo); + + TRACE_DEVEL("fcn->ST_GetSessionInfo returned: 0x%lx\n", rv); + TRACE_DEVEL("Slot %lu State %lx Flags %lx DevErr %lx\n", + pInfo->slotID, pInfo->state, pInfo->flags, + pInfo->ulDeviceError); + + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_GetSessionInfo + +//------------------------------------------------------------------------ +// API function C_GetSlotInfo +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +#ifdef PKCS64 + +CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) +{ + Slot_Info_t_64 *sinfp; + Slot_Mgr_Socket_t *shData; + + TRACE_INFO("C_GetSlotInfo Slot=%lu ptr=%p\n", slotID, (void *)pInfo); + + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + shData = &(Anchor->SocketDataP); + + if (!pInfo) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + sinfp = shData->slot_info; + sinfp += slotID; + + if (slotID >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + return CKR_SLOT_ID_INVALID; + } + // Netscape and others appear to call + // this for every slot. If the slot does not have + // a registered STDLL, then this is a FUnction Failed case + if (sinfp->present == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + + } +#ifdef __64BIT__ + + memcpy(pInfo, (char *) &(sinfp->pk_slot), sizeof(CK_SLOT_INFO)); + +#else + + memcpy((char *) &(pInfo->slotDescription[0]), + (char *) &(sinfp->pk_slot.slotDescription[0]), + sizeof(pInfo->slotDescription)); + memcpy((char *) &(pInfo->manufacturerID[0]), + (char *) &(sinfp->pk_slot.manufacturerID[0]), + sizeof(pInfo->manufacturerID)); + + pInfo->flags = sinfp->pk_slot.flags; + pInfo->hardwareVersion = sinfp->pk_slot.hardwareVersion; + pInfo->firmwareVersion = sinfp->pk_slot.firmwareVersion; + +#endif + + return CKR_OK; +} // end of C_GetSlotInfo + +#else + +CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) +{ + uint16 count; + uint16 index; + uint16 sindx; + Slot_Info_t *sinfp; + Slot_Mgr_Socket_t *shData = &(Anchor->SocketDataP); + + TRACE_INFO("C_GetSlotInfo Slot=%d ptr=%p\n", slotID, (void *)pInfo); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pInfo) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + sinfp = shData->slot_info; + sinfp += slotID; + count = 0; + + if (slotID >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + return CKR_SLOT_ID_INVALID; + } + // Netscape and others appear to call + // this for every slot. If the slot does not have + // a registered STDLL, then this is a FUnction Failed case + if (sinfp->present == FALSE) { + TRACE_ERROR("%s: No STDLL present.\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + + } + memcpy(pInfo, (char *) &(sinfp->pk_slot), sizeof(CK_SLOT_INFO)); + + return CKR_OK; +} // end of C_GetSlotInfo + +#endif + +//------------------------------------------------------------------------ +// API function C_GetSlotList +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_GetSlotList(CK_BBOOL tokenPresent, + CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount) +{ + CK_ULONG count; + uint16 index; + uint16 sindx; + Slot_Mgr_Socket_t *shData; + +#ifdef PKCS64 + Slot_Info_t_64 *sinfp; +#else + Slot_Info_t *sinfp; +#endif + + TRACE_INFO("C_GetSlotList\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + shData = &(Anchor->SocketDataP); + + // Null pSlotList is valid to get count for array allocation + if (pulCount == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + TRACE_DEVEL(" Present %d Count %lu\n", tokenPresent, *pulCount); + + sinfp = shData->slot_info; + count = 0; + // Count the slots based off the present flag + // Go through all the slots and count them up + // Remember if the tokenPresent Flag is set do not count the + // not present ones. + // + // ------------------------------------------------------------ + // + // Present indicates that the slot is managed by the Slot manager + // and that an appropriate registration has been made in the DB + // + // It does not imply that a token is present. + // Slots with STDLL's are ALWAYS present in the system wether they + // have a token or not is determined from the token functions. + // + // According to the spec the tokenPresent flag indicates if all + // slots are wanted, or those which have tokens present. We will + // use this to mean if a STDLL is present or not. All slots + // are in the system, if a STDLL is attached to a slot, then it is + // present( not to be confused with the Tokens flags indicating + // presence). Presence of a STDLL on a slot indicates that there + // is a "token reader" available. + // + // Note: All slots should be named by the slot manager with the + // slot id in them... + // ------------------------------------------------------------ + // + // Note: The CK_INFO_STRUCT present flag indicates that a token is present + // in the reader located in the slot. Right now we are dealing only + // with non-removable tokens, so the slot flags set in the slot DB + // are fixed by the STDLL. Ultimately when we get to removable tokens, the + // slot manager will have to monitor the device in the slot and set the flag + // accordingly. + // + // This does however change the reporting back of Slot Lists... + // + // We were using the presence of a STDLL to indicate if a Token is present + // or not. however we need to report back based on 2 flags. + // + // First a stdll must be in the table, second the slot info flags must be + // set to present to return. + // ---------------------------------------------- + // + // Also need to validate that the STDLL successfully loaded. + + for (index = 0; index < NUMBER_SLOTS_MANAGED; index++) { + // if there is a STDLL in the slot then we have to count it + // otherwise the slot is NOT counted. + if (sinfp[index].present == TRUE && slot_loaded[index] == TRUE) { + if (tokenPresent) { + if ((sinfp[index].pk_slot.flags & CKF_TOKEN_PRESENT)) { + count++; + } + } else { + count++; + } + } + } + + // If only the count is wanted then we set the value and exit + if (pSlotList == NULL) { + *pulCount = count; + return CKR_OK; + } + + // Verify that the buffer passed is large enough + if (*pulCount < count) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + *pulCount = count; + return CKR_BUFFER_TOO_SMALL; + } + + *pulCount = count; + + // Walk through the slot manager information and copy in the + // slot id to the list of slot indexes. + // + // This is incorrectly going to assume that the slots are + // sequentialy allocated. While most likely we should be robust + // and handle it. + // Count should correct based on the first loop. + // + for (sindx = 0, index = 0; + (index < NUMBER_SLOTS_MANAGED) && (sindx < count); index++) { + if (sinfp[index].present == TRUE && slot_loaded[index] == TRUE) { + if (tokenPresent) { + if (sinfp[index].pk_slot.flags & CKF_TOKEN_PRESENT) { + pSlotList[sindx] = sinfp[index].slot_number; + sindx++; // only increment when we have used it. + } + } else { + pSlotList[sindx] = sinfp[index].slot_number; + sindx++; // only increment when we have used it. + } + } + + } + return CKR_OK; +} // end of C_GetSlotList + +//------------------------------------------------------------------------ +// API function C_GetTokenInfo +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + Slot_Mgr_Socket_t *shData; + +#ifdef PKCS64 + Slot_Info_t_64 *sinfp; +#else + Slot_Info_t *sinfp; +#endif + + TRACE_INFO("C_GetTokenInfo\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + shData = &(Anchor->SocketDataP); + + if (!pInfo) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + if (slotID >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + return CKR_SLOT_ID_INVALID; + } + + sltp = &(Anchor->SltList[slotID]); + TRACE_DEVEL("Slot p = %p id %lu\n", (void *)sltp, slotID); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + // Need to check if the slot is not populated + // then we can return the proper return code for a + // slot that has no content. + sinfp = shData->slot_info; + if (sinfp[slotID].present == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_GetTokenInfo) { + rv = fcn->ST_GetTokenInfo(sltp->TokData, slotID, pInfo); + if (rv == CKR_OK) { + get_sess_count(slotID, &(pInfo->ulSessionCount)); + } + TRACE_DEVEL("rv %lu CK_TOKEN_INFO Flags %lx\n", rv, pInfo->flags); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_GetTokenInfo + +void Call_Finalize() +{ + C_Finalize(NULL); + return; +} + +//------------------------------------------------------------------------ +// API function C_Initialize +//------------------------------------------------------------------------ +// Netscape Required +// +// +//------------------------------------------------------------------------ +CK_RV C_Initialize(CK_VOID_PTR pVoid) +{ + CK_C_INITIALIZE_ARGS *pArg; + char fcnmap = 0; + CK_RV rc = CKR_OK; + + /* + * Lock so that only one thread can run C_Initialize or C_Finalize at + * a time + */ + pthread_mutex_lock(&GlobMutex); + + trace_initialize(); + + TRACE_INFO("C_Initialize\n"); + + if (!Anchor) { + Anchor = (API_Proc_Struct_t *) malloc(sizeof(API_Proc_Struct_t)); + if (Anchor == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + } else { + // Linux the atfork routines handle this + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_ALREADY_INITIALIZED)); + rc = CKR_CRYPTOKI_ALREADY_INITIALIZED; + goto done; + } + + // Clear out the load list + memset(slot_loaded, 0, sizeof(int) * NUMBER_SLOTS_MANAGED); + + TRACE_DEBUG("Anchor allocated at %s\n", (char *) Anchor); + + // Validation of the parameters passed + + // if pVoid is NULL, then everything is OK. The applicaiton + // will not be doing multi thread accesses. We can use the OS + // locks anyhow. + // + if (pVoid != NULL) { + TRACE_DEVEL("Initialization arg = %p Flags %lu\n", pVoid, + ((CK_C_INITIALIZE_ARGS *) pVoid)->flags); + + pArg = (CK_C_INITIALIZE_ARGS *) pVoid; + + // Check for a pReserved set + if (pArg->pReserved != NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto error; + } + // Set up a bit map indicating the presense of the functions. + fcnmap = (pArg->CreateMutex ? 0x01 << 0 : 0); + fcnmap |= (pArg->DestroyMutex ? 0x01 << 1 : 0); + fcnmap |= (pArg->LockMutex ? 0x01 << 2 : 0); + fcnmap |= (pArg->UnlockMutex ? 0x01 << 3 : 0); + + // Verify that all or none of the functions are set + if (fcnmap != 0) { + if (fcnmap != 0x0f) { + OCK_SYSLOG(LOG_ERR, "C_Initialize: Invalid " + "number of functions passed in " + "argument structure.\n"); + rc = CKR_ARGUMENTS_BAD; + goto error; + } + } + // If we EVER need to create threads from this library we must + // check the Flags for the Can_Create_OS_Threads flag + // Right now the library DOES NOT create threads and therefore this + // check is irrelavant. + if (pArg->flags & CKF_LIBRARY_CANT_CREATE_OS_THREADS) { + TRACE_DEVEL("Can't create OS threads...This is OK\n"); + } + // Since this is an initialization path, we will be verbose in the + // code rather than efficient. + // + // in reality, we only need to check for case 3 since all others + // are acceptable to us... for one reason or another. + // + // Case 1 Flag not set and functiopn pointers NOT supplied + if (!(pArg->flags & CKF_OS_LOCKING_OK) && !(fcnmap)) { + ; + // This is COOL. Same as a NUL pointer Locking is irrelavent. + } else { + // Case 2. Flags set and Fcn pointers NOT supplied. + if ((pArg->flags & CKF_OS_LOCKING_OK) && !(fcnmap)) { + ; + // This to is COOL since we require native locking + } else { + // Case 3 Flag Not set and pointers supplied. Can't handle this + // one. + if (!(pArg->flags & CKF_OS_LOCKING_OK) && fcnmap) { + OCK_SYSLOG(LOG_ERR, "C_Initialize: " + "Application specified that " + "OS locking is invalid. " + "PKCS11 Module requires OS " "locking.\n"); + // Only support Native OS locking. + rc = CKR_CANT_LOCK; + goto error; + } else { + // Case 4 Flag set and fcn pointers set + if ((pArg->flags & CKF_OS_LOCKING_OK) && fcnmap) { + ; // This is also cool. + } else { + // Were really hosed here since this should not have + // occured + TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR)); + rc = CKR_GENERAL_ERROR; + goto error; + } + } + } + } + + } else { + // Pointer to void... + // This is OK we can go on from here. + ; + } + + // Create the shared memory lock. + if (CreateProcLock() != CKR_OK) { + TRACE_ERROR("Process Lock Failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto error; + } + //Zero out API_Proc_Struct + //Map Shared Memory Region + //if ( Shared Memory Mapped not Successful ) + // Free allocated Memory + // Return CKR_HOST_MEMORY + memset((char *) Anchor, 0, sizeof(API_Proc_Struct_t)); + bt_init(&Anchor->sess_btree, free); + Anchor->Pid = getpid(); + + // Get shared memory + if ((Anchor->SharedMemP = attach_shared_memory()) == NULL) { + OCK_SYSLOG(LOG_ERR, "C_Initialize: Module failed to attach to " + "shared memory. Verify that the slot management " + "daemon is running, errno=%d\n", errno); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto error; + } + TRACE_DEBUG("Shared memory %p \n", Anchor->SharedMemP); + + if (!init_socket_data()) { + OCK_SYSLOG(LOG_ERR, "C_Initialize: Module failed to create a " + "socket. Verify that the slot management daemon is " + "running.\n"); + TRACE_ERROR("Cannot attach to socket.\n"); + rc = CKR_FUNCTION_FAILED; + goto error_shm; + } + // Initialize structure values + + //Register with pkcsslotd + if (!API_Register()) { + // free memory allocated + // return CKR_FUNCTION_FAILED + // return CKR_FUNCTION_NOT_SUPPORTED; + TRACE_ERROR("Failed to register process with pkcsslotd.\n"); + rc = CKR_FUNCTION_FAILED; + goto error_shm; + } + // + // load all the slot DLL's here + { + CK_SLOT_ID slotID; + API_Slot_t *sltp; + + for (slotID = 0; slotID < NUMBER_SLOTS_MANAGED; slotID++) { + sltp = &(Anchor->SltList[slotID]); + slot_loaded[slotID] = DL_Load_and_Init(sltp, slotID); + } + + } + + pthread_mutex_unlock(&GlobMutex); + return CKR_OK; + +error_shm: + detach_shared_memory(Anchor->SharedMemP); + +error: + bt_destroy(&Anchor->sess_btree); + + free((void *) Anchor); + Anchor = NULL; + +done: + pthread_mutex_unlock(&GlobMutex); + + return rc; +} // end of C_Initialize + +//------------------------------------------------------------------------ +// API function C_InitPIN +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_InitPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pPin, CK_ULONG ulPinLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_InitPin\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + // A Null Pin with a Len is invalid + // A Null pin with a 0 len is no pin at all? + if (!pPin && ulPinLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + // XXX Remove me, this test should be completely unnecessary + // Move this to after the session validation... + if (rSession.slotID >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + return CKR_SLOT_ID_INVALID; + } + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_InitPIN) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_InitPIN + +//------------------------------------------------------------------------ +// API function C_InitToken +//------------------------------------------------------------------------ +//Netscape NEVER Calls this according to the Netscape documentation + +CK_RV C_InitToken(CK_SLOT_ID slotID, + CK_CHAR_PTR pPin, CK_ULONG ulPinLen, CK_CHAR_PTR pLabel) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + + TRACE_INFO("C_InitToken\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (slotID >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + return CKR_SLOT_ID_INVALID; + } + // Null pPin and a pinlen is a problem + if (!pPin && ulPinLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + if (!pLabel) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + // Prior to invoking the Tokens initialization, the + // API needs to verify that NO other applications have any + // sessions established with this particular slot + // + // Hooks into the shared memory to determine how many sessions + // on a given token are open need to be added. + // When a session is opened, it increments the count. When + // closed it decrements the count. Protected by an MUTEX + // In the shared memory region the slot_info[slotID].sesscount + // variable needs to be checked, and held locked until the operation + // is complete. + if (sessions_exist(slotID)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_EXISTS)); + return CKR_SESSION_EXISTS; + } + + sltp = &(Anchor->SltList[slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_InitToken) { + rv = fcn->ST_InitToken(sltp->TokData, slotID, pPin, ulPinLen, pLabel); + TRACE_DEVEL("fcn->ST_InitToken returned: 0x%lx\n", rv); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_Login +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_Login(CK_SESSION_HANDLE hSession, + CK_USER_TYPE userType, CK_CHAR_PTR pPin, CK_ULONG ulPinLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_Login\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } +#if 0 + /* Allow incorrect PIN checks to fall into the SC_Login + * function, since v2.11 requires flags to be set. - KEY + */ + if (!pPin) { + return CKR_PIN_INCORRECT; + } +#endif + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_Login) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_Login + +//------------------------------------------------------------------------ +// API function C_Logout +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_Logout(CK_SESSION_HANDLE hSession) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_Logout\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_Logout) { + // Map the Session to the slot session + rv = fcn->ST_Logout(sltp->TokData, &rSession); + TRACE_DEVEL("fcn->ST_Logout returned:0x%lx\n", rv); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_Logout + +//------------------------------------------------------------------------ +// API function C_OpenSession +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ +// +// Note: Need to worry about handling the Notify and Applicaiton call backs +// that are here... STDLL will NEVER deal with these... The +// usage of them appears to be optional from the specification +// but we may need to do something with them at a later date. +// +CK_RV C_OpenSession(CK_SLOT_ID slotID, + CK_FLAGS flags, + CK_VOID_PTR pApplication, + CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T *apiSessp; + + TRACE_INFO("C_OpenSession %lu %lx %p %p %p\n", slotID, flags, + pApplication, *(void **)(&Notify), *(void **)(&phSession)); + + if (!(flags & CKF_SERIAL_SESSION)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_PARALLEL_NOT_SUPPORTED)); + return CKR_SESSION_PARALLEL_NOT_SUPPORTED; + } + + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (slotID >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + return CKR_SLOT_ID_INVALID; + } + + if (!phSession) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + sltp = &(Anchor->SltList[slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + // + // Need to handle the failure of a load here... + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + + if ((apiSessp = (ST_SESSION_T *) malloc(sizeof(ST_SESSION_T))) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + if (fcn->ST_OpenSession) { + rv = fcn->ST_OpenSession(sltp->TokData, slotID, flags, + &(apiSessp->sessionh)); + TRACE_DEVEL("fcn->ST_OpenSession returned: 0x%lx\n", rv); + + // If the session allocation is successful, then we need to + // complete the API session block and return. Otherwise + // we free the API session block and exit + if (rv == CKR_OK) { + /* add a refernece to this handle/slot_id pair to the binary tree we + * maintain at the API level, returning the API-level object's + * handle as the session handle the app will get + */ + *phSession = AddToSessionList(apiSessp); + if (*phSession == 0) { + /* 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); + free(apiSessp); + rv = CKR_HOST_MEMORY; + goto done; + } + apiSessp->slotID = slotID; + + // NOTE: Need to add Session counter to the shared + // memory slot value.... Atomic operation. + // sharedmem->slot_info[slotID].sessioncount incremented + // when ever a session is attached. + // Also increment the per process slot counter to indicate + // how many sessions this process owns of the total amount. This + // way if the process abends garbage collection in the slot manager + // can adequatly clean up the total count value... + incr_sess_counts(slotID); + + } else { + free(apiSessp); + } + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + free(apiSessp); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + done: + return rv; + +} // end of C_OpenSession + +//------------------------------------------------------------------------ +// API function C_SeedRandom +//------------------------------------------------------------------------ + +CK_RV C_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, + CK_ULONG ulSeedLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_SeedRandom\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pSeed && ulSeedLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_SeedRandom) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_SetAttributeValue +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_SetAttributeValue(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_SetAttributeValue\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + if (!pTemplate) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + if (!ulCount) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_SetAttributeValue) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_SetAttributeValue + +//------------------------------------------------------------------------ +// API function C_SetOperationState +//------------------------------------------------------------------------ + +CK_RV C_SetOperationState(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pOperationState, + CK_ULONG ulOperationStateLen, + CK_OBJECT_HANDLE hEncryptionKey, + CK_OBJECT_HANDLE hAuthenticationKey) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_SetOperationState\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + if (!pOperationState || ulOperationStateLen == 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_SetOperationState) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_SetPIN +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_SetPIN(CK_SESSION_HANDLE hSession, + CK_CHAR_PTR pOldPin, + CK_ULONG ulOldLen, CK_CHAR_PTR pNewPin, CK_ULONG ulNewLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_SetPIN\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pOldPin || !pNewPin) + return CKR_PIN_INVALID; + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_SetPIN) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_SetPIN + +//------------------------------------------------------------------------ +// API function C_Sign +//------------------------------------------------------------------------ +// Netscape Required +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_Sign(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG_PTR pulSignatureLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_Sign\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pData || !pulSignatureLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_Sign) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_Sign + +//------------------------------------------------------------------------ +// API function C_SignEncryptUpdate +//------------------------------------------------------------------------ + +CK_RV C_SignEncryptUpdate(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, + CK_ULONG ulPartLen, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_SignEncryptUpdate\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pPart || !pulEncryptedPartLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_SignEncryptUpdate) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_SignFinal +//------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_SignFinal(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_SignEncryptUpdate\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pulSignatureLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_SignFinal) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_SignFinal + +//------------------------------------------------------------------------ +// API function C_SignInit +//------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_SignInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_SignInit\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_SignInit) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_SignInit + +//------------------------------------------------------------------------ +// API function C_SignRecover +//------------------------------------------------------------------------ + +CK_RV C_SignRecover(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pData, + CK_ULONG ulDataLen, + CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_SignRecover\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pData || !pulSignatureLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_SignRecover) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_SignRecoverInit +//------------------------------------------------------------------------ + +CK_RV C_SignRecoverInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_SignRecoverInit\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_SignRecoverInit) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_SignUpdate +//------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------ + +CK_RV C_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, + CK_ULONG ulPartLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_SignUpdate\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_SignUpdate) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} // end of C_SignUpdate + +//------------------------------------------------------------------------ +// API function C_UnwrapKey +//------------------------------------------------------------------------ +// Netscape Required + +CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hUnwrappingKey, + CK_BYTE_PTR pWrappedKey, + CK_ULONG ulWrappedKeyLen, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_UnwrapKey\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + if (!phKey) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + // what about the other pointers... probably need + // to be set correctly + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_UnwrapKey) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_Verify +//------------------------------------------------------------------------ +// Netscape Required + +CK_RV C_Verify(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pData, + CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG ulSignatureLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_Verify\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pData || !pSignature) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_Verify) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_VerifyFinal +//------------------------------------------------------------------------ + +CK_RV C_VerifyFinal(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_VerifyFinal\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pSignature) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_VerifyFinal) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_VerifyInit +//------------------------------------------------------------------------ + +CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_VerifyInit\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_VerifyInit) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_VerifyRecover +//------------------------------------------------------------------------ +// Netscape Required + +CK_RV C_VerifyRecover(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pSignature, + CK_ULONG ulSignatureLen, + CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_VerifyRecover\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + if (!pSignature || !pulDataLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_VerifyRecover) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_VerifyRecoverInit +//------------------------------------------------------------------------ + +CK_RV C_VerifyRecoverInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_VerifyRecoverInit\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_VerifyRecoverInit) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_VerifyUpdate +//------------------------------------------------------------------------ + +CK_RV C_VerifyUpdate(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_VerifyUpdate\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_VerifyUpdate) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +//------------------------------------------------------------------------ +// API function C_WaitForSlotEvent +//------------------------------------------------------------------------ +// +// +//NOTE: We need to implement this one even though Netscape does not +//make use of this... +// +//Standard code template won't work with this. We need to look at +//the slot manager and the shared memory indicating the slot bitmap +//Blocking needs to be worked out. At the initial release do not +//support BLocked calls on wait for slot event. +// +//Support Note: +//This function is really used for removable tokens, and is pretty +//inefficient. It may be best to return CKR_FUNCTION_UNSUPPORTED +//if it becomes a field issue, until removable token support is fully +//implemented. Be forewarned. +//------------------------------------------------------------------------ + +CK_RV C_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, + CK_VOID_PTR pReserved) +{ + UNUSED(flags); + UNUSED(pSlot); + UNUSED(pReserved); + +#ifdef PLUGGABLE_TOKENS_SUPPORTED +#ifdef PKCS64 + Slot_Mgr_Proc_t_64 *procp; +#else + Slot_Mgr_Proc_t *procp; +#endif +#endif + + TRACE_INFO("C_WaitForSlotEvent\n"); + + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } +#ifndef PLUGGABLE_TOKENS_SUPPORTED + // Since there are no tokens which we support that have the + // ability to create slot events, and slotd does not + // fully support this (it needs to be aware of the functions exported + // by an STDLL to poll the slot for a token event and this + // has not been fully implemented at this time, although the + // design and structure of the shared memory in slotd do. + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + return CKR_FUNCTION_NOT_SUPPORTED; +#else + // Get the pointer to the process element.. + // This could be done in a single line, but for readability we do it + // in 2 steps. + + shm = Anchor->SharedMemP; + procp = &shm->proc_table[Anchor->MgrProcIndex]; + + // Grab the mutex for the application in shared memory + // Check the bit mask for non-zero. If the bit mask is non-zero + // find the first slot which is set and set the pSlot value + // and return CKR_OK. + + // for now we will just lock the whole shared memory + // REally should be the procp->proc_mutex + // but this is such an infrequent thing that we will simply get + // the global shared memory lock + ProcLock(); + if (procp->slotmap) { + // find the first bit set + // This will have to change if more than 32 slots ever get supported + // including the test for a bit turned on.. + for (i = 0; NUMBER_SLOTS_MANAGED; i++) { + if (procp->slotmap & (1 << i)) { + break; + } + } + *pSlot = i; // set the flag + ProcUnLock(); + return CKR_OK; + } else { + if (flags & CKF_DONT_BLOCK) { + ProcUnLock(); + return CKR_NO_EVENT; + } else { + // WE need to + // 1. Set the blocking variable in the system map to true. + // 2. clear the condition variable + // + // Note: for now we will just poll the bitmap every + // second or look for the error field to go to true. + + // Check first if we are already blocking on another thread + // for this process. According to the spec this behavior is + // undefined. + // We will choose to fail the call. + if (procp->blocking) { + TRACE_DEVEL("WaitForSlot event called by process twice.\n"); + ProcUnLock(); // Unlock aftersetting + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + procp->error = 0; + procp->blocking = 0x01; + ProcUnLock(); // Unlock aftersetting + + // NOTE: We need to have an asynchronous mechanism for + // the slot manager to wake up anyone blocking on this. + // But Since we are not supporting removable tokens, this + // call should be almos never made. It might be best to + // return CKR_FUNCTION_UNSUPPORTED, but we'll wait and see. + while (!procp->slotmap && !procp->error) { + // Note This is really bad form. But what the heck + sleep(1); + } + ProcLock(); + procp->blocking = 0; + if (procp->error) { + ProcUnLock(); + TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR)); + return CKR_GENERAL_ERROR; + // We bailed on this because we were terminating + // General error should cause the calling thread to not try + // anything else... We need to look at how this holds up in + // practice. + } else { + // must have fallen out of loop because of a slot getting an + // event + for (i = 0; NUMBER_SLOTS_MANAGED; i++) { + if (procp->slotmap & (1 << i)) { + break; + } + } + *pSlot = i; // set the flag + ProcUnLock(); + return CKR_OK; + } + } + } +#endif +} // end of C_WaitForSlotEvent + +//------------------------------------------------------------------------ +// API function +// C_WrapKey +//------------------------------------------------------------------------ +// Netscape Required + +CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hWrappingKey, + CK_OBJECT_HANDLE hKey, + CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen) +{ + CK_RV rv; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + ST_SESSION_T rSession; + + TRACE_INFO("C_WrapKey\n"); + if (API_Initialized() == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + // other pointers??? + + if (!Valid_Session(hSession, &rSession)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + TRACE_ERROR("Session handle id: %lu\n", hSession); + return CKR_SESSION_HANDLE_INVALID; + } + TRACE_INFO("Valid Session handle id: %lu\n", rSession.sessionh); + + sltp = &(Anchor->SltList[rSession.slotID]); + if (sltp->DLLoaded == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if ((fcn = sltp->FcnList) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_TOKEN_NOT_PRESENT)); + return CKR_TOKEN_NOT_PRESENT; + } + if (fcn->ST_WrapKey) { + // 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); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + rv = CKR_FUNCTION_NOT_SUPPORTED; + } + + return rv; +} + +#ifdef __sun +#pragma init(api_init) +#else +void api_init(void) __attribute__ ((constructor)); +#endif + +void api_init(void) +{ + // Should only have to do the atfork stuff at load time... + if (!Initialized) { + pthread_atfork(NULL, NULL, (void (*)()) child_fork_initializer); + Initialized = 1; + } +} + +#ifdef __sun +#pragma fini(api_fini) +#else +void api_fini(void) __attribute__ ((destructor)); +#endif + +void api_fini() +{ + if (API_Initialized() == TRUE) { + Call_Finalize(); + } +} diff --git a/usr/lib/api/apiproto.h b/usr/lib/api/apiproto.h new file mode 100644 index 0000000..871f377 --- /dev/null +++ b/usr/lib/api/apiproto.h @@ -0,0 +1,55 @@ +/* + * 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 + */ + +// +// API local internal function prototypes +// +// +// + + +#ifndef _APIEXT_H +#define _APIEXT_H + +#include "apictl.h" + +void *attach_shared_memory(); +void detach_shared_memory(char *); + + +int API_Initialized(); +int API_Register(); +void API_UnRegister(); +int DL_Load_and_Init(API_Slot_t *, CK_SLOT_ID); + + +CK_RV CreateProcLock(); +CK_RV ProcLock(void); +CK_RV ProcUnLock(void); +CK_RV ProcClose(void); + +void _init(void); +void get_sess_count(CK_SLOT_ID, CK_ULONG *); +void incr_sess_counts(CK_SLOT_ID); +void decr_sess_counts(CK_SLOT_ID); +unsigned long AddToSessionList(ST_SESSION_T *); +void RemoveFromSessionList(CK_SESSION_HANDLE); +int Valid_Session(CK_SESSION_HANDLE, ST_SESSION_T *); +void DL_UnLoad(API_Slot_t *, CK_SLOT_ID); +void DL_Unload(API_Slot_t *); + +void CK_Info_From_Internal(CK_INFO_PTR dest, CK_INFO_PTR_64 src); + +int sessions_exist(CK_SLOT_ID); + +void CloseAllSessions(CK_SLOT_ID slot_id, CK_BBOOL in_fork_initializer); +int init_socket_data(); + +#endif diff --git a/usr/lib/api/apiutil.c b/usr/lib/api/apiutil.c new file mode 100644 index 0000000..6e099b1 --- /dev/null +++ b/usr/lib/api/apiutil.c @@ -0,0 +1,634 @@ +/* + * 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 + */ + +// +// +//AIX Pkcs11 Api Utility functions +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include // Function prototypes for PKCS11 +#include +#include +#include + +#include +#include +#include +#include + +static int xplfd = -1; +pthread_rwlock_t xplfd_rwlock = PTHREAD_RWLOCK_INITIALIZER; + +#include + +#define LIBLOCATION LIB_PATH + +extern API_Proc_Struct_t *Anchor; + +#include +#include "trace.h" +#include "ock_syslog.h" + +CK_RV CreateProcLock(void) +{ + if (xplfd == -1) { + + /* The slot mgr daemon should have already created lock, + * so just open it so we can get a lock... + */ + xplfd = open(OCK_API_LOCK_FILE, O_RDONLY); + + if (xplfd == -1) { + OCK_SYSLOG(LOG_ERR, "Could not open %s\n", OCK_API_LOCK_FILE); + return CKR_FUNCTION_FAILED; + } + } + + return CKR_OK; +} + +CK_RV ProcLock(void) +{ + if (pthread_rwlock_wrlock(&xplfd_rwlock)) { + TRACE_ERROR("Lock failed.\n"); + return CKR_CANT_LOCK; + } + + if (xplfd != -1) { + flock(xplfd, LOCK_EX); + } else { + TRACE_DEVEL("No file descriptor to lock with.\n"); + return CKR_CANT_LOCK; + } + + return CKR_OK; +} + +CK_RV ProcUnLock(void) +{ + if (xplfd != -1) { + flock(xplfd, LOCK_UN); + } else { + TRACE_DEVEL("No file descriptor to unlock with.\n"); + return CKR_CANT_LOCK; + } + + if (pthread_rwlock_unlock(&xplfd_rwlock)) { + TRACE_ERROR("Unlock failed.\n"); + return CKR_CANT_LOCK; + } + + return CKR_OK; +} + +CK_RV ProcClose(void) +{ + if (xplfd != -1) + close(xplfd); + else + TRACE_DEVEL("ProcClose: No file descriptor open to close.\n"); + + return CKR_OK; +} + +unsigned long AddToSessionList(ST_SESSION_T *pSess) +{ + unsigned long handle; + + handle = bt_node_add(&(Anchor->sess_btree), pSess); + + return handle; +} + +void RemoveFromSessionList(CK_SESSION_HANDLE handle) +{ + bt_node_free(&(Anchor->sess_btree), handle, TRUE); +} + +struct closeme_arg { + CK_SLOT_ID slot_id; + CK_BBOOL in_fork_initializer; +}; + +/* CloseMe + * + * Callback function used to close an individual session for a slot + */ +void CloseMe(STDLL_TokData_t *tokdata, void *node_value, + unsigned long node_handle, void *arg) +{ + CK_RV rv; + struct closeme_arg *closeme_arg = (struct closeme_arg *) arg; + ST_SESSION_T *s = (ST_SESSION_T *) node_value; + API_Slot_t *sltp; + STDLL_FcnList_t *fcn; + + UNUSED(tokdata); + + if (s->slotID == closeme_arg->slot_id) { + /* the single ugliest part about moving to a binary tree: these are the + * guts of the C_CloseSession function, copied here without tests for + * validity, since if we're here, they must already have been valid */ + sltp = &(Anchor->SltList[closeme_arg->slot_id]); + fcn = sltp->FcnList; + rv = fcn->ST_CloseSession(sltp->TokData, s, + closeme_arg->in_fork_initializer); + if (rv == CKR_OK) { + decr_sess_counts(closeme_arg->slot_id); + bt_node_free(&(Anchor->sess_btree), node_handle, TRUE); + } + } +} + +/* CloseAllSessions + * + * Run through all the nodes in the binary tree and call CloseMe on each one. + * CloseMe will look at @slot_id and if it matches, will close the session. + * Once all the nodes are closed, we check to see if the tree is empty and if + * so, destroy it + */ +void CloseAllSessions(CK_SLOT_ID slot_id, CK_BBOOL in_fork_initializer) +{ + API_Slot_t *sltp = &(Anchor->SltList[slot_id]); + struct closeme_arg arg; + + arg.slot_id = slot_id; + arg.in_fork_initializer = in_fork_initializer; + + /* for every node in the API-level session tree, call CloseMe on it */ + bt_for_each_node(sltp->TokData, &(Anchor->sess_btree), CloseMe, + (void *)&arg); + +} + +int Valid_Session(CK_SESSION_HANDLE handle, ST_SESSION_T *rSession) +{ + ST_SESSION_T *tmp; + int rc; + + tmp = bt_get_node_value(&(Anchor->sess_btree), handle); + if (tmp) { + rSession->slotID = tmp->slotID; + rSession->sessionh = tmp->sessionh; + } + rc = tmp ? TRUE : FALSE; + bt_put_node_value(&(Anchor->sess_btree), tmp); + tmp = NULL; + + return rc; +} + +int API_Initialized() +{ + if (Anchor == NULL) + return FALSE; + + return TRUE; +} + +int slot_present(CK_SLOT_ID id) +{ + Slot_Mgr_Socket_t *shData = &(Anchor->SocketDataP); +#ifdef PKCS64 + Slot_Info_t_64 *sinfp; +#else + Slot_Info_t *sinfp; +#endif + + sinfp = &(shData->slot_info[id]); + if (sinfp->present == FALSE) { + return FALSE; + } + + return TRUE; +} + +void get_sess_count(CK_SLOT_ID slotID, CK_ULONG *ret) +{ + Slot_Mgr_Shr_t *shm; + + shm = Anchor->SharedMemP; + ProcLock(); + *ret = shm->slot_global_sessions[slotID]; + ProcUnLock(); +} + +void incr_sess_counts(CK_SLOT_ID slotID) +{ + Slot_Mgr_Shr_t *shm; +#ifdef PKCS64 + Slot_Mgr_Proc_t_64 *procp; +#else + Slot_Mgr_Proc_t *procp; +#endif + + // Get the slot mutex + shm = Anchor->SharedMemP; + + ProcLock(); + + shm->slot_global_sessions[slotID]++; + + procp = &shm->proc_table[Anchor->MgrProcIndex]; + procp->slot_session_count[slotID]++; + + ProcUnLock(); +} + +void decr_sess_counts(CK_SLOT_ID slotID) +{ + Slot_Mgr_Shr_t *shm; +#ifdef PKCS64 + Slot_Mgr_Proc_t_64 *procp; +#else + Slot_Mgr_Proc_t *procp; +#endif + + // Get the slot mutex + shm = Anchor->SharedMemP; + + ProcLock(); + + if (shm->slot_global_sessions[slotID] > 0) { + shm->slot_global_sessions[slotID]--; + } + + procp = &shm->proc_table[Anchor->MgrProcIndex]; + if (procp->slot_session_count[slotID] > 0) { + procp->slot_session_count[slotID]++; + } + + ProcUnLock(); +} + +// Check if any sessions from other applicaitons exist on this particular +// token.... This will also validate our own sessions as well. +// There might be an issue with the fact that a session is created but the +// number is not incremented until the session allocation is completed by +// the token. The API may need to lock the shared memory prior to creating +// the session and then unlock when the stdll has completed its work. +// Closing sessions should probably behave the same way. +int sessions_exist(CK_SLOT_ID slotID) +{ + Slot_Mgr_Shr_t *shm; + uint32 numSessions; + + // Get the slot mutex + shm = Anchor->SharedMemP; + + ProcLock(); + numSessions = shm->slot_global_sessions[slotID]; + ProcUnLock(); + + return numSessions != 0; +} + +// Register the process with PKCSSLOTD in the shared memory. +// This call must be made with the API Global Mutex Locked +// and the Anchor control block initialized with the +// shared memory. No checking for shared memory validity is done +int API_Register() +{ + long int reuse = -1, free = -1; + Slot_Mgr_Shr_t *shm; + +#ifdef PKCS64 + Slot_Mgr_Proc_t_64 *procp; +#else + Slot_Mgr_Proc_t *procp; +#endif + + uint16 indx; + + // Grab the Shared Memory lock to prevent other updates to the + // SHM Process + // The registration is done to allow for future handling of + // the Slot Event List. Which is maintained by the Slotd. + + shm = Anchor->SharedMemP; + + ProcLock(); + + procp = shm->proc_table; + for (indx = 0; indx < NUMBER_PROCESSES_ALLOWED; indx++, procp++) { + // Is the entry in use + + if (procp->inuse == TRUE) { + // Handle the weird case of the process terminating without + // un-registering, and restarting with exactly the same PID + // before the slot manager garbage collection can performed. + // To eliminate the race condition between garbage collection + // the lock should protect us. + // This should be a VERY rare (if ever) occurrence, given the + // way AIX deals with re-allocation of PID;s, however if this + // ever gets ported over to another platform we want to deal + // with this accordingly since it may re-use pids differently + // (Linux appears to re-use pids more rapidly). + if (procp->proc_id == getpid()) { + if (reuse == -1) { + reuse = indx; + } + } + } else { + //Already found the first free + if (free == -1) { + free = indx; + } + } + } + + // If we did not find a free entry then we fail the routine + if ((reuse == -1) && (free == -1)) { + ProcUnLock(); + return FALSE; + } + // check if we are reusing a control block or taking the first free. + // Since the mutex is held, we don;t have to worry about some other + // process grabbing the slot... Garbage collection from + // the slotd should not affect this since it will grab the mutex + // before doing its thing. + if (reuse != -1) { + procp = &(shm->proc_table[reuse]); + indx = reuse; + } else { + procp = &(shm->proc_table[free]); + indx = free; + } + +#ifdef PKCS64 + memset((char *) procp, 0, sizeof(Slot_Mgr_Proc_t_64)); +#else + memset((char *) procp, 0, sizeof(Slot_Mgr_Proc_t)); +#endif + procp->inuse = TRUE; + procp->proc_id = getpid(); + procp->reg_time = time(NULL); + + Anchor->MgrProcIndex = indx; + + TRACE_DEVEL("API_Register MgrProcIndc %d pid %ld \n", procp->proc_id, + (long int) Anchor->MgrProcIndex); + + //??? What to do about the Mutex and cond variable + //Does initializing them in the slotd allow for them to not be + //initialized in the application. + + ProcUnLock(); + + return TRUE; +} + +// DeRegister the process with PKCSSLOTD in the shared memory. +// This call must be made with the API Global Mutex Locked +// and the Anchor control block initialized with the +// shared memory. No checking for shared memory validity is done +void API_UnRegister() +{ + Slot_Mgr_Shr_t *shm; + +#ifdef PKCS64 + Slot_Mgr_Proc_t_64 *procp; +#else + Slot_Mgr_Proc_t *procp; +#endif + + // Grab the Shared Memory lock to prevent other updates to the + // SHM Process + // The registration is done to allow for future handling of + // the Slot Event List. Which is maintained by the Slotd. + + shm = Anchor->SharedMemP; + + ProcLock(); + + procp = &(shm->proc_table[Anchor->MgrProcIndex]); + +#ifdef PKCS64 + memset((char *) procp, 0, sizeof(Slot_Mgr_Proc_t_64)); +#else + memset((char *) procp, 0, sizeof(Slot_Mgr_Proc_t)); +#endif + + Anchor->MgrProcIndex = 0; + + //??? What to do about the Mutex and cond variable + //Does initializing them in the slotd allow for them to not be + //initialized in the application. + + ProcUnLock(); +} + +void DL_UnLoad(API_Slot_t *sltp, CK_SLOT_ID slotID) +{ + Slot_Mgr_Socket_t *shData = &(Anchor->SocketDataP); +#ifdef PKCS64 + Slot_Info_t_64 *sinfp; +#else + Slot_Info_t *sinfp; +#endif + + sinfp = &(shData->slot_info[slotID]); + + if (sinfp->present == FALSE) { + return; + } + if (!sltp->dlop_p) { + return; + } + // Call the routine to properly unload the DLL + DL_Unload(sltp); + + return; +} + +int DL_Loaded(char *location, DLL_Load_t *dllload) +{ + int i; + + for (i = 0; i < NUMBER_SLOTS_MANAGED; i++) { + if (dllload[i].dll_name != NULL) { + TRACE_DEBUG("DL_LOADED Looking for index %d name %s\n", + i, dllload[i].dll_name); + if (strcmp(location, dllload[i].dll_name) == 0) { + return i; // Return the index of the dll + } + } + } + + return -1; // Indicate failure to find the dll +} + +#ifdef PKCS64 +int DL_Load(Slot_Info_t_64 *sinfp, API_Slot_t *sltp, DLL_Load_t *dllload) +#else +int DL_Load(Slot_Info_t *sinfp, API_Slot_t *sltp, DLL_Load_t *dllload) +#endif +{ + int i; + + TRACE_DEBUG("DL_LOAD\n"); + for (i = 0; i < NUMBER_SLOTS_MANAGED; i++) { + if (dllload[i].dll_name == NULL) { + TRACE_DEBUG("Empty slot at %d \n", i); + break; + } + } + if (i == NUMBER_SLOTS_MANAGED) { + TRACE_DEBUG("No empty slots.\n"); + return 0; // Failed to find it.. + } + + dllload[i].dll_name = sinfp->dll_location; // Point to the location + + dllload[i].dlop_p = dlopen(sinfp->dll_location, (RTLD_GLOBAL | RTLD_LAZY)); + + if (dllload[i].dlop_p != NULL) { + sltp->dlop_p = dllload[i].dlop_p; + sltp->dll_information = &dllload[i]; + dllload[i].dll_load_count++;; + + } else { + char *e = dlerror(); + OCK_SYSLOG(LOG_WARNING, + "%s: dlopen() failed for [%s]; dlerror = [%s]\n", + __func__, sinfp->dll_location, e); + TRACE_DEVEL("DL_Load of %s failed, dlerror: %s\n", + sinfp->dll_location, e); + sltp->dlop_p = NULL; + return 0; + } + + return 1; +} + +void DL_Unload(API_Slot_t *sltp) +{ + DLL_Load_t *dllload; + + // Decrement the count of loads. When 0 then unload this thing; + // + dllload = sltp->dll_information; + dllload->dll_load_count--; + if (dllload->dll_load_count == 0) { + dlclose(dllload->dlop_p); + dllload->dll_name = NULL; + } + // Clear out the slot information + sltp->DLLoaded = FALSE; + sltp->dlop_p = NULL; + sltp->pSTfini = NULL; + sltp->pSTcloseall = NULL; +} + +int DL_Load_and_Init(API_Slot_t *sltp, CK_SLOT_ID slotID) +{ + Slot_Mgr_Socket_t *shData = &(Anchor->SocketDataP); +#ifdef PKCS64 + Slot_Info_t_64 *sinfp; +#else + Slot_Info_t *sinfp; +#endif + CK_RV (*pSTinit)(API_Slot_t *, CK_SLOT_ID, SLOT_INFO *, + struct trace_handle_t); + CK_RV rv; + int dll_len, dl_index; + DLL_Load_t *dllload; + + // Get pointer to shared memory from the anchor block + // + + sinfp = &(shData->slot_info[slotID]); + dllload = Anchor->DLLs; // list of dll's in the system + + if (sinfp->present == FALSE) { + return FALSE; + } + + if ((dll_len = strlen(sinfp->dll_location))) { + // Check if this DLL has been loaded already.. If so, just increment + // the counter in the dllload structure and copy the data to + // the slot pointer. + if ((dl_index = DL_Loaded(sinfp->dll_location, dllload)) != -1) { + dllload[dl_index].dll_load_count++; + sltp->dll_information = &dllload[dl_index]; + sltp->dlop_p = dllload[dl_index].dlop_p; + } else { + TRACE_DEBUG("DL_Load_and_Init dll_location %s\n", + sinfp->dll_location); + DL_Load(sinfp, sltp, dllload); + } + } else { + return FALSE; + } + + if (!sltp->dlop_p) { + TRACE_DEBUG("DL_Load_and_Init pointer %p\n", sltp->dlop_p); + + return FALSE; + } + + *(void **)(&pSTinit) = dlsym(sltp->dlop_p, "ST_Initialize"); + if (!pSTinit) { + // Unload the DLL + DL_Unload(sltp); + return FALSE; + } + // Returns true or false + rv = pSTinit(sltp, slotID, sinfp, trace); + TRACE_DEBUG("return from STDDLL Init = %lx\n", rv); + + if (rv != CKR_OK) { + // clean up and unload + DL_Unload(sltp); + sltp->DLLoaded = FALSE; + return FALSE; + } else { + sltp->DLLoaded = TRUE; + // Check if a SC_Finalize function has been exported + *(void **)(&sltp->pSTfini) = dlsym(sltp->dlop_p, "SC_Finalize"); + *(void **)(&sltp->pSTcloseall) = + dlsym(sltp->dlop_p, "SC_CloseAllSessions"); + return TRUE; + } + + return TRUE; +} + +// copies internal representation of ck_info structure to local process +// representation +void CK_Info_From_Internal(CK_INFO_PTR dest, CK_INFO_PTR_64 src) +{ + dest->cryptokiVersion = src->cryptokiVersion; + + memcpy(dest->manufacturerID, src->manufacturerID, + sizeof(dest->manufacturerID)); + + dest->flags = src->flags; + + memcpy(dest->libraryDescription, src->libraryDescription, + sizeof(dest->libraryDescription)); + + dest->libraryVersion = src->libraryVersion; +} diff --git a/usr/lib/api/shrd_mem.c.in b/usr/lib/api/shrd_mem.c.in new file mode 100644 index 0000000..2f51eda --- /dev/null +++ b/usr/lib/api/shrd_mem.c.in @@ -0,0 +1,151 @@ +/* + * 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 + */ + + +// +// Pkcs11 Api Shared Memory Routines +// + +#if NGPTH +#include +#else +#include +#endif + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + + +#include +#include +#include +#include +#include + +#include +#include + +#define MAPFILENAME "@CONFIG_PATH@/.apimap" + +extern API_Proc_Struct_t *Anchor; +// +// Will attach to the shared memory that has been created +// by the slot manager daemon. +// A NULL pointer will return if the memory region is invalid +// for any reason +void *attach_shared_memory() +{ + int shmid; + char *shmp; + struct stat statbuf; + struct group *grp; + struct passwd *pw, *epw; + uid_t uid, euid; + +#if !(MMAP) + // Really should fstat the tok_path, since it will be the actual + // executable of the slotmgr, however at this time we won't bother + // for the prototype. /tmp/slotmgr will have to be an existing file. + + if (stat(TOK_PATH, &statbuf) < 0) { + // The Stat token origin file does not work... Kick it out + return NULL; + } + + uid = getuid(); + euid = geteuid(); + // only check group membership if not root user + if (uid != 0 && euid != 0) { + int i, member = 0; + grp = getgrnam("pkcs11"); + if (!grp) { + // group pkcs11 not known to the system + return NULL; + } + pw = getpwuid(uid); + epw = getpwuid(euid); + for (i = 0; grp->gr_mem[i]; i++) { + if (pw) { + if (!strncmp(pw->pw_name, + grp->gr_mem[i], + strlen(pw->pw_name))) { + member = 1; + break; + } + } + if (epw) { + if (!strncmp(epw->pw_name, + grp->gr_mem[i], strlen(epw->pw_name))) { + member = 1; + break; + } + } + } + if (!member) { + return NULL; + } + } + + Anchor->shm_tok = ftok(TOK_PATH, 'b'); + + // Get the shared memory id. + shmid = shmget(Anchor->shm_tok, sizeof(Slot_Mgr_Shr_t), + S_IWUSR | S_IWGRP | S_IRGRP | S_IRUSR); + if (shmid < 0) { + return NULL; + } + + + shmp = (void *) shmat(shmid, NULL, 0); + if (!shmp) { + return NULL; + } + + return shmp; +#else + int fd; +#warning "EXPERIMENTAL" + fd = open(MAPFILENAME, O_RDWR); + + if (fd < 0) { + return NULL; //Failed the file should exist and be valid + } + shmp = (char *) mmap(NULL, sizeof(Slot_Mgr_Shr_t), PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + close(fd); + if (!shmp) { + return NULL; + } + return shmp; +#endif +} + +// +//Detach the shared memory from the api when finished. +// + +void detach_shared_memory(char *shmp) +{ +#if !(MMAP) + shmdt(shmp); +#else + munmap(shmp, sizeof(Slot_Mgr_Shr_t)); +#endif +} diff --git a/usr/lib/api/socket_client.c b/usr/lib/api/socket_client.c new file mode 100644 index 0000000..6bacf15 --- /dev/null +++ b/usr/lib/api/socket_client.c @@ -0,0 +1,136 @@ +/* + * 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 + */ + +/* (C) COPYRIGHT Google Inc. 2013 */ + +// +// Pkcs11 Api Socket client routines +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "apiproto.h" +#include "slotmgr.h" +#include "apictl.h" +#include "ock_syslog.h" + +extern API_Proc_Struct_t *Anchor; +// +// Will fill out the Slot_Mgr_Socket_t structure in the Anchor global data +// structure with the values passed by the pkcsslotd via a socket RPC. +int init_socket_data() +{ + int socketfd; + struct sockaddr_un daemon_address; + struct stat file_info; + struct group *grp; + int n; + unsigned int bytes_received = 0; + Slot_Mgr_Socket_t *daemon_socket_data = NULL; + int ret = FALSE; + + if (stat(SOCKET_FILE_PATH, &file_info)) { + OCK_SYSLOG(LOG_ERR, + "init_socket_data: failed to find socket file, errno=%d", + errno); + return FALSE; + } + + grp = getgrnam("pkcs11"); + if (!grp) { + OCK_SYSLOG(LOG_ERR, + "init_socket_data: pkcs11 group does not exist, errno=%d", + errno); + return FALSE; + } + + if (file_info.st_uid != 0 || file_info.st_gid != grp->gr_gid) { + OCK_SYSLOG(LOG_ERR, + "init_socket_data: incorrect permissions on socket file"); + return FALSE; + } + + if ((socketfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + OCK_SYSLOG(LOG_ERR, + "init_socket_data: failed to create socket, errno=%d", + errno); + return FALSE; + } + + memset(&daemon_address, 0, sizeof(struct sockaddr_un)); + daemon_address.sun_family = AF_UNIX; + strcpy(daemon_address.sun_path, SOCKET_FILE_PATH); + + if (connect(socketfd, (struct sockaddr *) &daemon_address, + sizeof(struct sockaddr_un)) != 0) { + OCK_SYSLOG(LOG_ERR, + "init_socket_data: failed to connect to slotmanager daemon, " + "errno=%d", + errno); + goto exit; + } + // allocate data buffer + daemon_socket_data = + (Slot_Mgr_Socket_t *) malloc(sizeof(*daemon_socket_data)); + if (!daemon_socket_data) { + OCK_SYSLOG(LOG_ERR, "init_socket_data: failed to \ + allocate %lu bytes \ + for daemon data, errno=%d", + sizeof(*daemon_socket_data), errno); + goto exit; + } + + while (bytes_received < sizeof(*daemon_socket_data)) { + n = read(socketfd, ((char *) daemon_socket_data) + bytes_received, + sizeof(*daemon_socket_data) - bytes_received); + if (n < 0) { + // read error + if (errno == EINTR) + continue; + OCK_SYSLOG(LOG_ERR, "init_socket_data: read error \ + on daemon socket, errno=%d", errno); + goto exit; + } else if (n == 0) { + // eof but we still expect some bytes + OCK_SYSLOG(LOG_ERR, "init_socket_data: read returned \ + with eof but we still \ + expect %lu bytes from daemon", + sizeof(*daemon_socket_data) - bytes_received); + goto exit; + } else { + // n > 0, we got some bytes + bytes_received += n; + } + } + + ret = TRUE; + + // copy the Slot_Mgr_Socket_t struct into global + // Anchor SocketDataPdata buffer + memcpy(&(Anchor->SocketDataP), daemon_socket_data, + sizeof(*daemon_socket_data)); + +exit: + //free the data buffer after copy + if (daemon_socket_data) + free(daemon_socket_data); + + close(socketfd); + + return ret; +} diff --git a/usr/lib/cca_stdll/LICENSE b/usr/lib/cca_stdll/LICENSE new file mode 100644 index 0000000..c9990a7 --- /dev/null +++ b/usr/lib/cca_stdll/LICENSE @@ -0,0 +1,213 @@ +Common Public License Version 1.0 + +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC +LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM +CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + + a) in the case of the initial Contributor, the initial code and +documentation distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + + i) changes to the Program, and + + ii) additions to the Program; + + where such changes and/or additions to the Program originate from and are +distributed by that particular Contributor. A Contribution 'originates' from a +Contributor if it was added to the Program by such Contributor itself or anyone +acting on such Contributor's behalf. Contributions do not include additions to +the Program which: (i) are separate modules of software distributed in +conjunction with the Program under their own license agreement, and (ii) are not +derivative works of the Program. + +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents " mean patent claims licensable by a Contributor which are +necessarily infringed by the use or sale of its Contribution alone or when +combined with the Program. + +"Program" means the Contributions distributed in accordance with this Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, +including all Contributors. + +2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby grants +Recipient a non-exclusive, worldwide, royalty-free copyright license to +reproduce, prepare derivative works of, publicly display, publicly perform, +distribute and sublicense the Contribution of such Contributor, if any, and such +derivative works, in source code and object code form. + + b) Subject to the terms of this Agreement, each Contributor hereby grants +Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed +Patents to make, use, sell, offer to sell, import and otherwise transfer the +Contribution of such Contributor, if any, in source code and object code form. +This patent license shall apply to the combination of the Contribution and the +Program if, at the time the Contribution is added by the Contributor, such +addition of the Contribution causes such combination to be covered by the +Licensed Patents. The patent license shall not apply to any other combinations +which include the Contribution. No hardware per se is licensed hereunder. + + c) Recipient understands that although each Contributor grants the licenses +to its Contributions set forth herein, no assurances are provided by any +Contributor that the Program does not infringe the patent or other intellectual +property rights of any other entity. Each Contributor disclaims any liability to +Recipient for claims brought by any other entity based on infringement of +intellectual property rights or otherwise. As a condition to exercising the +rights and licenses granted hereunder, each Recipient hereby assumes sole +responsibility to secure any other intellectual property rights needed, if any. +For example, if a third party patent license is required to allow Recipient to +distribute the Program, it is Recipient's responsibility to acquire that license +before distributing the Program. + + d) Each Contributor represents that to its knowledge it has sufficient +copyright rights in its Contribution, if any, to grant the copyright license set +forth in this Agreement. + +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under its +own license agreement, provided that: + + a) it complies with the terms and conditions of this Agreement; and + + b) its license agreement: + + i) effectively disclaims on behalf of all Contributors all warranties and +conditions, express and implied, including warranties or conditions of title and +non-infringement, and implied warranties or conditions of merchantability and +fitness for a particular purpose; + + ii) effectively excludes on behalf of all Contributors all liability for +damages, including direct, indirect, special, incidental and consequential +damages, such as lost profits; + + iii) states that any provisions which differ from this Agreement are offered +by that Contributor alone and not by any other party; and + + iv) states that source code for the Program is available from such +Contributor, and informs licensees how to obtain it in a reasonable manner on or +through a medium customarily used for software exchange. + +When the Program is made available in source code form: + + a) it must be made available under this Agreement; and + + b) a copy of this Agreement must be included with each copy of the Program. + +Contributors may not remove or alter any copyright notices contained within the +Program. + +Each Contributor must identify itself as the originator of its Contribution, if +any, in a manner that reasonably allows subsequent Recipients to identify the +originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with +respect to end users, business partners and the like. While this license is +intended to facilitate the commercial use of the Program, the Contributor who +includes the Program in a commercial product offering should do so in a manner +which does not create potential liability for other Contributors. Therefore, if +a Contributor includes the Program in a commercial product offering, such +Contributor ("Commercial Contributor") hereby agrees to defend and indemnify +every other Contributor ("Indemnified Contributor") against any losses, damages +and costs (collectively "Losses") arising from claims, lawsuits and other legal +actions brought by a third party against the Indemnified Contributor to the +extent caused by the acts or omissions of such Commercial Contributor in +connection with its distribution of the Program in a commercial product +offering. The obligations in this section do not apply to any claims or Losses +relating to any actual or alleged intellectual property infringement. In order +to qualify, an Indemnified Contributor must: a) promptly notify the Commercial +Contributor in writing of such claim, and b) allow the Commercial Contributor to +control, and cooperate with the Commercial Contributor in, the defense and any +related settlement negotiations. The Indemnified Contributor may participate in +any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product +offering, Product X. That Contributor is then a Commercial Contributor. If that +Commercial Contributor then makes performance claims, or offers warranties +related to Product X, those performance claims and warranties are such +Commercial Contributor's responsibility alone. Under this section, the +Commercial Contributor would have to defend claims against the other +Contributors related to those performance claims and warranties, and if a court +requires any other Contributor to pay any damages as a result, the Commercial +Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR +IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each +Recipient is solely responsible for determining the appropriateness of using and +distributing the Program and assumes all risks associated with its exercise of +rights under this Agreement, including but not limited to the risks and costs of +program errors, compliance with applicable laws, damage to or loss of data, +programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY +CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST +PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS +GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable +law, it shall not affect the validity or enforceability of the remainder of the +terms of this Agreement, and without further action by the parties hereto, such +provision shall be reformed to the minimum extent necessary to make such +provision valid and enforceable. + +If Recipient institutes patent litigation against a Contributor with respect to +a patent applicable to software (including a cross-claim or counterclaim in a +lawsuit), then any patent licenses granted by that Contributor to such Recipient +under this Agreement shall terminate as of the date such litigation is filed. In +addition, if Recipient institutes patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging that the Program +itself (excluding combinations of the Program with other software or hardware) +infringes such Recipient's patent(s), then such Recipient's rights granted under +Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to +comply with any of the material terms or conditions of this Agreement and does +not cure such failure in a reasonable period of time after becoming aware of +such noncompliance. If all Recipient's rights under this Agreement terminate, +Recipient agrees to cease use and distribution of the Program as soon as +reasonably practicable. However, Recipient's obligations under this Agreement +and any licenses granted by Recipient relating to the Program shall continue and +survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in +order to avoid inconsistency the Agreement is copyrighted and may only be +modified in the following manner. The Agreement Steward reserves the right to +publish new versions (including revisions) of this Agreement from time to time. +No one other than the Agreement Steward has the right to modify this Agreement. +IBM is the initial Agreement Steward. IBM may assign the responsibility to serve +as the Agreement Steward to a suitable separate entity. Each new version of the +Agreement will be given a distinguishing version number. The Program (including +Contributions) may always be distributed subject to the version of the Agreement +under which it was received. In addition, after a new version of the Agreement +is published, Contributor may elect to distribute the Program (including its +Contributions) under the new version. Except as expressly stated in Sections +2(a) and 2(b) above, Recipient receives no rights or licenses to the +intellectual property of any Contributor under this Agreement, whether +expressly, by implication, estoppel or otherwise. All rights in the Program not +expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the +intellectual property laws of the United States of America. No party to this +Agreement will bring a legal action under this Agreement more than one year +after the cause of action arose. Each party waives its rights to a jury trial in +any resulting litigation. diff --git a/usr/lib/cca_stdll/cca_func.h b/usr/lib/cca_stdll/cca_func.h new file mode 100644 index 0000000..65fa876 --- /dev/null +++ b/usr/lib/cca_stdll/cca_func.h @@ -0,0 +1,1278 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 1997-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 + */ + +/******************************************************************************/ +/* US Government Users Restricted Rights - Use, duplication or disclosure */ +/* restricted by GSA ADP Schedule Contract with IBM Corp. */ +/******************************************************************************/ +/* */ +/* This header file contains the Security API C language */ +/* prototypes. See the user publications for more information. */ +/* */ +/******************************************************************************/ + +/* Clear Key Import */ +typedef void (**CSNBCKI_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *clear_key, + unsigned char *target_key_identifier); + +/* Clear Key Import Multiple */ +typedef void (*CSNBCKM_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *clear_key_length, + unsigned char *clear_key, + unsigned char *target_key_identifier); + +/* Data Key Export */ +typedef void (*CSNBDKX_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *source_key_identifier, + unsigned char *exporter_key_identifier, + unsigned char *target_key_token); + +/* Data Key Import */ +typedef void (*CSNBDKM_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *source_key_token, + unsigned char *importer_key_identifier, + unsigned char *target_key_identifier); + +/* DES Master Key Process */ +typedef void (*CSNBMKP_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, unsigned char *key_part); + +/* Key Export */ +typedef void (*CSNBKEX_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_type, + unsigned char *source_key_identifier, + unsigned char *exporter_key_identifier, + unsigned char *target_key_token); + +/* Key Generate */ +typedef void (*CSNBKGN_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_form, + unsigned char *key_length, + unsigned char *key_type_1, + unsigned char *key_type_2, + unsigned char *KEK_key_identifier_1, + unsigned char *KEK_key_identifier_2, + unsigned char *generated_key_identifier_1, + unsigned char *generated_key_identifier_2); + +/* Key Generate2 */ +typedef void (*CSNBKGN2_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *clear_key_bit_length, + unsigned char *key_type_1, + unsigned char *key_type_2, + long *key_name_1_length, + unsigned char *key_name_1, + long *key_name_2_length, + unsigned char *key_name_2, + long *user_associated_data_1_length, + unsigned char *user_associated_data_1, + long *user_associated_data_2_length, + unsigned char *user_associated_data_2, + long *key_encrypting_key_identifier_1_length, + unsigned char *key_encrypting_key_identifier_1, + long *key_encrypting_key_identifier_2_length, + unsigned char *key_encrypting_key_identifier_2, + long *generated_key_identifier_1_length, + unsigned char *generated_key_identifier_1, + long *generated_key_identifier_2_length, + unsigned char *generated_key_identifier_2); + +/* Key Import */ +typedef void (*CSNBKIM_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_type, + unsigned char *source_key_token, + unsigned char *importer_key_identifier, + unsigned char *target_key_identifier); + +/* Key Part Import */ +typedef void (*CSNBKPI_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_part, + unsigned char *key_identifier); + +/* Key Part Import2 */ +typedef void (*CSNBKPI2_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *clear_key_part_length, + unsigned char *clear_key_part, + long *key_identifier_length, + unsigned char *key_identifier); + +/* Key Storage Initialization */ +typedef void (*CSNBKSI_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *file_name_length, + unsigned char *file_name, + long *description_length, + unsigned char *description, + unsigned char *clear_master_key); + +/* Key Record Create */ +typedef void (*CSNBKRC_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, unsigned char *key_label); +/* AES Key Record Create */ +typedef void (*CSNBAKRC_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_label, + long *key_token_length, unsigned char *key_token); + +/* Key Record Delete */ +typedef void (*CSNBKRD_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_identifier); + +/* Key Record List */ +typedef void (*CSNBKRL_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_label, + long *data_set_name_length, + unsigned char *data_set_name, + unsigned char *security_server_name); + +/* Key Record Read */ +typedef void (*CSNBKRR_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_label, unsigned char *key_token); + +/* Key Record Write */ +typedef void (*CSNBKRW_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_token, unsigned char *key_label); + +/* PKA Key Record Create */ +typedef void (*CSNDKRC_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_label, + long *key_token_length, unsigned char *key_token); + +/* PKA Key Record Delete */ +typedef void (*CSNDKRD_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_identifier); + +/* PKA Key Record List */ +typedef void (*CSNDKRL_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_label, + long *data_set_name_length, + unsigned char *data_set_name, + unsigned char *security_server_name); + +/* PKA Key Record Read */ +typedef void (*CSNDKRR_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_label, + long *key_token_length, unsigned char *key_token); + +/* PKA Key Record Write */ +typedef void (*CSNDKRW_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_label, + long *key_token_length, unsigned char *key_token); + +/* Key Test */ +typedef void (*CSNBKYT_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_identifier, + unsigned char *random_number, + unsigned char *verification_pattern); + +/* Key Test Extended @b3a*/ +typedef void (*CSNBKYTX_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_identifier, + unsigned char *random_number, + unsigned char *verification_pattern, + unsigned char *kek_key_identifier); + +/* Des Key Token Change */ +typedef void (*CSNBKTC_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_identifier); + +/* Key Translate */ +typedef void (*CSNBKTR_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *input_key_token, + unsigned char *input_KEK_key_identifier, + unsigned char *output_KEK_key_identifier, + unsigned char *output_key_token); + +/* Random Number Generate */ +typedef void (*CSNBRNG_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *form, unsigned char *random_number); + +/* Random Number Generate Long */ +typedef void (*CSNBRNGL_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *seed_length, + unsigned char *seed, + long *random_number_length, + unsigned char *random_number); + +typedef void (*CSNBSAE_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, + long *key_params_length, + unsigned char *key_params, + long *block_size, + long *initialization_vector_length, + unsigned char *initialization_vector, + long *chaining_vector_length, + unsigned char *chaining_vector, + long *text_length, + unsigned char *text, + long *ciphertext_length, + unsigned char *ciphertext, + long *optional_data_length, + unsigned char *optional_data); + +typedef void (*CSNBSAD_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, + long *key_params_length, + unsigned char *key_params, + long *block_size, + long *initialization_vector_length, + unsigned char *initialization_vector, + long *chaining_vector_length, + unsigned char *chaining_vector, + long *ciphertext_length, + unsigned char *ciphertext, + long *text_length, + unsigned char *text, + long *optional_data_length, + unsigned char *optional_data); + +/* Decipher */ +typedef void (*CSNBDEC_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_identifier, + long *text_length, + unsigned char *ciphertext, + unsigned char *initialization_vector, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *chaining_vector, + unsigned char *plaintext); + +/* Encipher */ +typedef void (*CSNBENC_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_identifier, + long *text_length, + unsigned char *plaintext, + unsigned char *initialization_vector, + long *rule_array_count, + unsigned char *rule_array, + long *pad_character, + unsigned char *chaining_vector, + unsigned char *ciphertext); + +/* MAC Generate */ +typedef void (*CSNBMGN_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_identifier, + long *text_length, + unsigned char *text, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *chaining_vector, unsigned char *MAC); + +/* MAC Verify */ +typedef void (*CSNBMVR_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_identifier, + long *text_length, + unsigned char *text, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *chaining_vector, unsigned char *MAC); + +/* Key Token Build */ +typedef void (*CSNBKTB_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_token, + unsigned char *key_type, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_value, + void *reserved_field_1, + long *reserved_field_2, + unsigned char *reserved_field_3, + unsigned char *control_vector, + unsigned char *reserved_field_4, + long *reserved_field_5, + unsigned char *reserved_field_6, + unsigned char *master_key_verification_number); + + +/* Key Token Build2 */ +typedef void (*CSNBKTB2_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *clear_key_bit_length, + unsigned char *clear_key_value, + long *key_name_length, + unsigned char *key_name, + long *user_associated_data_length, + unsigned char *user_associated_data, + long *token_data_length, + unsigned char *token_data, + long *reserved_length, + unsigned char *reserved, + long *target_key_token_length, + unsigned char *target_key_token); + +/* PKA Key Generate */ +typedef void (*CSNDPKG_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *regeneration_data_length, + unsigned char *regeneration_data, + long *skeleton_key_token_length, + unsigned char *skeleton_key_token, + unsigned char *transport_key_identifier, + long *generated_key_identifier_length, + unsigned char *generated_key_identifier); + +/* PKA Key Token Build */ +typedef void (*CSNDPKB_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_values_structure_length, + unsigned char *key_values_structure, + long *key_name_ln, + unsigned char *key_name, + long *reserved_1_length, + unsigned char *reserved_1, + long *reserved_2_length, + unsigned char *reserved_2, + long *reserved_3_length, + unsigned char *reserved_3, + long *reserved_4_length, + unsigned char *reserved_4, + long *reserved_5_length, + unsigned char *reserved_5, + long *token_length, unsigned char *token); + +/* One Way Hash */ +typedef void (*CSNBOWH_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *text_length, + unsigned char *text, + long *chaining_vector_length, + unsigned char *chaining_vector, + long *hash_length, unsigned char *hash); + +/* PKA Key Import */ +typedef void (*CSNDPKI_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *source_key_token_length, + unsigned char *source_key_token, + unsigned char *importer_key_identifier, + long *target_key_identifier_length, + unsigned char *target_key_identifier); + +/* Digital Signature Generate */ +typedef void (*CSNDDSG_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *PKA_private_key_id_length, + unsigned char *PKA_private_key_id, + long *hash_length, + unsigned char *hash, + long *signature_field_length, + long *signature_bit_length, + unsigned char *signature_field); + +/* Digital Signature Verify */ +typedef void (*CSNDDSV_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *PKA_public_key_id_length, + unsigned char *PKA_public_key_id, + long *hash_length, + unsigned char *hash, + long *signature_field_length, + unsigned char *signature_field); + +/* PKA Key Token Change */ +typedef void (*CSNDKTC_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_id_length, unsigned char *key_id); + +/* PKA Public Key Extract */ +typedef void (*CSNDPKX_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *source_key_identifier_length, + unsigned char *source_key_identifier, + long *target_key_token_length, + unsigned char *target_key_token); + +/* PKA Symmetric Key Import */ +typedef void (*CSNDSYI_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *RSA_enciphered_key_length, + unsigned char *RSA_enciphered_key, + long *RSA_private_key_identifier_len, + unsigned char *RSA_private_key_identifier, + long *target_key_identifier_length, + unsigned char *target_key_identifier); + +/* PKA Symmetric Key Export */ +typedef void (*CSNDSYX_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *source_key_identifier_length, + unsigned char *source_key_identifier, + long *RSA_public_key_identifier_len, + unsigned char *RSA_public_key_identifier, + long *RSA_enciphered_key_length, + unsigned char *RSA_enciphered_key); + +/* Crypto Facility Query */ +typedef void (*CSUACFQ_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *verb_data_length, unsigned char *verb_data); + +/* Crypto Facility Control */ +typedef void (*CSUACFC_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *verb_data_length, unsigned char *verb_data); + +/* Compose SET Block */ +typedef void (*CSNDSBC_t) (long *ReturnCode, + long *ReasonCode, + long *ExitDataLength, + unsigned char *ExitData, + long *RuleArrayCount, + unsigned char *RuleArray, + unsigned char *BlockContentsIdentifier, + long *XDataStringLength, + unsigned char *XDataString, + long *DataToEncryptLength, + unsigned char *DataToEncrypt, + long *DataToHashLength, + unsigned char *DataToHash, + unsigned char *InitializationVector, + long *RSAPublicKeyIdentifierLength, + unsigned char *RSAPublicKeyIdentifier, + long *DESKeyBLockLength, + unsigned char *DESKeyBlock, + long *RSAOAEPBlockLength, + unsigned char *RSAOAEPBlock, + unsigned char *ChainingVector, + unsigned char *DESEncryptedDataBlock); + +/* Decompose SET Block */ +typedef void (*CSNDSBD_t) (long *ReturnCode, + long *ReasonCode, + long *ExitDataLength, + unsigned char *ExitData, + long *RuleArrayCount, + unsigned char *RuleArray, + long *RSAOAEPBlockLength, + unsigned char *RSAOAEPBlock, + long *DESEncryptedDataBlockLength, + unsigned char *DESEncryptedDataBlock, + unsigned char *InitializationVector, + long *RSAPrivateKeyIdentifierLength, + unsigned char *RSAPrivateKeyIdentifier, + long *DESKeyBLockLength, + unsigned char *DESKeyBlock, + unsigned char *BlockContentsIdentifier, + long *XDataStringLength, + unsigned char *XDataString, + unsigned char *ChainingVector, + unsigned char *DataBlock, + long *HashBlockLength, unsigned char *HashBlock); + +/* Access Control Logon */ +typedef void (*CSUALCT_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *user_id, + long *auth_parm_length, + unsigned char *auth_parm, + long *auth_data_length, unsigned char *auth_data); + +/* Access Control Maintenance */ +typedef void (*CSUAACM_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *name, + long *output_data_length, + unsigned char *output_data); + +/* Access Control Initialization */ +typedef void (*CSUAACI_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *verb_data_1_length, + unsigned char *verb_data_1, + long *verb_data_2_length, + unsigned char *verb_data_2); + + +/* PKA Public Key Hash Register */ +typedef void (*CSNDPKH_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *public_key_name, + long *hash_data_length, unsigned char *hash_data); + + +/* PKA Public Key Register */ +typedef void (*CSNDPKR_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *public_key_name, + long *public_key_certificate_length, + unsigned char *public_key_certificate); + + +/* Master Key Distribution */ +typedef void (*CSUAMKD_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *share_index, + unsigned char *private_key_name, + unsigned char *certifying_key_name, + long *certificate_length, + unsigned char *certificate, + long *clone_info_encrypting_key_length, + unsigned char *clone_info_encrypting_key, + long *clone_info_length, unsigned char *clone_info); + + +/* Retained Key Delete */ +typedef void (*CSNDRKD_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, unsigned char *key_label); + + +/* Retained Key List */ +typedef void (*CSNDRKL_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_label_mask, + long *retained_keys_count, + long *key_labels_count, unsigned char *key_labels); + +/* Symmetric Key Generate */ +typedef void (*CSNDSYG_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_encrypting_key, + long *rsapub_key_length, + unsigned char *rsapub_key, + long *locenc_key_length, + unsigned char *locenc_key, + long *rsaenc_key_length, unsigned char *rsaenc_key); + + +/* Encrypted PIN Translate */ +typedef void (*CSNBPTR_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *in_PIN_enc_key_id, + unsigned char *out_PIN_enc_key_id, + unsigned char *in_PIN_profile, + unsigned char *in_PAN_data, + unsigned char *in_PIN_blk, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *out_PIN_profile, + unsigned char *out_PAN_data, + long *sequence_number, unsigned char *put_PIN_blk); + + +/* Clear PIN Encrypt */ +typedef void (*CSNBCPE_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *PIN_enc_key_id, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *clear_PIN, + unsigned char *PIN_profile, + unsigned char *PAN_data, + long *sequence_number, + unsigned char *encrypted_PIN_blk); + + +/* Clear PIN Generate Alternate */ +typedef void (*CSNBCPA_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *PIN_enc_key_id, + unsigned char *PIN_gen_key_id, + unsigned char *PIN_profile, + unsigned char *PAN_data, + unsigned char *encrypted_PIN_blk, + long *rule_array_count, + unsigned char *rule_array, + long *PIN_check_length, + unsigned char *data_array, + unsigned char *returned_result); + + +/* Clear PIN Generate */ +typedef void (*CSNBPGN_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *PIN_gen_key_id, + long *rule_array_count, + unsigned char *rule_array, + long *PIN_length, + long *PIN_check_length, + unsigned char *data_array, + unsigned char *returned_result); + + +/* Encrypted PIN Verify */ +typedef void (*CSNBPVR_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *PIN_enc_key_id, + unsigned char *PIN_ver_key_id, + unsigned char *PIN_profile, + unsigned char *PAN_data, + unsigned char *encrypted_PIN_blk, + long *rule_array_count, + unsigned char *rule_array, + long *PIN_check_length, unsigned char *data_array); + +/* Diversified Key Generate */ +typedef void (*CSNBDKG_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *generating_key_id, + long *data_length, + unsigned char *data, + unsigned char *decrypting_key_id, + unsigned char *generated_key_id); + +/* Encrypted PIN Generate */ +typedef void (*CSNBEPG_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *PIN_gen_key_id, + unsigned char *outPIN_enc_key_id, + long *rule_array_count, + unsigned char *rule_array, + long *PIN_length, + unsigned char *data_array, + unsigned char *outPIN_profile, + unsigned char *PAN_data, + long *sequence_number, + unsigned char *encrypted_PIN_blk); + +/* Cryptographic Variable Encipher */ +typedef void (*CSNBCVE_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *cvarenc_key_id, + long *text_length, + unsigned char *plain_text, + unsigned char *init_vector, + unsigned char *cipher_text); + +/* CVV Generate */ +typedef void (*CSNBCSG_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *PAN_data, + unsigned char *expiration_date, + unsigned char *service_code, + unsigned char *key_a_id, + unsigned char *key_b_id, + unsigned char *generated_cvv); + +/* CVV Verify */ +typedef void (*CSNBCSV_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *PAN_data, + unsigned char *expiration_date, + unsigned char *service_code, + unsigned char *key_a_id, + unsigned char *key_b_id, + unsigned char *generated_cvv); + +/* Control Vector Generate */ +typedef void (*CSNBCVG_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_type, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *reserved_field_1, + unsigned char *control_vector); + +/* Key Token Parse */ +typedef void (*CSNBKTP_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_token, + unsigned char *key_type, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_value, + void *master_key_verification_pattern_v03, + long *reserved_field_1, + unsigned char *reserved_field_2, + unsigned char *control_vector, + unsigned char *reserved_field_3, + long *reserved_field_4, + unsigned char *reserved_field_5, + unsigned char *master_key_verification_pattern_v00); + +/* PKA Encrypt */ +typedef void (*CSNDPKE_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_value_length, + unsigned char *key_value, + long *data_struct_length, + unsigned char *data_struct, + long *RSA_public_key_length, + unsigned char *RSA_public_key, + long *RSA_encipher_length, + unsigned char *RSA_encipher); + +/* PKA Decrypt */ +typedef void (*CSNDPKD_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *enciphered_key_length, + unsigned char *enciphered_key, + long *data_struct_length, + unsigned char *data_struct, + long *RSA_private_key_length, + unsigned char *RSA_private_key, + long *key_value_length, unsigned char *key_value); + +/* Prohibit Export */ +typedef void (*CSNBPEX_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_identifier); + +/* Prohibit Export Extended */ +typedef void (*CSNBPEXX_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *Source_key_token, + unsigned char *Kek_key_identifier); + +/* Random Number/Known Answer Test */ +typedef void (*CSUARNT_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, unsigned char *rule_array); + +/* Control Vector Translate */ +typedef void (*CSNBCVT_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *kek_key_identifier, + unsigned char *source_key_token, + unsigned char *array_key_left, + unsigned char *mask_array_left, + unsigned char *array_key_right, + unsigned char *mask_array_right, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *target_key_token); + +/* MDC Generate */ +typedef void (*CSNBMDG_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *text_length, + unsigned char *text_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *chaining_vector, unsigned char *MDC); + +/* Cryptographic Resource Allocate */ +typedef void (*CSUACRA_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *resource_name_length, + unsigned char *resource_name); + +/* Cryptographic Resource Deallocate */ +typedef void (*CSUACRD_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *resource_name_length, + unsigned char *resource_name); + +/* Transaction Validation */ +typedef void (*CSNBTRV_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *transaction_key_length, + unsigned char *transaction_key, + long *transaction_info_length, + unsigned char *transaction_info, + long *validation_values_length, + unsigned char *validation_values); + +/* Secure Messaging for Keys */ +typedef void (*CSNBSKY_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *input_key_indentifier, + unsigned char *key_encrypting_key, + unsigned char *session_key, + long *text_length, + unsigned char *clear_text, + unsigned char *initialization_vector, + long *key_offset, + long *key_offset_field_length, + unsigned char *cipher_text, + unsigned char *output_chaining_value); + +/* Secure Messaging for PINs */ +typedef void (*CSNBSPN_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *in_PIN_blk, + unsigned char *in_PIN_enc_key_id, + unsigned char *in_PIN_profile, + unsigned char *in_PAN_data, + unsigned char *secmsg_key, + unsigned char *out_PIN_profile, + unsigned char *out_PAN_data, + long *text_length, + unsigned char *clear_text, + unsigned char *initialization_vector, + long *PIN_offset, + long *PIN_offset_field_length, + unsigned char *cipher_text, + unsigned char *output_chaining_value); + +/* PIN Change/Unblock */ +typedef void (*CSNBPCU_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *authenticationMasterKeyLength, + unsigned char *authenticationMasterKey, + long *issuerMasterKeyLength, + unsigned char *issuerMasterKey, + long *keyGenerationDataLength, + unsigned char *keyGenerationData, + long *newRefPinKeyLength, + unsigned char *newRefPinKey, + unsigned char *newRefPinBlock, + unsigned char *newRefPinProfile, + unsigned char *newRefPanData, + long *currentRefPinKeyLength, + unsigned char *currentRefPinKey, + unsigned char *currentRefPinBlock, + unsigned char *currentRefPinProfile, + unsigned char *currentRefPanData, + long *outputPinDataLength, + unsigned char *outputPinData, + unsigned char *outputPinProfile, + long *outputPinMessageLength, + unsigned char *outputPinMessage); + +/* PCF/CUSP Key Conversion */ +typedef void (*CSUAPCV_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *KEK_key_identifier_length, + unsigned char *KEK_key_identifier, + long *PCF_key_list_length, + unsigned char *PCF_key_list, + long *output_key_list_length, + unsigned char *output_key_list); + +/*Process Request Block*/ +typedef void (*CSUAPRB_t) (long *pReturnCode, + long *pReasonCode, + long *pExitDataLength, + unsigned char *pExitData, + long *pRuleArrayCount, + unsigned char *pRuleArray, + long *pSourceLength, + unsigned char *pSource, + long *pOutFileNameLength, + unsigned char *pOutFileName, + long *pReplyLength, unsigned char *pReply); + +/* Diffie-Hellman Key Load */ +typedef void (*CSUADHK_t) (long *ReturnCode, + long *ReasonCode, + long *ExitDataLength, + unsigned char *ExitData, + long *RuleArrayCount, + unsigned char *RuleArray, + unsigned char *DHModulus, + unsigned char *DHGenerator, + unsigned char *DHKeyPart, + long *TransportKeyHashLength, + unsigned char *TransportKeyHash, + unsigned char *Reserved1, + unsigned char *Reserved2, + unsigned char *Reserved3, unsigned char *Reserved4); + +/* Diffie-Hellman Key Query */ +typedef void (*CSUADHQ_t) (long *ReturnCode, + long *ReasonCode, + long *ExitDataLength, + unsigned char *ExitData, + long *RuleArrayCount, + unsigned char *RuleArray, + unsigned char *DHModulus, + unsigned char *DHGenerator, + unsigned char *DHKeyPart, + long *TransportKeyHashLength, + unsigned char *TransportKeyHash, + unsigned char *Reserved1, + unsigned char *Reserved2, + unsigned char *Reserved3, unsigned char *Reserved4); + +/* Trusted Block Create */ +typedef void (*CSNDTBC_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *input_block_length, + unsigned char *input_block_identifier, + unsigned char *transport_key_identifier, + long *trusted_blokc_length, + unsigned char *trusted_blokc_identifier); + +/* Remote Key Export */ +typedef void (*CSNDRKX_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *trusted_block_length, + unsigned char *trusted_block_identifier, + long *certificate_length, + unsigned char *certificate, + long *certificate_parms_length, + unsigned char *certificate_parms, + long *transport_key_length, + unsigned char *transport_key_identifier, + long *rule_id_length, + unsigned char *rule_id, + long *export_key_kek_length, + unsigned char *export_key_kek_identifier, + long *export_key_length, + unsigned char *export_key_identifier, + long *asym_encrypted_key_length, + unsigned char *asym_encrypted_key, + long *sym_encrypted_key_length, + unsigned char *sym_encrypted_key, + long *extra_data_length, + unsigned char *extra_data, + long *key_check_parameters_length, + unsigned char *key_check_parameters, + long *key_check_length, + unsigned char *key_check_value); + +/* Key Encryption Translate */ +typedef void (*CSNBKET_t) (long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *kek_identifier_length, + unsigned char *kek_identifier, + long *key_in_length, + unsigned char *key_in, + long *key_out_length, unsigned char *key_out); + + +/* HMAC Generate */ +typedef void (*CSNBHMG_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, + long *message_text_length, + unsigned char *message_text, + long *chaining_vector_length, + unsigned char *chaining_vector, + long *MAC_length, unsigned char *MAC_text); + +/* HMAC Verify */ +typedef void (*CSNBHMV_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, + long *message_text_length, + unsigned char *message_text, + long *chaining_vector_length, + unsigned char *chaining_vector, + long *MAC_length, unsigned char *MAC_text); diff --git a/usr/lib/cca_stdll/cca_specific.c b/usr/lib/cca_stdll/cca_specific.c new file mode 100644 index 0000000..fbc3a90 --- /dev/null +++ b/usr/lib/cca_stdll/cca_specific.c @@ -0,0 +1,3811 @@ +/* + * 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 + */ + +/* + * openCryptoki CCA token + * + * Author: Kent E. Yoder + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cca_stdll.h" +#include "pkcs11types.h" +#include "p11util.h" +#include "defs.h" +#include "host_defs.h" +#include "tok_specific.h" +#include "tok_struct.h" +#include "h_extern.h" +#include "csulincl.h" +#include "ec_defs.h" +#include "trace.h" +#include "ock_syslog.h" +#include "cca_func.h" +#include + +/** + * EC definitions + */ + +/** + * the point is encoded as z||x, where the octet z specifies + * which solution of the quadratic equation y is + */ +#define POINT_CONVERSION_COMPRESSED 0x02 + +/** + * the point is encoded as z||x||y, where z is the octet 0x04 + */ +#define POINT_CONVERSION_UNCOMPRESSED 0x04 + +/** + * the point is encoded as z||x||y, where the octet z specifies + * which solution of the quadratic equation y is + */ +#define POINT_CONVERSION_HYBRID 0x06 + + +const char manuf[] = "IBM"; +const char model[] = "CCA"; +const char descr[] = "IBM CCA Token"; +const char label[] = "ccatok"; + +#define CCASHAREDLIB "libcsulcca.so" + +static CSNBCKI_t dll_CSNBCKI; +static CSNBCKM_t dll_CSNBCKM; +static CSNBDKX_t dll_CSNBDKX; +static CSNBDKM_t dll_CSNBDKM; +static CSNBMKP_t dll_CSNBMKP; +static CSNBKEX_t dll_CSNBKEX; +static CSNBKGN_t dll_CSNBKGN; +static CSNBKGN2_t dll_CSNBKGN2; +static CSNBKIM_t dll_CSNBKIM; +static CSNBKPI_t dll_CSNBKPI; +static CSNBKPI2_t dll_CSNBKPI2; +static CSNBKSI_t dll_CSNBKSI; +static CSNBKRC_t dll_CSNBKRC; +static CSNBAKRC_t dll_CSNBAKRC; +static CSNBKRD_t dll_CSNBKRD; +static CSNBKRL_t dll_CSNBKRL; +static CSNBKRR_t dll_CSNBKRR; +static CSNBKRW_t dll_CSNBKRW; +static CSNDKRC_t dll_CSNDKRC; +static CSNDKRD_t dll_CSNDKRD; +static CSNDKRL_t dll_CSNDKRL; +static CSNDKRR_t dll_CSNDKRR; +static CSNDKRW_t dll_CSNDKRW; +static CSNBKYT_t dll_CSNBKYT; +static CSNBKYTX_t dll_CSNBKYTX; +static CSNBKTC_t dll_CSNBKTC; +static CSNBKTR_t dll_CSNBKTR; +static CSNBRNG_t dll_CSNBRNG; +static CSNBRNGL_t dll_CSNBRNGL; +static CSNBSAE_t dll_CSNBSAE; +static CSNBSAD_t dll_CSNBSAD; +static CSNBDEC_t dll_CSNBDEC; +static CSNBENC_t dll_CSNBENC; +static CSNBMGN_t dll_CSNBMGN; +static CSNBMVR_t dll_CSNBMVR; +static CSNBKTB_t dll_CSNBKTB; +static CSNBKTB2_t dll_CSNBKTB2; +static CSNDPKG_t dll_CSNDPKG; +static CSNDPKB_t dll_CSNDPKB; +static CSNBOWH_t dll_CSNBOWH; +static CSNDPKI_t dll_CSNDPKI; +static CSNDDSG_t dll_CSNDDSG; +static CSNDDSV_t dll_CSNDDSV; +static CSNDKTC_t dll_CSNDKTC; +static CSNDPKX_t dll_CSNDPKX; +static CSNDSYI_t dll_CSNDSYI; +static CSNDSYX_t dll_CSNDSYX; +static CSUACFQ_t dll_CSUACFQ; +static CSUACFC_t dll_CSUACFC; +static CSNDSBC_t dll_CSNDSBC; +static CSNDSBD_t dll_CSNDSBD; +static CSUALCT_t dll_CSUALCT; +static CSUAACM_t dll_CSUAACM; +static CSUAACI_t dll_CSUAACI; +static CSNDPKH_t dll_CSNDPKH; +static CSNDPKR_t dll_CSNDPKR; +static CSUAMKD_t dll_CSUAMKD; +static CSNDRKD_t dll_CSNDRKD; +static CSNDRKL_t dll_CSNDRKL; +static CSNDSYG_t dll_CSNDSYG; +static CSNBPTR_t dll_CSNBPTR; +static CSNBCPE_t dll_CSNBCPE; +static CSNBCPA_t dll_CSNBCPA; +static CSNBPGN_t dll_CSNBPGN; +static CSNBPVR_t dll_CSNBPVR; +static CSNBDKG_t dll_CSNBDKG; +static CSNBEPG_t dll_CSNBEPG; +static CSNBCVE_t dll_CSNBCVE; +static CSNBCSG_t dll_CSNBCSG; +static CSNBCSV_t dll_CSNBCSV; +static CSNBCVG_t dll_CSNBCVG; +static CSNBKTP_t dll_CSNBKTP; +static CSNDPKE_t dll_CSNDPKE; +static CSNDPKD_t dll_CSNDPKD; +static CSNBPEX_t dll_CSNBPEX; +static CSNBPEXX_t dll_CSNBPEXX; +static CSUARNT_t dll_CSUARNT; +static CSNBCVT_t dll_CSNBCVT; +static CSNBMDG_t dll_CSNBMDG; +static CSUACRA_t dll_CSUACRA; +static CSUACRD_t dll_CSUACRD; +static CSNBTRV_t dll_CSNBTRV; +static CSNBSKY_t dll_CSNBSKY; +static CSNBSPN_t dll_CSNBSPN; +static CSNBPCU_t dll_CSNBPCU; +static CSUAPCV_t dll_CSUAPCV; +static CSUAPRB_t dll_CSUAPRB; +static CSUADHK_t dll_CSUADHK; +static CSUADHQ_t dll_CSUADHQ; +static CSNDTBC_t dll_CSNDTBC; +static CSNDRKX_t dll_CSNDRKX; +static CSNBKET_t dll_CSNBKET; +static CSNBHMG_t dll_CSNBHMG; +static CSNBHMV_t dll_CSNBHMV; + +/* mechanisms provided by this token */ +static const MECH_LIST_ELEMENT cca_mech_list[] = { + {CKM_DES_KEY_GEN, {8, 8, CKF_HW | CKF_GENERATE}}, + {CKM_DES3_KEY_GEN, {24, 24, CKF_HW | CKF_GENERATE}}, + {CKM_RSA_PKCS_KEY_PAIR_GEN, {512, 4096, CKF_HW | CKF_GENERATE_KEY_PAIR}}, + {CKM_RSA_PKCS, {512, 4096, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_SIGN | + CKF_VERIFY}}, + {CKM_MD5_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA1_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA256_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {CKM_DES_CBC, + {8, 8, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, + {CKM_DES_CBC_PAD, + {8, 8, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, + {CKM_DES3_CBC, + {24, 24, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, + {CKM_DES3_CBC_PAD, + {24, 24, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, +#ifndef NOAES + {CKM_AES_KEY_GEN, {16, 32, CKF_HW | CKF_GENERATE}}, + {CKM_AES_ECB, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, + {CKM_AES_CBC, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, + {CKM_AES_CBC_PAD, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, +#endif + {CKM_SHA512, {0, 0, CKF_HW | CKF_DIGEST}}, + {CKM_SHA512_HMAC, {256, 2048, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA512_HMAC_GENERAL, {256, 2048, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA384, {0, 0, CKF_HW | CKF_DIGEST}}, + {CKM_SHA384_HMAC, {192, 2048, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA384_HMAC_GENERAL, {192, 2048, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA256, {0, 0, CKF_HW | CKF_DIGEST}}, + {CKM_SHA256_HMAC, {128, 2048, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA256_HMAC_GENERAL, {128, 2048, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA224, {0, 0, CKF_HW | CKF_DIGEST}}, + {CKM_SHA224_HMAC, {112, 2048, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA224_HMAC_GENERAL, {112, 2048, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA_1, {0, 0, CKF_DIGEST}}, + {CKM_SHA_1_HMAC, {80, 2048, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA_1_HMAC_GENERAL, {80, 2048, CKF_SIGN | CKF_VERIFY}}, + {CKM_MD5, {0, 0, CKF_DIGEST}}, + {CKM_EC_KEY_PAIR_GEN, {160, 521, CKF_HW | CKF_GENERATE_KEY_PAIR | + CKF_EC_NAMEDCURVE | CKF_EC_F_P}}, + {CKM_ECDSA, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE | + CKF_EC_F_P}}, + {CKM_ECDSA_SHA1, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | + CKF_EC_NAMEDCURVE | CKF_EC_F_P}}, + {CKM_GENERIC_SECRET_KEY_GEN, {80, 2048, CKF_HW | CKF_GENERATE}}, + {CKM_ECDSA_SHA224, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | + CKF_EC_NAMEDCURVE | CKF_EC_F_P}}, + {CKM_GENERIC_SECRET_KEY_GEN, {80, 2048, CKF_HW | CKF_GENERATE}}, + {CKM_ECDSA_SHA256, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | + CKF_EC_NAMEDCURVE | CKF_EC_F_P}}, + {CKM_GENERIC_SECRET_KEY_GEN, {80, 2048, CKF_HW | CKF_GENERATE}}, + {CKM_ECDSA_SHA384, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | + CKF_EC_NAMEDCURVE | CKF_EC_F_P}}, + {CKM_GENERIC_SECRET_KEY_GEN, {80, 2048, CKF_HW | CKF_GENERATE}}, + {CKM_ECDSA_SHA512, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | + CKF_EC_NAMEDCURVE | CKF_EC_F_P}}, + {CKM_GENERIC_SECRET_KEY_GEN, {80, 2048, CKF_HW | CKF_GENERATE}} +}; + +static const CK_ULONG cca_mech_list_len = + (sizeof(cca_mech_list) / sizeof(MECH_LIST_ELEMENT)); + +CK_RV token_specific_rng(STDLL_TokData_t * tokdata, CK_BYTE * output, + CK_ULONG bytes) +{ + long return_code, reason_code; + unsigned char rule_array[CCA_KEYWORD_SIZE]; + CK_ULONG bytes_so_far = 0, num_bytes; + long rule_array_count = 1, zero = 0; + CK_RV rv; + + UNUSED(tokdata); + + memcpy(rule_array, "RANDOM ", (size_t) CCA_KEYWORD_SIZE); + + while (bytes_so_far < bytes) { + num_bytes = bytes - bytes_so_far; + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNBRNGL failed. return:%ld, reason:%ld\n", + return_code, reason_code); + rv = CKR_FUNCTION_FAILED; + return rv; + } + + bytes_so_far += num_bytes; + } + + return CKR_OK; +} + +static CK_RV cca_resolve_lib_sym(void *hdl) +{ + char *error = NULL; + + dlerror(); /* Clear existing error */ + + *(void **)(&dll_CSNBCKI) = dlsym(hdl, "CSNBCKI"); + *(void **)(&dll_CSNBCKM) = dlsym(hdl, "CSNBCKM"); + *(void **)(&dll_CSNBDKX) = dlsym(hdl, "CSNBDKX"); + *(void **)(&dll_CSNBDKM) = dlsym(hdl, "CSNBDKM"); + *(void **)(&dll_CSNBMKP) = dlsym(hdl, "CSNBMKP"); + *(void **)(&dll_CSNBKEX) = dlsym(hdl, "CSNBKEX"); + *(void **)(&dll_CSNBKGN) = dlsym(hdl, "CSNBKGN"); + *(void **)(&dll_CSNBKGN2) = dlsym(hdl, "CSNBKGN2"); + *(void **)(&dll_CSNBKIM) = dlsym(hdl, "CSNBKIM"); + *(void **)(&dll_CSNBKPI) = dlsym(hdl, "CSNBKPI"); + *(void **)(&dll_CSNBKPI2) = dlsym(hdl, "CSNBKPI2"); + *(void **)(&dll_CSNBKSI) = dlsym(hdl, "CSNBKSI"); + *(void **)(&dll_CSNBKRC) = dlsym(hdl, "CSNBKRC"); + *(void **)(&dll_CSNBAKRC) = dlsym(hdl, "CSNBAKRC"); + *(void **)(&dll_CSNBKRD) = dlsym(hdl, "CSNBKRD"); + *(void **)(&dll_CSNBKRL) = dlsym(hdl, "CSNBKRL"); + *(void **)(&dll_CSNBKRR) = dlsym(hdl, "CSNBKRR"); + *(void **)(&dll_CSNBKRW) = dlsym(hdl, "CSNBKRW"); + *(void **)(&dll_CSNDKRC) = dlsym(hdl, "CSNDKRC"); + *(void **)(&dll_CSNDKRD) = dlsym(hdl, "CSNDKRD"); + *(void **)(&dll_CSNDKRL) = dlsym(hdl, "CSNDKRL"); + *(void **)(&dll_CSNDKRR) = dlsym(hdl, "CSNDKRR"); + *(void **)(&dll_CSNDKRW) = dlsym(hdl, "CSNDKRW"); + *(void **)(&dll_CSNBKYT) = dlsym(hdl, "CSNBKYT"); + *(void **)(&dll_CSNBKYTX) = dlsym(hdl, "CSNBKYTX"); + *(void **)(&dll_CSNBKTC) = dlsym(hdl, "CSNBKTC"); + *(void **)(&dll_CSNBKTR) = dlsym(hdl, "CSNBKTR"); + *(void **)(&dll_CSNBRNG) = dlsym(hdl, "CSNBRNG"); + *(void **)(&dll_CSNBRNGL) = dlsym(hdl, "CSNBRNGL"); + *(void **)(&dll_CSNBSAE) = dlsym(hdl, "CSNBSAE"); + *(void **)(&dll_CSNBSAD) = dlsym(hdl, "CSNBSAD"); + *(void **)(&dll_CSNBDEC) = dlsym(hdl, "CSNBDEC"); + *(void **)(&dll_CSNBENC) = dlsym(hdl, "CSNBENC"); + *(void **)(&dll_CSNBMGN) = dlsym(hdl, "CSNBMGN"); + *(void **)(&dll_CSNBMVR) = dlsym(hdl, "CSNBMVR"); + *(void **)(&dll_CSNBKTB) = dlsym(hdl, "CSNBKTB"); + *(void **)(&dll_CSNBKTB2) = dlsym(hdl, "CSNBKTB2"); + *(void **)(&dll_CSNDPKG) = dlsym(hdl, "CSNDPKG"); + *(void **)(&dll_CSNDPKB) = dlsym(hdl, "CSNDPKB"); + *(void **)(&dll_CSNBOWH) = dlsym(hdl, "CSNBOWH"); + *(void **)(&dll_CSNDPKI) = dlsym(hdl, "CSNDPKI"); + *(void **)(&dll_CSNDDSG) = dlsym(hdl, "CSNDDSG"); + *(void **)(&dll_CSNDDSV) = dlsym(hdl, "CSNDDSV"); + *(void **)(&dll_CSNDKTC) = dlsym(hdl, "CSNDKTC"); + *(void **)(&dll_CSNDPKX) = dlsym(hdl, "CSNDPKX"); + *(void **)(&dll_CSNDSYI) = dlsym(hdl, "CSNDSYI"); + *(void **)(&dll_CSNDSYX) = dlsym(hdl, "CSNDSYX"); + *(void **)(&dll_CSUACFQ) = dlsym(hdl, "CSUACFQ"); + *(void **)(&dll_CSUACFC) = dlsym(hdl, "CSUACFC"); + *(void **)(&dll_CSNDSBC) = dlsym(hdl, "CSNDSBC"); + *(void **)(&dll_CSNDSBD) = dlsym(hdl, "CSNDSBD"); + *(void **)(&dll_CSUALCT) = dlsym(hdl, "CSUALCT"); + *(void **)(&dll_CSUAACM) = dlsym(hdl, "CSUAACM"); + *(void **)(&dll_CSUAACI) = dlsym(hdl, "CSUAACI"); + *(void **)(&dll_CSNDPKH) = dlsym(hdl, "CSNDPKH"); + *(void **)(&dll_CSNDPKR) = dlsym(hdl, "CSNDPKR"); + *(void **)(&dll_CSUAMKD) = dlsym(hdl, "CSUAMKD"); + *(void **)(&dll_CSNDRKD) = dlsym(hdl, "CSNDRKD"); + *(void **)(&dll_CSNDRKL) = dlsym(hdl, "CSNDRKL"); + *(void **)(&dll_CSNDSYG) = dlsym(hdl, "CSNDSYG"); + *(void **)(&dll_CSNBPTR) = dlsym(hdl, "CSNBPTR"); + *(void **)(&dll_CSNBCPE) = dlsym(hdl, "CSNBCPE"); + *(void **)(&dll_CSNBCPA) = dlsym(hdl, "CSNBCPA"); + *(void **)(&dll_CSNBPGN) = dlsym(hdl, "CSNBPGN"); + *(void **)(&dll_CSNBPVR) = dlsym(hdl, "CSNBPVR"); + *(void **)(&dll_CSNBDKG) = dlsym(hdl, "CSNBDKG"); + *(void **)(&dll_CSNBEPG) = dlsym(hdl, "CSNBEPG"); + *(void **)(&dll_CSNBCVE) = dlsym(hdl, "CSNBCVE"); + *(void **)(&dll_CSNBCSG) = dlsym(hdl, "CSNBCSG"); + *(void **)(&dll_CSNBCSV) = dlsym(hdl, "CSNBCSV"); + *(void **)(&dll_CSNBCVG) = dlsym(hdl, "CSNBCVG"); + *(void **)(&dll_CSNBKTP) = dlsym(hdl, "CSNBKTP"); + *(void **)(&dll_CSNDPKE) = dlsym(hdl, "CSNDPKE"); + *(void **)(&dll_CSNDPKD) = dlsym(hdl, "CSNDPKD"); + *(void **)(&dll_CSNBPEX) = dlsym(hdl, "CSNBPEX"); + *(void **)(&dll_CSNBPEXX) = dlsym(hdl, "CSNBPEXX"); + *(void **)(&dll_CSUARNT) = dlsym(hdl, "CSUARNT"); + *(void **)(&dll_CSNBCVT) = dlsym(hdl, "CSNBCVT"); + *(void **)(&dll_CSNBMDG) = dlsym(hdl, "CSNBMDG"); + *(void **)(&dll_CSUACRA) = dlsym(hdl, "CSUACRA"); + *(void **)(&dll_CSUACRD) = dlsym(hdl, "CSUACRD"); + *(void **)(&dll_CSNBTRV) = dlsym(hdl, "CSNBTRV"); + *(void **)(&dll_CSNBSKY) = dlsym(hdl, "CSNBSKY"); + *(void **)(&dll_CSNBSPN) = dlsym(hdl, "CSNBSPN"); + *(void **)(&dll_CSNBPCU) = dlsym(hdl, "CSNBPCU"); + *(void **)(&dll_CSUAPCV) = dlsym(hdl, "CSUAPCV"); + *(void **)(&dll_CSUAPRB) = dlsym(hdl, "CSUAPRB"); + *(void **)(&dll_CSUADHK) = dlsym(hdl, "CSUADHK"); + *(void **)(&dll_CSUADHQ) = dlsym(hdl, "CSUADHQ"); + *(void **)(&dll_CSNDTBC) = dlsym(hdl, "CSNDTBC"); + *(void **)(&dll_CSNDRKX) = dlsym(hdl, "CSNDRKX"); + *(void **)(&dll_CSNBKET) = dlsym(hdl, "CSNBKET"); + *(void **)(&dll_CSNBHMG) = dlsym(hdl, "CSNBHMG"); + *(void **)(&dll_CSNBHMV) = dlsym(hdl, "CSNBHMV"); + + if ((error = dlerror()) != NULL) { + OCK_SYSLOG(LOG_ERR, "%s\n", error); + exit(EXIT_FAILURE); + } + + return CKR_OK; +} + +CK_RV token_specific_init(STDLL_TokData_t * tokdata, CK_SLOT_ID SlotNumber, + char *conf_name) +{ + unsigned char rule_array[256] = { 0, }; + long return_code, reason_code, rule_array_count, verb_data_length; + void *lib_csulcca; + CK_RV rc; + + UNUSED(conf_name); + + TRACE_INFO("cca %s slot=%lu running\n", __func__, SlotNumber); + + tokdata->mech_list = (MECH_LIST_ELEMENT *)cca_mech_list; + tokdata->mech_list_len = cca_mech_list_len; + + lib_csulcca = dlopen(CCASHAREDLIB, RTLD_GLOBAL | RTLD_NOW); + if (lib_csulcca == NULL) { + OCK_SYSLOG(LOG_ERR, "%s: Error loading library: '%s' [%s]\n", + __func__, CCASHAREDLIB, dlerror()); + TRACE_ERROR("%s: Error loading shared library '%s' [%s]\n", + __func__, CCASHAREDLIB, dlerror()); + return CKR_FUNCTION_FAILED; + } + + rc = cca_resolve_lib_sym(lib_csulcca); + if (rc) + exit(rc); + + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSUACFQ failed. return:%ld, reason:%ld\n", + 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_STATCCAE_SYM_CMK_OFFSET], "2 ", 8)) { + OCK_SYSLOG(LOG_WARNING, + "Warning: CCA symmetric master key is not yet loaded"); + } + if (memcmp(&rule_array[CCA_STATCCAE_ASYM_CMK_OFFSET], "2 ", 8)) { + OCK_SYSLOG(LOG_WARNING, + "Warning: CCA asymmetric master key is not yet loaded"); + } + + return CKR_OK; +} + +CK_RV token_specific_final(STDLL_TokData_t *tokdata, + CK_BBOOL in_fork_initializer) +{ + UNUSED(tokdata); + UNUSED(in_fork_initializer); + + TRACE_INFO("cca %s running\n", __func__); + + return CKR_OK; +} + +static CK_RV cca_key_gen(enum cca_key_type type, CK_BYTE * key, + unsigned char *key_form, unsigned char *key_type_1, + CK_ULONG key_size) +{ + + long return_code, reason_code; + unsigned char key_length[CCA_KEYWORD_SIZE]; + unsigned char key_type_2[CCA_KEYWORD_SIZE] = { 0, }; + unsigned char kek_key_identifier_1[CCA_KEY_ID_SIZE] = { 0, }; + unsigned char kek_key_identifier_2[CCA_KEY_ID_SIZE] = { 0, }; + unsigned char generated_key_identifier_2[CCA_KEY_ID_SIZE] = { 0, }; + + if (type == CCA_DES_KEY) { + switch (key_size) { + case 8: + memcpy(key_length, "KEYLN8 ", (size_t) CCA_KEYWORD_SIZE); + break; + case 24: + memcpy(key_length, "KEYLN24 ", (size_t) CCA_KEYWORD_SIZE); + break; + default: + TRACE_ERROR("Invalid key length: %lu\n", key_size); + return CKR_KEY_SIZE_RANGE; + } + } else if (type == CCA_AES_KEY) { + switch (key_size) { + case 16: + memcpy(key_length, "KEYLN16 ", CCA_KEYWORD_SIZE); + break; + case 24: + memcpy(key_length, "KEYLN24 ", (size_t) CCA_KEYWORD_SIZE); + break; + case 32: + memcpy(key_length, " ", (size_t) CCA_KEYWORD_SIZE); + break; + default: + TRACE_ERROR("Invalid key length: %lu\n", key_size); + return CKR_KEY_SIZE_RANGE; + } + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNBKGN(KEYGEN) failed. return:%ld, reason:%ld\n", + return_code, reason_code); + return CKR_FUNCTION_FAILED; + } + + return CKR_OK; +} + +CK_RV token_specific_des_key_gen(STDLL_TokData_t * tokdata, CK_BYTE * des_key, + CK_ULONG len, CK_ULONG keysize) +{ + unsigned char key_form[CCA_KEYWORD_SIZE]; + unsigned char key_type_1[CCA_KEYWORD_SIZE]; + + UNUSED(tokdata); + + /* make sure key is the right size for the token */ + if (len != CCA_KEY_ID_SIZE) + return CKR_FUNCTION_FAILED; + + memcpy(key_form, "OP ", (size_t) CCA_KEYWORD_SIZE); + memcpy(key_type_1, "DATA ", (size_t) CCA_KEYWORD_SIZE); + + return cca_key_gen(CCA_DES_KEY, des_key, key_form, key_type_1, keysize); +} + + +CK_RV token_specific_des_ecb(STDLL_TokData_t * tokdata, + CK_BYTE * in_data, + CK_ULONG in_data_len, + CK_BYTE * out_data, + CK_ULONG * out_data_len, + OBJECT * key, CK_BYTE encrypt) +{ + UNUSED(tokdata); + UNUSED(in_data); + UNUSED(in_data_len); + UNUSED(out_data); + UNUSED(out_data_len); + UNUSED(key); + UNUSED(encrypt); + + TRACE_INFO("Unsupported function reached.\n"); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV token_specific_des_cbc(STDLL_TokData_t * tokdata, + 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) +{ + long return_code, reason_code, rule_array_count, length; + long pad_character = 0; + //char iv[8] = { 0xfe, 0x43, 0x12, 0xed, 0xaa, 0xbb, 0xdd, 0x90 }; + unsigned char chaining_vector[CCA_OCV_SIZE]; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE]; + CK_BYTE *local_out = out_data; + CK_ATTRIBUTE *attr = NULL; + + UNUSED(tokdata); + + if (template_attribute_find(key->template, + CKA_IBM_OPAQUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + + /* We need to have 8 bytes more than the in data length in case CCA + * adds some padding, although this extra 8 bytes may not be needed. + * If *out_data_len is not 8 bytes larger than in_data_len, then + * we'll malloc the needed space and get the data back from CCA in this + * malloc'd buffer. If it turns out that the extra 8 bytes wasn't + * needed, we just silently copy the data to the user's buffer and + * free our malloc'd space, returning as normal. If the space was + * needed, we return an error and no memory corruption happens. */ + if (*out_data_len < (in_data_len + 8)) { + local_out = malloc(in_data_len + 8); + if (!local_out) { + TRACE_ERROR("Malloc of %lu bytes failed.\n", in_data_len + 8); + return CKR_HOST_MEMORY; + } + } + + length = in_data_len; + + 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); + } + + if (return_code != CCA_SUCCESS) { + if (encrypt) + TRACE_ERROR("CSNBENC (DES ENCRYPT) failed. return:%ld," + " reason:%ld\n", return_code, reason_code); + else + TRACE_ERROR("CSNBDEC (DES DECRYPT) failed. return:%ld," + " reason:%ld\n", return_code, reason_code); + if (out_data != local_out) + free(local_out); + return CKR_FUNCTION_FAILED; + } else if (reason_code != 0) { + if (encrypt) + TRACE_WARNING("CSNBENC (DES ENCRYPT) succeeded, but" + " returned reason:%ld\n", reason_code); + else + TRACE_WARNING("CSNBDEC (DES DECRYPT) succeeded, but" + " returned reason:%ld\n", reason_code); + } + + /* If we malloc'd a new buffer due to overflow concerns and the data + * coming out turned out to be bigger than expected, return an error. + * + * Else, memcpy the data back to the user's buffer + */ + if ((local_out != out_data) && ((CK_ULONG) length > *out_data_len)) { + TRACE_DEVEL("CKR_BUFFER_TOO_SMALL: %ld bytes to write into %ld " + "bytes space\n", length, *out_data_len); + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + free(local_out); + return CKR_BUFFER_TOO_SMALL; + } else if (local_out != out_data) { + memcpy(out_data, local_out, (size_t) length); + free(local_out); + } + + *out_data_len = length; + + return CKR_OK; +} + +CK_RV token_specific_tdes_ecb(STDLL_TokData_t * tokdata, + CK_BYTE * in_data, + CK_ULONG in_data_len, + CK_BYTE * out_data, + CK_ULONG * out_data_len, + OBJECT * key, CK_BYTE encrypt) +{ + UNUSED(tokdata); + UNUSED(in_data); + UNUSED(in_data_len); + UNUSED(out_data); + UNUSED(out_data_len); + UNUSED(key); + UNUSED(encrypt); + + TRACE_WARNING("Unsupported function reached.\n"); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + +CK_RV token_specific_tdes_cbc(STDLL_TokData_t * tokdata, + 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) +{ + /* Since keys are opaque objects in this token and there's only + * one encipher command to CCA, we can just pass through */ + return token_specific_des_cbc(tokdata, in_data, in_data_len, out_data, + out_data_len, key, init_v, encrypt); +} + +uint16_t cca_inttok_privkey_get_len(CK_BYTE * tok) +{ + return *(uint16_t *) & tok[CCA_RSA_INTTOK_PRIVKEY_LENGTH_OFFSET]; +} + +/* Given a CCA internal token private key object, get the modulus */ +CK_RV cca_inttok_privkey_get_n(CK_BYTE * tok, CK_ULONG * n_len, CK_BYTE * n) +{ + uint16_t privkey_length, n_length; + uint32_t privkey_n_offset; + + privkey_length = *(uint16_t *) & tok[CCA_RSA_INTTOK_PRIVKEY_LENGTH_OFFSET]; + n_length = *(uint16_t *) & tok[CCA_RSA_INTTOK_PRIVKEY_N_LENGTH_OFFSET]; + + if (n_length > (*n_len)) { + TRACE_ERROR("Not enough room to return n.(Got %lu, need %hu)\n", + *n_len, n_length); + return CKR_FUNCTION_FAILED; + } + + privkey_n_offset = privkey_length - n_length; + + memcpy(n, &tok[privkey_n_offset], (size_t) n_length); + *n_len = n_length; + + return CKR_OK; +} + +/* Given a CCA internal token pubkey object, get the public exponent */ +CK_RV cca_inttok_pubkey_get_e(CK_BYTE * tok, CK_ULONG * e_len, CK_BYTE * e) +{ + uint16_t e_length; + + e_length = *(uint16_t *) & tok[CCA_RSA_INTTOK_PUBKEY_E_LENGTH_OFFSET]; + + if (e_length > (*e_len)) { + TRACE_ERROR("Not enough room to return e.(Got %lu, need %hu)\n", + *e_len, e_length); + return CKR_FUNCTION_FAILED; + } + + memcpy(e, &tok[CCA_RSA_INTTOK_PUBKEY_E_OFFSET], (size_t) e_length); + *e_len = (CK_ULONG) e_length; + + return CKR_OK; +} + +CK_RV token_create_keypair_object(TEMPLATE * tmpl, CK_ULONG tok_len, + CK_BYTE * tok) +{ + uint16_t privkey_len, pubkey_offset; + CK_BYTE n[CCATOK_MAX_N_LEN], e[CCATOK_MAX_E_LEN]; + CK_ULONG n_len = CCATOK_MAX_N_LEN, e_len = CCATOK_MAX_E_LEN; + CK_ATTRIBUTE *modulus, *pub_exp, *opaque_key; + CK_RV rv; + + privkey_len = + cca_inttok_privkey_get_len(&tok[CCA_RSA_INTTOK_PRIVKEY_OFFSET]); + pubkey_offset = privkey_len + CCA_RSA_INTTOK_HDR_LENGTH; + + /* That's right, n is stored in the private key area. Get it there */ + if ((rv = cca_inttok_privkey_get_n(&tok[CCA_RSA_INTTOK_PRIVKEY_OFFSET], + &n_len, n))) { + TRACE_DEVEL("cca_inttok_privkey_get_n() failed. rv=0x%lx\n", rv); + return rv; + } + + /* Get e */ + if ((rv = cca_inttok_pubkey_get_e(&tok[pubkey_offset], &e_len, e))) { + TRACE_DEVEL("cca_inttok_pubkey_get_e() failed. rv=0x%lx\n", rv); + return rv; + } + + /* Add n's value to the template */ + if ((rv = build_attribute(CKA_MODULUS, n, n_len, &modulus))) { + TRACE_DEVEL("build_attribute for n failed. rv=0x%lx\n", rv); + return rv; + } + template_update_attribute(tmpl, modulus); + + /* Add e's value to the template */ + if ((rv = build_attribute(CKA_PUBLIC_EXPONENT, e, e_len, &pub_exp))) { + TRACE_DEVEL("build_attribute for e failed. rv=0x%lx\n", rv); + return rv; + } + template_update_attribute(tmpl, pub_exp); + + /* Add the opaque key object to the template */ + if ((rv = build_attribute(CKA_IBM_OPAQUE, tok, tok_len, &opaque_key))) { + TRACE_DEVEL("build_attribute for opaque key failed. rv=0x%lx\n", rv); + return rv; + } + template_update_attribute(tmpl, opaque_key); + + return CKR_OK; +} + +#if 0 +CK_RV +token_create_priv_key(TEMPLATE * priv_tmpl, CK_ULONG tok_len, CK_BYTE * tok) +{ + CK_BYTE n[CCATOK_MAX_N_LEN]; + CK_ULONG n_len = CCATOK_MAX_N_LEN; + CK_RV rv; + CK_ATTRIBUTE *opaque_key, *modulus; + + /* That's right, n is stored in the private key area. Get it there */ + if ((rv = cca_inttok_privkey_get_n(&tok[CCA_RSA_INTTOK_PRIVKEY_OFFSET], + &n_len, n))) { + TRACE_DEVEL("cca_inttok_privkey_get_n() failed. rv=0x%lx", rv); + return rv; + } + + /* Add n's value to the template. We need to do this for the private + * key as well as the public key because openCryptoki checks data + * sizes against the size of the CKA_MODULUS attribute of whatever + * key object it gets */ + if ((rv = build_attribute(CKA_MODULUS, n, n_len, &modulus))) { + TRACE_DEVEL("build_attribute for n failed. rv=0x%lx", rv); + return rv; + } + template_update_attribute(priv_tmpl, modulus); + + /* Add the opaque key object to the template */ + if ((rv = build_attribute(CKA_IBM_OPAQUE, tok, tok_len, &opaque_key))) { + TRACE_DEVEL("build_attribute for opaque key failed. rv=0x%lx", rv); + return rv; + } + template_update_attribute(priv_tmpl, opaque_key); + + return CKR_OK; +} +#endif + +CK_RV token_specific_rsa_generate_keypair(STDLL_TokData_t * tokdata, + TEMPLATE * publ_tmpl, + TEMPLATE * priv_tmpl) +{ + long return_code, reason_code, rule_array_count; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + + long key_value_structure_length; + long private_key_name_length, key_token_length; + unsigned char key_value_structure[CCA_KEY_VALUE_STRUCT_SIZE] = { 0, }; + unsigned char private_key_name[CCA_PRIVATE_KEY_NAME_SIZE] = { 0, }; + unsigned char key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; + + long regeneration_data_length, generated_key_token_length; + unsigned char regeneration_data[CCA_REGENERATION_DATA_SIZE] = { 0, }; + unsigned char transport_key_identifier[CCA_KEY_ID_SIZE] = { 0, }; + unsigned char generated_key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; + + uint16_t size_of_e; + uint16_t mod_bits; + CK_ATTRIBUTE *pub_exp = NULL, *attr = NULL; + CK_RV rv; + CK_BYTE_PTR ptr; + CK_ULONG tmpsize, tmpexp; + + UNUSED(tokdata); + + if (!template_attribute_find(publ_tmpl, CKA_MODULUS_BITS, &attr)) { + TRACE_ERROR("Could not find CKA_MODULUS_BITS for the key.\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + mod_bits = *(CK_ULONG *) attr->pValue; + + + /* If e is specified in the template, use it */ + rv = template_attribute_find(publ_tmpl, CKA_PUBLIC_EXPONENT, &pub_exp); + if (rv == TRUE) { + + /* Per CCA manual, we really only support 3 values here: * + * * 0 (generate random public exponent) * + * * 3 or * + * * 65537 * + * Trim the P11 value so we can check what's comming our way */ + + tmpsize = pub_exp->ulValueLen; + ptr = p11_bigint_trim(pub_exp->pValue, &tmpsize); + /* If we trimmed the number correctly, only 3 bytes are * + * sufficient to hold 65537 (0x010001) */ + if (tmpsize > 3) + return CKR_TEMPLATE_INCONSISTENT; + + /* make pValue into CK_ULONG so we can compare */ + tmpexp = 0; + memcpy((unsigned char *) &tmpexp + sizeof(CK_ULONG) - tmpsize, + ptr, tmpsize); /* right align */ + + /* Check for one of the three allowed values */ + if ((tmpexp != 0) && (tmpexp != 3) && (tmpexp != 65537)) + return CKR_TEMPLATE_INCONSISTENT; + + + size_of_e = (uint16_t) tmpsize; + + memcpy(&key_value_structure[CCA_PKB_E_SIZE_OFFSET], + &size_of_e, (size_t) CCA_PKB_E_SIZE); + memcpy(&key_value_structure[CCA_PKB_E_OFFSET], ptr, (size_t) tmpsize); + } + + key_value_structure_length = CCA_KEY_VALUE_STRUCT_SIZE; + memcpy(key_value_structure, &mod_bits, sizeof(uint16_t)); + + /* One last check. CCA can't auto-generate a random public * + * exponent if the modulus length is more than 2048 bits * + * We should be ok checking the public exponent length in the * + * key_value_structure, since either the caller never * + * specified it or we trimmed it's size. The size should be * + * zero if the value is zero in both cases. * + * public exponent has CCA_PKB_E_SIZE_OFFSET offset with * + * 2-bytes size */ + if (mod_bits > 2048 && + key_value_structure[CCA_PKB_E_SIZE_OFFSET] == 0x00 && + key_value_structure[CCA_PKB_E_SIZE_OFFSET + 1] == 0x00) { + return CKR_TEMPLATE_INCONSISTENT; + } + + rule_array_count = 2; + memcpy(rule_array, "RSA-CRT KEY-MGMT", (size_t) (CCA_KEYWORD_SIZE * 2)); + + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNDPKB (RSA KEY TOKEN BUILD) failed. return:%ld," + " reason:%ld\n", return_code, reason_code); + return CKR_FUNCTION_FAILED; + } + + rule_array_count = 1; + memset(rule_array, 0, sizeof(rule_array)); + memcpy(rule_array, "MASTER ", (size_t) CCA_KEYWORD_SIZE); + + generated_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, + &generated_key_token_length, generated_key_token); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNDPKG (RSA KEY GENERATE) failed. return:%ld," + " reason:%ld\n", return_code, reason_code); + return CKR_FUNCTION_FAILED; + } + + TRACE_DEVEL("RSA secure key token generated. size: %ld\n", + generated_key_token_length); + + rv = token_create_keypair_object(publ_tmpl, generated_key_token_length, + generated_key_token); + if (rv != CKR_OK) { + TRACE_DEVEL("token_create_keypair_object failed. rv:%lu\n", rv); + return rv; + } + + rv = token_create_keypair_object(priv_tmpl, generated_key_token_length, + generated_key_token); + if (rv != CKR_OK) + TRACE_DEVEL("token_create_keypair_object failed. rv:%lu\n", rv); + + return rv; +} + + +CK_RV token_specific_rsa_encrypt(STDLL_TokData_t * tokdata, + CK_BYTE * in_data, + CK_ULONG in_data_len, + CK_BYTE * out_data, + CK_ULONG * out_data_len, OBJECT * key_obj) +{ + long return_code, reason_code, rule_array_count, data_structure_length; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + CK_ATTRIBUTE *attr; + + UNUSED(tokdata); + + /* Find the secure key token */ + if (!template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr)) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + /* The max value allowable by CCA for out_data_len is 512, so cap the + * incoming value if its too large. CCA will throw error 8, 72 otherwise. + */ + if (*out_data_len > 512) + *out_data_len = 512; + + rule_array_count = 1; + memcpy(rule_array, "PKCS-1.2", CCA_KEYWORD_SIZE); + + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNDPKE (RSA ENCRYPT) failed. return:%ld, reason:%ld\n", + return_code, reason_code); + return CKR_FUNCTION_FAILED; + } else if (reason_code != 0) { + TRACE_WARNING("CSNDPKE (RSA ENCRYPT) succeeded, but" + " returned reason:%ld\n", reason_code); + } + + return CKR_OK; +} + +CK_RV token_specific_rsa_decrypt(STDLL_TokData_t * tokdata, + CK_BYTE * in_data, + CK_ULONG in_data_len, + CK_BYTE * out_data, + CK_ULONG * out_data_len, OBJECT * key_obj) +{ + long return_code, reason_code, rule_array_count, data_structure_length; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + CK_ATTRIBUTE *attr; + + UNUSED(tokdata); + + /* Find the secure key token */ + if (!template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr)) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + /* The max value allowable by CCA for out_data_len is 512, so cap the + * incoming value if its too large. CCA will throw error 8, 72 otherwise. + */ + if (*out_data_len > 512) + *out_data_len = 512; + + rule_array_count = 1; + memcpy(rule_array, "PKCS-1.2", CCA_KEYWORD_SIZE); + + 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); + } + + return CKR_OK; +} + +CK_RV token_specific_rsa_sign(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) +{ + long return_code, reason_code, rule_array_count; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + long signature_bit_length; + CK_ATTRIBUTE *attr; + + UNUSED(tokdata); + UNUSED(sess); + + /* Find the secure key token */ + if (!template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr)) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + /* The max value allowable by CCA for out_data_len is 512, so cap the + * incoming value if its too large. CCA will throw error 8, 72 otherwise. + */ + if (*out_data_len > 512) + *out_data_len = 512; + + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNDDSG (RSA SIGN) failed. return :%ld, reason: %ld\n", + return_code, reason_code); + return CKR_FUNCTION_FAILED; + } else if (reason_code != 0) { + TRACE_WARNING("CSNDDSG (RSA SIGN) succeeded, but " + "returned reason: %ld\n", reason_code); + } + + return CKR_OK; +} + +CK_RV token_specific_rsa_verify(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) +{ + long return_code, reason_code, rule_array_count; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + CK_ATTRIBUTE *attr; + + UNUSED(tokdata); + UNUSED(sess); + + /* Find the secure key token */ + if (!template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr)) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + /* The max value allowable by CCA for out_data_len is 512, so cap the + * incoming value if its too large. CCA will throw error 8, 72 otherwise. + */ + if (out_data_len > 512) + out_data_len = 512; + + 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); + + if (return_code == 4 && reason_code == 429) { + return CKR_SIGNATURE_INVALID; + } else if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNDDSV (RSA VERIFY) failed. return:%ld, reason:%ld\n", + return_code, reason_code); + if (return_code == 8 && reason_code == 72) { + /* + * Return CKR_SIGNATURE_INVALID in case of return code 8 and + * reason code 72 because we dont know why the RSA op failed + * and it may have failed due to a tampered signature being + * greater or equal to the modulus. + */ + return CKR_SIGNATURE_INVALID; + } + return CKR_FUNCTION_FAILED; + } + + if (reason_code != 0) { + TRACE_WARNING("CSNDDSV (RSA VERIFY) succeeded, but" + " returned reason:%ld\n", reason_code); + } + return CKR_OK; +} + + +#ifndef NOAES +CK_RV token_specific_aes_key_gen(STDLL_TokData_t * tokdata, CK_BYTE * aes_key, + CK_ULONG len, CK_ULONG key_size) +{ + long return_code, reason_code; + unsigned char key_token[CCA_KEY_ID_SIZE] = { 0, }; + unsigned char key_form[CCA_KEYWORD_SIZE]; + unsigned char key_type[CCA_KEYWORD_SIZE]; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0x20, }; + long exit_data_len = 0, rule_array_count; + unsigned char exit_data[4] = { 0, }; + unsigned char reserved_1[4] = { 0, }; + unsigned char point_to_array_of_zeros = 0; + unsigned char mkvp[16] = { 0, }; + + UNUSED(tokdata); + + /* make sure key is the right size for the token */ + if (len != CCA_KEY_ID_SIZE) + return CKR_FUNCTION_FAILED; + + memcpy(rule_array, "INTERNALAES NO-KEY ", + (size_t) (CCA_KEYWORD_SIZE * 3)); + memcpy(key_type, "DATA ", (size_t) CCA_KEYWORD_SIZE); + + switch (key_size) { + case 16: + memcpy(rule_array + 3 * CCA_KEYWORD_SIZE, "KEYLN16 ", CCA_KEYWORD_SIZE); + break; + case 24: + memcpy(rule_array + 3 * CCA_KEYWORD_SIZE, "KEYLN24 ", + (size_t) CCA_KEYWORD_SIZE); + break; + case 32: + memcpy(rule_array + 3 * CCA_KEYWORD_SIZE, "KEYLN32 ", + (size_t) CCA_KEYWORD_SIZE); + break; + default: + TRACE_ERROR("Invalid key length: %lu\n", key_size); + return CKR_KEY_SIZE_RANGE; + } + + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNBTKB (TOKEN BUILD) failed. return:%ld," + " reason:%ld\n", return_code, reason_code); + return CKR_FUNCTION_FAILED; + } + memcpy(key_form, "OP ", (size_t) CCA_KEYWORD_SIZE); + memcpy(key_type, "AESTOKEN", (size_t) CCA_KEYWORD_SIZE); + memcpy(aes_key, key_token, (size_t) CCA_KEY_ID_SIZE); + + return cca_key_gen(CCA_AES_KEY, aes_key, key_form, key_type, key_size); +} + +CK_RV token_specific_aes_ecb(STDLL_TokData_t * tokdata, + CK_BYTE * in_data, + CK_ULONG in_data_len, + CK_BYTE * out_data, + CK_ULONG * out_data_len, + OBJECT * key, CK_BYTE encrypt) +{ + long return_code, reason_code, rule_array_count; + long block_size = 16; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE]; + long opt_data_len = 0, key_params_len = 0, exit_data_len = 0, IV_len = 0, + chain_vector_len = 0; + unsigned char exit_data[1]; + CK_BYTE *local_out = out_data; + CK_ATTRIBUTE *attr = NULL; + long int key_len; + + UNUSED(tokdata); + + if (template_attribute_find(key->template, + CKA_IBM_OPAQUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + + key_len = 64; + 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); + } + + if (return_code != CCA_SUCCESS) { + if (encrypt) { + TRACE_ERROR("CSNBSAE (AES ENCRYPT) failed. return:%ld," + " reason:%ld\n", return_code, reason_code); + } else { + TRACE_ERROR("CSNBSAD (AES DECRYPT) failed. return:%ld," + " reason:%ld\n", return_code, reason_code); + } + (*out_data_len) = 0; + return CKR_FUNCTION_FAILED; + } else if (reason_code != 0) { + if (encrypt) { + TRACE_WARNING("CSNBSAE (AES ENCRYPT) succeeded, but" + " returned reason:%ld\n", reason_code); + } else { + TRACE_WARNING("CSNBSAD (AES DECRYPT) succeeded, but" + " returned reason:%ld\n", reason_code); + } + } + + return CKR_OK; +} + +CK_RV token_specific_aes_cbc(STDLL_TokData_t * tokdata, + 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) +{ + long return_code, reason_code, rule_array_count, length; + long block_size = 16; + unsigned char chaining_vector[32]; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE]; + long opt_data_len = 0, key_params_len = 0, exit_data_len = 0, IV_len = 16, + chain_vector_len = 32; + CK_BYTE *local_out = out_data; + unsigned char exit_data[1]; + CK_ATTRIBUTE *attr = NULL; + long int key_len; + + UNUSED(tokdata); + + // get the key value + if (template_attribute_find(key->template, + CKA_IBM_OPAQUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + + if (in_data_len % 16 == 0) { + rule_array_count = 3; + memcpy(rule_array, "AES KEYIDENTINITIAL ", + rule_array_count * (size_t) CCA_KEYWORD_SIZE); + } else { + if ((encrypt) && (*out_data_len < (in_data_len + 16))) { + local_out = malloc(in_data_len + 16); + if (!local_out) { + TRACE_ERROR("Malloc of %lu bytes failed.\n", in_data_len + 16); + return CKR_HOST_MEMORY; + } + } + + rule_array_count = 3; + memcpy(rule_array, "AES PKCS-PADKEYIDENT", + rule_array_count * (size_t) CCA_KEYWORD_SIZE); + } + + length = in_data_len; + key_len = 64; + 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); + } + + if (return_code != CCA_SUCCESS) { + if (encrypt) { + TRACE_ERROR("CSNBSAE (AES ENCRYPT) failed. return:%ld," + " reason:%ld\n", return_code, reason_code); + } else { + TRACE_ERROR("CSNBSAD (AES DECRYPT) failed. return:%ld," + " reason:%ld\n", return_code, reason_code); + } + (*out_data_len) = 0; + if (local_out != out_data) + free(local_out); + return CKR_FUNCTION_FAILED; + } else if (reason_code != 0) { + if (encrypt) { + TRACE_WARNING("CSNBSAE (AES ENCRYPT) succeeded, but" + " returned reason:%ld\n", reason_code); + } else { + TRACE_WARNING("CSNBSAD (AES DECRYPT) succeeded, but" + " returned reason:%ld\n", reason_code); + } + } + + /* If we malloc'd a new buffer due to overflow concerns and the data + * coming out turned out to be bigger than expected, return an error. + * + * Else, memcpy the data back to the user's buffer + */ + if ((local_out != out_data) && ((CK_ULONG) length > *out_data_len)) { + TRACE_ERROR("buffer too small: %ld bytes to write into %ld " + "bytes space\n", length, *out_data_len); + free(local_out); + return CKR_BUFFER_TOO_SMALL; + } else if (local_out != out_data) { + memcpy(out_data, local_out, (size_t) length); + free(local_out); + } + + *out_data_len = length; + + return CKR_OK; +} +#endif + +/* See the top of this file for the declarations of mech_list and + * mech_list_len. + */ +CK_RV token_specific_get_mechanism_list(STDLL_TokData_t * tokdata, + CK_MECHANISM_TYPE * pMechanismList, + CK_ULONG * pulCount) +{ + return ock_generic_get_mechanism_list(tokdata, pMechanismList, pulCount); +} + +CK_RV token_specific_get_mechanism_info(STDLL_TokData_t * tokdata, + CK_MECHANISM_TYPE type, + CK_MECHANISM_INFO * pInfo) +{ + return ock_generic_get_mechanism_info(tokdata, type, pInfo); +} + +CK_RV build_update_attribute(TEMPLATE * tmpl, + CK_ATTRIBUTE_TYPE type, + CK_BYTE * data, CK_ULONG data_len) +{ + CK_ATTRIBUTE *attr; + CK_RV rv; + if ((rv = build_attribute(type, data, data_len, &attr))) { + TRACE_DEVEL("Build attribute for type=%lu failed rv=0x%lx\n", type, rv); + return rv; + } + template_update_attribute(tmpl, attr); + + return CKR_OK; +} + +CK_BBOOL is_curve_error(long return_code, long reason_code) +{ + if (return_code == 8) { + /* + * The following reason codes denote that the curve is not supported + * 8 874 (36A) Error in Cert processing. Elliptic Curve is not + * supported. + * 8 2158 (86E) There is a mismatch between ECC key tokens of curve + * types, key lengths, or both. Curve types and key + * lengths must match. + * 8 6015 (177F) An ECC curve type is invalid or its usage is + * inconsistent. + * 8 6017 (1781) Curve size p is invalid or its usage is inconsistent. + */ + switch (reason_code) { + case 874: + case 2158: + case 6015: + case 6017: + return TRUE; + } + } + return FALSE; +} + +static CK_RV curve_supported(TEMPLATE *templ, uint8_t *curve_type, uint16_t *curve_bitlen) +{ + CK_ATTRIBUTE *attr = NULL; + unsigned int i; + + /* Check if curve supported */ + if (!template_attribute_find(templ, CKA_ECDSA_PARAMS, &attr)) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + for (i = 0; i < NUMEC; i++) { + if ((attr->ulValueLen == der_ec_supported[i].data_size) && + (memcmp(attr->pValue, der_ec_supported[i].data, + attr->ulValueLen) == 0) && + (der_ec_supported[i].curve_type == PRIME_CURVE || + der_ec_supported[i].curve_type == BRAINPOOL_CURVE)) { + *curve_type = der_ec_supported[i].curve_type; + *curve_bitlen = der_ec_supported[i].len_bits; + return CKR_OK; + } + } + + return CKR_CURVE_NOT_SUPPORTED; +} + +uint16_t cca_ec_privkey_offset(CK_BYTE * tok) +{ + uint8_t privkey_id = CCA_PRIVKEY_ID, privkey_rec; + privkey_rec = ntohs(*(uint8_t *) & tok[CCA_EC_HEADER_SIZE]); + + if ((memcmp(&privkey_rec, &privkey_id, sizeof(uint8_t)) == 0)) { + return CCA_EC_HEADER_SIZE; + } + TRACE_WARNING("+++++++++ Token key private section is CORRUPTED\n"); + + return CCA_EC_HEADER_SIZE; +} + +uint16_t cca_ec_publkey_offset(CK_BYTE * tok) +{ + uint16_t priv_offset, privSec_len; + uint8_t publkey_id = CCA_PUBLKEY_ID, publkey_rec; + + priv_offset = cca_ec_privkey_offset(tok); + privSec_len = + ntohs(*(uint16_t *) & tok[priv_offset + CCA_SECTION_LEN_OFFSET]); + publkey_rec = ntohs(*(uint8_t *) & tok[priv_offset + privSec_len]); + + if ((memcmp(&publkey_rec, &publkey_id, sizeof(uint8_t)) == 0)) { + return (priv_offset + privSec_len); + } + TRACE_WARNING("++++++++ Token key public section is CORRUPTED\n"); + + return (priv_offset + privSec_len); +} + +CK_RV token_create_ec_keypair(TEMPLATE * publ_tmpl, + TEMPLATE * priv_tmpl, + CK_ULONG tok_len, CK_BYTE * tok) +{ + uint16_t pubkey_offset, qlen_offset, q_offset; + CK_ULONG q_len; + CK_BYTE q[CCATOK_EC_MAX_Q_LEN]; + CK_RV rv; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *ecpoint = NULL; + CK_ULONG ecpoint_len; + + /* + * The token includes the header section first, + * the private key section in the middle, + * and the public key section last. + */ + + /* The pkcs#11v2.20: + * CKA_ECDSA_PARAMS must be in public key's template when + * generating key pair and added to private key template. + * CKA_EC_POINT added to public key when key is generated. + */ + + /* + * Get Q data for public key. + */ + pubkey_offset = cca_ec_publkey_offset(tok); + + qlen_offset = pubkey_offset + CCA_EC_INTTOK_PUBKEY_Q_LEN_OFFSET; + q_len = *(uint16_t *) & tok[qlen_offset]; + q_len = ntohs(q_len); + + if (q_len > CCATOK_EC_MAX_Q_LEN) { + TRACE_ERROR("Not enough room to return q. (Got %d, need %ld)\n", + CCATOK_EC_MAX_Q_LEN, q_len); + return CKR_FUNCTION_FAILED; + } + + q_offset = pubkey_offset + CCA_EC_INTTOK_PUBKEY_Q_OFFSET; + memcpy(q, &tok[q_offset], (size_t) q_len); + + rv = ber_encode_OCTET_STRING(FALSE, &ecpoint, &ecpoint_len, q, q_len); + if (rv != CKR_OK) { + TRACE_DEVEL("ber_encode_OCTET_STRING failed\n"); + return rv; + } + + if ((rv = build_update_attribute(publ_tmpl, CKA_EC_POINT, + ecpoint, ecpoint_len))) { + TRACE_DEVEL("build_update_attribute for q failed rv=0x%lx\n", rv); + free(ecpoint); + return rv; + } + free(ecpoint); + + /* Add ec params to private key */ + if (!template_attribute_find(publ_tmpl, CKA_ECDSA_PARAMS, &attr)) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + if ((rv = build_update_attribute(priv_tmpl, CKA_ECDSA_PARAMS, + attr->pValue, attr->ulValueLen))) { + TRACE_DEVEL("build_update_attribute for der data failed " + "rv=0x%lx\n", rv); + return rv; + } + + /* + * Save the CKA_IBM_OPAQUE for both keys. + */ + if ((rv = build_update_attribute(publ_tmpl, + CKA_IBM_OPAQUE, tok, tok_len))) { + TRACE_DEVEL("build_update_attribute for tok failed rv=0x%lx\n", rv); + return rv; + } + + if ((rv = build_update_attribute(priv_tmpl, + CKA_IBM_OPAQUE, tok, tok_len))) { + TRACE_DEVEL("build_update_attribute for tok failed rv=0x%lx\n", rv); + return rv; + } + + return CKR_OK; +} + +CK_RV token_specific_ec_generate_keypair(STDLL_TokData_t * tokdata, + TEMPLATE * publ_tmpl, + TEMPLATE * priv_tmpl) +{ + long return_code, reason_code, rule_array_count, exit_data_len = 0; + unsigned char *exit_data = NULL; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + long key_value_structure_length, private_key_name_length, key_token_length; + unsigned char key_value_structure[CCA_EC_KEY_VALUE_STRUCT_SIZE] = { 0, }; + unsigned char private_key_name[CCA_PRIVATE_KEY_NAME_SIZE] = { 0, }; + unsigned char key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; + long regeneration_data_length, generated_key_token_length; + unsigned char regeneration_data[CCA_REGENERATION_DATA_SIZE] = { 0, }; + unsigned char transport_key_identifier[CCA_KEY_ID_SIZE] = { 0, }; + unsigned char generated_key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; + CK_RV rv; + long param1 = 0; + unsigned char *param2 = NULL; + uint8_t curve_type; + uint16_t curve_bitlen; + + UNUSED(tokdata); + + rv = curve_supported(publ_tmpl, &curve_type, &curve_bitlen); + if (rv != CKR_OK) { + TRACE_ERROR("Curve not supported\n"); + return rv; + } + + /* + * See CCA doc: page 94 for offset of data in key_value_structure + */ + memcpy(key_value_structure, + &curve_type, sizeof(uint8_t)); + memcpy(&key_value_structure[CCA_PKB_EC_LEN_OFFSET], + &curve_bitlen, sizeof(uint16_t)); + + key_value_structure_length = CCA_EC_KEY_VALUE_STRUCT_SIZE; + + rule_array_count = 1; + memcpy(rule_array, "ECC-PAIR", (size_t) (CCA_KEYWORD_SIZE)); + + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNDPKB (EC KEY TOKEN BUILD) failed. return:%ld," + " reason:%ld\n", return_code, reason_code); + if (is_curve_error(return_code, reason_code)) + return CKR_CURVE_NOT_SUPPORTED; + return CKR_FUNCTION_FAILED; + } + + rule_array_count = 1; + memset(rule_array, 0, sizeof(rule_array)); + memcpy(rule_array, "MASTER ", (size_t) CCA_KEYWORD_SIZE); + + generated_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, + &generated_key_token_length, generated_key_token); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNDPKG (EC KEY GENERATE) failed." + " return:%ld, reason:%ld\n", return_code, reason_code); + if (is_curve_error(return_code, reason_code)) + return CKR_CURVE_NOT_SUPPORTED; + return CKR_FUNCTION_FAILED; + } + + TRACE_DEVEL("ECC secure key token generated. size: %ld\n", + generated_key_token_length); + + rv = token_create_ec_keypair(publ_tmpl, priv_tmpl, + generated_key_token_length, + generated_key_token); + if (rv != CKR_OK) { + TRACE_DEVEL("token_create_ec_keypair failed. rv: %lu\n", rv); + return rv; + } + + return rv; +} + +CK_RV token_specific_ec_sign(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) +{ + long return_code, reason_code, rule_array_count; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + long signature_bit_length; + CK_ATTRIBUTE *attr; + + UNUSED(tokdata); + UNUSED(sess); + + /* Find the secure key token */ + if (!template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr)) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + /* CCA doc: page 113 */ + rule_array_count = 1; + memcpy(rule_array, "ECDSA ", 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNDDSG (EC SIGN) failed. return:%ld," + " reason:%ld\n", return_code, reason_code); + if (is_curve_error(return_code, reason_code)) + return CKR_CURVE_NOT_SUPPORTED; + return CKR_FUNCTION_FAILED; + } else if (reason_code != 0) { + TRACE_WARNING("CSNDDSG (EC SIGN) succeeded, but" + " returned reason:%ld\n", reason_code); + } + + return CKR_OK; +} + +CK_RV token_specific_ec_verify(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) +{ + long return_code, reason_code, rule_array_count; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + CK_ATTRIBUTE *attr; + + UNUSED(tokdata); + UNUSED(sess); + + /* Find the secure key token */ + if (!template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr)) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + /* CCA doc: page 118 */ + 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); + + if (return_code == 4 && reason_code == 429) { + return CKR_SIGNATURE_INVALID; + } else if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNDDSV (EC VERIFY) failed. return:%ld," + " reason:%ld\n", return_code, reason_code); + if (is_curve_error(return_code, reason_code)) + return CKR_CURVE_NOT_SUPPORTED; + return CKR_FUNCTION_FAILED; + } else if (reason_code != 0) { + TRACE_WARNING("CSNDDSV (EC VERIFY) succeeded, but" + " returned reason:%ld\n", reason_code); + } + + return CKR_OK; +} + +CK_RV token_specific_sha_init(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * ctx, + CK_MECHANISM * mech) +{ + CK_ULONG hash_size; + struct cca_sha_ctx *cca_ctx; + + UNUSED(tokdata); + + switch (mech->mechanism) { + case CKM_SHA_1: + hash_size = SHA1_HASH_SIZE; + break; + case CKM_SHA224: + hash_size = SHA224_HASH_SIZE; + break; + case CKM_SHA256: + hash_size = SHA256_HASH_SIZE; + break; + case CKM_SHA384: + hash_size = SHA384_HASH_SIZE; + break; + case CKM_SHA512: + hash_size = SHA512_HASH_SIZE; + break; + default: + return CKR_MECHANISM_INVALID; + } + + ctx->context = calloc(1, sizeof(struct cca_sha_ctx)); + if (ctx->context == NULL) { + TRACE_ERROR("malloc failed in sha digest init\n"); + return CKR_HOST_MEMORY; + } + ctx->context_len = sizeof(struct cca_sha_ctx); + + cca_ctx = (struct cca_sha_ctx *) ctx->context; + cca_ctx->chain_vector_len = CCA_CHAIN_VECTOR_LEN; + cca_ctx->hash_len = hash_size; + /* tail_len is already 0 */ + + return CKR_OK; +} + +CK_RV token_specific_sha(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * ctx, + CK_BYTE * in_data, CK_ULONG in_data_len, + CK_BYTE * out_data, CK_ULONG * out_data_len) +{ + struct cca_sha_ctx *cca_ctx; + long return_code, reason_code, rule_array_count = 2; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + + UNUSED(tokdata); + + if (!ctx || !ctx->context) + return CKR_OPERATION_NOT_INITIALIZED; + + if (!in_data || !out_data) + return CKR_ARGUMENTS_BAD; + + cca_ctx = (struct cca_sha_ctx *) ctx->context; + + if (*out_data_len < (CK_ULONG)cca_ctx->hash_len) + return CKR_BUFFER_TOO_SMALL; + + switch (ctx->mech.mechanism) { + case CKM_SHA_1: + memcpy(rule_array, "SHA-1 ONLY ", CCA_KEYWORD_SIZE * 2); + cca_ctx->part = CCA_HASH_PART_ONLY; + break; + case CKM_SHA224: + memcpy(rule_array, "SHA-224 ONLY ", CCA_KEYWORD_SIZE * 2); + cca_ctx->part = CCA_HASH_PART_ONLY; + break; + case CKM_SHA256: + memcpy(rule_array, "SHA-256 ONLY ", CCA_KEYWORD_SIZE * 2); + cca_ctx->part = CCA_HASH_PART_ONLY; + break; + case CKM_SHA384: + memcpy(rule_array, "SHA-384 ONLY ", CCA_KEYWORD_SIZE * 2); + cca_ctx->part = CCA_HASH_PART_ONLY; + break; + case CKM_SHA512: + memcpy(rule_array, "SHA-512 ONLY ", CCA_KEYWORD_SIZE * 2); + cca_ctx->part = CCA_HASH_PART_ONLY; + break; + default: + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNBOWH failed. return:%ld, reason:%ld\n", + return_code, reason_code); + return CKR_FUNCTION_FAILED; + } + + memcpy(out_data, cca_ctx->hash, cca_ctx->hash_len); + *out_data_len = cca_ctx->hash_len; + + /* ctx->context should get freed in digest_mgr_cleanup() */ + return CKR_OK; +} + +CK_RV token_specific_sha_update(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * ctx, + CK_BYTE * in_data, CK_ULONG in_data_len) +{ + struct cca_sha_ctx *cca_ctx; + long return_code, reason_code, total, buffer_len, rule_array_count = 2; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + CK_RV rc = CKR_OK; + unsigned char *buffer = NULL; + int blocksz, blocksz_mask, use_buffer = 0; + + UNUSED(tokdata); + + if (!in_data) + return CKR_ARGUMENTS_BAD; + + if (!ctx || !ctx->context) + return CKR_OPERATION_NOT_INITIALIZED; + + switch (ctx->mech.mechanism) { + case CKM_SHA_1: + blocksz = SHA1_BLOCK_SIZE; + blocksz_mask = SHA1_BLOCK_SIZE_MASK; + break; + case CKM_SHA224: + blocksz = SHA224_BLOCK_SIZE; + blocksz_mask = SHA224_BLOCK_SIZE_MASK; + break; + case CKM_SHA256: + blocksz = SHA256_BLOCK_SIZE; + blocksz_mask = SHA256_BLOCK_SIZE_MASK; + break; + case CKM_SHA384: + blocksz = SHA384_BLOCK_SIZE; + blocksz_mask = SHA384_BLOCK_SIZE_MASK; + break; + case CKM_SHA512: + blocksz = SHA512_BLOCK_SIZE; + blocksz_mask = SHA512_BLOCK_SIZE_MASK; + break; + default: + return CKR_MECHANISM_INVALID; + } + + cca_ctx = (struct cca_sha_ctx *) ctx->context; + + /* just send if input a multiple of block size and + * cca_ctx-> tail is empty. + */ + if ((cca_ctx->tail_len == 0) && ((in_data_len & blocksz_mask) == 0)) + goto send; + + /* at this point, in_data is not multiple of blocksize + * and/or there is saved data from previous update still + * needing to be processed + */ + + /* get totals */ + total = cca_ctx->tail_len + in_data_len; + + /* see if we have enough to fill a block */ + if (total >= blocksz) { + int remainder; + + remainder = total & blocksz_mask; + buffer_len = total - remainder; + + /* allocate a buffer for sending... */ + if (!(buffer = malloc(buffer_len))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + + memcpy(buffer, cca_ctx->tail, cca_ctx->tail_len); + memcpy(buffer + cca_ctx->tail_len, in_data, in_data_len - remainder); + use_buffer = 1; + + /* save remainder data for next time */ + if (remainder) + memcpy(cca_ctx->tail, + in_data + (in_data_len - remainder), remainder); + cca_ctx->tail_len = remainder; + + } else { + /* not enough to fill a block, save off data for next round */ + memcpy(cca_ctx->tail + cca_ctx->tail_len, in_data, in_data_len); + cca_ctx->tail_len += in_data_len; + return CKR_OK; + } + +send: + switch (ctx->mech.mechanism) { + case CKM_SHA_1: + if (cca_ctx->part == CCA_HASH_PART_FIRST) { + memcpy(rule_array, "SHA-1 FIRST ", CCA_KEYWORD_SIZE * 2); + cca_ctx->part = CCA_HASH_PART_MIDDLE; + } else { + memcpy(rule_array, "SHA-1 MIDDLE ", CCA_KEYWORD_SIZE * 2); + } + break; + case CKM_SHA224: + if (cca_ctx->part == CCA_HASH_PART_FIRST) { + memcpy(rule_array, "SHA-224 FIRST ", CCA_KEYWORD_SIZE * 2); + cca_ctx->part = CCA_HASH_PART_MIDDLE; + } else { + memcpy(rule_array, "SHA-224 MIDDLE ", CCA_KEYWORD_SIZE * 2); + } + break; + case CKM_SHA256: + if (cca_ctx->part == CCA_HASH_PART_FIRST) { + memcpy(rule_array, "SHA-256 FIRST ", CCA_KEYWORD_SIZE * 2); + cca_ctx->part = CCA_HASH_PART_MIDDLE; + } else { + memcpy(rule_array, "SHA-256 MIDDLE ", CCA_KEYWORD_SIZE * 2); + } + break; + case CKM_SHA384: + if (cca_ctx->part == CCA_HASH_PART_FIRST) { + memcpy(rule_array, "SHA-384 FIRST ", CCA_KEYWORD_SIZE * 2); + cca_ctx->part = CCA_HASH_PART_MIDDLE; + } else { + memcpy(rule_array, "SHA-384 MIDDLE ", CCA_KEYWORD_SIZE * 2); + } + break; + case CKM_SHA512: + if (cca_ctx->part == CCA_HASH_PART_FIRST) { + memcpy(rule_array, "SHA-512 FIRST ", CCA_KEYWORD_SIZE * 2); + cca_ctx->part = CCA_HASH_PART_MIDDLE; + } else { + memcpy(rule_array, "SHA-512 MIDDLE ", CCA_KEYWORD_SIZE * 2); + } + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNBOWH (SHA UPDATE) failed. return:%ld," + " reason:%ld\n", return_code, reason_code); + rc = CKR_FUNCTION_FAILED; + } + +done: + if (buffer) + free(buffer); + return rc; +} + +CK_RV token_specific_sha_final(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * ctx, + CK_BYTE * out_data, CK_ULONG * out_data_len) +{ + struct cca_sha_ctx *cca_ctx; + long return_code, reason_code, rule_array_count = 2; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + + UNUSED(tokdata); + + if (!ctx || !ctx->context) + return CKR_OPERATION_NOT_INITIALIZED; + + cca_ctx = (struct cca_sha_ctx *) ctx->context; + if (*out_data_len < (CK_ULONG)cca_ctx->hash_len) { + TRACE_ERROR("out buf too small for hash: %lu\n", *out_data_len); + return CKR_BUFFER_TOO_SMALL; + } + + switch (ctx->mech.mechanism) { + case CKM_SHA_1: + if (cca_ctx->part == CCA_HASH_PART_FIRST) { + memcpy(rule_array, "SHA-1 ONLY ", CCA_KEYWORD_SIZE * 2); + } else { + /* there's some extra data we need to hash to + * complete the operation + */ + memcpy(rule_array, "SHA-1 LAST ", CCA_KEYWORD_SIZE * 2); + } + break; + case CKM_SHA224: + if (cca_ctx->part == CCA_HASH_PART_FIRST) { + memcpy(rule_array, "SHA-224 ONLY ", CCA_KEYWORD_SIZE * 2); + } else { + /* there's some extra data we need to hash to + * complete the operation + */ + memcpy(rule_array, "SHA-224 LAST ", CCA_KEYWORD_SIZE * 2); + } + break; + case CKM_SHA256: + if (cca_ctx->part == CCA_HASH_PART_FIRST) { + memcpy(rule_array, "SHA-256 ONLY ", CCA_KEYWORD_SIZE * 2); + } else { + /* there's some extra data we need to hash to + * complete the operation + */ + memcpy(rule_array, "SHA-256 LAST ", CCA_KEYWORD_SIZE * 2); + } + break; + case CKM_SHA384: + if (cca_ctx->part == CCA_HASH_PART_FIRST) { + memcpy(rule_array, "SHA-384 ONLY ", CCA_KEYWORD_SIZE * 2); + } else { + /* there's some extra data we need to hash to + * complete the operation + */ + memcpy(rule_array, "SHA-384 LAST ", CCA_KEYWORD_SIZE * 2); + } + break; + case CKM_SHA512: + if (cca_ctx->part == CCA_HASH_PART_FIRST) { + memcpy(rule_array, "SHA-512 ONLY ", CCA_KEYWORD_SIZE * 2); + } else { + /* there's some extra data we need to hash to + * complete the operation + */ + memcpy(rule_array, "SHA-512 LAST ", CCA_KEYWORD_SIZE * 2); + } + break; + default: + return CKR_MECHANISM_INVALID; + } + + TRACE_DEBUG("tail_len: %lu, tail: %p, cvl: %lu, sl: %lu\n", + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNBOWH (SHA FINAL) failed. return:%ld," + " reason:%ld\n", return_code, reason_code); + return CKR_FUNCTION_FAILED; + } + + memcpy(out_data, cca_ctx->hash, cca_ctx->hash_len); + *out_data_len = cca_ctx->hash_len; + + /* ctx->context should get freed in digest_mgr_cleanup() */ + return CKR_OK; +} + +static long get_mac_len(CK_MECHANISM * mech) +{ + switch (mech->mechanism) { + case CKM_SHA_1_HMAC_GENERAL: + case CKM_SHA224_HMAC_GENERAL: + case CKM_SHA256_HMAC_GENERAL: + case CKM_SHA384_HMAC_GENERAL: + case CKM_SHA512_HMAC_GENERAL: + return *(CK_ULONG *) (mech->pParameter); + case CKM_SHA_1_HMAC: + return SHA1_HASH_SIZE; + case CKM_SHA224_HMAC: + return SHA224_HASH_SIZE; + case CKM_SHA256_HMAC: + return SHA256_HASH_SIZE; + case CKM_SHA384_HMAC: + return SHA384_HASH_SIZE; + case CKM_SHA512_HMAC: + return SHA512_HASH_SIZE; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return -1; + } +} + +static CK_RV ccatok_hmac_init(SIGN_VERIFY_CONTEXT * ctx, CK_MECHANISM * mech, + CK_OBJECT_HANDLE key) +{ + struct cca_sha_ctx *cca_ctx; + long maclen = -1; + + UNUSED(key); + + maclen = get_mac_len(mech); + if (maclen < 0) + return CKR_MECHANISM_INVALID; + + ctx->context = calloc(1, sizeof(struct cca_sha_ctx)); + if (ctx->context == NULL) { + TRACE_ERROR("malloc failed in sha digest init\n"); + return CKR_HOST_MEMORY; + } + ctx->context_len = sizeof(struct cca_sha_ctx); + + cca_ctx = (struct cca_sha_ctx *) ctx->context; + + memset(cca_ctx, 0, sizeof(struct cca_sha_ctx)); + cca_ctx->chain_vector_len = CCA_CHAIN_VECTOR_LEN; + cca_ctx->hash_len = maclen; + + return CKR_OK; +} + +CK_RV token_specific_hmac_sign_init(STDLL_TokData_t * tokdata, SESSION * sess, + CK_MECHANISM * mech, CK_OBJECT_HANDLE key) +{ + UNUSED(tokdata); + + return ccatok_hmac_init(&sess->sign_ctx, mech, key); +} + +CK_RV token_specific_hmac_verify_init(STDLL_TokData_t * tokdata, SESSION * sess, + CK_MECHANISM * mech, CK_OBJECT_HANDLE key) +{ + UNUSED(tokdata); + + return ccatok_hmac_init(&sess->verify_ctx, mech, key); +} + +CK_RV ccatok_hmac(STDLL_TokData_t * tokdata, SIGN_VERIFY_CONTEXT * ctx, + CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * signature, + CK_ULONG * sig_len, CK_BBOOL sign) +{ + struct cca_sha_ctx *cca_ctx; + long keylen, return_code = 0, reason_code = 0, rule_array_count = 3; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE]; + OBJECT *key = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_RV rc = CKR_OK; + + if (!ctx || !ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + cca_ctx = (struct cca_sha_ctx *) ctx->context; + + if (sign && !sig_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + if (template_attribute_find(key->template, + CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + keylen = attr->ulValueLen; + if (template_attribute_find(key->template, + CKA_IBM_OPAQUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + switch (ctx->mech.mechanism) { + case CKM_SHA_1_HMAC_GENERAL: + case CKM_SHA_1_HMAC: + memcpy(rule_array, "HMAC SHA-1 ONLY ", 3 * CCA_KEYWORD_SIZE); + break; + case CKM_SHA224_HMAC_GENERAL: + case CKM_SHA224_HMAC: + memcpy(rule_array, "HMAC SHA-224 ONLY ", 3 * CCA_KEYWORD_SIZE); + break; + case CKM_SHA256_HMAC_GENERAL: + case CKM_SHA256_HMAC: + memcpy(rule_array, "HMAC SHA-256 ONLY ", 3 * CCA_KEYWORD_SIZE); + break; + case CKM_SHA384_HMAC_GENERAL: + case CKM_SHA384_HMAC: + memcpy(rule_array, "HMAC SHA-384 ONLY ", 3 * CCA_KEYWORD_SIZE); + break; + case CKM_SHA512_HMAC_GENERAL: + case CKM_SHA512_HMAC: + memcpy(rule_array, "HMAC SHA-512 ONLY ", 3 * CCA_KEYWORD_SIZE); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + TRACE_INFO("HMAC key length is %ld\n", keylen); + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNBHMG (HMAC GENERATE) failed. " + "return:%ld, reason:%ld\n", return_code, reason_code); + *sig_len = 0; + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Copy the signature into the user supplied variable. + * For hmac general mechs, only copy over the specified + * number of bytes for the mac. + */ + 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); + + if (return_code == 4 && (reason_code == 429 || reason_code == 1)) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + rc = CKR_SIGNATURE_INVALID; + goto done; + } else if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNBHMV (HMAC VERIFY) failed. return:%ld," + " reason:%ld\n", return_code, reason_code); + rc = CKR_FUNCTION_FAILED; + goto done; + } else if (reason_code != 0) { + TRACE_WARNING("CSNBHMV (HMAC VERIFY) succeeded, but" + " returned reason:%ld\n", reason_code); + } + } + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + +CK_RV token_specific_hmac_sign(STDLL_TokData_t * tokdata, SESSION * sess, + CK_BYTE * in_data, CK_ULONG in_data_len, + CK_BYTE * signature, CK_ULONG * sig_len) +{ + return ccatok_hmac(tokdata, &sess->sign_ctx, in_data, in_data_len, + signature, sig_len, TRUE); +} + +CK_RV token_specific_hmac_verify(STDLL_TokData_t * tokdata, SESSION * sess, + CK_BYTE * in_data, CK_ULONG in_data_len, + CK_BYTE * signature, CK_ULONG sig_len) +{ + return ccatok_hmac(tokdata, &sess->verify_ctx, in_data, in_data_len, + signature, &sig_len, FALSE); +} + +CK_RV ccatok_hmac_update(STDLL_TokData_t * tokdata, SIGN_VERIFY_CONTEXT * ctx, + CK_BYTE * in_data, CK_ULONG in_data_len, CK_BBOOL sign) +{ + struct cca_sha_ctx *cca_ctx; + long return_code, reason_code, total, buffer_len; + long hsize, rule_array_count = 3; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + unsigned char *buffer = NULL; + int blocksz, blocksz_mask, use_buffer = 0; + OBJECT *key = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_RV rc = CKR_OK; + + if (!ctx || !ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + + /* if zero input data, then just do nothing and return. + * "final" should catch if this is case of hashing zero input. + */ + if (in_data_len == 0) + return CKR_OK; + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + if (template_attribute_find(key->template, + CKA_IBM_OPAQUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + switch (ctx->mech.mechanism) { + case CKM_SHA_1_HMAC: + case CKM_SHA_1_HMAC_GENERAL: + case CKM_SHA224_HMAC: + case CKM_SHA256_HMAC: + case CKM_SHA256_HMAC_GENERAL: + blocksz = SHA1_BLOCK_SIZE; // set to 64 bytes + blocksz_mask = SHA1_BLOCK_SIZE_MASK; // set to 63 + break; + case CKM_SHA384_HMAC: + case CKM_SHA384_HMAC_GENERAL: + case CKM_SHA512_HMAC: + case CKM_SHA512_HMAC_GENERAL: + blocksz = SHA512_BLOCK_SIZE; // set to 128 bytes + blocksz_mask = SHA512_BLOCK_SIZE_MASK; // set to 127 + break; + default: + rc = CKR_MECHANISM_INVALID; + goto done; + } + + cca_ctx = (struct cca_sha_ctx *) ctx->context; + + /* just send if input a multiple of block size and + * cca_ctx-> tail is empty. + */ + if ((cca_ctx->tail_len == 0) && ((in_data_len & blocksz_mask) == 0)) + goto send; + + /* at this point, in_data is not multiple of blocksize + * and/or there is saved data from previous update still + * needing to be processed + */ + + /* get totals */ + total = cca_ctx->tail_len + in_data_len; + + /* see if we have enough to fill a block */ + if (total >= blocksz) { + int remainder; + + remainder = total & blocksz_mask; // save left over + buffer_len = total - remainder; + + /* allocate a buffer for sending... */ + if (!(buffer = malloc(buffer_len))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + + /* copy data to send. + * first get any data saved in tail from prior call, + * then fill up remaining space in block with in_data + */ + memcpy(buffer, cca_ctx->tail, cca_ctx->tail_len); + memcpy(buffer + cca_ctx->tail_len, in_data, in_data_len - remainder); + use_buffer = 1; + + /* save remainder data for next time */ + if (remainder) + memcpy(cca_ctx->tail, + in_data + (in_data_len - remainder), remainder); + cca_ctx->tail_len = remainder; + } else { + /* not enough to fill a block, + * so save off data for next round + */ + memcpy(cca_ctx->tail + cca_ctx->tail_len, in_data, in_data_len); + cca_ctx->tail_len += in_data_len; + rc = CKR_OK; + goto done; + } + +send: + switch (ctx->mech.mechanism) { + case CKM_SHA_1_HMAC: + case CKM_SHA_1_HMAC_GENERAL: + hsize = SHA1_HASH_SIZE; + memcpy(rule_array, "HMAC SHA-1 ", CCA_KEYWORD_SIZE * 2); + break; + case CKM_SHA224_HMAC: + case CKM_SHA224_HMAC_GENERAL: + hsize = SHA224_HASH_SIZE; + memcpy(rule_array, "HMAC SHA-224 ", CCA_KEYWORD_SIZE * 2); + break; + case CKM_SHA256_HMAC: + case CKM_SHA256_HMAC_GENERAL: + hsize = SHA256_HASH_SIZE; + memcpy(rule_array, "HMAC SHA-256 ", CCA_KEYWORD_SIZE * 2); + break; + case CKM_SHA384_HMAC: + case CKM_SHA384_HMAC_GENERAL: + hsize = SHA384_HASH_SIZE; + memcpy(rule_array, "HMAC SHA-384 ", CCA_KEYWORD_SIZE * 2); + break; + case CKM_SHA512_HMAC: + case CKM_SHA512_HMAC_GENERAL: + hsize = SHA512_HASH_SIZE; + memcpy(rule_array, "HMAC SHA-512 ", CCA_KEYWORD_SIZE * 2); + break; + } + + if (cca_ctx->part == CCA_HASH_PART_FIRST) { + memcpy(rule_array + (CCA_KEYWORD_SIZE * 2), "FIRST ", + CCA_KEYWORD_SIZE); + cca_ctx->part = CCA_HASH_PART_MIDDLE; + } else { + memcpy(rule_array + (CCA_KEYWORD_SIZE * 2), "MIDDLE ", + CCA_KEYWORD_SIZE); + } + + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNBHMG (HMAC SIGN UPDATE) failed. " + "return:%ld, reason:%ld\n", return_code, reason_code); + 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); + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNBHMG (HMAC VERIFY UPDATE) failed. " + "return:%ld, reason:%ld\n", return_code, reason_code); + rc = CKR_FUNCTION_FAILED; + } + } +done: + if (buffer) + free(buffer); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + +CK_RV token_specific_hmac_sign_update(STDLL_TokData_t * tokdata, SESSION * sess, + CK_BYTE * in_data, CK_ULONG in_data_len) +{ + return ccatok_hmac_update(tokdata, &sess->sign_ctx, in_data, + in_data_len, TRUE); +} + +CK_RV token_specific_hmac_verify_update(STDLL_TokData_t * tokdata, + SESSION * sess, CK_BYTE * in_data, + CK_ULONG in_data_len) +{ + return ccatok_hmac_update(tokdata, &sess->verify_ctx, in_data, + in_data_len, FALSE); +} + +CK_RV ccatok_hmac_final(STDLL_TokData_t * tokdata, SIGN_VERIFY_CONTEXT * ctx, + CK_BYTE * signature, CK_ULONG * sig_len, CK_BBOOL sign) +{ + struct cca_sha_ctx *cca_ctx; + long return_code, reason_code, rule_array_count = 3; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + OBJECT *key = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_RV rc = CKR_OK; + + if (!ctx || !ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + if (template_attribute_find(key->template, + CKA_IBM_OPAQUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + cca_ctx = (struct cca_sha_ctx *) ctx->context; + + switch (ctx->mech.mechanism) { + case CKM_SHA_1_HMAC: + case CKM_SHA_1_HMAC_GENERAL: + memcpy(rule_array, "HMAC SHA-1 ", CCA_KEYWORD_SIZE * 2); + break; + case CKM_SHA224_HMAC: + case CKM_SHA224_HMAC_GENERAL: + memcpy(rule_array, "HMAC SHA-224 ", CCA_KEYWORD_SIZE * 2); + break; + case CKM_SHA256_HMAC: + case CKM_SHA256_HMAC_GENERAL: + memcpy(rule_array, "HMAC SHA-256 ", CCA_KEYWORD_SIZE * 2); + break; + case CKM_SHA384_HMAC: + case CKM_SHA384_HMAC_GENERAL: + memcpy(rule_array, "HMAC SHA-384 ", CCA_KEYWORD_SIZE * 2); + break; + case CKM_SHA512_HMAC: + case CKM_SHA512_HMAC_GENERAL: + memcpy(rule_array, "HMAC SHA-512 ", CCA_KEYWORD_SIZE * 2); + break; + default: + rc = CKR_MECHANISM_INVALID; + goto done; + } + + if (cca_ctx->part == CCA_HASH_PART_FIRST) + memcpy(rule_array + (CCA_KEYWORD_SIZE * 2), "ONLY ", + CCA_KEYWORD_SIZE); + else + memcpy(rule_array + (CCA_KEYWORD_SIZE * 2), "LAST ", + CCA_KEYWORD_SIZE); + + TRACE_INFO("CSNBHMG: key length is %lu\n", attr->ulValueLen); + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNBHMG (HMAC SIGN FINAL) failed. " + "return:%ld, reason:%ld\n", return_code, reason_code); + *sig_len = 0; + rc = CKR_FUNCTION_FAILED; + goto done; + } + /* Copy the signature into the user supplied variable. + * For hmac general mechs, only copy over the specified + * number of bytes for the mac. + */ + 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, + &cca_ctx->tail_len, cca_ctx->tail, + &cca_ctx->chain_vector_len, cca_ctx->chain_vector, + &cca_ctx->hash_len, signature); + + if (return_code == 4 && (reason_code == 429 || reason_code == 1)) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + rc = CKR_SIGNATURE_INVALID; + goto done; + } else if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNBHMV (HMAC VERIFY) failed. return:%ld," + " reason:%ld\n", return_code, reason_code); + rc = CKR_FUNCTION_FAILED; + goto done; + } else if (reason_code != 0) { + TRACE_WARNING("CSNBHMV (HMAC VERIFY) succeeded, but" + " returned reason:%ld\n", reason_code); + } + + } + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + +CK_RV token_specific_hmac_sign_final(STDLL_TokData_t * tokdata, SESSION * sess, + CK_BYTE * signature, CK_ULONG * sig_len) +{ + return ccatok_hmac_final(tokdata, &sess->sign_ctx, signature, sig_len, + TRUE); +} + +CK_RV token_specific_hmac_verify_final(STDLL_TokData_t * tokdata, + SESSION * sess, CK_BYTE * signature, + CK_ULONG sig_len) +{ + return ccatok_hmac_final(tokdata, &sess->verify_ctx, signature, + &sig_len, FALSE); +} + +static CK_RV rsa_import_privkey_crt(TEMPLATE * priv_tmpl) +{ + long return_code, reason_code, rule_array_count, total = 0; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + + long offset, key_value_structure_length = CCA_KEY_VALUE_STRUCT_SIZE; + long private_key_name_length, key_token_length, target_key_token_length; + + unsigned char key_value_structure[CCA_KEY_VALUE_STRUCT_SIZE] = { 0, }; + unsigned char private_key_name[CCA_PRIVATE_KEY_NAME_SIZE] = { 0, }; + unsigned char key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; + unsigned char target_key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; + unsigned char transport_key_identifier[CCA_KEY_ID_SIZE] = { 0, }; + + uint16_t size_of_e; + uint16_t mod_bits, mod_bytes, bytes; + CK_ATTRIBUTE *opaque_key = NULL, *pub_exp = NULL, *mod = NULL, + *p_prime = NULL, *q_prime = NULL, *dmp1 = NULL, *dmq1 = NULL, *iqmp = + NULL, *priv_exp = NULL; + CK_RV rc; + + /* Look for parameters to set key in the CRT format */ + if (!template_attribute_find(priv_tmpl, CKA_PRIME_1, &p_prime)) { + TRACE_ERROR("CKA_PRIME_1 attribute missing for CRT.\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + total += p_prime->ulValueLen; + + if (!template_attribute_find(priv_tmpl, CKA_PRIME_2, &q_prime)) { + TRACE_ERROR("CKA_PRIME_2 attribute missing for CRT.\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + total += q_prime->ulValueLen; + + if (!template_attribute_find(priv_tmpl, CKA_EXPONENT_1, &dmp1)) { + TRACE_ERROR("CKA_EXPONENT_1 attribute missing for CRT.\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + total += dmp1->ulValueLen; + + if (!template_attribute_find(priv_tmpl, CKA_EXPONENT_2, &dmq1)) { + TRACE_ERROR("CKA_EXPONENT_2 attribute missing for CRT.\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + total += dmq1->ulValueLen; + + if (!template_attribute_find(priv_tmpl, CKA_COEFFICIENT, &iqmp)) { + TRACE_ERROR("CKA_COEFFICIENT attribute missing for CRT.\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + total += iqmp->ulValueLen; + + if (!template_attribute_find(priv_tmpl, CKA_PUBLIC_EXPONENT, &pub_exp)) { + TRACE_ERROR("CKA_PUBLIC_EXPONENT attribute missing for CRT.\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + total += pub_exp->ulValueLen; + + if (!template_attribute_find(priv_tmpl, CKA_MODULUS, &mod)) { + TRACE_ERROR("CKA_MODULUS attribute missing for CRT.\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + total += mod->ulValueLen; + + /* check total length does not exceed key_value_structure_length */ + if ((total + 18) > key_value_structure_length) { + TRACE_ERROR("total length of key exceeds CCA_KEY_VALUE_STRUCT_SIZE.\n"); + return CKR_KEY_SIZE_RANGE; + } + + /* Build key token for RSA-PRIV format. + * Fields according to Table 9. + * PKA_Key_Token_Build key-values-structure + */ + + memset(key_value_structure, 0, key_value_structure_length); + + /* Field #1 - Length of modulus in bits */ + mod_bits = htons(mod->ulValueLen * 8); + memcpy(&key_value_structure[0], &mod_bits, sizeof(uint16_t)); + + /* Field #2 - Length of modulus field in bytes */ + mod_bytes = htons(mod->ulValueLen); + memcpy(&key_value_structure[2], &mod_bytes, sizeof(uint16_t)); + + /* Field #3 - Length of public exponent field in bytes */ + size_of_e = htons(pub_exp->ulValueLen); + memcpy(&key_value_structure[4], &size_of_e, sizeof(uint16_t)); + + /* Field #4 - Reserved, binary zero, two bytes */ + + /* Field #5 - Length of prime P */ + bytes = htons(p_prime->ulValueLen); + memcpy(&key_value_structure[8], &bytes, sizeof(uint16_t)); + + /* Field #6 - Length of prime Q */ + bytes = htons(q_prime->ulValueLen); + memcpy(&key_value_structure[10], &bytes, sizeof(uint16_t)); + + /* Field #7 - Length of dp in bytes */ + bytes = htons(dmp1->ulValueLen); + memcpy(&key_value_structure[12], &bytes, sizeof(uint16_t)); + + /* Field #8 - Length of dq in bytes */ + bytes = htons(dmq1->ulValueLen); + memcpy(&key_value_structure[14], &bytes, sizeof(uint16_t)); + + /* Field #9 - Length of U in bytes */ + bytes = htons(iqmp->ulValueLen); + memcpy(&key_value_structure[16], &bytes, sizeof(uint16_t)); + + /* Field #10 - Modulus */ + memcpy(&key_value_structure[18], mod->pValue, mod_bytes); + + offset = 18 + mod_bytes; + + /* Field #11 - Public Exponent */ + memcpy(&key_value_structure[offset], pub_exp->pValue, pub_exp->ulValueLen); + + offset += pub_exp->ulValueLen; + + /* Field #12 - Prime numer, p */ + memcpy(&key_value_structure[offset], p_prime->pValue, p_prime->ulValueLen); + + offset += p_prime->ulValueLen; + + /* Field #13 - Prime numer, q */ + memcpy(&key_value_structure[offset], q_prime->pValue, q_prime->ulValueLen); + + offset += q_prime->ulValueLen; + + /* Field #14 - dp = dmod(p-1) */ + memcpy(&key_value_structure[offset], dmp1->pValue, dmp1->ulValueLen); + + offset += dmp1->ulValueLen; + + /* Field #15 - dq = dmod(q-1) */ + memcpy(&key_value_structure[offset], dmq1->pValue, dmq1->ulValueLen); + + offset += dmq1->ulValueLen; + + /* Field #16 - U = (q^-1)mod(p) */ + memcpy(&key_value_structure[offset], iqmp->pValue, iqmp->ulValueLen); + + /* Now build a key token with the imported public key */ + + rule_array_count = 2; + memcpy(rule_array, "RSA-CRT KEY-MGMT", (size_t) (CCA_KEYWORD_SIZE * 2)); + + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNDPKB (RSA KEY TOKEN BUILD RSA CRT) failed." + " return:%ld, reason:%ld\n", return_code, reason_code); + rc = CKR_FUNCTION_FAILED; + goto err; + } + + /* Now import the PKA key token */ + rule_array_count = 0; + /* memcpy(rule_array, " ", (size_t)(CCA_KEYWORD_SIZE * 1)); */ + + target_key_token_length = CCA_KEY_TOKEN_SIZE; + + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNDPKI (RSA KEY TOKEN IMPORT) failed." + " return:%ld, reason:%ld\n", return_code, reason_code); + rc = CKR_FUNCTION_FAILED; + goto err; + } + + /* Add the key object to the template */ + if ((rc = build_attribute(CKA_IBM_OPAQUE, target_key_token, + target_key_token_length, &opaque_key))) { + TRACE_DEVEL("build_attribute failed\n"); + goto err; + } + rc = template_update_attribute(priv_tmpl, opaque_key); + if (rc != CKR_OK) { + TRACE_DEVEL("template_update_attribute failed\n"); + goto err; + } + + OPENSSL_cleanse(p_prime->pValue, p_prime->ulValueLen); + OPENSSL_cleanse(q_prime->pValue, q_prime->ulValueLen); + OPENSSL_cleanse(dmp1->pValue, dmp1->ulValueLen); + OPENSSL_cleanse(dmq1->pValue, dmq1->ulValueLen); + OPENSSL_cleanse(iqmp->pValue, iqmp->ulValueLen); + if (template_attribute_find(priv_tmpl, CKA_PRIVATE_EXPONENT, &priv_exp)) { + OPENSSL_cleanse(priv_exp->pValue, priv_exp->ulValueLen); + } + + rc =CKR_OK; + +err: + OPENSSL_cleanse(key_value_structure, sizeof(key_value_structure)); + return rc; +} + +static CK_RV rsa_import_pubkey(TEMPLATE * publ_tmpl) +{ + long return_code, reason_code, rule_array_count; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + + long key_value_structure_length = CCA_KEY_VALUE_STRUCT_SIZE; + long private_key_name_length, key_token_length; + unsigned char key_value_structure[CCA_KEY_VALUE_STRUCT_SIZE] = { 0, }; + unsigned char private_key_name[CCA_PRIVATE_KEY_NAME_SIZE] = { 0, }; + unsigned char key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; + + uint16_t size_of_e; + uint16_t mod_bits, mod_bytes; + CK_ATTRIBUTE *opaque_key = NULL, *pub_exp = NULL; + CK_ATTRIBUTE *pub_mod = NULL, *attr = NULL; + CK_RV rc; + + /* check that modulus and public exponent are available */ + if (!template_attribute_find(publ_tmpl, CKA_PUBLIC_EXPONENT, &pub_exp)) { + TRACE_ERROR("CKA_PUBLIC_EXPONENT attribute missing.\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + + if (!template_attribute_find(publ_tmpl, CKA_MODULUS, &pub_mod)) { + TRACE_ERROR("CKA_MODULUS attribute missing.\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + + if (!template_attribute_find(publ_tmpl, CKA_MODULUS_BITS, &attr)) { + TRACE_ERROR("CKA_MODULUS_BITS attribute missing.\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + + /* check total length does not exceed key_value_structure_length */ + if ((pub_mod->ulValueLen + 8) > (CK_ULONG)key_value_structure_length) { + TRACE_ERROR("total length of key exceeds CCA_KEY_VALUE_STRUCT_SIZE.\n"); + return CKR_KEY_SIZE_RANGE; + } + + /* In case the application hasn't filled it */ + if (*(CK_ULONG *) attr->pValue == 0) + mod_bits = htons(pub_mod->ulValueLen * 8); + else + mod_bits = htons(*(CK_ULONG *) attr->pValue); + + /* Build key token for RSA-PUBL format */ + memset(key_value_structure, 0, key_value_structure_length); + + /* Fields according to Table 9. + * PKA_Key_Token_Build key-values-structure + */ + + /* Field #1 - Length of modulus in bits */ + memcpy(&key_value_structure[0], &mod_bits, sizeof(uint16_t)); + + /* Field #2 - Length of modulus field in bytes */ + mod_bytes = htons(pub_mod->ulValueLen); + memcpy(&key_value_structure[2], &mod_bytes, sizeof(uint16_t)); + + /* Field #3 - Length of public exponent field in bytes */ + size_of_e = htons((uint16_t) pub_exp->ulValueLen); + memcpy(&key_value_structure[4], &size_of_e, sizeof(uint16_t)); + + /* Field #4 - private key exponent length; skip */ + + /* Field #5 - Modulus */ + memcpy(&key_value_structure[8], pub_mod->pValue, + (size_t) pub_mod->ulValueLen); + + /* Field #6 - Public exponent. Its offset depends on modulus size */ + memcpy(&key_value_structure[8 + mod_bytes], + pub_exp->pValue, (size_t) pub_exp->ulValueLen); + + /* Field #7 - Private exponent. Skip */ + + rule_array_count = 1; + memcpy(rule_array, "RSA-PUBL", (size_t) (CCA_KEYWORD_SIZE * 1)); + + private_key_name_length = 0; + + key_token_length = CCA_KEY_TOKEN_SIZE; + + // 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNDPKB (RSA KEY TOKEN BUILD RSA-PUBL) failed." + " return:%ld, reason:%ld\n", return_code, reason_code); + return CKR_FUNCTION_FAILED; + } + // Add the key object to the template. + if ((rc = build_attribute(CKA_IBM_OPAQUE, key_token, key_token_length, + &opaque_key))) { + TRACE_DEVEL("build_attribute failed\n"); + return rc; + } + + rc = template_update_attribute(publ_tmpl, opaque_key); + if (rc != CKR_OK) { + TRACE_DEVEL("template_update_attribute failed\n"); + return rc; + } + + return CKR_OK; +} + +static CK_RV import_symmetric_key(OBJECT * object, CK_ULONG keytype) +{ + CK_RV rc; + long return_code, reason_code, rule_array_count; + unsigned char target_key_id[CCA_KEY_ID_SIZE] = { 0 }; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0 }; + CK_ATTRIBUTE *opaque_key = NULL; + CK_ATTRIBUTE *attr = NULL; + + rc = template_attribute_find(object->template, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Incomplete key template\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + + switch (keytype) { + case CKK_AES: + memcpy(rule_array, "AES ", CCA_KEYWORD_SIZE); + break; + case CKK_DES: + case CKK_DES3: + memcpy(rule_array, "DES ", CCA_KEYWORD_SIZE); + break; + default: + return CKR_KEY_FUNCTION_NOT_PERMITTED; + } + + rule_array_count = 1; + + dll_CSNBCKM(&return_code, &reason_code, NULL, NULL, &rule_array_count, + rule_array, (long int *)&attr->ulValueLen, attr->pValue, + target_key_id); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNBCKM failed. return:%ld, reason:%ld\n", + return_code, reason_code); + return CKR_FUNCTION_FAILED; + } + + /* Add the key object to the template */ + if ((rc = build_attribute(CKA_IBM_OPAQUE, target_key_id, + CCA_KEY_ID_SIZE, &opaque_key))) { + TRACE_DEVEL("build_attribute(CKA_IBM_OPAQUE) failed\n"); + return rc; + } + rc = template_update_attribute(object->template, opaque_key); + if (rc != CKR_OK) { + TRACE_DEVEL("template_update_attribute(CKA_IBM_OPAQUE) failed\n"); + return rc; + } + + /* zero clear key value */ + OPENSSL_cleanse(attr->pValue, attr->ulValueLen); + + return CKR_OK; +} + + +static CK_RV import_generic_secret_key(OBJECT * object) +{ + CK_RV rc; + long return_code, reason_code, rule_array_count; + unsigned char key_token[CCA_KEY_TOKEN_SIZE] = { 0 }; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0 }; + long key_name_len = 0, clr_key_len = 0; + long user_data_len = 0, key_part_len = 0; + long token_data_len = 0, verb_data_len = 0; + long key_token_len = sizeof(key_token); + CK_ATTRIBUTE *opaque_key = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_ULONG keylen; + + rc = template_attribute_find(object->template, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Incomplete Generic Secret (HMAC) key template\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + keylen = attr->ulValueLen; + /* key len needs to be 80-2048 bits */ + if (8 * keylen < 80 || 8 * keylen > 2048) { + TRACE_ERROR("HMAC key size of %lu bits not within" + " CCA required range of 80-2048 bits\n", 8 * keylen); + return CKR_KEY_SIZE_RANGE; + } + + memcpy(rule_array, "INTERNALNO-KEY HMAC MAC GENERATE", + 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); + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNBKTB2 (HMAC KEY TOKEN BUILD) failed." + " return:%ld, reason:%ld\n", return_code, reason_code); + return CKR_FUNCTION_FAILED; + } + + memcpy(rule_array, "HMAC FIRST MIN1PART", 3 * CCA_KEYWORD_SIZE); + rule_array_count = 3; + 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, attr->pValue, &key_token_len, + key_token); + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNBKPI2 (HMAC KEY IMPORT FIRST) failed." + " return:%ld, reason:%ld\n", return_code, reason_code); + return CKR_FUNCTION_FAILED; + } + + memcpy(rule_array, "HMAC COMPLETE", 2 * CCA_KEYWORD_SIZE); + rule_array_count = 2; + 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); + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNBKPI2 (HMAC KEY IMPORT COMPLETE) failed." + " return:%ld, reason:%ld\n", return_code, reason_code); + return CKR_FUNCTION_FAILED; + } + + /* Add the key object to the template */ + if ((rc = build_attribute(CKA_IBM_OPAQUE, key_token, key_token_len, + &opaque_key))) { + TRACE_DEVEL("build_attribute(CKA_IBM_OPAQUE) failed\n"); + return rc; + } + rc = template_update_attribute(object->template, opaque_key); + if (rc != CKR_OK) { + TRACE_DEVEL("template_update_attribute(CKA_IBM_OPAQUE) failed\n"); + return rc; + } + + /* zero clear key value */ + OPENSSL_cleanse(attr->pValue, attr->ulValueLen); + + return CKR_OK; +} + +static CK_RV build_private_EC_key_value_structure(CK_BYTE *privkey, CK_ULONG privlen, + CK_BYTE *pubkey, CK_ULONG publen, + uint8_t curve_type, uint16_t curve_bitlen, + unsigned char *key_value_structure, long *key_value_structure_length) +{ + ECC_PAIR ecc_pair; + + ecc_pair.curve_type = curve_type; + ecc_pair.reserved = 0x00; + ecc_pair.p_bitlen = curve_bitlen; + ecc_pair.d_length = privlen; + + /* Adjust public key if necessary: there may be an indication if the public + * key is compressed, uncompressed, or hybrid. */ + if (publen == 2 * privlen + 1) { + if (pubkey[0] == POINT_CONVERSION_UNCOMPRESSED || + pubkey[0] == POINT_CONVERSION_HYBRID || + pubkey[0] == POINT_CONVERSION_HYBRID+1) { + /* uncompressed or hybrid EC public key */ + ecc_pair.q_length = publen; + memcpy(key_value_structure, &ecc_pair, sizeof(ECC_PAIR)); + memcpy(key_value_structure + sizeof(ECC_PAIR), privkey, privlen); + memcpy(key_value_structure + sizeof(ECC_PAIR) + privlen, pubkey, publen); + *key_value_structure_length = sizeof(ECC_PAIR) + privlen + publen; + } else { + TRACE_ERROR("Unsupported public key format\n"); + return CKR_TEMPLATE_INCONSISTENT; + } + } else if (publen == 2 * privlen) { + /* uncompressed or hybrid EC public key without leading indication */ + ecc_pair.q_length = publen + 1; + memcpy(key_value_structure, &ecc_pair, sizeof(ECC_PAIR)); + memcpy(key_value_structure + sizeof(ECC_PAIR), privkey, privlen); + memset(key_value_structure + sizeof(ECC_PAIR) + privlen, POINT_CONVERSION_UNCOMPRESSED, 1); + memcpy(key_value_structure + sizeof(ECC_PAIR) + privlen + 1, pubkey, publen); + *key_value_structure_length = sizeof(ECC_PAIR) + privlen + 1 + publen; + } else { + TRACE_ERROR("Unsupported private/public key length (%ld,%ld)\n",privlen,publen); + TRACE_ERROR("Compressed public keys are not supported by this token.\n"); + return CKR_TEMPLATE_INCONSISTENT; + } + + return CKR_OK; +} + +static unsigned int bitlen2bytelen(uint16_t bitlen) +{ + if (bitlen != CURVE521) + return bitlen / 8; + + return bitlen / 8 + 1; +} + +static CK_RV build_public_EC_key_value_structure(CK_BYTE *pubkey, CK_ULONG publen, + uint8_t curve_type, uint16_t curve_bitlen, + unsigned char *key_value_structure, long *key_value_structure_length) +{ + ECC_PUBL ecc_publ; + + ecc_publ.curve_type = curve_type; + ecc_publ.reserved = 0x00; + ecc_publ.p_bitlen = curve_bitlen; + + if (publen == 2 * bitlen2bytelen(curve_bitlen) + 1) { + if (pubkey[0] == POINT_CONVERSION_UNCOMPRESSED || + pubkey[0] == POINT_CONVERSION_HYBRID || + pubkey[0] == POINT_CONVERSION_HYBRID+1) { + /* uncompressed or hybrid EC public key */ + ecc_publ.q_length = publen; + memcpy(key_value_structure, &ecc_publ, sizeof(ECC_PUBL)); + memcpy(key_value_structure + sizeof(ECC_PUBL), pubkey, publen); + *key_value_structure_length = sizeof(ECC_PUBL) + publen; + } else { + TRACE_ERROR("Unsupported public key format\n"); + return CKR_TEMPLATE_INCONSISTENT; + } + } else if (publen == 2 * bitlen2bytelen(curve_bitlen)) { + /* uncompressed or hybrid EC public key without leading 0x04 */ + ecc_publ.q_length = publen + 1; + memcpy(key_value_structure, &ecc_publ, sizeof(ECC_PUBL)); + 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 { + 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; +} + +static CK_RV ec_import_privkey(TEMPLATE *priv_templ) +{ + long private_key_name_length, key_token_length, target_key_token_length; + long return_code, reason_code, rule_array_count, exit_data_len = 0; + long key_value_structure_length, param1=0; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + unsigned char key_value_structure[CCA_KEY_VALUE_STRUCT_SIZE] = { 0, }; + unsigned char private_key_name[CCA_PRIVATE_KEY_NAME_SIZE] = { 0, }; + unsigned char key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; + unsigned char transport_key_identifier[CCA_KEY_ID_SIZE] = { 0, }; + unsigned char target_key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; + unsigned char *exit_data = NULL; + unsigned char *param2=NULL; + CK_BYTE *privkey = NULL, *pubkey = NULL; + CK_ATTRIBUTE *attr = NULL, *opaque_key; + CK_ULONG privlen = 0, publen = 0; + CK_RV rc; + uint8_t curve_type; + uint16_t curve_bitlen; + CK_ULONG field_len; + + /* Check if curve supported and determine curve type and bitlen */ + rc = curve_supported(priv_templ, &curve_type, &curve_bitlen); + if (rc != CKR_OK) { + TRACE_ERROR("Curve not supported by this token.\n"); + return rc; + } + + /* Find private key data in template */ + rc = template_attribute_find(priv_templ, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + privlen = attr->ulValueLen; + privkey = attr->pValue; + + /* Find public key data as BER encoded OCTET STRING in template */ + rc = template_attribute_find(priv_templ, CKA_EC_POINT, &attr); + if (rc == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + rc = ber_decode_OCTET_STRING(attr->pValue, &pubkey, &publen, + &field_len); + if (rc != CKR_OK || attr->ulValueLen != field_len) { + TRACE_DEVEL("ber decoding of public key failed\n"); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + /* Build key_value_structure */ + memset(key_value_structure, 0, CCA_KEY_VALUE_STRUCT_SIZE); + + rc = build_private_EC_key_value_structure(privkey, privlen, + pubkey, publen, curve_type, curve_bitlen, + (unsigned char *)&key_value_structure, + &key_value_structure_length); + if (rc != CKR_OK) + return rc; + + /* Build key token */ + rule_array_count = 1; + memcpy(rule_array, "ECC-PAIR", (size_t)(CCA_KEYWORD_SIZE)); + private_key_name_length = 0; + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNDPKB (EC KEY TOKEN BUILD) failed. return:%ld," + " reason:%ld\n", return_code, reason_code); + if (is_curve_error(return_code, reason_code)) + return CKR_CURVE_NOT_SUPPORTED; + return CKR_FUNCTION_FAILED; + } + + /* Now import the PKA key token */ + rule_array_count = 1; + memcpy(rule_array, "ECC ", (size_t)(CCA_KEYWORD_SIZE)); + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNDPKI (EC KEY TOKEN IMPORT) failed." " return:%ld, reason:%ld\n", + return_code, reason_code); + if (is_curve_error(return_code, reason_code)) + return CKR_CURVE_NOT_SUPPORTED; + return CKR_FUNCTION_FAILED; + } + + /* Add key token to template as CKA_IBM_OPAQUE */ + if ((rc = build_attribute(CKA_IBM_OPAQUE, target_key_token, + target_key_token_length, &opaque_key))) { + TRACE_DEVEL("build_attribute(CKA_IBM_OPAQUE) failed\n"); + return rc; + } + + rc = template_update_attribute(priv_templ, opaque_key); + if (rc != CKR_OK) { + TRACE_DEVEL("template_update_attribute(CKA_IBM_OPAQUE) failed\n"); + return rc; + } + + /* zero clear key values */ + OPENSSL_cleanse(privkey, privlen); + + return CKR_OK; +} + +static CK_RV ec_import_pubkey(TEMPLATE *pub_templ) +{ + CK_RV rc; + long return_code, reason_code, rule_array_count, exit_data_len = 0; + long private_key_name_length, key_token_length; + unsigned char *exit_data = NULL; + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; + long key_value_structure_length; + unsigned char key_value_structure[CCA_KEY_VALUE_STRUCT_SIZE] = { 0, }; + unsigned char private_key_name[CCA_PRIVATE_KEY_NAME_SIZE] = { 0, }; + unsigned char key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; + CK_ATTRIBUTE *opaque_key; + long param1=0; + unsigned char *param2=NULL; + uint8_t curve_type; + uint16_t curve_bitlen; + 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); + if (rc != CKR_OK) { + TRACE_ERROR("Curve not supported by this token.\n"); + return rc; + } + + /* Find public key data as BER encoded OCTET STRING in template */ + rc = template_attribute_find(pub_templ, CKA_EC_POINT, &attr); + if (rc == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + rc = ber_decode_OCTET_STRING(attr->pValue, &pubkey, &publen, + &field_len); + if (rc != CKR_OK || attr->ulValueLen != field_len) { + TRACE_DEVEL("ber decoding of public key failed\n"); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + /* Build key_value_structure */ + memset(key_value_structure, 0, CCA_KEY_VALUE_STRUCT_SIZE); + + rc = build_public_EC_key_value_structure(pubkey, publen, + curve_type, curve_bitlen, + (unsigned char *)&key_value_structure, + &key_value_structure_length); + if (rc != CKR_OK) + return rc; + + /* Build public key token */ + rule_array_count = 1; + memcpy(rule_array, "ECC-PUBL", (size_t)(CCA_KEYWORD_SIZE)); + private_key_name_length = 0; + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNDPKB (EC KEY TOKEN BUILD) failed. return:%ld," + " reason:%ld\n", return_code, reason_code); + if (is_curve_error(return_code, reason_code)) + return CKR_CURVE_NOT_SUPPORTED; + return CKR_FUNCTION_FAILED; + } + + /* Public keys do not need to be wrapped, so just add public + key token to template as CKA_IBM_OPAQUE */ + if ((rc = build_attribute(CKA_IBM_OPAQUE, key_token, key_token_length, &opaque_key))) { + TRACE_DEVEL("build_attribute(CKA_IBM_OPAQUE) failed\n"); + return rc; + } + rc = template_update_attribute(pub_templ, opaque_key); + if (rc != CKR_OK) { + TRACE_DEVEL("template_update_attribute(CKA_IBM_OPAQUE) failed\n"); + return rc; + } + + return CKR_OK; +} + +CK_RV token_specific_object_add(STDLL_TokData_t *tokdata, SESSION *sess, OBJECT *object) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + CK_KEY_TYPE keytype; + CK_OBJECT_CLASS keyclass; + + UNUSED(tokdata); + UNUSED(sess); + + if (!object) { + TRACE_ERROR("Invalid argument\n"); + return CKR_FUNCTION_FAILED; + } + + rc = template_attribute_find(object->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + // not a key, so nothing to do. Just return. + TRACE_DEVEL("object not a key, no need to import.\n"); + return CKR_OK; + } + + keytype = *(CK_KEY_TYPE *)attr->pValue; + + switch (keytype) { + case CKK_RSA: + rc = template_attribute_find(object->template, CKA_CLASS, &attr); + if (rc == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + keyclass = *(CK_OBJECT_CLASS *)attr->pValue; + + switch(keyclass) { + case CKO_PUBLIC_KEY: + // do import public key and create opaque object + rc = rsa_import_pubkey(object->template); + break; + case CKO_PRIVATE_KEY: + // do import keypair and create opaque object + rc = rsa_import_privkey_crt(object->template); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + + if (rc != CKR_OK) { + TRACE_DEVEL("rsa import failed\n"); + return rc; + } + + break; + case CKK_AES: + case CKK_DES: + case CKK_DES3: + rc = import_symmetric_key(object, keytype); + if (rc != CKR_OK) { + TRACE_DEVEL("Symmetric key import failed, rc=0x%lx\n", + rc); + return rc; + } + TRACE_INFO("symmetric key with len=%ld successful imported\n", + attr->ulValueLen); + break; + case CKK_GENERIC_SECRET: + rc = import_generic_secret_key(object); + if (rc != CKR_OK) { + TRACE_DEVEL("Generic Secret (HMAC) key import failed " + " with rc=0x%lx\n", rc); + return rc; + } + TRACE_INFO("Generic Secret (HMAC) key with len=%ld successfully" + " imported\n", attr->ulValueLen); + break; + case CKK_EC: + rc = template_attribute_find(object->template, CKA_CLASS, &attr); + if (rc == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + keyclass = *(CK_OBJECT_CLASS *)attr->pValue; + + switch(keyclass) { + case CKO_PUBLIC_KEY: + // do import public key and create opaque object + rc = ec_import_pubkey(object->template); + break; + case CKO_PRIVATE_KEY: + // do import keypair and create opaque object + rc = ec_import_privkey(object->template); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + + if (rc != CKR_OK) { + TRACE_DEVEL("ec import failed\n"); + return rc; + } + break; + default: + /* unknown/unsupported key type */ + TRACE_ERROR("Unknown/unsupported key type 0x%lx\n", keytype); + return CKR_KEY_FUNCTION_NOT_PERMITTED; + } + + return CKR_OK; +} + +CK_RV token_specific_generic_secret_key_gen(STDLL_TokData_t * tokdata, + TEMPLATE * template) +{ + CK_RV rc; + long return_code, reason_code, rule_array_count; + long zero_length = 0; + long key_name_length = 0, clear_key_length = 0, user_data_length = 0; + CK_ATTRIBUTE *opaque_key = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_ULONG keylength = 0; + unsigned char key_type1[8] = { 0 }; + unsigned char key_type2[8] = { 0 }; + unsigned char key_token[CCA_KEY_TOKEN_SIZE] = { 0 }; + long key_token_length = sizeof(key_token); + unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0 }; + + UNUSED(tokdata); + + rc = template_attribute_find(template, CKA_VALUE_LEN, &attr); + if (rc == FALSE) { + TRACE_ERROR("Incomplete Generic Secret (HMAC) key template\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + + keylength = *(CK_ULONG *) attr->pValue; + + /* HMAC key length needs to be 80-2048 bits */ + if (((8 * keylength) < 80) || ((8 * keylength) > 2048)) { + TRACE_ERROR("HMAC key size of %lu bits not within CCA required " + "range of 80-2048 bits\n", 8 * keylength); + return CKR_KEY_SIZE_RANGE; + } + + rule_array_count = 4; + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNBKTB2 (HMAC KEY TOKEN BUILD) failed." + " return:%ld, reason:%ld\n", return_code, reason_code); + return CKR_FUNCTION_FAILED; + } + + /** generate the hmac key here **/ + /* reset some values usually previously */ + rule_array_count = 2; + memset(rule_array, 0, sizeof(rule_array)); + + key_token_length = sizeof(key_token); + + /* create rule_array with 2 keywords */ + memcpy(rule_array, "HMAC OP ", 2 * CCA_KEYWORD_SIZE); + + /* ask to create the hmac key with application + * specified key length in bits + */ + clear_key_length = keylength * 8; + memcpy(key_type1, "TOKEN ", CCA_KEYWORD_SIZE); + + /* for only one copy of key generated, specify 8 spaces in + * key_type2 per CCA basic services guide + */ + 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); + + if (return_code != CCA_SUCCESS) { + TRACE_ERROR("CSNBKGN2 (HMAC KEY GENERATE) failed." + " return:%ld, reason:%ld\n", return_code, reason_code); + return CKR_FUNCTION_FAILED; + } + + /* Add the key object to the template */ + rc = build_attribute(CKA_IBM_OPAQUE, key_token, key_token_length, + &opaque_key); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute(CKA_IBM_OPAQUE) failed\n"); + return rc; + } + + rc = template_update_attribute(template, opaque_key); + if (rc != CKR_OK) { + TRACE_DEVEL("template_update_attribute(CKA_IBM_OPAQUE) failed.\n"); + return rc; + } + + return CKR_OK; +} diff --git a/usr/lib/cca_stdll/cca_stdll.h b/usr/lib/cca_stdll/cca_stdll.h new file mode 100644 index 0000000..cdc902d --- /dev/null +++ b/usr/lib/cca_stdll/cca_stdll.h @@ -0,0 +1,106 @@ + +/* + * 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 + */ + +/* + * openCryptoki CCA token + * + * Author: Kent E. Yoder + * + */ + +#ifndef __CCA_STDLL_H__ +#define __CCA_STDLL_H__ + +/* CCA library constants */ + +#define CCA_PRIVATE_KEY_NAME_SIZE 64 +#define CCA_REGENERATION_DATA_SIZE 64 +#define CCA_KEY_TOKEN_SIZE 2500 +#define CCA_KEY_VALUE_STRUCT_SIZE 2500 +#define CCA_RULE_ARRAY_SIZE 256 +#define CCA_KEYWORD_SIZE 8 +#define CCA_KEY_ID_SIZE 64 +#define CCA_RNG_SIZE 8 +#define CCA_OCV_SIZE 18 +#define CCA_SUCCESS 0 +#define CCA_PKB_E_OFFSET 18 +#define CCA_PKB_E_SIZE 2 +#define CCA_PKB_E_SIZE_OFFSET 4 +#define CCA_CHAIN_VECTOR_LEN 128 + +/* Elliptic Curve constants */ +/* CCA spec: page 94 */ +#define CCA_EC_KEY_VALUE_STRUCT_SIZE 8 +#define CCA_PKB_EC_TYPE_OFFSET 0 +#define CCA_PKB_EC_LEN_OFFSET 2 +#define CCA_PKB_EC_PRIV_KEY_LEN_OFFSET 4 +#define CCA_PKB_EC_PUBL_KEY_LEN_OFFSET 6 +#define CCATOK_EC_MAX_D_LEN 66 +#define CCATOK_EC_MAX_Q_LEN 133 +/* Key token generated by CSNDPKG */ +/* CCA spec: page 460 & 470 & 471 */ +#define CCA_PRIVKEY_ID 0x20 +#define CCA_PUBLKEY_ID 0x21 +#define CCA_SECTION_LEN_OFFSET 2 +#define CCA_EC_HEADER_SIZE 8 +#define CCA_PRIV_P_LEN_OFFSET 12 +#define CCA_PUBL_P_LEN_OFFSET 10 +/* Offset into the EC public key section to length of q */ +#define CCA_EC_INTTOK_PUBKEY_Q_LEN_OFFSET 12 +/* Offset into the EC public key section to q */ +#define CCA_EC_INTTOK_PUBKEY_Q_OFFSET 14 + +/* CCA Internal Key Token parsing constants */ + +/* Size of an RSA internal key token header */ +#define CCA_RSA_INTTOK_HDR_LENGTH 8 +/* Offset into an RSA internal key token of the private key area */ +#define CCA_RSA_INTTOK_PRIVKEY_OFFSET 8 +/* Offset into an RSA key area of the total length */ +#define CCA_RSA_INTTOK_PRIVKEY_LENGTH_OFFSET 2 +#define CCA_RSA_INTTOK_PUBKEY_LENGTH_OFFSET 2 +/* Offset into an RSA private key area of the length of n, the modulus */ +#define CCA_RSA_INTTOK_PRIVKEY_N_LENGTH_OFFSET 64 +/* Offset into an RSA public key area of the length of e, the public exponent */ +#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 the STATCCAE command for the + * Current Symmetric Master Key register status */ +#define CCA_STATCCAE_SYM_CMK_OFFSET 8 +/* Offset into the rule_array returned by the STATCCAE command for the + * Current Asymmetric Master Key register status */ +#define CCA_STATCCAE_ASYM_CMK_OFFSET 56 + +/* CCA STDLL constants */ + +#define CCATOK_MAX_N_LEN 512 +#define CCATOK_MAX_E_LEN 256 + +enum cca_key_type { + CCA_AES_KEY, + CCA_DES_KEY +}; + +/* CCA STDLL debug logging definitions */ + +#ifdef DEBUG +#define CCADBG(fn, rc, reason) ock_logit("CCA_TOK DEBUG %s:%d %s failed. " \ + "return: %ld, reason: %ld\n", __func__, __LINE__, fn, rc, reason) + +#define DBG(fmt, ...) ock_logit("CCA_TOK DEBUG %s:%d %s " fmt "\n", \ + __FILE__, __LINE__, __func__, ##__VA_ARGS__) +#else +#define CCADBG(...) do { } while (0) +#define DBG(...) do { } while (0) +#endif + +#endif diff --git a/usr/lib/cca_stdll/cca_stdll.mk b/usr/lib/cca_stdll/cca_stdll.mk new file mode 100644 index 0000000..6e46a9d --- /dev/null +++ b/usr/lib/cca_stdll/cca_stdll.mk @@ -0,0 +1,45 @@ +nobase_lib_LTLIBRARIES += opencryptoki/stdll/libpkcs11_cca.la + +noinst_HEADERS += \ + usr/lib/cca_stdll/defs.h usr/lib/cca_stdll/csulincl.h \ + usr/lib/cca_stdll/cca_stdll.h usr/lib/cca_stdll/cca_func.h \ + usr/lib/cca_stdll/tok_struct.h + +opencryptoki_stdll_libpkcs11_cca_la_CFLAGS = \ + -DLINUX -DNOCDMF -DNODSA -DNODH -DNOECB \ + -DTOK_NEW_DATA_STORE=0x0003000c \ + -I${srcdir}/usr/lib/cca_stdll -I${srcdir}/usr/lib/common \ + -I${srcdir}/usr/include -DSTDLL_NAME=\"ccatok\" + +opencryptoki_stdll_libpkcs11_cca_la_LDFLAGS = -shared \ + -Wl,-z,defs,-Bsymbolic -lcrypto -lpthread -nostartfiles \ + -Wl,-soname,$@ -lrt -ldl \ + -Wl,--version-script=${srcdir}/opencryptoki_tok.map + +opencryptoki_stdll_libpkcs11_cca_la_SOURCES = \ + usr/lib/common/asn1.c usr/lib/common/dig_mgr.c \ + usr/lib/common/hwf_obj.c usr/lib/common/trace.c \ + usr/lib/common/key.c usr/lib/common/mech_list.c \ + usr/lib/common/mech_dh.c usr/lib/common/mech_rng.c \ + usr/lib/common/new_host.c usr/lib/common/sign_mgr.c \ + usr/lib/common/cert.c usr/lib/common/dp_obj.c \ + usr/lib/common/mech_aes.c usr/lib/common/mech_rsa.c \ + usr/lib/common/mech_ec.c usr/lib/common/obj_mgr.c \ + usr/lib/common/template.c usr/lib/common/data_obj.c \ + usr/lib/common/encr_mgr.c usr/lib/common/key_mgr.c \ + usr/lib/common/mech_md2.c usr/lib/common/mech_sha.c \ + usr/lib/common/object.c usr/lib/common/decr_mgr.c \ + usr/lib/common/globals.c usr/lib/common/loadsave.c \ + usr/lib/common/utility.c usr/lib/common/mech_des.c \ + usr/lib/common/mech_des3.c usr/lib/common/mech_md5.c \ + usr/lib/common/mech_ssl3.c usr/lib/common/verify_mgr.c \ + usr/lib/common/p11util.c usr/lib/common/sw_crypt.c \ + usr/lib/common/shared_memory.c usr/lib/cca_stdll/cca_specific.c +if ENABLE_LOCKS +opencryptoki_stdll_libpkcs11_cca_la_SOURCES += \ + usr/lib/common/lock_btree.c usr/lib/common/lock_sess_mgr.c +else +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 diff --git a/usr/lib/cca_stdll/csulincl.h b/usr/lib/cca_stdll/csulincl.h new file mode 100644 index 0000000..2fe12e7 --- /dev/null +++ b/usr/lib/cca_stdll/csulincl.h @@ -0,0 +1,2549 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 1997-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 + */ + +/******************************************************************************/ +/* Module Name: csulincl.h */ +/* */ +/* US Government Users Restricted Rights - Use, duplication or disclosure */ +/* restricted by GSA ADP Schedule Contract with IBM Corp. */ +/* */ +/* Function: */ +/* This header file contains the Security API C language prototypes for the */ +/* Linux platform. */ +/* */ +/* User publications are available at: */ +/* */ +/* http://www.ibm.com/security/cryptocards */ +/******************************************************************************/ + +/* + * Following check assures that this include file is included only once. + */ +#ifndef __CSULINCL__ +#define __CSULINCL__ + +/* + * Define system linkage macros for the target platform. + */ + +#define SECURITYAPI + +/* + * The following defintion statements are provided for backward compatibility in + * case some old version of applications are referring to these statements. This + * definitions will be removed in future. + */ + +#define CSNBAKRC CSNBAKRC +#define CSNBAKRD CSNBAKRD +#define CSNBAKRL CSNBAKRL +#define CSNBAKRR CSNBAKRR +#define CSNBAKRW CSNBAKRW +#define CSNBAPG CSNBAPG +#define CSNBCKC CSNBCKC +#define CSNBCKI CSNBCKI +#define CSNBCKM CSNBCKM +#define CSNBCPA CSNBCPA +#define CSNBCPE CSNBCPE +#define CSNBCSG CSNBCSG +#define CSNBCSV CSNBCSV +#define CSNBCVE CSNBCVE +#define CSNBCVG CSNBCVG +#define CSNBCVT CSNBCVT +#define CSNBDEC CSNBDEC +#define CSNBDKG CSNBDKG +#define CSNBDKG2 CSNBDKG2 +#define CSNBDKM CSNBDKM +#define CSNBDKX CSNBDKX +#define CSNBDMP CSNBDMP +#define CSNBDPC CSNBDPC +#define CSNBDPCG CSNBDPCG +#define CSNBDPMT CSNBDPMT +#define CSNBDPNU CSNBDPNU +#define CSNBDPT CSNBDPT +#define CSNBDPV CSNBDPV +#define CSNBDRP CSNBDRP +#define CSNBDRPG CSNBDRPG +#define CSNBDDPG CSNBDDPG +#define CSNBENC CSNBENC +#define CSNBEPG CSNBEPG +#define CSNBFPED CSNBFPED +#define CSNBFPEE CSNBFPEE +#define CSNBFPET CSNBFPET +#define CSNBHMG CSNBHMG +#define CSNBHMV CSNBHMV +#define CSNBKET CSNBKET +#define CSNBKEX CSNBKEX +#define CSNBKGN CSNBKGN +#define CSNBKGN2 CSNBKGN2 +#define CSNBKIM CSNBKIM +#define CSNBKPI CSNBKPI +#define CSNBKPI2 CSNBKPI2 +#define CSNBKRC CSNBKRC +#define CSNBKRD CSNBKRD +#define CSNBKRL CSNBKRL +#define CSNBKRR CSNBKRR +#define CSNBKRW CSNBKRW +#define CSNBKSI CSNBKSI +#define CSNBKTB CSNBKTB +#define CSNBKTB2 CSNBKTB2 +#define CSNBKTC CSNBKTC +#define CSNBKTC2 CSNBKTC2 +#define CSNBKTP CSNBKTP +#define CSNBKTP2 CSNBKTP2 +#define CSNBKTR CSNBKTR +#define CSNBKTR2 CSNBKTR2 +#define CSNBKYT CSNBKYT +#define CSNBKYTX CSNBKYTX +#define CSNBKYT2 CSNBKYT2 +#define CSNBMDG CSNBMDG +#define CSNBMGN CSNBMGN +#define CSNBMGN2 CSNBMGN2 +#define CSNBMKP CSNBMKP +#define CSNBMVR CSNBMVR +#define CSNBMVR2 CSNBMVR2 +#define CSNBOWH CSNBOWH +#define CSNBPCU CSNBPCU +#define CSNBPEX CSNBPEX +#define CSNBPEXX CSNBPEXX +#define CSNBPEX2 CSNBPEX2 +#define CSNBPFO CSNBPFO +#define CSNBPGN CSNBPGN +#define CSNBPTR CSNBPTR +#define CSNBPTRE CSNBPTRE +#define CSNBPVR CSNBPVR +#define CSNBRKA CSNBRKA +#define CSNBRNG CSNBRNG +#define CSNBRNGL CSNBRNGL +#define CSNBSAD CSNBSAD +#define CSNBSAE CSNBSAE +#define CSNBSKY CSNBSKY +#define CSNBSPN CSNBSPN +#define CSNBTRV CSNBTRV +#define CSNBUKD CSNBUKD +#define CSNBXEA CSNBXEA +#define CSNDDSG CSNDDSG +#define CSNDDSV CSNDDSV +#define CSNDEDH CSNDEDH +#define CSNDKRC CSNDKRC +#define CSNDKRD CSNDKRD +#define CSNDKRL CSNDKRL +#define CSNDKRR CSNDKRR +#define CSNDKRW CSNDKRW +#define CSNDKTC CSNDKTC +#define CSNDPKB CSNDPKB +#define CSNDPKD CSNDPKD +#define CSNDPKE CSNDPKE +#define CSNDPKG CSNDPKG +#define CSNDPKH CSNDPKH +#define CSNDPKI CSNDPKI +#define CSNDPKR CSNDPKR +#define CSNDPKT CSNDPKT +#define CSNDPKX CSNDPKX +#define CSNDRKD CSNDRKD +#define CSNDRKL CSNDRKL +#define CSNDRKX CSNDRKX +#define CSNDSBC CSNDSBC +#define CSNDSBD CSNDSBD +#define CSNDSXD CSNDSXD +#define CSNDSYG CSNDSYG +#define CSNDSYI CSNDSYI +#define CSNDSYI2 CSNDSYI2 +#define CSNDSYX CSNDSYX +#define CSNDTBC CSNDTBC +#define CSUAACI CSUAACI +#define CSUAACM CSUAACM +#define CSUACFC CSUACFC +#define CSUACFQ CSUACFQ +#define CSUACFV CSUACFV +#define CSUACRA CSUACRA +#define CSUACRD CSUACRD +#define CSUALCT CSUALCT +#define CSUALGQ CSUALGQ +#define CSUAMKD CSUAMKD +#define CSUAPRB CSUAPRB +#define CSUARNT CSUARNT +#define CSNBT31O CSNBT31O +#define CSNBT31P CSNBT31P +#define CSNBT31R CSNBT31R +#define CSNBT31I CSNBT31I +#define CSNBT31X CSNBT31X +#define CSNBCTT2 CSNBCTT2 +#ifdef TKE_WKSTN +#define CSUADHK CSUADHK +#define CSUADHQ CSUADHQ +#define CSUACIE CSUACIE +#define CSUAKIX CSUAKIX +#define CSUAKTX CSUAKTX +#define CSUAMKX CSUAMKX +#define CSUARNX CSUARNX +#define CSUASKE CSUASKE +#endif + + +/* + * security API prototypes + */ + +/* Authentication Parameter Generate */ +extern void SECURITYAPI CSNBAPG(long *pReturnCode, + long *pReasonCode, + long *pExitdatalength, + unsigned char *pExitdata, + long *pRule_array_count, + unsigned char *pRule_array, + long *pInboundPINEncryptingKeyLength, + unsigned char *pInboundPINEncryptingKey, + unsigned char *pEncryptedPINBlock, + unsigned char *pIssuerDomesticCode, + unsigned char *pCardSecureCode, + unsigned char *pPANData, + long *pAPEncryptingKeyIdLength, + unsigned char *pAPEncryptingKeyId, + unsigned char *pAPValue); + +/* TR-31 CVV Combine */ +extern void SECURITYAPI CSNBCKC(long *pReturnCode, + long *pReasonCode, + long *pExitDataLength, + unsigned char *pExitData, + long *pRuleArrayCount, + unsigned char *pRuleArray, + long *pKeyAIdentifierLength, + unsigned char *pKeyAIdentifier, + long *pKeyBIdentifierLength, + unsigned char *pKeyBIdentifier, + long *pOutputKeyIdentifierLength, + unsigned char *pOutputKeyIdentifier); + +/* Clear Key Import */ +extern void SECURITYAPI CSNBCKI(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *clear_key, + unsigned char *target_key_identifier); + +/* Clear Key Import Multiple */ +extern void SECURITYAPI CSNBCKM(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *clear_key_length, + unsigned char *clear_key, + unsigned char *target_key_identifier); + +/* Data Key Export */ +extern void SECURITYAPI CSNBDKX(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *source_key_identifier, + unsigned char *exporter_key_identifier, + unsigned char *target_key_token); + +/* Data Key Import */ +extern void SECURITYAPI CSNBDKM(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *source_key_token, + unsigned char *importer_key_identifier, + unsigned char *target_key_identifier); + +/* DK Migrate PIN */ +extern void SECURITYAPI CSNBDMP(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *PAN_data_length, + unsigned char *PAN_data, + long *card_p_data_length, + unsigned char *card_p_data, + long *card_t_data_length, + unsigned char *card_t_data, + long *ISO1_PIN_block_length, + unsigned char *ISO1_PIN_block, + long *IPIN_encryption_key_identifier_length, + unsigned char *IPIN_encryption_key_identifier, + long *PRW_key_identifier_length, + unsigned char *PRW_key_identifier, + long *OPIN_encryption_key_identifier_length, + unsigned char *OPIN_encryption_key_identifier, + long *OEPB_MAC_key_identifier_length, + unsigned char *OEPB_MAC_key_identifier, + long *PIN_reference_value_length, + unsigned char *PIN_reference_value, + long *PRW_random_number_length, + unsigned char *PRW_random_number, + long *output_encrypted_PIN_block_length, + unsigned char *output_encrypted_PIN_block, + long *PIN_block_MAC_length, + unsigned char *PIN_block_MAC); + +/* DK PIN Change */ +extern void SECURITYAPI CSNBDPC(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *PAN_data_length, + unsigned char *PAN_data, + long *card_p_data_length, + unsigned char *card_p_data, + long *card_t_data_length, + unsigned char *card_t_data, + long *cur_ISO1_PIN_block_length, + unsigned char *cur_ISO1_PIN_block, + long *new_ISO1_PIN_block_length, + unsigned char *new_ISO1_PIN_block, + long *card_script_data_length, + unsigned char *card_script_data, + long *script_offset, + long *script_offset_field_length, + long *script_initialization_vector_length, + unsigned char *script_initialization_vector, + unsigned char *output_PIN_profile, + long *PIN_reference_value_length, + unsigned char *PIN_reference_value, + long *PRW_random_number_length, + unsigned char *PRW_random_number, + long *PRW_key_identifier_length, + unsigned char *PRW_key_identifier, + long + *current_IPIN_encryption_key_identifier_length, + unsigned char + *current_IPIN_encryption_key_identifier, + long *new_IPIN_encryption_key_identifier_length, + unsigned char + *new_IPIN_encryption_key_identifier, + long *script_key_identifier_length, + unsigned char *script_key_identifier, + long *script_MAC_key_identifier_length, + unsigned char *script_MAC_key_identifier, + long *new_PRW_key_identifier_length, + unsigned char *new_PRW_key_identifier, + long *OPIN_encryption_key_identifier_length, + unsigned char *OPIN_encryption_key_identifier, + long *OEPB_MAC_key_identifier_length, + unsigned char *OEPB_MAC_key_identifier, + long *script_length, unsigned char *script, + long *script_MAC_length, + unsigned char *script_MAC, + long *new_PIN_reference_value_length, + unsigned char *new_PIN_reference_value, + long *new_PRW_random_number_length, + unsigned char *new_PRW_random_number, + long *output_encrypted_PIN_block_length, + unsigned char *output_encrypted_PIN_block, + long *PIN_block_MAC_length, + unsigned char *PIN_block_MAC); + +/* DK PRW CMAC Generate */ +extern void SECURITYAPI CSNBDPCG(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *current_PAN_data_length, + unsigned char *current_PAN_data, + long *new_PAN_data_length, + unsigned char *new_PAN_data, + long *current_card_data_length, + unsigned char *current_card_data, + long *new_card_data_length, + unsigned char *new_card_data, + long *PIN_reference_value_length, + unsigned char *PIN_reference_value, + long *CMAC_FUS_key_identifier_length, + unsigned char *CMAC_FUS_key_identifier, + long *CMAC_FUS_length, + unsigned char *CMAC_FUS); + +/* DK PAN Modify in Transaction */ +extern void SECURITYAPI CSNBDPMT(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *current_PAN_data_length, + unsigned char *current_PAN_data, + long *new_PAN_data_length, + unsigned char *new_PAN_data, + long *current_card_p_data_length, + unsigned char *current_card_p_data, + long *current_card_t_data_length, + unsigned char *current_card_t_data, + long *new_card_p_data_length, + unsigned char *new_card_p_data, + long *new_card_t_data_length, + unsigned char *new_card_t_data, + long *CMAC_FUS_length, + unsigned char *CMAC_FUS, + long *ISO_encrypted_PIN_block_length, + unsigned char *ISO_encrypted_PIN_block, + long *current_PIN_reference_value_length, + unsigned char *current_PIN_reference_value, + long *current_PRW_random_number_length, + unsigned char *current_PRW_random_number, + long *CMAC_FUS_key_identifier_length, + unsigned char *CMAC_FUS_key_identifier, + long *IPIN_encryption_key_identifier_length, + unsigned char *IPIN_encryption_key_identifier, + long *PRW_key_identifier_length, + unsigned char *PRW_key_identifier, + long *new_PRW_key_identifier_length, + unsigned char *new_PRW_key_identifier, + long *new_PIN_reference_value_length, + unsigned char *new_PIN_reference_value, + long *new_PRW_random_number_length, + unsigned char *new_PRW_random_number); + +/* DK PRW Card Number Update */ +extern void SECURITYAPI CSNBDPNU(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *card_p_data_length, + unsigned char *card_p_data, + long *card_t_data_length, + unsigned char *card_t_data, + long *encrypted_PIN_block_length, + unsigned char *encrypted_PIN_block, + long *PIN_block_MAC_length, + unsigned char *PIN_block_MAC, + long *PRW_key_identifier_length, + unsigned char *PRW_key_identifier, + long *IPIN_encryption_key_identifier_length, + unsigned char *IPIN_encryption_key_identifier, + long *IEPB_MAC_key_identifier_length, + unsigned char *IEPB_MAC_key_identifier, + long *OPIN_encryption_key_identifier_length, + unsigned char *OPIN_encryption_key_identifier, + long *OEPB_MAC_key_identifier_length, + unsigned char *OEPB_MAC_key_identifier, + long *PIN_reference_value_length, + unsigned char *PIN_reference_value, + long *PRW_random_number_length, + unsigned char *PRW_random_number, + long *new_encrypted_PIN_block_length, + unsigned char *new_encrypted_PIN_block, + long *new_PIN_block_MAC_length, + unsigned char *new_PIN_block_MAC); + +/* DK PAN Translate */ +extern void SECURITYAPI CSNBDPT(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *card_p_data_length, + unsigned char *card_p_data, + long *card_t_data_length, + unsigned char *card_t_data, + long *new_PAN_data_length, + unsigned char *new_PAN_data, + long *new_card_p_data_length, + unsigned char *new_card_p_data, + long *PIN_reference_value_length, + unsigned char *PIN_reference_value, + long *PRW_random_number_length, + unsigned char *PRW_random_number, + long *current_encrypted_PIN_block_length, + unsigned char *current_encrypted_PIN_block, + long *current_PIN_block_MAC_length, + unsigned char *current_PIN_block_MAC, + long *PRW_MAC_key_identifier_length, + unsigned char *PRW_MAC_key_identifier, + long *IPIN_encryption_key_identifier_length, + unsigned char *IPIN_encryption_key_identifier, + long *IEPB_MAC_key_identifier_length, + unsigned char *IEPB_MAC_key_identifier, + long *OPIN_encryption_key_identifier_length, + unsigned char *OPIN_encryption_key_identifier, + long *OEPB_MAC_key_identifier_length, + unsigned char *OEPB_MAC_key_identifier, + long *new_encrypted_PIN_block_length, + unsigned char *new_encrypted_PIN_block, + long *new_PIN_block_MAC_length, + unsigned char *new_PIN_block_MAC); + +/* DK PIN Verify */ +extern void SECURITYAPI CSNBDPV(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *PAN_data_length, + unsigned char *PAN_data, + long *card_data_length, + unsigned char *card_data, + long *PIN_reference_value_length, + unsigned char *PIN_reference_value, + long *PRW_random_number_length, + unsigned char *PRW_random_number, + long *ISO_encrypted_PIN_block_length, + unsigned char *ISO_encrypted_PIN_block, + long *PRW_key_identifier_length, + unsigned char *PRW_key_identifier, + long *IPIN_encryption_key_identifier_length, + unsigned char *IPIN_encryption_key_identifier); + +/* DK Regenerate PRW*/ +extern void SECURITYAPI CSNBDRP(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *card_p_data_length, + unsigned char *card_p_data, + long *card_t_data_length, + unsigned char *card_t_data, + long *encrypted_PIN_block_length, + unsigned char *encrypted_PIN_block, + long *PIN_block_MAC_length, + unsigned char *PIN_block_MAC, + long *PRW_key_identifier_length, + unsigned char *PRW_key_identifier, + long *IPIN_encryption_key_identifier_length, + unsigned char *IPIN_encryption_key_identifier, + long *IEPB_MAC_key_identifier_length, + unsigned char *IEPB_MAC_key_identifier, + long *OPIN_encryption_key_identifier_length, + unsigned char *OPIN_encryption_key_identifier, + long *OEPB_MAC_key_identifier_length, + unsigned char *OEPB_MAC_key_identifier, + long *PIN_reference_value_length, + unsigned char *PIN_reference_value, + long *PRW_random_number_length, + unsigned char *PRW_random_number, + long *new_encrypted_PIN_block_length, + unsigned char *new_encrypted_PIN_block, + long *new_PIN_block_MAC_length, + unsigned char *new_PIN_block_MAC); + +/* DK Random PIN Generate*/ +extern void SECURITYAPI CSNBDRPG(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *PAN_data_length, + unsigned char *PAN_data, + long *card_p_data_length, + unsigned char *card_p_data, + long *card_t_data_length, + unsigned char *card_t_data, + long *PIN_length, + long *PRW_key_identifier_length, + unsigned char *PRW_key_identifier, + long *PIN_print_key_identifier_length, + unsigned char *PIN_print_key_identifier, + long *OPIN_encryption_key_identifier_length, + unsigned char *OPIN_encryption_key_identifier, + long *OEPB_MAC_key_identifier_length, + unsigned char *OEPB_MAC_key_identifier, + long *PIN_reference_value_length, + unsigned char *PIN_reference_value, + long *PRW_random_number_length, + unsigned char *PRW_random_number, + long *PIN_print_block_length, + unsigned char *PIN_print_block, + long *encrypted_PIN_block_length, + unsigned char *encrypted_PIN_block, + long *PIN_block_MAC_length, + unsigned char *PIN_block_MAC); + +/* DK Deterministic PIN Generate*/ +extern void SECURITYAPI CSNBDDPG(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *account_info_ER_length, + unsigned char *account_info_ER, + long *PAN_data_length, + unsigned char *PAN_data, + long *card_p_data_length, + unsigned char *card_p_data, + long *card_t_data_length, + unsigned char *card_t_data, + long *PIN_length, + long *PIN_generation_key_identifier_length, + unsigned char *PIN_generation_key_identifier, + long *PRW_key_identifier_length, + unsigned char *PRW_key_identifier, + long *PIN_print_key_identifier_length, + unsigned char *PIN_print_key_identifier, + long *OPIN_encryption_key_identifier_length, + unsigned char *OPIN_encryption_key_identifier, + long *OEPB_MAC_key_identifier_length, + unsigned char *OEPB_MAC_key_identifier, + long *PIN_reference_value_length, + unsigned char *PIN_reference_value, + long *PRW_random_number_length, + unsigned char *PRW_random_number, + long *PIN_print_block_length, + unsigned char *PIN_print_block, + long *encrypted_PIN_block_length, + unsigned char *encrypted_PIN_block, + long *PIN_block_MAC_length, + unsigned char *PIN_block_MAC); + + +/* DES Master Key Process */ +extern void SECURITYAPI CSNBMKP(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_part); + +/* Key Export */ +extern void SECURITYAPI CSNBKEX(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_type, + unsigned char *source_key_identifier, + unsigned char *exporter_key_identifier, + unsigned char *target_key_token); + +/* Key Generate */ +extern void SECURITYAPI CSNBKGN(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_form, + unsigned char *key_length, + unsigned char *key_type_1, + unsigned char *key_type_2, + unsigned char *KEK_key_identifier_1, + unsigned char *KEK_key_identifier_2, + unsigned char *generated_key_identifier_1, + unsigned char *generated_key_identifier_2); + +/* Key Generate2 */ +extern void SECURITYAPI CSNBKGN2(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *clear_key_bit_length, + unsigned char *key_type_1, + unsigned char *key_type_2, + long *key_name_1_length, + unsigned char *key_name_1, + long *key_name_2_length, + unsigned char *key_name_2, + long *user_associated_data_1_length, + unsigned char *user_associated_data_1, + long *user_associated_data_2_length, + unsigned char *user_associated_data_2, + long *KEK_key_identifier_1_length, + unsigned char *KEK_key_identifier_1, + long *KEK_key_identifier_2_length, + unsigned char *KEK_key_identifier_2, + long *generated_key_identifier_1_length, + unsigned char *generated_key_identifier_1, + long *generated_key_identifier_2_length, + unsigned char *generated_key_identifier_2); + +/* Key Import */ +extern void SECURITYAPI CSNBKIM(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_type, + unsigned char *source_key_token, + unsigned char *importer_key_identifier, + unsigned char *target_key_identifier); + +/* Key Part Import */ +extern void SECURITYAPI CSNBKPI(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_part, + unsigned char *key_identifier); + +/* Key Part Import2 */ +extern void SECURITYAPI CSNBKPI2(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *clear_key_part_length, + unsigned char *clear_key_part, + long *key_identifier_length, + unsigned char *key_identifier); + + +/* Key Storage Initialization */ +extern void SECURITYAPI CSNBKSI(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *file_name_length, + unsigned char *file_name, + long *description_length, + unsigned char *description, + unsigned char *clear_master_key); + +/* Key Record Create */ +extern void SECURITYAPI CSNBKRC(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_label); + +/* Key Record Delete */ +extern void SECURITYAPI CSNBKRD(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_identifier); + +/* Key Record List */ +extern void SECURITYAPI CSNBKRL(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_label, + long *data_set_name_length, + unsigned char *data_set_name, + unsigned char *security_server_name); + +/* Key Record Read */ +extern void SECURITYAPI CSNBKRR(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_label, + unsigned char *key_token); + +/* Key Record Write */ +extern void SECURITYAPI CSNBKRW(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_token, + unsigned char *key_label); + +/* PKA Key Record Create */ +extern void SECURITYAPI CSNDKRC(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_label, + long *key_token_length, + unsigned char *key_token); + +/* PKA Key Record Delete */ +extern void SECURITYAPI CSNDKRD(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_identifier); + +/* PKA Key Record List */ +extern void SECURITYAPI CSNDKRL(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_label, + long *data_set_name_length, + unsigned char *data_set_name, + unsigned char *security_server_name); + +/* PKA Key Record Read */ +extern void SECURITYAPI CSNDKRR(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_label, + long *key_token_length, + unsigned char *key_token); + +/* PKA Key Record Write */ +extern void SECURITYAPI CSNDKRW(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_label, + long *key_token_length, + unsigned char *key_token); + +/* AES Key Record Create */ +extern void SECURITYAPI CSNBAKRC(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_label, + long *key_token_length, + unsigned char *key_token); + +/* AES Key Record Delete */ +extern void SECURITYAPI CSNBAKRD(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_identifier); + +/* AES Key Record List */ +extern void SECURITYAPI CSNBAKRL(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_label, + long *data_set_name_length, + unsigned char *data_set_name, + unsigned char *security_server_name); + +/* AES Key Record Read */ +extern void SECURITYAPI CSNBAKRR(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_label, + long *key_token_length, + unsigned char *key_token); + +/* AES Key Record Write */ +extern void SECURITYAPI CSNBAKRW(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_label, + long *key_token_length, + unsigned char *key_token); + +/* Key Test */ +extern void SECURITYAPI CSNBKYT(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_identifier, + unsigned char *value_1, unsigned char *value_2); + +/* Key Test Extended */ +extern void SECURITYAPI CSNBKYTX(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_identifier, + unsigned char *random_number, + unsigned char *verification_pattern, + unsigned char *kek_key_identifier); + +/* Key Test2 */ +extern void SECURITYAPI CSNBKYT2(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, + long *KEK_key_identifier_length, + unsigned char *KEK_key_identifier, + long *reserved_length, + unsigned char *reserved, + long *verification_pattern_length, + unsigned char *verification_pattern); + +/* DES Key Token Change */ +extern void SECURITYAPI CSNBKTC(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_identifier); + +/* Key Token Change 2 */ +extern void SECURITYAPI CSNBKTC2(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 */ +extern void SECURITYAPI CSNBKTR(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *input_key_token, + unsigned char *input_KEK_key_identifier, + unsigned char *output_KEK_key_identifier, + unsigned char *output_key_token); + +/* Key Translate2 */ +extern void SECURITYAPI CSNBKTR2(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *input_key_token_length, + unsigned char *input_key_token, + long *input_KEK_key_identifier_length, + unsigned char *input_KEK_key_identifier, + long *output_KEK_key_identifier_length, + unsigned char *output_KEK_key_identifier, + long *output_key_token_length, + unsigned char *output_key_token); + +/* Random Number Generate */ +extern void SECURITYAPI CSNBRNG(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *form, + unsigned char *random_number); + +/* Random Number Generate Long */ +extern void SECURITYAPI CSNBRNGL(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *reserved_length, + unsigned char *reserved, + long *random_number_length, + unsigned char *random_number); + +/* Decipher */ +extern void SECURITYAPI CSNBDEC(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_identifier, + long *text_length, + unsigned char *ciphertext, + unsigned char *initialization_vector, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *chaining_vector, + unsigned char *plaintext); + +/* Encipher */ +extern void SECURITYAPI CSNBENC(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_identifier, + long *text_length, + unsigned char *plaintext, + unsigned char *initialization_vector, + long *rule_array_count, + unsigned char *rule_array, + long *pad_character, + unsigned char *chaining_vector, + unsigned char *ciphertext); + +/* MAC Generate */ +extern void SECURITYAPI CSNBMGN(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_identifier, + long *text_length, + unsigned char *text, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *chaining_vector, + unsigned char *MAC); + +/* MAC Generate 2 */ +extern void SECURITYAPI CSNBMGN2(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, + long *message_text_length, + unsigned char *message_text, + long *chaining_vector_length, + unsigned char *chaining_vector, + long *MAC_length, unsigned char *MAC_text); + +/* MAC Verify */ +extern void SECURITYAPI CSNBMVR(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_identifier, + long *text_length, + unsigned char *text, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *chaining_vector, + unsigned char *MAC); + +/* MAC Verify 2 */ +extern void SECURITYAPI CSNBMVR2(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, + long *message_text_length, + unsigned char *message_text, + long *chaining_vector_length, + unsigned char *chaining_vector, + long *MAC_length, unsigned char *MAC_text); + +/* HMAC Generate */ +extern void SECURITYAPI CSNBHMG(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, + long *message_text_length, + unsigned char *message_text, + long *chaining_vector_length, + unsigned char *chaining_vector, + long *MAC_length, unsigned char *MAC_text); + +/* HMAC Verify */ +extern void SECURITYAPI CSNBHMV(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, + long *message_text_length, + unsigned char *message_text, + long *chaining_vector_length, + unsigned char *chaining_vector, + long *MAC_length, unsigned char *MAC_text); + +/* Key Token Build */ +extern void SECURITYAPI CSNBKTB(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_token, + unsigned char *key_type, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_value, + void *reserved_field_1, + long *reserved_field_2, + unsigned char *reserved_field_3, + unsigned char *control_vector, + unsigned char *reserved_field_4, + long *reserved_field_5, + unsigned char *reserved_field_6, + unsigned char *master_key_verification_number); + +/* Key Token Build2 */ +extern void SECURITYAPI CSNBKTB2(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *clear_key_bit_length, + unsigned char *clear_key_value, + long *key_name_length, + unsigned char *key_name, + long *user_associated_data_length, + unsigned char *user_associated_data, + long *token_data_length, + unsigned char *token_data, + long *reserved_length, + unsigned char *reserved, + long *target_key_token_length, + unsigned char *target_key_token); + +/* PKA Key Generate */ +extern void SECURITYAPI CSNDPKG(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *regeneration_data_length, + unsigned char *regeneration_data, + long *skeleton_key_token_length, + unsigned char *skeleton_key_token, + unsigned char *transport_key_identifier, + long *generated_key_identifier_length, + unsigned char *generated_key_identifier); + +/* PKA Key Token Build */ +extern void SECURITYAPI CSNDPKB(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *key_values_structure_length, + unsigned char *key_values_structure, + long *key_name_ln, + unsigned char *key_name, + long *customer_data_length, + unsigned char *customer_data, + long *reserved_2_length, + unsigned char *reserved_2, + long *reserved_3_length, + unsigned char *reserved_3, + long *reserved_4_length, + unsigned char *reserved_4, + long *reserved_5_length, + unsigned char *reserved_5, long *token_length, + unsigned char *token); + +/* One Way Hash */ +extern void SECURITYAPI CSNBOWH(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *text_length, + unsigned char *text, + long *chaining_vector_length, + unsigned char *chaining_vector, + long *hash_length, unsigned char *hash); + +/* PKA Key Import */ +extern void SECURITYAPI CSNDPKI(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *source_key_token_length, + unsigned char *source_key_token, + unsigned char *importer_key_identifier, + long *target_key_identifier_length, + unsigned char *target_key_identifier); + +/* Digital Signature Generate */ +extern void SECURITYAPI CSNDDSG(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *PKA_private_key_id_length, + unsigned char *PKA_private_key_id, + long *hash_length, + unsigned char *hash, + long *signature_field_length, + long *signature_bit_length, + unsigned char *signature_field); + +/* Digital Signature Verify */ +extern void SECURITYAPI CSNDDSV(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *PKA_public_key_id_length, + unsigned char *PKA_public_key_id, + long *hash_length, + unsigned char *hash, + long *signature_field_length, + unsigned char *signature_field); + +/* PKA Key Token Change */ +extern void SECURITYAPI CSNDKTC(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, long *key_id_length, + unsigned char *key_id); + +/* PKA Public Key Extract */ +extern void SECURITYAPI CSNDPKX(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *source_key_identifier_length, + unsigned char *source_key_identifier, + long *target_key_token_length, + unsigned char *target_key_token); + +/* PKA Symmetric Key Import */ +extern void SECURITYAPI CSNDSYI(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *RSA_enciphered_key_length, + unsigned char *RSA_enciphered_key, + long *RSA_private_key_identifier_len, + unsigned char *RSA_private_key_identifier, + long *target_key_identifier_length, + unsigned char *target_key_identifier); + +/* PKA Symmetric Key Import 2 */ +extern void SECURITYAPI CSNDSYI2(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *RSA_enciphered_key_length, + unsigned char *RSA_enciphered_key, + long *RSA_private_key_identifier_length, + unsigned char *RSA_private_key_identifier, + long *user_mod_data_length, + unsigned char *user_mod_data, + long *target_key_identifier_length, + unsigned char *target_key_identifier); + +/* PKA Symmetric Key Export */ +extern void SECURITYAPI CSNDSYX(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *source_key_identifier_length, + unsigned char *source_key_identifier, + long *RSA_public_key_identifier_len, + unsigned char *RSA_public_key_identifier, + long *RSA_enciphered_key_length, + unsigned char *RSA_enciphered_key); + +/* Crypto Facility Query */ +extern void SECURITYAPI CSUACFQ(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *verb_data_length, + unsigned char *verb_data); + +/* Crypto Facility Control */ +extern void SECURITYAPI CSUACFC(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *verb_data_length, + unsigned char *verb_data); + +/* SET Block Compose */ +extern void SECURITYAPI CSNDSBC(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *block_contents_identifier, + long *x_data_string_length, + unsigned char *x_data_string, + long *data_to_encrypt_length, + unsigned char *data_to_encrypt, + long *data_to_hash_length, + unsigned char *data_to_hash, + unsigned char *initialization_vector, + long *rsa_public_key_identifier_length, + unsigned char *rsa_public_key_identifier, + long *des_key_block_length, + unsigned char *des_key_block, + long *rsa_oaep_block_length, + unsigned char *rsa_oaep_block, + unsigned char *chaining_vector, + unsigned char *des_encrypted_data_block); + +/* SET Block Decompose */ +extern void SECURITYAPI CSNDSBD(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *rsa_oaep_block_length, + unsigned char *rsa_oaep_block, + long *des_encrypted_data_block_length, + unsigned char *des_encrypted_data_block, + unsigned char *initialization_vector, + long *rsa_private_key_identifier_length, + unsigned char *rsa_private_key_identifier, + long *des_key_block_length, + unsigned char *des_key_block, + unsigned char *block_contents_identifier, + long *x_data_string_length, + unsigned char *x_data_string, + unsigned char *chaining_vector, + unsigned char *data_block, + long *hash_block_length, + unsigned char *hash_block); + +// Symmetric Key Export with Data +extern void SECURITYAPI CSNDSXD(long *ReturnCode, + long *ReasonCode, + long *ExitDataLength, + unsigned char *ExitData, + long *RuleArrayCount, + unsigned char *RuleArray, + long *SourceKeyLength, + unsigned char *SourceKey, + long *Data_length, + long *Data_offset, + unsigned char *Data, + long *RSA_PublicKeyLength, + unsigned char *RSA_PublicKey, + long *EncipheredKeyLength, + unsigned char *EncipheredKey); + +/* Access Control Logon */ +extern void SECURITYAPI CSUALCT(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *user_id, + long *auth_parm_length, + unsigned char *auth_parm, + long *auth_data_length, + unsigned char *auth_data); + +/* Log Query */ +extern void SECURITYAPI CSUALGQ(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *log_number, + long *reserved0, + long *log_data_length, + unsigned char *log_data, + long *reserved1_length, + unsigned char *reserved1, + long *reserved2_length, + unsigned char *reserved2); + +/* Access Control Maintenance */ +extern void SECURITYAPI CSUAACM(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *name, + long *output_data_length, + unsigned char *output_data); + +/* Access Control Initialization */ +extern void SECURITYAPI CSUAACI(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *verb_data_1_length, + unsigned char *verb_data_1, + long *verb_data_2_length, + unsigned char *verb_data_2); + +/* PKA Public Key Hash Register */ +extern void SECURITYAPI CSNDPKH(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *public_key_name, + long *hash_data_length, + unsigned char *hash_data); + +/* PKA Public Key Register */ +extern void SECURITYAPI CSNDPKR(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *public_key_name, + long *public_key_certificate_length, + unsigned char *public_key_certificate); + +/* PKA Key Translate */ +extern void SECURITYAPI CSNDPKT(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *source_key_identifier_length, + unsigned char *source_key_identifier, + long *source_transport_key_identifier_length, + unsigned char *source_transport_key_identifier, + long *target_transport_key_identifier_length, + unsigned char *target_transport_key_identifier, + long *target_key_token_length, + unsigned char *target_key_token); + +/* Master Key Distribution */ +extern void SECURITYAPI CSUAMKD(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *share_index, + unsigned char *private_key_name, + unsigned char *certifying_key_name, + long *certificate_length, + unsigned char *certificate, + long *clone_info_encrypting_key_length, + unsigned char *clone_info_encrypting_key, + long *clone_info_length, + unsigned char *clone_info); + +/* Retained Key Delete */ +extern void SECURITYAPI CSNDRKD(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_label); + +/* Retained Key List */ +extern void SECURITYAPI CSNDRKL(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_label_mask, + long *retained_keys_count, + long *key_labels_count, + unsigned char *key_labels); + +/* Symmetric Key Generate */ +extern void SECURITYAPI CSNDSYG(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_encrypting_key, + long *rsapub_key_length, + unsigned char *rsapub_key, + long *locenc_key_length, + unsigned char *locenc_key, + long *rsaenc_key_length, + unsigned char *rsaenc_key); + +/* Encrypted PIN Translate */ +extern void SECURITYAPI CSNBPTR(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *in_PIN_enc_key_id, + unsigned char *out_PIN_enc_key_id, + unsigned char *in_PIN_profile, + unsigned char *in_PAN_data, + unsigned char *in_PIN_blk, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *out_PIN_profile, + unsigned char *out_PAN_data, + long *sequence_number, + unsigned char *put_PIN_blk); + +/* Encrypted PIN Translate Extended */ +extern void SECURITYAPI CSNBPTRE(long *pReturnCode, + long *pReasonCode, + long *pExitDataLength, + unsigned char *pExitData, + long *pRuleArrayCount, + unsigned char *pRuleArray, + long *pInPINEncKeyIDLength, + unsigned char *pInPINEncKeyID, + long *pOutPINEncKeyIDLength, + unsigned char *pOutPINEncKeyID, + long *pPANEncKeyIDLength, + unsigned char *pPANEncKeyID, + long *pInPINProfileLength, + unsigned char *pInPINProfile, + long *pPANDataLength, + unsigned char *pPANData, + long *pInPINBlkLength, + unsigned char *pInPINBlk, + long *pOutPINProfileLength, + unsigned char *pOutPINProfile, + long *pSequenceNumber, + long *pOutPINBlkLength, + unsigned char *pOutPINBlk, + long *pReserved1Length, + unsigned char *pReserved1, + long *pReserved2Length, + unsigned char *pReserved2); + +/* Clear PIN Encrypt */ +extern void SECURITYAPI CSNBCPE(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *PIN_enc_key_id, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *clear_PIN, + unsigned char *PIN_profile, + unsigned char *PAN_data, + long *sequence_number, + unsigned char *encrypted_PIN_blk); + +/* Clear PIN Generate Alternate */ +extern void SECURITYAPI CSNBCPA(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *PIN_enc_key_id, + unsigned char *PIN_gen_key_id, + unsigned char *PIN_profile, + unsigned char *PAN_data, + unsigned char *encrypted_PIN_blk, + long *rule_array_count, + unsigned char *rule_array, + long *PIN_check_length, + unsigned char *data_array, + unsigned char *returned_result); + +/* Clear PIN Generate */ +extern void SECURITYAPI CSNBPGN(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *PIN_gen_key_id, + long *rule_array_count, + unsigned char *rule_array, + long *PIN_length, + long *PIN_check_length, + unsigned char *data_array, + unsigned char *returned_result); + +/* Encrypted PIN Verify */ +extern void SECURITYAPI CSNBPVR(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *PIN_enc_key_id, + unsigned char *PIN_ver_key_id, + unsigned char *PIN_profile, + unsigned char *PAN_data, + unsigned char *encrypted_PIN_blk, + long *rule_array_count, + unsigned char *rule_array, + long *PIN_check_length, + unsigned char *data_array); + +/* Diversified Key Generate */ +extern void SECURITYAPI CSNBDKG(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *generating_key_id, + long *data_length, + unsigned char *data, + unsigned char *decrypting_key_id, + unsigned char *generated_key_id); + +/* Diversified Key Generate2 */ +extern void SECURITYAPI CSNBDKG2(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *generating_key_id_length, + unsigned char *generating_key_id, + long *derivation_data_length, + unsigned char *derivation_data, + long *reserved1_length, + unsigned char *reserved1, + long *reserved2_length, + unsigned char *reserved2, + long *generated_key_id1_length, + unsigned char *generated_key_id1, + long *generated_key_id2_length, + unsigned char *generated_key_id2); + +/* Encrypted PIN Generate */ +extern void SECURITYAPI CSNBEPG(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *PIN_gen_key_id, + unsigned char *outPIN_enc_key_id, + long *rule_array_count, + unsigned char *rule_array, + long *PIN_length, + unsigned char *data_array, + unsigned char *outPIN_profile, + unsigned char *PAN_data, + long *sequence_number, + unsigned char *encrypted_PIN_blk); + +/* FPE Decipher */ +extern void SECURITYAPI CSNBFPED(long *pReturnCode, + long *pReasonCode, + long *pExitDataLength, + unsigned char *pExitData, + long *pRuleArrayCount, + unsigned char *pRuleArray, + long *pEncPanLength, + unsigned char *pEncPan, + long *pEncChNameLength, + unsigned char *pEncChName, + long *pEncTrack1DdataLength, + unsigned char *pEncTrack1Ddata, + long *pEncTrack2DdataLength, + unsigned char *pEncTrack2Ddata, + long *pKeyIdentifierLength, + unsigned char *pKeyIdentifier, + long *pDerivationDataLength, + unsigned char *pDerivationData, + long *pClearPanLength, + unsigned char *pClearPan, + long *pClearChNameLength, + unsigned char *pClearChName, + long *pClearTrack1DdataLength, + unsigned char *pClearTrack1Ddata, + long *pClearTrack2DdataLength, + unsigned char *pClearTrack2Ddata, + long *pDukptPinKeyIdentifierLength, + unsigned char *pDukptPinKeyIdentifier, + long *pReserved1Length, + unsigned char *pReserved1, + long *pReserved2Length, + unsigned char *pReserved2); + +/* FPE Encipher */ +extern void SECURITYAPI CSNBFPEE(long *pReturnCode, + long *pReasonCode, + long *pExitDataLength, + unsigned char *pExitData, + long *pRuleArrayCount, + unsigned char *pRuleArray, + long *pClearPanLength, + unsigned char *pClearPan, + long *pClearChNameLength, + unsigned char *pClearChName, + long *pClearTrack1DdataLength, + unsigned char *pClearTrack1Ddata, + long *pClearTrack2DdataLength, + unsigned char *pClearTrack2Ddata, + long *pKeyIdentifierLength, + unsigned char *pKeyIdentifier, + long *pDerivationDataLength, + unsigned char *pDerivationData, + long *pEncPanLength, + unsigned char *pEncPan, + long *pEncChNameLength, + unsigned char *pEncChName, + long *pEncTrack1DdataLength, + unsigned char *pEncTrack1Ddata, + long *pEncTrack2DdataLength, + unsigned char *pEncTrack2Ddata, + long *pDukptPinKeyIdentifierLength, + unsigned char *pDukptPinKeyIdentifier, + long *pReserved1Length, + unsigned char *pReserved1, + long *pReserved2Length, + unsigned char *pReserved2); + +/* FPE_Translate */ +extern void SECURITYAPI CSNBFPET(long *pReturnCode, + long *pReasonCode, + long *pExitDataLength, + unsigned char *pExitData, + long *pRuleArrayCount, + unsigned char *pRuleArray, + long *pInputPanLength, + unsigned char *pInputPan, + long *pInputChNameLength, + unsigned char *pInputChName, + long *pInputTrack1DdataLength, + unsigned char *pInputTrack1Ddata, + long *pInputTrack2DdataLength, + unsigned char *pInputTrack2Ddata, + long *pInputKeyIdentifierLength, + unsigned char *pInputKeyIdentifier, + long *pOutputKeyIdentifierLength, + unsigned char *pOutputKeyIdentifier, + long *pDerivationDataLength, + unsigned char *pDerivationData, + long *pOutputPanLength, + unsigned char *pOutputPan, + long *pOutputChNameLength, + unsigned char *pOutputChName, + long *pOutputTrack1DdataLength, + unsigned char *pOutputTrack1Ddata, + long *pOutputTrack2DdataLength, + unsigned char *pOutputTrack2Ddata, + long *pDukptPinKeyIdentifierLength, + unsigned char *pDukptPinKeyIdentifier, + long *pReserved1Length, + unsigned char *pReserved1, + long *pReserved2Length, + unsigned char *pReserved2); + +/* Cryptographic Variable Encipher */ +extern void SECURITYAPI CSNBCVE(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *cvarenc_key_id, + long *text_length, + unsigned char *plain_text, + unsigned char *init_vector, + unsigned char *cipher_text); + +/* CVV Generate */ +extern void SECURITYAPI CSNBCSG(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *PAN_data, + unsigned char *expiration_date, + unsigned char *service_code, + unsigned char *key_a_id, + unsigned char *key_b_id, + unsigned char *generated_cvv); + +/* CVV Verify */ +extern void SECURITYAPI CSNBCSV(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *PAN_data, + unsigned char *expiration_date, + unsigned char *service_code, + unsigned char *key_a_id, + unsigned char *key_b_id, + unsigned char *generated_cvv); + +/* Control Vector Generate */ +extern void SECURITYAPI CSNBCVG(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_type, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *reserved_field_1, + unsigned char *control_vector); + +/* Key Token Parse */ +extern void SECURITYAPI CSNBKTP(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_token, + unsigned char *key_type, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_value, + void *master_key_verification_pattern_v03, + long *reserved_field_2, + unsigned char *reserved_field_3, + unsigned char *control_vector, + unsigned char *reserved_field_4, + long *reserved_field_5, + unsigned char *reserved_field_6, + unsigned char + *master_key_verification_pattern_v00); + +/* Key Token Parse2 */ +extern void SECURITYAPI CSNBKTP2(long *pReturnCode, + long *pReasonCode, + long *pExitDataLength, + unsigned char *pExitData, + long *pKeyTokenLength, + unsigned char *pKeyToken, + unsigned char *pKeyType, + long *pRuleArrayCount, + unsigned char *pRuleArray, + long *pKeyMaterialState, + long *pPayloadBitLength, + unsigned char *pPayload, + long *pKeyVerificationType, + long *pKeyVerificationPatternLength, + unsigned char *pKeyVerificationPattern, + long *pKeyWrappingMethod, + long *pKeyHashMethod, + long *pKeyNameLength, + unsigned char *pKeyName, + long *pTLVDataLength, + unsigned char *pTLVData, + long *pUserAssocDataLength, + unsigned char *pUserAssocData, + long *pReservedLength, + unsigned char *pReserved); + +/* PKA Encrypt */ +extern void SECURITYAPI CSNDPKE(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *key_value_length, + unsigned char *key_value, + long *data_struct_length, + unsigned char *data_struct, + long *RSA_public_key_length, + unsigned char *RSA_public_key, + long *RSA_encipher_length, + unsigned char *RSA_encipher); + +/* PKA Decrypt */ +extern void SECURITYAPI CSNDPKD(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *enciphered_key_length, + unsigned char *enciphered_key, + long *data_struct_length, + unsigned char *data_struct, + long *RSA_private_key_length, + unsigned char *RSA_private_key, + long *key_value_length, + unsigned char *key_value); + +/* Prohibit Export */ +extern void SECURITYAPI CSNBPEX(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *key_identifier); + +/* Prohibit Export Extended */ +extern void SECURITYAPI CSNBPEXX(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *Source_key_token, + unsigned char *Kek_key_identifier); + +/* Prohibit Export 2 */ +extern void SECURITYAPI CSNBPEX2(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, + long *KEK_key_identifier_length, + unsigned char *KEK_key_identifier); + +/* Pin From Offset */ +extern void SECURITYAPI CSNBPFO(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *PIN_enc_key_id_length, + unsigned char *PIN_enc_key_id, + long *PIN_gen_key_id_length, + unsigned char *PIN_gen_key_id, + unsigned char *PIN_profile, + unsigned char *PAN_data, + unsigned char *offset, + long *reserved_1, + unsigned char *data_array, + long *encrypted_PIN_blk_length, + unsigned char *encrypted_PIN_blk); + +/* Restrict Key Attribute */ +extern void SECURITYAPI CSNBRKA(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, + long *KEK_key_identifier_length, + unsigned char *KEK_key_identifier, + long *opt_parameter1_length, + unsigned char *opt_parameter1, + long *opt_parameter2_length, + unsigned char *opt_parameter2); + + +/* Random Number/Known Answer Test */ +extern void SECURITYAPI CSUARNT(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array); + +/* Control Vector Translate */ +extern void SECURITYAPI CSNBCVT(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + unsigned char *kek_key_identifier, + unsigned char *source_key_token, + unsigned char *array_key_left, + unsigned char *mask_array_left, + unsigned char *array_key_right, + unsigned char *mask_array_right, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *target_key_token); + +/* MDC Generate */ +extern void SECURITYAPI CSNBMDG(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *text_length, + unsigned char *text_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *chaining_vector, + unsigned char *MDC); + +/* Cryptographic Resource Allocate */ +extern void SECURITYAPI CSUACRA(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *resource_name_length, + unsigned char *resource_name); + +/* Cryptographic Resource Deallocate */ +extern void SECURITYAPI CSUACRD(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *resource_name_length, + unsigned char *resource_name); + +/* Transaction Validation */ +extern void SECURITYAPI CSNBTRV(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *transaction_key_length, + unsigned char *transaction_key, + long *transaction_info_length, + unsigned char *transaction_info, + long *validation_values_length, + unsigned char *validation_values); + +/* Secure Messaging for Keys */ +extern void SECURITYAPI CSNBSKY(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *input_key_indentifier, + unsigned char *key_encrypting_key, + unsigned char *session_key, + long *text_length, + unsigned char *clear_text, + unsigned char *initialization_vector, + long *key_offset, + long *key_offset_field_length, + unsigned char *cipher_text, + unsigned char *output_chaining_value); + +/* Secure Messaging for PINs */ +extern void SECURITYAPI CSNBSPN(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *in_PIN_blk, + unsigned char *in_PIN_enc_key_id, + unsigned char *in_PIN_profile, + unsigned char *in_PAN_data, + unsigned char *secmsg_key, + unsigned char *out_PIN_profile, + unsigned char *out_PAN_data, + long *text_length, + unsigned char *clear_text, + unsigned char *initialization_vector, + long *PIN_offset, + long *PIN_offset_field_length, + unsigned char *cipher_text, + unsigned char *output_chaining_value); + +/* PIN Change/Unblock */ +extern void SECURITYAPI CSNBPCU(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *authenticationMasterKeyLength, + unsigned char *authenticationMasterKey, + long *issuerMasterKeyLength, + unsigned char *issuerMasterKey, + long *keyGenerationDataLength, + unsigned char *keyGenerationData, + long *newRefPinKeyLength, + unsigned char *newRefPinKey, + unsigned char *newRefPinBlock, + unsigned char *newRefPinProfile, + unsigned char *newRefPanData, + long *currentRefPinKeyLength, + unsigned char *currentRefPinKey, + unsigned char *currentRefPinBlock, + unsigned char *currentRefPinProfile, + unsigned char *currentRefPanData, + long *outputPinDataLength, + unsigned char *outputPinData, + unsigned char *outputPinProfile, + long *outputPinMessageLength, + unsigned char *outputPinMessage); + +/* DUKPT Key Generate verb */ +void SECURITYAPI CSNBUKD(long *ReturnCode, + long *ReasonCode, + long *ExitDataLength, + unsigned char *ExitData, + long *pRuleArrayCount, + unsigned char *RuleArray, + long *pBaseDerivationKeyIdentifierLength, + unsigned char *pBaseDerivationKeyIdentifier, + long *pDerivationDataLength, + unsigned char *pDerivationData, + long *pGeneratedKeyIdentifier1Length, + unsigned char *GeneratedKeyIdentifier1, + long *pGeneratedKeyIdentifier2Length, + unsigned char *GeneratedKeyIdentifier2, + long *pGeneratedKeyIdentifier3Length, + unsigned char *GeneratedKeyIdentifier3, + long *pTransportKeyIdentifierLength, + unsigned char *TransportKeyIdentifier, + long *pReserved2Length, + unsigned char *Reserved2, + long *pReserved3Length, + unsigned char *Reserved3, + long *pReserved4Length, + unsigned char *Reserved4, + long *pReserved5Length, + unsigned char *Reserved5, + long *pReserved6Length, unsigned char *Reserved6); + +/*Translate Characters */ +extern void SECURITYAPI CSNBXEA(long *ReturnCode, + long *ReasonCode, + long *ExitDataLength, + unsigned char *ExitData, + long *RuleArrayCount, + unsigned char *RuleArray, + long *TextLength, + unsigned char *SourceText, + unsigned char *TargetText, + long *CodeTableLength, + unsigned char *CodeTable); + +/*Process Request Block*/ +extern void SECURITYAPI CSUAPRB(long *pReturnCode, + long *pReasonCode, + long *pExitDataLength, + unsigned char *pExitData, + long *pRuleArrayCount, + unsigned char *pRuleArray, + long *pSourceLength, + unsigned char *pSource, + long *pOutFileNameLength, + unsigned char *pOutFileName, long *pReplyLength, + unsigned char *pReply); + +/* Trusted Block Create */ +extern void SECURITYAPI CSNDTBC(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *input_block_length, + unsigned char *input_block_identifier, + unsigned char *transport_key_identifier, + long *trusted_block_length, + unsigned char *trusted_block_identifier); + +/* Remote Key Export */ +extern void SECURITYAPI CSNDRKX(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *trusted_block_length, + unsigned char *trusted_block_identifier, + long *certificate_length, + unsigned char *certificate, + long *certificate_parms_length, + unsigned char *certificate_parms, + long *transport_key_length, + unsigned char *transport_key_identifier, + long *rule_id_length, + unsigned char *rule_id, + long *export_key_kek_length, + unsigned char *export_key_kek_identifier, + long *export_key_length, + unsigned char *export_key_identifier, + long *asym_encrypted_key_length, + unsigned char *asym_encrypted_key, + long *sym_encrypted_key_length, + unsigned char *sym_encrypted_key, + long *extra_data_length, + unsigned char *extra_data, + long *key_check_parameters_length, + unsigned char *key_check_parameters, + long *key_check_length, + unsigned char *key_check_value); + +/* Key Encryption Translate */ +extern void SECURITYAPI CSNBKET(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *kek_identifier_length, + unsigned char *kek_identifier, + long *key_in_length, + unsigned char *key_in, long *key_out_length, + unsigned char *key_out); + +/* Symmetric Algorithm Encipher */ +extern void SECURITYAPI CSNBSAE(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *key_length, + unsigned char *key_identifier, + long *key_parms_length, + unsigned char *key_parms, + long *block_size, + long *initialization_vector_length, + unsigned char *initialization_vector, + long *chain_data_length, + unsigned char *chain_data, + long *clear_text_length, + unsigned char *clear_text, + long *cipher_text_length, + unsigned char *cipher_text, + long *optional_data_length, + unsigned char *optional_data); + +/* Symmetric Algorithm Decipher */ +extern void SECURITYAPI CSNBSAD(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *key_length, + unsigned char *key_identifier, + long *key_parms_length, + unsigned char *key_parms, + long *block_size, + long *initialization_vector_length, + unsigned char *initialization_vector, + long *chain_data_length, + unsigned char *chain_data, + long *cipher_text_length, + unsigned char *cipher_text, + long *clear_text_length, + unsigned char *clear_text, + long *optional_data_length, + unsigned char *optional_data); + +/* Crypto Facility Version (SAPI_ONLY) */ +extern void SECURITYAPI CSUACFV(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *version_data_length, + unsigned char *version_data); + +/* TR-31 Optional Data Build */ +extern void SECURITYAPI CSNBT31O(long *pReturnCode, + long *pReasonCode, + long *pExitDataLength, + unsigned char *pExitData, + long *pRuleArrayCount, + unsigned char *pRuleArray, + long *pOptBlocksBfrLength, + long *pOptBlocksLength, + unsigned char *pOptBlocks, + long *pNumOptBlocks, + unsigned char *pOptBlockID, + long *pOptBlockDataLength, + unsigned char *pOptBlockData); + +/* TR-31 Key Token Parse */ +extern void SECURITYAPI CSNBT31P(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *tr31_key_length, + unsigned char *tr31_key, + unsigned char *key_block_version, + long *key_block_length, + unsigned char *key_usage, + unsigned char *algorithm, + unsigned char *mode, + unsigned char *key_version_number, + unsigned char *exportability, + long *num_opt_blocks); + +/* TR-31 Key Import */ +extern void SECURITYAPI CSNBT31I(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *tr31_key_block_length, + unsigned char *tr31_key_block, + long *unwrap_kek_identifier_length, + unsigned char *unwrap_kek_identifier, + long *wrap_kek_identifier_length, + unsigned char *wrap_kek_identifier, + long *output_key_identifier_length, + unsigned char *output_key_identifier, + long *num_opt_blks, long *cv_source, + long *protection_method); + +/* TR-31 Key Export */ +extern void SECURITYAPI CSNBT31X(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *key_version_number, + long *key_field_length, + long *source_key_identifier_length, + unsigned char *source_key_identifier, + long *unwrap_kek_identifier_length, + unsigned char *unwrap_kek_identifier, + long *wrap_kek_identifier_length, + unsigned char *wrap_kek_identifier, + long *opt_blks_length, + unsigned char *opt_blks, + long *tr31_key_block_length, + unsigned char *tr31_key_block); + +/* TR-31 Optional Data Read */ +extern void SECURITYAPI CSNBT31R(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *tr31_key_length, + unsigned char *tr31_key, + unsigned char *opt_block_id, + long *num_opt_blocks, + unsigned char *opt_block_ids, + unsigned char *opt_block_lengths, + long *opt_block_data_length, + unsigned char *opt_block_data); + +/* Elliptic Curve Diffie-Hellman */ +extern void SECURITYAPI CSNDEDH(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *private_key_identifier_length, + unsigned char *private_key_identifier, + long *private_KEK_key_identifier_length, + unsigned char *private_KEK_key_identifier, + long *public_key_identifier_length, + unsigned char *public_key_identifier, + long *chaining_vector_length, + unsigned char *chaining_vector, + long *party_identifier_length, + unsigned char *party_identifier, + long *key_bit_length, + long *reserved_length, + unsigned char *reserved, + long *reserved2_length, + unsigned char *reserved2, + long *reserved3_length, + unsigned char *reserved3, + long *reserved4_length, + unsigned char *reserved4, + long *reserved5_length, + unsigned char *reserved5, + long *output_KEK_key_identifier_length, + unsigned char *output_KEK_key_identifier, + long *output_key_identifier_length, + unsigned char *output_key_identifier); + +/* Cipher Text Translate 2 */ +extern void SECURITYAPI CSNBCTT2(long *pReturnCode, + long *pReasonCode, + long *pExitDataLength, + unsigned char *pExitData, + long *pRuleArrayCount, + unsigned char *pRuleArray, + long *pKeyIdInLen, + unsigned char *pKeyIdIn, + long *pInitVectorInLen, + unsigned char *pInitVectorIn, + long *pCipherTextInLen, + unsigned char *pCipherTextIn, + long *pChainingVectorLen, + unsigned char *pChainingVector, + long *pKeyIdOutLen, + unsigned char *pKeyIdOut, + long *pInitVectorOutLen, + unsigned char *pInitVectorOut, + long *pCipherTextOutLen, + unsigned char *pCipherTextOut, + long *pReserved1Len, + unsigned char *pReserved1, + long *pReserved2Len, + unsigned char *pReserved2); + + +#ifdef TKE_WKSTN +/* Diffie-Hellman Key Load */ +extern void SECURITYAPI CSUADHK(long *ReturnCode, + long *ReasonCode, + long *ExitDataLength, + unsigned char *ExitData, + long *RuleArrayCount, + unsigned char *RuleArray, + unsigned char *DHModulus, + unsigned char *DHGenerator, + unsigned char *DHKeyPart, + long *TransportKeyHashLength, + unsigned char *TransportKeyHash, + long *DHModulusLength, + unsigned char *PartyID, + unsigned char *Reserved1, + unsigned char *Reserved2); + +/* Diffie-Hellman Key Query */ +extern void SECURITYAPI CSUADHQ(long *ReturnCode, + long *ReasonCode, + long *ExitDataLength, + unsigned char *ExitData, + long *RuleArrayCount, + unsigned char *RuleArray, + unsigned char *DHModulus, + unsigned char *DHGenerator, + unsigned char *DHKeyPart, + long *TransportKeyHashLength, + unsigned char *TransportKeyHash, + long *DHModulusLength, + unsigned char *PartyID, + unsigned char *Reserved1, + unsigned char *Reserved2); + +/* Certificate Import Export */ +extern void SECURITYAPI CSUACIE(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *public_key_certificate_length, + unsigned char *public_key_certificate); + +/* Random Number Extend */ +extern void SECURITYAPI CSUARNX(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *key_length, + unsigned char *key, + long *rnum_length, + unsigned char *rnum, + long *rnum_hash_length, + unsigned char *rnum_hash, + long *sk_hash_length, + unsigned char *sk_hash, + long *secdata_length, + unsigned char *secdata, long *optdata_length, + unsigned char *optdata); + +/* Session Key Establish */ +extern void SECURITYAPI CSUASKE(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + long *cert_in_length, + unsigned char *cert_in, + long *cert_out_length, + unsigned char *cert_out, + long *key_block_length, + unsigned char *key_block, + long *key_signature_length, + unsigned char *key_signature, + long *key_vp_length, + unsigned char *key_vp, long *rnum_length, + unsigned char *rnum); + +/* Key Transport to Export */ +extern void SECURITYAPI CSUAKTX(long *ReturnCode, + long *ReasonCode, + long *ExitDataLength, + unsigned char *ExitData, + long *rule_array_count, + unsigned char *rule_array, + long *key_data_length, + unsigned char *key_data, + long *secure_data_length, + unsigned char *secure_data, + long *key_data_vp_length, + unsigned char *key_data_vp, + long *session_key_vp_length, + unsigned char *session_key_vp, + long *xport_key_vp_length, + unsigned char *xport_key_vp, + long *xlt_key_data_length, + unsigned char *xlt_key_data, + long *xlt_secure_data_length, + unsigned char *xlt_secure_data); + +/* Master Key Process Extended */ +extern void SECURITYAPI CSUAMKX(long *return_code, + long *reason_code, + long *exit_data_length, + unsigned char *exit_data, + long *rule_array_count, + unsigned char *rule_array, + unsigned char *Key_part, + long *Seskey_vp_length, + unsigned char *Seskey_vp, + long *Keypart_vp_length, + unsigned char *Keypart_vp); + +/* Key Part Import Extended */ +extern void SECURITYAPI CSUAKIX(long *pReturnCode, + long *pReasonCode, + long *pExitDataLength, + unsigned char *pExitData, + long *pRuleArrayCount, + unsigned char *pRuleArray, + unsigned char *pKeyPart, + unsigned char *pKeyIdentifier, + long *pSeskey_vp_length, + unsigned char *pSeskey_vp, + long *pKeypart_vp_length, + unsigned char *pKeypart_vp); + + +#endif // TKE_WKSTN +#endif // __CSULINCL__ diff --git a/usr/lib/cca_stdll/defs.h b/usr/lib/cca_stdll/defs.h new file mode 100644 index 0000000..ea73520 --- /dev/null +++ b/usr/lib/cca_stdll/defs.h @@ -0,0 +1,43 @@ +/* + * 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: defs.h + * + * Contains various definitions needed by both the host-side + * and coprocessor-side code. + */ + +#ifndef _CCA_DEFS_H +#define _CCA_DEFS_H + +#include "../common/defs.h" + +#undef MAX_PIN_LEN +#undef MIN_PIN_LEN +#define MAX_PIN_LEN 128 +#define MIN_PIN_LEN 4 + +#define CCA_CHAIN_VECTOR_LEN 128 +#define CCA_HASH_PART_FIRST 0 +#define CCA_HASH_PART_MIDDLE 1 +#define CCA_HASH_PART_LAST 2 +#define CCA_HASH_PART_ONLY 3 + +struct cca_sha_ctx { + unsigned char chain_vector[CCA_CHAIN_VECTOR_LEN]; + long chain_vector_len; + unsigned char tail[MAX_SHA_BLOCK_SIZE]; + long tail_len; + unsigned char hash[MAX_SHA_HASH_SIZE]; + long hash_len; + int part; +}; + +#endif diff --git a/usr/lib/cca_stdll/tok_struct.h b/usr/lib/cca_stdll/tok_struct.h new file mode 100644 index 0000000..39d19c1 --- /dev/null +++ b/usr/lib/cca_stdll/tok_struct.h @@ -0,0 +1,134 @@ +/* + * 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 + */ + +/* + * openCryptoki CCA token + * + */ + +#ifndef __TOK_STRUCT_H +#define __TOK_STRUCT_H +#include + +#include "tok_spec_struct.h" + +#ifndef CCA_CONFIG_PATH + +#ifndef CONFIG_PATH +#warning CONFIG_PATH not set, using default (/usr/local/var/lib/opencryptoki) +#define CONFIG_PATH "/usr/local/var/lib/opencryptoki" +#endif // #ifndef CONFIG_PATH + +#define CCA_CONFIG_PATH CONFIG_PATH "/ccatok" +#endif // #ifndef CCA_CONFIG_PATH + +token_spec_t token_specific = { + CCA_CONFIG_PATH, + "ccatok", + 64, + // Token data info: + { + FALSE, // Don't use per guest data store + TRUE, // Use master key + CKM_DES3_CBC, // Data store encryption + (CK_BYTE *)"12345678", // Default initialization vector for pins + (CK_BYTE *)"10293847", // Default initialization vector for objects + }, + NULL, // creatlock + NULL, // attach_shm + &token_specific_init, + NULL, // init_token_data + NULL, // load_token_data + NULL, // save_token_data + &token_specific_rng, + &token_specific_final, + NULL, // init_token + NULL, // login + NULL, // logout + NULL, // init_pin + NULL, // set_pin + // DES + &token_specific_des_key_gen, + &token_specific_des_ecb, + &token_specific_des_cbc, + // Triple DES + &token_specific_tdes_ecb, + &token_specific_tdes_cbc, + NULL, // tdes_ofb + NULL, // tdes_cfb + NULL, // tdes_mac + NULL, // tdes_cmac + // RSA + &token_specific_rsa_decrypt, + &token_specific_rsa_encrypt, + &token_specific_rsa_sign, + &token_specific_rsa_verify, + NULL, // rsa_verify_recover + NULL, // rsa_x509_decrypt + NULL, // rsa_x509_encrypt + NULL, // rsa_x509_sign + NULL, // rsa_x509_verify + NULL, // rsa_x509_verify_recover + NULL, // rsa_oaep_decrypt + NULL, // rsa_oaep_encrypt + NULL, // rsa_pss_sign + NULL, // rsa_pss_verify + &token_specific_rsa_generate_keypair, + // Elliptic Curve + &token_specific_ec_sign, + &token_specific_ec_verify, + &token_specific_ec_generate_keypair, + NULL, // ecdh_derive + NULL, // dh_pkcs_derive + NULL, // dh_pkcs_key_pair_gen + // SHA + token_specific_sha_init, + token_specific_sha, + token_specific_sha_update, + token_specific_sha_final, + // HMAC + &token_specific_hmac_sign_init, + &token_specific_hmac_sign, + &token_specific_hmac_sign_update, + &token_specific_hmac_sign_final, + &token_specific_hmac_verify_init, + &token_specific_hmac_verify, + &token_specific_hmac_verify_update, + &token_specific_hmac_verify_final, + &token_specific_generic_secret_key_gen, +#ifndef NOAES + // AES + &token_specific_aes_key_gen, + &token_specific_aes_ecb, + &token_specific_aes_cbc, +#else + NULL, + NULL, + NULL, +#endif + NULL, // aes_ctr + NULL, // aes_gcm_init, + NULL, // aes_gcm + NULL, // aes_gcm_update + NULL, // aes_gcm_final + NULL, // aes_ofb + NULL, // aes_cfb + NULL, // aes_mac + NULL, // aes_cmac + // DSA + NULL, // dsa_generate_keypair + NULL, // dsa_sign + NULL, // dsa_verify + &token_specific_get_mechanism_list, + &token_specific_get_mechanism_info, + &token_specific_object_add +}; + +#endif diff --git a/usr/lib/common/asn1.c b/usr/lib/common/asn1.c new file mode 100644 index 0000000..01d600c --- /dev/null +++ b/usr/lib/common/asn1.c @@ -0,0 +1,4285 @@ +/* + * 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 + */ + +// ASN.1 encoding/decoding routines +// +// This code is a mess... +// + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "p11util.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "trace.h" + + +// +// +CK_ULONG ber_encode_INTEGER(CK_BBOOL length_only, + CK_BYTE **ber_int, + CK_ULONG *ber_int_len, CK_BYTE *data, + CK_ULONG data_len) +{ + CK_BYTE *buf = NULL; + CK_ULONG len, padding = 0; + + // ber encoded integers are alway signed. So if the msb of the first byte + // is set, this would indicate an negative value if we just copy the + // (unsigned) big integer from *data to the ber buffer. So in this case + // a preceding 0x00 byte is stored before the actual data. The decode + // function does the reverse and may skip this padding. + + if ((length_only && data_len && (!data || *data & 0x80)) + || (data_len && data && *data & 0x80)) + padding = 1; + + // if data_len < 127 use short-form length id + // if data_len < 256 use long-form length id with 1-byte length field + // if data_len < 65536 use long-form length id with 2-byte length field + // if data_len < 16777216 use long-form length id with 3-byte length field + // + if (data_len + padding < 128) { + len = 1 + 1 + padding + data_len; + } else if (data_len + padding < 256) { + len = 1 + (1 + 1) + padding + data_len; + } else if (data_len + padding < (1 << 16)) { + len = 1 + (1 + 2) + padding + data_len; + } else if (data_len + padding < (1 << 24)) { + len = 1 + (1 + 3) + padding + data_len; + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + if (length_only == TRUE) { + *ber_int_len = len; + return CKR_OK; + } + + buf = (CK_BYTE *) malloc(len); + if (!buf) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + if (data_len + padding < 128) { + buf[0] = 0x02; + buf[1] = data_len + padding; + if (padding) { + buf[2] = 0x00; + if (data && data_len) + memcpy(&buf[3], data, data_len); + } else { + if (data && data_len) + memcpy(&buf[2], data, data_len); + } + *ber_int_len = len; + *ber_int = buf; + return CKR_OK; + } + + if (data_len + padding < 256) { + buf[0] = 0x02; + buf[1] = 0x81; + buf[2] = data_len + padding; + if (padding) { + buf[3] = 0x00; + if (data && data_len) + memcpy(&buf[4], data, data_len); + } else { + if (data && data_len) + memcpy(&buf[3], data, data_len); + } + *ber_int_len = len; + *ber_int = buf; + return CKR_OK; + } + + if (data_len + padding < (1 << 16)) { + buf[0] = 0x02; + buf[1] = 0x82; + buf[2] = ((data_len + padding) >> 8) & 0xFF; + buf[3] = ((data_len + padding)) & 0xFF; + if (padding) { + buf[4] = 0x00; + if (data && data_len) + memcpy(&buf[5], data, data_len); + } else { + if (data && data_len) + memcpy(&buf[4], data, data_len); + } + *ber_int_len = len; + *ber_int = buf; + return CKR_OK; + } + + if (data_len + padding < (1 << 24)) { + buf[0] = 0x02; + buf[1] = 0x83; + buf[2] = ((data_len + padding) >> 16) & 0xFF; + buf[3] = ((data_len + padding) >> 8) & 0xFF; + buf[4] = ((data_len + padding)) & 0xFF; + if (padding) { + buf[5] = 0x00; + if (data) + memcpy(&buf[6], data, data_len); + } else { + if (data) + memcpy(&buf[5], data, data_len); + } + *ber_int_len = len; + *ber_int = buf; + return CKR_OK; + } + // we should never reach this + // + free(buf); + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + + +// +// +CK_RV ber_decode_INTEGER(CK_BYTE *ber_int, + CK_BYTE **data, CK_ULONG *data_len, + CK_ULONG *field_len) +{ + CK_ULONG len, length_octets; + + if (!ber_int) { + TRACE_ERROR("Invalid function argument.\n"); + return CKR_FUNCTION_FAILED; + } + if (ber_int[0] != 0x02) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + // ber encoded integers are alway signed. So it may be that the very first + // byte is just a padding 0x00 value because the following byte has the msb + // set and without the padding the value would indicate a negative value. + // However, opencryptoki always stores big integers 'unsigned' meaning + // even when the msb is set, there is no preceding 0x00. Even more some + // tests may fail e.g. the size in bytes of a modulo big integer should be + // modulo bits / 8 which is not true with preceeding 0x00 byte. + + // short form lengths are easy + // + if ((ber_int[1] & 0x80) == 0) { + len = ber_int[1] & 0x7F; + *data = &ber_int[2]; + *data_len = len; + if (ber_int[2] == 0x00) { + *data = &ber_int[3]; + *data_len = len - 1; + } + *field_len = 1 + 1 + len; + return CKR_OK; + } + + length_octets = ber_int[1] & 0x7F; + + if (length_octets == 1) { + len = ber_int[2]; + *data = &ber_int[3]; + *data_len = len; + if (ber_int[3] == 0x00) { + *data = &ber_int[4]; + *data_len = len - 1; + } + *field_len = 1 + (1 + 1) + len; + return CKR_OK; + } + + if (length_octets == 2) { + len = ber_int[2]; + len = len << 8; + len |= ber_int[3]; + *data = &ber_int[4]; + *data_len = len; + if (ber_int[4] == 0x00) { + *data = &ber_int[5]; + *data_len = len - 1; + } + *field_len = 1 + (1 + 2) + len; + return CKR_OK; + } + + if (length_octets == 3) { + len = ber_int[2]; + len = len << 8; + len |= ber_int[3]; + len = len << 8; + len |= ber_int[4]; + *data = &ber_int[5]; + *data_len = len; + if (ber_int[5] == 0x00) { + *data = &ber_int[6]; + *data_len = len - 1; + } + *field_len = 1 + (1 + 3) + len; + return CKR_OK; + } + // > 3 length octets implies a length > 16MB which isn't possible for + // the coprocessor + // + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + + +// +// +CK_RV ber_encode_OCTET_STRING(CK_BBOOL length_only, + CK_BYTE **str, + CK_ULONG *str_len, CK_BYTE *data, + CK_ULONG data_len) +{ + CK_BYTE *buf = NULL; + CK_ULONG len; + + // I only support Primitive encoding for OCTET STRINGS + // + + // if data_len < 128 use short-form length id + // if data_len < 256 use long-form length id with 1-byte length field + // if data_len < 65536 use long-form length id with 2-byte length field + // + + if (data_len < 128) { + len = 1 + 1 + data_len; + } else if (data_len < 256) { + len = 1 + (1 + 1) + data_len; + } else if (data_len < (1 << 16)) { + len = 1 + (1 + 2) + data_len; + } else if (data_len < (1 << 24)) { + len = 1 + (1 + 3) + data_len; + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + if (length_only == TRUE) { + *str_len = len; + return CKR_OK; + } + + buf = (CK_BYTE *) malloc(len); + if (!buf) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + if (data_len < 128) { + buf[0] = 0x04; // primitive, OCTET STRING + buf[1] = data_len; + memcpy(&buf[2], data, data_len); + + *str_len = len; + *str = buf; + return CKR_OK; + } + + if (data_len < 256) { + buf[0] = 0x04; // primitive, OCTET STRING + buf[1] = 0x81; // length header -- 1 length octets + buf[2] = data_len; + + memcpy(&buf[3], data, data_len); + + *str_len = len; + *str = buf; + return CKR_OK; + } + + if (data_len < (1 << 16)) { + buf[0] = 0x04; // primitive, OCTET STRING + buf[1] = 0x82; // length header -- 2 length octets + buf[2] = (data_len >> 8) & 0xFF; + buf[3] = (data_len) & 0xFF; + + memcpy(&buf[4], data, data_len); + + *str_len = len; + *str = buf; + return CKR_OK; + } + + if (data_len < (1 << 24)) { + buf[0] = 0x04; // primitive, OCTET STRING + buf[1] = 0x83; // length header -- 3 length octets + buf[2] = (data_len >> 16) & 0xFF; + buf[3] = (data_len >> 8) & 0xFF; + buf[4] = (data_len) & 0xFF; + + memcpy(&buf[5], data, data_len); + + *str_len = len; + *str = buf; + return CKR_OK; + } + // we should never reach this + // + free(buf); + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + + +// +// +CK_RV ber_decode_OCTET_STRING(CK_BYTE *str, + CK_BYTE **data, + CK_ULONG *data_len, CK_ULONG *field_len) +{ + CK_ULONG len, length_octets; + + // I only support decoding primitive OCTET STRINGS + // + + if (!str) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + if (str[0] != 0x04) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + // short form lengths are easy + // + if ((str[1] & 0x80) == 0) { + len = str[1] & 0x7F; + + *data = &str[2]; + *data_len = len; + *field_len = 1 + (1) + len; + return CKR_OK; + } + + length_octets = str[1] & 0x7F; + + if (length_octets == 1) { + len = str[2]; + + *data = &str[3]; + *data_len = len; + *field_len = 1 + (1 + 1) + len; + return CKR_OK; + } + + if (length_octets == 2) { + len = str[2]; + len = len << 8; + len |= str[3]; + + *data = &str[4]; + *data_len = len; + *field_len = 1 + (1 + 2) + len; + return CKR_OK; + } + + if (length_octets == 3) { + len = str[2]; + len = len << 8; + len |= str[3]; + len = len << 8; + len |= str[4]; + + *data = &str[5]; + *data_len = len; + *field_len = 1 + (1 + 3) + len; + return CKR_OK; + } + // > 3 length octets implies a length > 16MB + // + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + +/** + * Here we assume that the indication about unused bits is NOT + * part of the data. It will be added by this function. + */ +CK_ULONG ber_encode_BIT_STRING(CK_BBOOL length_only, + CK_BYTE **ber_str, + CK_ULONG *ber_str_len, CK_BYTE *data, + CK_ULONG data_len, + CK_BYTE unused_bits) +{ + CK_BYTE *buf = NULL; + CK_ULONG len; + + // if data_len < 127 use short-form length id + // if data_len < 256 use long-form length id with 1-byte length field + // if data_len < 65536 use long-form length id with 2-byte length field + // if data_len < 16777216 use long-form length id with 3-byte length field + + if (data_len + 1 < 128) { + len = 1 + 1 + 1 + data_len; + } else if (data_len + 1 < 256) { + len = 1 + (1 + 1) + 1 + data_len; + } else if (data_len + 1 < (1 << 16)) { + len = 1 + (1 + 2) + 1 + data_len; + } else if (data_len + 1 < (1 << 24)) { + len = 1 + (1 + 3) + 1 + data_len; + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + if (length_only == TRUE) { + *ber_str_len = len; + return CKR_OK; + } + + buf = (CK_BYTE *) malloc(len); + if (!buf) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + if (data_len + 1 < 128) { + buf[0] = 0x03; + buf[1] = data_len + 1; + buf[2] = unused_bits; + if (data && data_len) + memcpy(&buf[3], data, data_len); + *ber_str_len = len; + *ber_str = buf; + return CKR_OK; + } + + if (data_len + 1 < 256) { + buf[0] = 0x03; + buf[1] = 0x81; + buf[2] = data_len + 1; + buf[3] = unused_bits; + if (data && data_len) + memcpy(&buf[4], data, data_len); + *ber_str_len = len; + *ber_str = buf; + return CKR_OK; + } + + if (data_len + 1 < (1 << 16)) { + buf[0] = 0x03; + buf[1] = 0x82; + buf[2] = ((data_len + 1) >> 8) & 0xFF; + buf[3] = ((data_len + 1)) & 0xFF; + buf[4] = unused_bits; + if (data && data_len) + memcpy(&buf[5], data, data_len); + *ber_str_len = len; + *ber_str = buf; + return CKR_OK; + } + + if (data_len + 1 < (1 << 24)) { + buf[0] = 0x03; + buf[1] = 0x83; + buf[2] = ((data_len + 1) >> 16) & 0xFF; + buf[3] = ((data_len + 1) >> 8) & 0xFF; + buf[4] = ((data_len + 1)) & 0xFF; + buf[5] = unused_bits; + if (data) + memcpy(&buf[6], data, data_len); + *ber_str_len = len; + *ber_str = buf; + return CKR_OK; + } + // we should never reach this + // + free(buf); + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + +/** + * Here the 'unused bits' byte is part of the returned decoded data. + * The first byte of output parm *data is the number of unused bits and must + * be removed later by the calling function. + */ +CK_RV ber_decode_BIT_STRING(CK_BYTE *str, + CK_BYTE **data, + CK_ULONG *data_len, CK_ULONG *field_len) +{ + CK_ULONG len, length_octets; + + if (!str) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + if (str[0] != 0x03) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + if ((str[1] & 0x80) == 0) { + len = str[1] & 0x7F; + + *data = &str[2]; + *data_len = len; + *field_len = 1 + (1) + len; + return CKR_OK; + } + + length_octets = str[1] & 0x7F; + + if (length_octets == 1) { + len = str[2]; + + *data = &str[3]; + *data_len = len; + *field_len = 1 + (1 + 1) + len; + return CKR_OK; + } + + if (length_octets == 2) { + len = str[2]; + len = len << 8; + len |= str[3]; + + *data = &str[4]; + *data_len = len; + *field_len = 1 + (1 + 2) + len; + return CKR_OK; + } + + if (length_octets == 3) { + len = str[2]; + len = len << 8; + len |= str[3]; + len = len << 8; + len |= str[4]; + + *data = &str[5]; + *data_len = len; + *field_len = 1 + (1 + 3) + len; + return CKR_OK; + } + // > 3 length octets implies a length > 16MB + // + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + +// +// +CK_RV ber_encode_SEQUENCE(CK_BBOOL length_only, + CK_BYTE **seq, + CK_ULONG *seq_len, CK_BYTE *data, CK_ULONG data_len) +{ + CK_BYTE *buf = NULL; + CK_ULONG len; + + // if data_len < 127 use short-form length id + // if data_len < 65536 use long-form length id with 2-byte length field + // + + if (data_len < 128) { + len = 1 + 1 + data_len; + } else if (data_len < 256) { + len = 1 + (1 + 1) + data_len; + } else if (data_len < (1 << 16)) { + len = 1 + (1 + 2) + data_len; + } else if (data_len < (1 << 24)) { + len = 1 + (1 + 3) + data_len; + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + if (length_only == TRUE) { + *seq_len = len; + return CKR_OK; + } + + buf = (CK_BYTE *) malloc(len); + if (!buf) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + if (data_len < 128) { + buf[0] = 0x30; // constructed, SEQUENCE + buf[1] = data_len; + memcpy(&buf[2], data, data_len); + + *seq_len = len; + *seq = buf; + return CKR_OK; + } + + if (data_len < 256) { + buf[0] = 0x30; // constructed, SEQUENCE + buf[1] = 0x81; // length header -- 1 length octets + buf[2] = data_len; + + memcpy(&buf[3], data, data_len); + + *seq_len = len; + *seq = buf; + return CKR_OK; + } + + if (data_len < (1 << 16)) { + buf[0] = 0x30; // constructed, SEQUENCE + buf[1] = 0x82; // length header -- 2 length octets + buf[2] = (data_len >> 8) & 0xFF; + buf[3] = (data_len) & 0xFF; + + memcpy(&buf[4], data, data_len); + + *seq_len = len; + *seq = buf; + return CKR_OK; + } + + if (data_len < (1 << 24)) { + buf[0] = 0x30; // constructed, SEQUENCE + buf[1] = 0x83; // length header -- 3 length octets + buf[2] = (data_len >> 16) & 0xFF; + buf[3] = (data_len >> 8) & 0xFF; + buf[4] = (data_len) & 0xFF; + + memcpy(&buf[5], data, data_len); + + *seq_len = len; + *seq = buf; + return CKR_OK; + } + + free(buf); + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + + +// +// +CK_RV ber_decode_SEQUENCE(CK_BYTE *seq, + CK_BYTE **data, CK_ULONG *data_len, + CK_ULONG *field_len) +{ + CK_ULONG len, length_octets; + + + if (!seq) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + if (seq[0] != 0x30) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + // short form lengths are easy + // + if ((seq[1] & 0x80) == 0) { + len = seq[1] & 0x7F; + + *data = &seq[2]; + *data_len = len; + *field_len = 1 + (1) + len; + return CKR_OK; + } + + length_octets = seq[1] & 0x7F; + + if (length_octets == 1) { + len = seq[2]; + + *data = &seq[3]; + *data_len = len; + *field_len = 1 + (1 + 1) + len; + return CKR_OK; + } + + if (length_octets == 2) { + len = seq[2]; + len = len << 8; + len |= seq[3]; + + *data = &seq[4]; + *data_len = len; + *field_len = 1 + (1 + 2) + len; + return CKR_OK; + } + + if (length_octets == 3) { + len = seq[2]; + len = len << 8; + len |= seq[3]; + len = len << 8; + len |= seq[4]; + + *data = &seq[5]; + *data_len = len; + *field_len = 1 + (1 + 3) + len; + return CKR_OK; + } + // > 3 length octets implies a length > 16MB + // + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + +// +// +CK_RV ber_encode_CHOICE(CK_BBOOL length_only, + CK_BYTE option, + CK_BYTE **str, + CK_ULONG *str_len, CK_BYTE *data, CK_ULONG data_len) +{ + CK_BYTE *buf = NULL; + CK_ULONG len; + + /* + * if data_len < 127 use short-form length id + * if data_len < 65536 use long-form length id with 2-byte length field + */ + + if (data_len < 128) { + len = 1 + 1 + data_len; + } else if (data_len < 256) { + len = 1 + (1 + 1) + data_len; + } else if (data_len < (1 << 16)) { + len = 1 + (1 + 2) + data_len; + } else if (data_len < (1 << 24)) { + len = 1 + (1 + 3) + data_len; + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + if (length_only == TRUE) { + *str_len = len; + return CKR_OK; + } + + buf = (CK_BYTE *) malloc(len); + if (!buf) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + if (data_len < 128) { + buf[0] = 0xA0 | option; // constructed, CHOICE + buf[1] = data_len; + memcpy(&buf[2], data, data_len); + + *str_len = len; + *str = buf; + return CKR_OK; + } + + if (data_len < 256) { + buf[0] = 0xA0 | option; // constructed, CHOICE + buf[1] = 0x81; // length header -- 1 length octets + buf[2] = data_len; + + memcpy(&buf[3], data, data_len); + + *str_len = len; + *str = buf; + return CKR_OK; + } + + if (data_len < (1 << 16)) { + buf[0] = 0xA0 | option; // constructed, CHOICE + buf[1] = 0x82; // length header -- 2 length octets + buf[2] = (data_len >> 8) & 0xFF; + buf[3] = (data_len) & 0xFF; + + memcpy(&buf[4], data, data_len); + + *str_len = len; + *str = buf; + return CKR_OK; + } + if (data_len < (1 << 24)) { + buf[0] = 0xA0 | option; // constructed, CHOICE + buf[1] = 0x83; // length header -- 3 length octets + buf[2] = (data_len >> 16) & 0xFF; + buf[3] = (data_len >> 8) & 0xFF; + buf[4] = (data_len) & 0xFF; + + memcpy(&buf[5], data, data_len); + + *str_len = len; + *str = buf; + return CKR_OK; + } + + free(buf); + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + +// PrivateKeyInfo ::= SEQUENCE { +// version Version -- always '0' for now +// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier +// privateKey PrivateKey +// attributes +// } +// +CK_RV ber_decode_CHOICE(CK_BYTE *choice, + CK_BYTE **data, + CK_ULONG *data_len, CK_ULONG *field_len, + CK_ULONG *option) +{ + CK_ULONG len, length_octets; + + + if (!choice) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + if ((choice[0] & 0xE0) != 0xA0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + *option = choice[0] & 0x1F; + + // short form lengths are easy + // + if ((choice[1] & 0x80) == 0) { + len = choice[1] & 0x7F; + *data = &choice[2]; + *data_len = len; + *field_len = 1 + (1) + len; + return CKR_OK; + } + + length_octets = choice[1] & 0x7F; + + if (length_octets == 1) { + len = choice[2]; + *data = &choice[3]; + *data_len = len; + *field_len = 1 + (1 + 1) + len; + return CKR_OK; + } + + if (length_octets == 2) { + len = choice[2]; + len = len << 8; + len |= choice[3]; + *data = &choice[4]; + *data_len = len; + *field_len = 1 + (1 + 2) + len; + return CKR_OK; + } + + if (length_octets == 3) { + len = choice[2]; + len = len << 8; + len |= choice[3]; + len = len << 8; + len |= choice[4]; + *data = &choice[5]; + *data_len = len; + *field_len = 1 + (1 + 3) + len; + return CKR_OK; + } + // > 3 length octets implies a length > 16MB + // + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; +} + +// PrivateKeyInfo ::= SEQUENCE { +// version Version -- always '0' for now +// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier +// privateKey PrivateKey +// attributes +// } +// +CK_RV ber_encode_PrivateKeyInfo(CK_BBOOL length_only, + CK_BYTE **data, + CK_ULONG *data_len, + const CK_BYTE *algorithm_id, + const CK_ULONG algorithm_id_len, + CK_BYTE *priv_key, CK_ULONG priv_key_len) +{ + CK_BYTE *buf = NULL; + CK_BYTE *tmp = NULL; + CK_BYTE version[] = { 0 }; + CK_ULONG len, total; + CK_RV rc; + + len = 0; + + rc = ber_encode_INTEGER(TRUE, NULL, &total, version, sizeof(version)); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + return rc; + } else { + len += total; + } + + len += algorithm_id_len; + + rc = ber_encode_OCTET_STRING(TRUE, NULL, &total, priv_key, priv_key_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_OCTET_STRING failed\n"); + return rc; + } + + len += total; + + // for this stuff, attributes can be suppressed. + // + + if (length_only == TRUE) { + rc = ber_encode_SEQUENCE(TRUE, NULL, &total, NULL, len); + + if (rc == CKR_OK) + *data_len = total; + if (rc != CKR_OK) + TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); + return rc; + } + + buf = (CK_BYTE *) malloc(len); + if (!buf) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + len = 0; + rc = ber_encode_INTEGER(FALSE, &tmp, &total, version, sizeof(version)); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + goto error; + } + if (tmp != NULL) { + memcpy(buf + len, tmp, total); + len += total; + free(tmp); + } + + memcpy(buf + len, algorithm_id, algorithm_id_len); + len += algorithm_id_len; + + rc = ber_encode_OCTET_STRING(FALSE, &tmp, &total, priv_key, priv_key_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_OCTET_STRING failed\n"); + goto error; + } + memcpy(buf + len, tmp, total); + len += total; + free(tmp); + + rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf, len); + if (rc != CKR_OK) + TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); + +error: + free(buf); + + return rc; +} + + +// +// +CK_RV ber_decode_PrivateKeyInfo(CK_BYTE *data, + CK_ULONG data_len, + CK_BYTE **algorithm, + CK_ULONG *alg_len, CK_BYTE **priv_key) +{ + CK_BYTE *buf = NULL; + CK_BYTE *alg = NULL; + CK_BYTE *ver = NULL; + CK_ULONG buf_len, offset, len, field_len; + CK_RV rc; + + if (!data || (data_len == 0)) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + rc = ber_decode_SEQUENCE(data, &buf, &buf_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); + return rc; + } + // version -- we just ignore this + // + offset = 0; + rc = ber_decode_INTEGER(buf + offset, &ver, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + return rc; + } + offset += field_len; + + // 'buf' is now pointing to the PrivateKeyAlgorithmIdentifier + // + rc = ber_decode_SEQUENCE(buf + offset, &alg, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); + return rc; + } + *algorithm = alg; + *alg_len = len; + + rc = ber_decode_OCTET_STRING(alg + len, priv_key, &buf_len, &field_len); + if (rc != CKR_OK) + TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); + + return rc; +} + +/*Extract data from an SPKI + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING + * } + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + */ +CK_RV ber_decode_SPKI(CK_BYTE *spki, CK_BYTE **alg_oid, CK_ULONG *alg_oid_len, + CK_BYTE **param, CK_ULONG *param_len, + CK_BYTE **key, CK_ULONG *key_len) +{ + CK_BYTE *out_seq, *id_seq, *bit_str; + CK_BYTE *data; + CK_ULONG data_len; + CK_ULONG field_len; + CK_RV rc; + + *alg_oid_len = 0; + *param_len = 0; + *key_len = 0; + out_seq = spki; + rc = ber_decode_SEQUENCE(out_seq, &data, &data_len, &field_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_decode_SEQUENCE #1 failed rc=0x%lx\n", + __func__, rc); + return rc; + } + + id_seq = out_seq + field_len - data_len; + /* get id seq */ + rc = ber_decode_SEQUENCE(id_seq, &data, &data_len, &field_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_decode_SEQUENCE #2 failed rc=0x%lx\n", + __func__, rc); + return rc; + } + + *alg_oid = data; + *alg_oid_len = data[1] + 2; + + *param = data + *alg_oid_len; + *param_len = data_len - *alg_oid_len; + + bit_str = id_seq + field_len; + /* get bitstring */ + rc = ber_decode_BIT_STRING(bit_str, key, key_len, &field_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_decode_BIT_STRING failed rc=0x%lx\n", + __func__, rc); + return rc; + } + + (*key_len)--; /* remove 'unused bits' byte from length */ + (*key)++; + + return CKR_OK; +} + + +// RSAPrivateKey ::= SEQUENCE { +// version Version -- always '0' for now +// modulus INTEGER +// publicExponent INTEGER +// if secure key +// opaque OCTET_STRING +// else +// privateExponent INTEGER +// prime1 INTEGER +// prime2 INTEGER +// exponent1 INTEGER +// exponent2 INTEGER +// coefficient INTEGER +// } +// +CK_RV ber_encode_RSAPrivateKey(CK_BBOOL length_only, + CK_BYTE **data, + CK_ULONG *data_len, + CK_ATTRIBUTE *modulus, + CK_ATTRIBUTE *publ_exp, + CK_ATTRIBUTE *priv_exp, + CK_ATTRIBUTE *prime1, + CK_ATTRIBUTE *prime2, + CK_ATTRIBUTE *exponent1, + CK_ATTRIBUTE *exponent2, + CK_ATTRIBUTE *coeff, CK_ATTRIBUTE *opaque) +{ + CK_BYTE *buf = NULL; + CK_BYTE *buf2 = NULL; + CK_ULONG len, offset; + CK_BYTE version[] = { 0 }; + CK_RV rc; + + + offset = 0; + rc = 0; + + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, sizeof(version)); + offset += len; + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, modulus->ulValueLen); + offset += len; + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, publ_exp->ulValueLen); + offset += len; + if (opaque != NULL) { + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, opaque->ulValueLen); + offset += len; + } else { + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, priv_exp->ulValueLen); + offset += len; + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, prime1->ulValueLen); + offset += len; + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, prime2->ulValueLen); + offset += len; + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, exponent1->ulValueLen); + offset += len; + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, exponent2->ulValueLen); + offset += len; + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, coeff->ulValueLen); + offset += len; + } + + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + return CKR_FUNCTION_FAILED; + } + if (length_only == TRUE) { + rc = ber_encode_SEQUENCE(TRUE, NULL, &len, NULL, offset); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); + return rc; + } + rc = ber_encode_PrivateKeyInfo(TRUE, + NULL, data_len, + NULL, ber_AlgIdRSAEncryptionLen, + NULL, len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); + return rc; + } + return rc; + } + + buf = (CK_BYTE *) malloc(offset); + if (!buf) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + offset = 0; + rc = 0; + + rc = ber_encode_INTEGER(FALSE, &buf2, &len, version, sizeof(version)); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + goto error; + } + if (buf2 != NULL) { + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + } + + rc = ber_encode_INTEGER(FALSE, &buf2, &len, + (CK_BYTE *) modulus + sizeof(CK_ATTRIBUTE), + modulus->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + goto error; + } + if (buf2 != NULL) { + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + } + + rc = ber_encode_INTEGER(FALSE, &buf2, &len, + (CK_BYTE *) publ_exp + sizeof(CK_ATTRIBUTE), + publ_exp->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + goto error; + } + if (buf2 != NULL) { + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + } + + if (opaque != NULL) { + // the CKA_IBM_OPAQUE attrib + rc = ber_encode_OCTET_STRING(FALSE, &buf2, &len, + (CK_BYTE *) opaque + + sizeof(CK_ATTRIBUTE), opaque->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_OCTET_STRING failed\n"); + goto error; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + } else { + rc = ber_encode_INTEGER(FALSE, &buf2, &len, + (CK_BYTE *) priv_exp + sizeof(CK_ATTRIBUTE), + priv_exp->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + goto error; + } + if (buf2 != NULL) { + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + } + + rc = ber_encode_INTEGER(FALSE, &buf2, &len, + (CK_BYTE *) prime1 + sizeof(CK_ATTRIBUTE), + prime1->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + goto error; + } + if (buf2 != NULL) { + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + } + + rc = ber_encode_INTEGER(FALSE, &buf2, &len, + (CK_BYTE *) prime2 + sizeof(CK_ATTRIBUTE), + prime2->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + goto error; + } + if (buf2 != NULL) { + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + } + + rc = ber_encode_INTEGER(FALSE, &buf2, &len, + (CK_BYTE *) exponent1 + sizeof(CK_ATTRIBUTE), + exponent1->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + goto error; + } + if (buf2 != NULL) { + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + } + + rc = ber_encode_INTEGER(FALSE, &buf2, &len, + (CK_BYTE *) exponent2 + sizeof(CK_ATTRIBUTE), + exponent2->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + goto error; + } + if (buf2 != NULL) { + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + } + + rc = ber_encode_INTEGER(FALSE, &buf2, &len, + (CK_BYTE *) coeff + sizeof(CK_ATTRIBUTE), + coeff->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + goto error; + } + if (buf2 != NULL) { + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + } + } + + rc = ber_encode_SEQUENCE(FALSE, &buf2, &len, buf, offset); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); + goto error; + } + rc = ber_encode_PrivateKeyInfo(FALSE, + data, data_len, + ber_AlgIdRSAEncryption, + ber_AlgIdRSAEncryptionLen, buf2, len); + if (rc != CKR_OK) { + TRACE_ERROR("ber_encode_PrivateKeyInfo failed\n"); + } +error: + if (buf2) + free(buf2); + if (buf) + free(buf); + + return rc; +} + + +// +// +CK_RV ber_decode_RSAPrivateKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **modulus, + CK_ATTRIBUTE **publ_exp, + CK_ATTRIBUTE **priv_exp, + CK_ATTRIBUTE **prime1, + CK_ATTRIBUTE **prime2, + CK_ATTRIBUTE **exponent1, + CK_ATTRIBUTE **exponent2, + CK_ATTRIBUTE **coeff, + CK_ATTRIBUTE **opaque, CK_BBOOL isopaque) +{ + CK_ATTRIBUTE *n_attr = NULL; + CK_ATTRIBUTE *e_attr = NULL; + CK_ATTRIBUTE *d_attr = NULL; + CK_ATTRIBUTE *p_attr = NULL; + CK_ATTRIBUTE *q_attr = NULL; + CK_ATTRIBUTE *e1_attr = NULL; + CK_ATTRIBUTE *e2_attr = NULL; + CK_ATTRIBUTE *coeff_attr = NULL; + CK_ATTRIBUTE *o_attr = NULL; + + CK_BYTE *alg = NULL; + CK_BYTE *rsa_priv_key = NULL; + CK_BYTE *buf = NULL; + CK_BYTE *tmp = NULL; + CK_ULONG offset, buf_len, field_len, len; + CK_RV rc; + + rc = ber_decode_PrivateKeyInfo(data, data_len, &alg, &len, &rsa_priv_key); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_PrivateKeyInfo failed\n"); + return rc; + } + // make sure we're dealing with an RSA key + // + if (memcmp(alg, ber_rsaEncryption, ber_rsaEncryptionLen) != 0) { + // probably ought to use a different error + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + rc = ber_decode_SEQUENCE(rsa_priv_key, &buf, &buf_len, &field_len); + if (rc != CKR_OK) + return rc; + + // parse the RSAPrivateKey + // + offset = 0; + + // Version + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } + offset += field_len; + + // modulus + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } + offset += field_len; + + // public exponent + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } + offset += field_len; + + if (isopaque) { + // opaque attribute, the CCA key + // + rc = ber_decode_OCTET_STRING(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); + goto cleanup; + } + offset += field_len; + } else { + + // private exponent + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } + offset += field_len; + + // prime #1 + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } + offset += field_len; + + // prime #2 + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } + offset += field_len; + + // exponent #1 + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } + offset += field_len; + + // exponent #2 + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } + offset += field_len; + + // coefficient + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } + offset += field_len; + + if (offset > buf_len) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + } + + // + // it looks okay. build the attributes + // + + offset = 0; + + // skip the version + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } + offset += field_len; + + // modulus + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_MODULUS, tmp, len, &n_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + offset += field_len; + } + + // public exponent + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_PUBLIC_EXPONENT, tmp, len, &e_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + offset += field_len; + } + + if (isopaque) { + // opaque attribute, the CCA key + // + rc = ber_decode_OCTET_STRING(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_IBM_OPAQUE, tmp, len, &o_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + offset += field_len; + } + *opaque = o_attr; + } else { + // private exponent + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_PRIVATE_EXPONENT, tmp, len, &d_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + offset += field_len; + } + + // prime #1 + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_PRIME_1, tmp, len, &p_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + offset += field_len; + } + + // prime #2 + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_PRIME_2, tmp, len, &q_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + offset += field_len; + } + + // exponent #1 + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_EXPONENT_1, tmp, len, &e1_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + offset += field_len; + } + + // exponent #2 + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_EXPONENT_2, tmp, len, &e2_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + offset += field_len; + } + + // coefficient + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_COEFFICIENT, tmp, len, &coeff_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + offset += len; + } + *priv_exp = d_attr; + *prime1 = p_attr; + *prime2 = q_attr; + *exponent1 = e1_attr; + *exponent2 = e2_attr; + *coeff = coeff_attr; + } + + *modulus = n_attr; + *publ_exp = e_attr; + + return CKR_OK; + +cleanup: + if (n_attr) + free(n_attr); + if (e_attr) + free(e_attr); + if (isopaque) { + if (o_attr) + free(o_attr); + } else { + if (d_attr) + free(d_attr); + if (p_attr) + free(p_attr); + if (q_attr) + free(q_attr); + if (e1_attr) + free(e1_attr); + if (e2_attr) + free(e2_attr); + if (coeff_attr) + free(coeff_attr); + } + + return rc; +} + +CK_RV ber_encode_RSAPublicKey(CK_BBOOL length_only, CK_BYTE **data, + CK_ULONG *data_len, CK_ATTRIBUTE *modulus, + CK_ATTRIBUTE *publ_exp) +{ + CK_ULONG len, offset, total, total_len; + CK_RV rc; + CK_BYTE *buf = NULL; + CK_BYTE *buf2 = NULL; + CK_BYTE *buf3 = NULL; + BerValue *val; + BerElement *ber; + + UNUSED(length_only); + + offset = 0; + rc = 0; + total_len = ber_AlgIdRSAEncryptionLen; + total = 0; + + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, modulus->ulValueLen); + offset += len; + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, publ_exp->ulValueLen); + offset += len; + + if (rc != CKR_OK) { + TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); + return rc; + } + + buf = (CK_BYTE *) malloc(offset); + if (!buf) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + return CKR_HOST_MEMORY; + } + offset = 0; + rc = 0; + + rc = ber_encode_INTEGER(FALSE, &buf2, &len, + (CK_BYTE *) modulus + sizeof(CK_ATTRIBUTE), + modulus->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); + return rc; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + + rc = ber_encode_INTEGER(FALSE, &buf2, &len, + (CK_BYTE *) publ_exp + sizeof(CK_ATTRIBUTE), + publ_exp->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); + return rc; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + + rc = ber_encode_SEQUENCE(FALSE, &buf2, &len, buf, offset); + if (rc != CKR_OK) { + TRACE_DEVEL("%s ber_encode_Seq failed with rc=0x%lx\n", __func__, rc); + return rc; + } + + /* length of outer sequence */ + rc = ber_encode_OCTET_STRING(TRUE, NULL, &total, buf2, len); + if (rc != CKR_OK) { + TRACE_DEVEL("%s ber_encode_Oct_Str failed with rc=0x%lx\n", __func__, + rc); + return rc; + } else { + total_len += total + 1; + } + + /* mem for outer sequence */ + buf3 = (CK_BYTE *) malloc(total_len); + if (!buf3) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + return CKR_HOST_MEMORY; + } + total_len = 0; + + /* copy alg id */ + memcpy(buf3 + total_len, ber_AlgIdRSAEncryption, ber_AlgIdRSAEncryptionLen); + total_len += ber_AlgIdRSAEncryptionLen; + + /* need a bitstring */ + ber = ber_alloc_t(LBER_USE_DER); + rc = ber_put_bitstring(ber, (char *)buf2, len * 8, 0x03); + rc = ber_flatten(ber, &val); + memcpy(buf3 + total_len, val->bv_val, val->bv_len); + total_len += val->bv_len; + + rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf3, total_len); + if (rc != CKR_OK) + TRACE_DEVEL("%s ber_encode_Seq failed with rc=0x%lx\n", __func__, rc); + + return rc; +} + +CK_RV ber_decode_RSAPublicKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **modulus, + CK_ATTRIBUTE **publ_exp) +{ + CK_ATTRIBUTE *modulus_attr = NULL; + CK_ATTRIBUTE *publ_exp_attr = NULL; + + CK_BYTE *algid_RSABase = NULL; + CK_BYTE *algid = NULL; + CK_ULONG algid_len; + CK_BYTE *param = NULL; + CK_ULONG param_len; + CK_BYTE *val = NULL; + CK_ULONG val_len; + CK_BYTE *seq; + CK_ULONG seq_len; + CK_BYTE *mod; + CK_ULONG mod_len; + CK_BYTE *exp; + CK_ULONG exp_len; + CK_ULONG field_len, offset, len; + CK_RV rc; + + UNUSED(data_len); // XXX can this parameter be removed ? + + rc = ber_decode_SPKI(data, &algid, &algid_len, ¶m, ¶m_len, + &val, &val_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_SPKI failed\n"); + return rc; + } + + /* + * Make sure we're dealing with an DH key. + */ + rc = ber_decode_SEQUENCE((CK_BYTE *)ber_AlgIdRSAEncryption, &algid_RSABase, + &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); + return rc; + } + + if (memcmp(algid, algid_RSABase, len) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + rc = ber_decode_SEQUENCE(val, &seq, &seq_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); + return rc; + } + + rc = ber_decode_INTEGER(seq, &mod, &mod_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + return rc; + } + + offset = field_len; + rc = ber_decode_INTEGER(seq + offset, &exp, &exp_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + return rc; + } + + // build modulus attribute + rc = build_attribute(CKA_MODULUS, mod, mod_len, &modulus_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + // build base attribute + rc = build_attribute(CKA_PUBLIC_EXPONENT, exp, exp_len, &publ_exp_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + + *modulus = modulus_attr; + *publ_exp = publ_exp_attr; + return CKR_OK; + +cleanup: + if (modulus_attr) + free(modulus_attr); + if (publ_exp_attr) + free(publ_exp_attr); + + return rc; +} + + +// DSA is a little different from RSA +// +// DSAPrivateKey ::= INTEGER +// +// The 'parameters' field of the AlgorithmIdentifier are as follows: +// +// DSSParameters ::= SEQUENCE { +// prime1 INTEGER +// prime2 INTEGER +// base INTEGER +// } +// +CK_RV ber_encode_DSAPrivateKey(CK_BBOOL length_only, + CK_BYTE **data, + CK_ULONG *data_len, + CK_ATTRIBUTE *prime1, + CK_ATTRIBUTE *prime2, + CK_ATTRIBUTE *base, CK_ATTRIBUTE *priv_key) +{ + CK_BYTE *param = NULL; + CK_BYTE *buf = NULL; + CK_BYTE *tmp = NULL; + CK_BYTE *alg = NULL; + CK_ULONG offset, len, param_len; + CK_ULONG alg_len; + CK_RV rc; + + + // build the DSS parameters first + // + offset = 0; + rc = 0; + + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, prime1->ulValueLen); + offset += len; + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, prime2->ulValueLen); + offset += len; + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, base->ulValueLen); + offset += len; + + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + return CKR_FUNCTION_FAILED; + } + if (length_only == TRUE) { + rc = ber_encode_SEQUENCE(TRUE, NULL, ¶m_len, NULL, offset); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); + return rc; + } + rc = ber_encode_INTEGER(TRUE, NULL, &len, NULL, priv_key->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + return rc; + } + rc = ber_encode_PrivateKeyInfo(TRUE, + NULL, data_len, + NULL, ber_idDSALen + param_len, + NULL, len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); + } + return rc; + } + // 'buf' will be the sequence data for the AlgorithmIdentifyer::parameter + // + buf = (CK_BYTE *) malloc(offset); + if (!buf) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + len = 0; + offset = 0; + + rc = ber_encode_INTEGER(FALSE, &tmp, &len, + (CK_BYTE *) prime1 + sizeof(CK_ATTRIBUTE), + prime1->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + goto error; + } + if (tmp != NULL) { + memcpy(buf + offset, tmp, len); + offset += len; + free(tmp); + tmp = NULL; + } + + rc = ber_encode_INTEGER(FALSE, &tmp, &len, + (CK_BYTE *) prime2 + sizeof(CK_ATTRIBUTE), + prime2->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + goto error; + } + if (tmp != NULL) { + memcpy(buf + offset, tmp, len); + offset += len; + free(tmp); + tmp = NULL; + } + + rc = ber_encode_INTEGER(FALSE, &tmp, &len, + (CK_BYTE *) base + sizeof(CK_ATTRIBUTE), + base->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + goto error; + } + if (tmp != NULL) { + memcpy(buf + offset, tmp, len); + offset += len; + free(tmp); + tmp = NULL; + } + + rc = ber_encode_SEQUENCE(FALSE, ¶m, ¶m_len, buf, offset); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); + free(buf); + return rc; + } + + free(buf); + buf = NULL; + + // Build the DSA AlgorithmIdentifier + // + // AlgorithmIdentifier ::= SEQUENCE { + // algorithm OBJECT IDENTIFIER + // parameters ANY DEFINED BY algorithm OPTIONAL + // } + // + len = ber_idDSALen + param_len; + buf = (CK_BYTE *) malloc(len); + if (!buf) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto error; + } + memcpy(buf, ber_idDSA, ber_idDSALen); + memcpy(buf + ber_idDSALen, param, param_len); + + free(param); + param = NULL; + + rc = ber_encode_SEQUENCE(FALSE, &alg, &alg_len, buf, len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); + goto error; + } + free(buf); + buf = NULL; + + // build the private key INTEGER + // + rc = ber_encode_INTEGER(FALSE, &buf, &len, + (CK_BYTE *) priv_key + sizeof(CK_ATTRIBUTE), + priv_key->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + goto error; + } + + rc = ber_encode_PrivateKeyInfo(FALSE, + data, data_len, alg, alg_len, buf, len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); + goto error; + } + +error: + if (alg) + free(alg); + if (buf) + free(buf); + if (param) + free(param); + if (tmp) + free(tmp); + + return rc; +} + + +// +// +CK_RV ber_decode_DSAPrivateKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **prime, + CK_ATTRIBUTE **subprime, + CK_ATTRIBUTE **base, CK_ATTRIBUTE **priv_key) +{ + CK_ATTRIBUTE *p_attr = NULL; + CK_ATTRIBUTE *q_attr = NULL; + CK_ATTRIBUTE *g_attr = NULL; + CK_ATTRIBUTE *x_attr = NULL; + CK_BYTE *alg = NULL; + CK_BYTE *buf = NULL; + CK_BYTE *dsakey = NULL; + CK_BYTE *tmp = NULL; + CK_ULONG buf_len, field_len, len, offset; + CK_RV rc; + + + rc = ber_decode_PrivateKeyInfo(data, data_len, &alg, &len, &dsakey); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_PrivateKeyInfo failed\n"); + return rc; + } + // make sure we're dealing with a DSA key. just compare the OBJECT + // IDENTIFIER + // + if (memcmp(alg, ber_idDSA, ber_idDSALen) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + // extract the parameter data into ATTRIBUTES + // + rc = ber_decode_SEQUENCE(alg + ber_idDSALen, &buf, &buf_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); + return rc; + } + offset = 0; + + // prime + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } + offset += field_len; + + // subprime + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } + offset += field_len; + + // base + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } + offset += field_len; + + if (offset > buf_len) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + // + // it looks okay. build the attributes + // + + offset = 0; + + // prime + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_PRIME, tmp, len, &p_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + offset += field_len; + } + + // subprime + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_SUBPRIME, tmp, len, &q_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + offset += field_len; + } + + // base + // + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_BASE, tmp, len, &g_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + offset += field_len; + } + + // now get the private key + // + rc = ber_decode_INTEGER(dsakey, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_VALUE, tmp, len, &x_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + offset += field_len; + } + + *prime = p_attr; + *subprime = q_attr; + *base = g_attr; + *priv_key = x_attr; + + return CKR_OK; + +cleanup: + if (p_attr) + free(p_attr); + if (q_attr) + free(q_attr); + if (g_attr) + free(g_attr); + if (x_attr) + free(x_attr); + + return rc; +} + +CK_RV ber_encode_DSAPublicKey(CK_BBOOL length_only, CK_BYTE **data, + CK_ULONG *data_len, CK_ATTRIBUTE *prime, + CK_ATTRIBUTE *subprime, CK_ATTRIBUTE *base, + CK_ATTRIBUTE *value) +{ + CK_ULONG len, parm_len, id_len, pub_len, offset, total; + CK_RV rc = 0; + CK_BYTE *buf = NULL; + CK_BYTE *buf2 = NULL; + BerValue *val; + BerElement *ber; + + /* Calculate the BER container length + * + * SPKI := SEQUENCE { + * SEQUENCE { + * OID + * Parameters + * } + * BITSTRING public key + * } + */ + + offset = 0; + rc = 0; + total = 0; + parm_len = 0; + id_len = 0; + pub_len = 0; + + /* OID and parameters */ + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, prime->ulValueLen); + offset += len; + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, subprime->ulValueLen); + offset += len; + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, base->ulValueLen); + offset += len; + rc |= ber_encode_SEQUENCE(TRUE, NULL, &parm_len, NULL, offset); + rc |= + ber_encode_SEQUENCE(TRUE, NULL, &id_len, NULL, ber_idDSALen + parm_len); + + /* public key */ + rc |= + ber_encode_INTEGER(FALSE, &buf, &len, value->pValue, value->ulValueLen); + ber = ber_alloc_t(LBER_USE_DER); + rc = ber_put_bitstring(ber, (char *)buf, len * 8, 0x03); + rc = ber_flatten(ber, &val); + pub_len = val->bv_len; + ber_free(ber, 1); + free(buf); + + rc |= ber_encode_SEQUENCE(TRUE, NULL, &total, NULL, id_len + pub_len); + + if (rc != CKR_OK) { + TRACE_DEVEL("%s der_encode_sequence failed with rc=0x%lx\n", __func__, + rc); + return rc; + } + + if (length_only == TRUE) { + *data_len = total; + return rc; + } + + buf = (CK_BYTE *) malloc(id_len + pub_len); + if (!buf) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + return CKR_HOST_MEMORY; + } + + /* Parameters */ + offset = 0; + rc = ber_encode_INTEGER(FALSE, &buf2, &len, prime->pValue, + prime->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); + return rc; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + + rc = ber_encode_INTEGER(FALSE, &buf2, &len, subprime->pValue, + subprime->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); + return rc; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + + rc = ber_encode_INTEGER(FALSE, &buf2, &len, base->pValue, base->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); + return rc; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + + rc = ber_encode_SEQUENCE(FALSE, &buf2, &parm_len, buf, offset); + if (rc != CKR_OK) { + TRACE_DEVEL("%s ber_encode_Seq failed with rc=0x%lx\n", __func__, rc); + return rc; + } + + /* OID and parameters */ + memcpy(buf, ber_idDSA, ber_idDSALen); + memcpy(buf + ber_idDSALen, buf2, parm_len); + free(buf2); + + rc = ber_encode_SEQUENCE(FALSE, &buf2, &id_len, buf, + ber_idDSALen + parm_len); + if (rc != CKR_OK) { + TRACE_DEVEL("%s ber_encode_Seq failed with rc=0x%lx\n", __func__, rc); + return rc; + } + free(buf); + + /* public key */ + rc = ber_encode_INTEGER(FALSE, &buf, &len, value->pValue, + value->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); + return rc; + } + + ber = ber_alloc_t(LBER_USE_DER); + rc = ber_put_bitstring(ber, (char *)buf, len * 8, 0x03); + rc = ber_flatten(ber, &val); + free(buf); + + buf = (CK_BYTE *) malloc(id_len + val->bv_len); + if (!buf) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + return CKR_HOST_MEMORY; + } + memcpy(buf, buf2, id_len); + memcpy(buf + id_len, val->bv_val, val->bv_len); + free(buf2); + ber_free(ber, 1); + + /* outer sequence */ + rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf, id_len + pub_len); + if (rc != CKR_OK) { + TRACE_DEVEL("%s der_encode_Seq failed with rc=0x%lx\n", __func__, rc); + return rc; + } + free(buf); + + return rc; +} + +CK_RV ber_decode_DSAPublicKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **prime, + CK_ATTRIBUTE **subprime, + CK_ATTRIBUTE **base, + CK_ATTRIBUTE **value) +{ + CK_ATTRIBUTE *prime_attr = NULL; + CK_ATTRIBUTE *subprime_attr = NULL; + CK_ATTRIBUTE *base_attr = NULL; + CK_ATTRIBUTE *value_attr = NULL; + + CK_BYTE *algid = NULL; + CK_ULONG algid_len; + CK_BYTE *param = NULL; + CK_ULONG param_len; + CK_BYTE *val = NULL; + CK_ULONG val_len; + CK_BYTE *seq; + CK_ULONG seq_len; + CK_BYTE *p; + CK_ULONG p_len; + CK_BYTE *sp; + CK_ULONG sp_len; + CK_BYTE *b; + CK_ULONG b_len; + CK_ULONG field_len, offset; + CK_RV rc; + + UNUSED(data_len); // XXX can this parameter be removed ? + + rc = ber_decode_SPKI(data, &algid, &algid_len, ¶m, ¶m_len, + &val, &val_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_SPKI failed\n"); + return rc; + } + + /* + * Make sure we're dealing with an DSA key. + */ + if (memcmp(algid, ber_idDSA, ber_idDSALen) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + rc = ber_decode_SEQUENCE(param, &seq, &seq_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); + return rc; + } + + rc = ber_decode_INTEGER(seq, &p, &p_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + return rc; + } + + offset = field_len; + rc = ber_decode_INTEGER(seq + offset, &sp, &sp_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + return rc; + } + + offset += field_len; + rc = ber_decode_INTEGER(seq + offset, &b, &b_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + return rc; + } + + // build prime attribute + rc = build_attribute(CKA_PRIME, p, p_len, &prime_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + // build subprime attribute + rc = build_attribute(CKA_SUBPRIME, sp, sp_len, &subprime_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + // build base attribute + rc = build_attribute(CKA_BASE, b, b_len, &base_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + // build value attribute + rc = build_attribute(CKA_VALUE, val, val_len, &value_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + + *prime = prime_attr; + *subprime = subprime_attr; + *base = base_attr; + *value = value_attr; + return CKR_OK; + +cleanup: + if (prime_attr) + free(prime_attr); + if (subprime_attr) + free(subprime_attr); + if (base_attr) + free(base_attr); + if (value_attr) + free(value_attr); + + return rc; +} + + +/* + * ECC Functions + */ +// +// + + + +// +// +CK_RV der_encode_ECPrivateKey(CK_BBOOL length_only, + CK_BYTE **data, + CK_ULONG *data_len, + CK_ATTRIBUTE *params, + CK_ATTRIBUTE *point, + CK_ATTRIBUTE *opaque, CK_ATTRIBUTE *pubkey) +{ + CK_BYTE *buf = NULL; + CK_BYTE *buf2 = NULL; + CK_ULONG len, offset = 0; + CK_BYTE version[] = { 1 }; // ecPrivkeyVer1 + CK_BYTE der_AlgIdEC[der_AlgIdECBaseLen + params->ulValueLen]; + CK_ULONG der_AlgIdECLen = sizeof(der_AlgIdEC); + CK_BYTE *ecpoint; + CK_ULONG ecpoint_len, field_len; + BerElement *ber; + BerValue *val; + CK_RV rc = 0; + + /* Calculate BER encoding length + * Inner SEQUENCE of + * Integer (version), OCTET STRING (private key) + * and CHOICE [1] BIT STRING (public key) + */ + // version + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, sizeof(version)); + offset += len; + + // private key octet + if (opaque != NULL) { + rc |= ber_encode_OCTET_STRING(TRUE, NULL, &len, NULL, + opaque->ulValueLen); + offset += len; + } else { + rc |= ber_encode_OCTET_STRING(TRUE, NULL, &len, NULL, + point->ulValueLen); + offset += len; + } + if (rc != CKR_OK) { + TRACE_DEVEL("der encoding failed\n"); + return CKR_FUNCTION_FAILED; + } + // public key bit string + if (pubkey && pubkey->pValue) { + rc = ber_decode_OCTET_STRING(pubkey->pValue, &ecpoint, &ecpoint_len, + &field_len); + if (rc != CKR_OK || pubkey->ulValueLen != field_len) { + TRACE_DEVEL("ber decoding of public key failed\n"); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + ber = ber_alloc_t(LBER_USE_DER); + rc = ber_put_bitstring(ber, (char *)ecpoint, ecpoint_len * 8, 0x03); + rc = ber_flatten(ber, &val); + + ber_encode_CHOICE(TRUE, 1, &buf2, &len, (CK_BYTE *)val->bv_val, + val->bv_len); + offset += len; + ber_free(ber, 1); + } + + if (length_only == TRUE) { + rc = ber_encode_SEQUENCE(TRUE, NULL, &len, NULL, offset); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); + return rc; + } + rc = ber_encode_PrivateKeyInfo(TRUE, NULL, data_len, NULL, + der_AlgIdECLen, NULL, len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); + return rc; + } + return rc; + } + + /* Now starting with the real data */ + buf = (CK_BYTE *) malloc(offset); + if (!buf) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + offset = 0; + rc = 0; + + rc = ber_encode_INTEGER(FALSE, &buf2, &len, version, sizeof(version)); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + goto error; + } + if (buf2 != NULL) { + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + } + + if (opaque != NULL) { + // the CKA_IBM_OPAQUE attrib + rc = ber_encode_OCTET_STRING(FALSE, &buf2, &len, + (CK_BYTE *) opaque + + sizeof(CK_ATTRIBUTE), opaque->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_OCTET_STRING failed\n"); + goto error; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + } else { + rc = ber_encode_OCTET_STRING(FALSE, &buf2, &len, + (CK_BYTE *) point + + sizeof(CK_ATTRIBUTE), point->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + goto error; + } + if (buf2 != NULL) { + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + } + } + + /* generate optional bit-string of public key */ + if (pubkey && pubkey->pValue) { + rc = ber_decode_OCTET_STRING(pubkey->pValue, &ecpoint, &ecpoint_len, + &field_len); + if (rc != CKR_OK || pubkey->ulValueLen != field_len) { + TRACE_DEVEL("ber decoding of public key failed\n"); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + ber = ber_alloc_t(LBER_USE_DER); + rc = ber_put_bitstring(ber, (char *)ecpoint, ecpoint_len * 8, 0x03); + rc = ber_flatten(ber, &val); + + ber_encode_CHOICE(FALSE, 1, &buf2, &len, (CK_BYTE *)val->bv_val, + val->bv_len); + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + ber_free(ber, 1); + } + + rc = ber_encode_SEQUENCE(FALSE, &buf2, &len, buf, offset); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); + goto error; + } + + /* concatenate EC algorithm-id + specific curve id */ + memcpy(der_AlgIdEC, der_AlgIdECBase, der_AlgIdECBaseLen); + memcpy(der_AlgIdEC + der_AlgIdECBaseLen, params->pValue, + params->ulValueLen); + /* adjust length field */ + der_AlgIdEC[1] = der_AlgIdEC[1] + params->ulValueLen; + + rc = ber_encode_PrivateKeyInfo(FALSE, data, data_len, der_AlgIdEC, + der_AlgIdECLen, buf2, len); + if (rc != CKR_OK) { + TRACE_ERROR("ber_encode_PrivateKeyInfo failed\n"); + } + +error: + if (buf2) + free(buf2); + if (buf) + free(buf); + + return rc; +} + +// +// From RFC 5915: +// +// ECPrivateKey ::= SEQUENCE { +// version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), +// privateKey OCTET STRING, +// parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, +// publicKey [1] BIT STRING OPTIONAL +// } +// +CK_RV der_decode_ECPrivateKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **params, + CK_ATTRIBUTE **pub_key, + CK_ATTRIBUTE **priv_key, + CK_ATTRIBUTE **opaque_key, CK_BBOOL isOpaque) +{ + CK_ATTRIBUTE *pub_attr = NULL; + CK_ATTRIBUTE *priv_attr = NULL; + CK_ATTRIBUTE *opaque_attr = NULL; + CK_ATTRIBUTE *parm_attr = NULL; + CK_BYTE *alg = NULL; + CK_BYTE *buf = NULL; + CK_BYTE *priv_buf = NULL; + CK_BYTE *pub_buf = NULL; + CK_BYTE *parm_buf = NULL; + CK_BYTE *eckey = NULL; + CK_BYTE *version = NULL; + CK_BYTE *choice = NULL; + CK_ULONG version_len, alg_len, priv_len, pub_len, parm_len, buf_len; + CK_ULONG buf_offset, field_len, offset, choice_len, option; + CK_ULONG pubkey_available = 0; + CK_BYTE *ecpoint = NULL; + CK_ULONG ecpoint_len; + CK_RV rc; + + + /* Decode PrivateKeyInfo into alg and eckey */ + rc = ber_decode_PrivateKeyInfo(data, data_len, &alg, &alg_len, &eckey); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_PrivateKeyInfo failed\n"); + return rc; + } + + /* Check OBJECT IDENTIFIER to make sure this is an EC key */ + if (memcmp(alg, ber_idEC, ber_idECLen) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + /* Decode the ecdhkey into buf */ + rc = ber_decode_SEQUENCE(eckey, &buf, &buf_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); + return rc; + } + offset = 0; + + /* Decode version (INTEGER) */ + rc = ber_decode_INTEGER(buf + offset, &version, &version_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } + offset += field_len; + + /* Decode private key (OCTET_STRING) */ + rc = ber_decode_OCTET_STRING(buf + offset, &priv_buf, &priv_len, + &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); + goto cleanup; + } + offset += field_len; + + /* Check if there is an optional public key */ + buf_offset = buf - data; + if (buf_offset + offset < data_len) { + + /* Decode CHOICE */ + rc = ber_decode_CHOICE(buf + offset, &choice, &choice_len, &field_len, + &option); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_CHOICE failed\n"); + goto cleanup; + } + offset += field_len - choice_len; + + /* Decode public key (BIT_STRING) according to option */ + switch (option) { + case 0: + /* parameters [0] ECParameters {{ NamedCurve }} OPTIONAL + * These params, if available, are assumed to be the same as algo + * above, so nothing to do here. + */ + break; + case 1: + /* publicKey [1] BIT STRING OPTIONAL */ + rc = ber_decode_BIT_STRING(buf + offset, &pub_buf, &pub_len, + &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_BIT_STRING failed\n"); + goto cleanup; + } + pubkey_available = 1; + break; + default: + TRACE_DEVEL("ber_decode_CHOICE returned invalid or unsupported " + "option %ld\n", option); + goto cleanup; + } + } + + /* Now build attribute for CKA_ECDSA_PARAMS */ + parm_buf = alg + ber_idECLen; + parm_len = alg_len - ber_idECLen; + rc = build_attribute(CKA_ECDSA_PARAMS, parm_buf, parm_len, &parm_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute for CKA_ECDSA_PARAMS failed\n"); + goto cleanup; + } + + /* Build attr for public key as BER encoded OCTET STRING */ + if (pubkey_available) { + rc = ber_encode_OCTET_STRING(FALSE, &ecpoint, &ecpoint_len, + pub_buf, pub_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_OCTET_STRING failed\n"); + goto cleanup; + } + + rc = build_attribute(CKA_EC_POINT, ecpoint, ecpoint_len, &pub_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute for public key failed\n"); + goto cleanup; + } + } + + /* Build attr for private key */ + if (isOpaque) { + rc = build_attribute(CKA_IBM_OPAQUE, priv_buf, priv_len, &opaque_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute for private key failed\n"); + goto cleanup; + } + } else { + rc = build_attribute(CKA_VALUE, priv_buf, priv_len, &priv_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute for private key failed\n"); + goto cleanup; + } + } + + *pub_key = pub_attr; // may be NULL if no BIT_STRING available + *priv_key = priv_attr; // may be NULL if key is opaque + *opaque_key = opaque_attr; + *params = parm_attr; + if (ecpoint) + free(ecpoint); + + return CKR_OK; + +cleanup: + if (pub_attr) + free(pub_attr); + if (priv_attr) + free(priv_attr); + if (opaque_attr) + free(opaque_attr); + if (parm_attr) + free(parm_attr); + if (ecpoint) + free(ecpoint); + + return rc; +} + +CK_RV ber_encode_ECPublicKey(CK_BBOOL length_only, CK_BYTE **data, + CK_ULONG *data_len, CK_ATTRIBUTE *params, + CK_ATTRIBUTE *point) +{ + CK_ULONG len, total; + CK_ULONG algid_len = der_AlgIdECBaseLen + params->ulValueLen; + CK_RV rc = 0; + CK_BYTE *buf = NULL; + BerValue *val; + BerElement *ber; + CK_BYTE *ecpoint; + CK_ULONG ecpoint_len, field_len; + + /* CKA_EC_POINT is an BER encoded OCTET STRING. Extract it. */ + rc = ber_decode_OCTET_STRING((CK_BYTE *)point->pValue, &ecpoint, + &ecpoint_len, &field_len); + if (rc != CKR_OK || point->ulValueLen != field_len) { + TRACE_DEVEL("%s ber_decode_OCTET_STRING failed\n", __func__); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + /* Calculate the BER container length + * + * SPKI := SEQUENCE { + * SEQUENCE { + * OID + * Parameters + * } + * BITSTRING public key + * } + */ + rc = ber_encode_SEQUENCE(TRUE, NULL, &len, NULL, algid_len); + if (rc != CKR_OK) { + TRACE_DEVEL("%s der_encode_sequence failed with rc=0x%lx\n", + __func__, rc); + return rc; + } + + /* public key */ + ber = ber_alloc_t(LBER_USE_DER); + rc = ber_put_bitstring(ber, (char *)ecpoint, ecpoint_len * 8, 0x03); + rc = ber_flatten(ber, &val); + + rc = ber_encode_SEQUENCE(TRUE, NULL, &total, NULL, len + val->bv_len); + if (rc != CKR_OK) { + TRACE_DEVEL("%s der_encode_sequence failed with rc=0x%lx\n", + __func__, rc); + return rc; + } + ber_free(ber, 1); + + if (length_only == TRUE) { + *data_len = total; + return rc; + } + + /* Now compute with real data */ + buf = (CK_BYTE *) malloc(total); + if (!buf) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + return CKR_HOST_MEMORY; + } + + memcpy(buf, der_AlgIdECBase, der_AlgIdECBaseLen); + memcpy(buf + der_AlgIdECBaseLen, params->pValue, params->ulValueLen); + buf[1] += params->ulValueLen; + + /* generate bitstring */ + ber = ber_alloc_t(LBER_USE_DER); + rc = ber_put_bitstring(ber, (char *)ecpoint, ecpoint_len * 8, 0x03); + rc = ber_flatten(ber, &val); + + memcpy(buf + der_AlgIdECBaseLen + params->ulValueLen, val->bv_val, + val->bv_len); + ber_free(ber, 1); + + rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf, + der_AlgIdECBaseLen + + params->ulValueLen + val->bv_len); + if (rc != CKR_OK) { + TRACE_DEVEL("%s der_encode_Seq failed with rc=0x%lx\n", __func__, rc); + return rc; + } + free(buf); + + return rc; +} + +/* + * ASN.1 type PrivateKeyInfo ::= SEQUENCE { + * version Version + * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier + * privateKey PrivateKey + * attributes OPTIONAL + * } + * + * Where PrivateKey is defined as follows for EC: + * + * ASN.1 type RSAPrivateKey + * + * ECPrivateKey ::= SEQUENCE { + * version Version + * privateKey OCTET STRING + * parameters [0] ECParameters (OPTIONAL) + * publicKey [1] BIT STRING (OPTIONAL) + * } + */ +CK_RV der_decode_ECPublicKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **ec_params, + CK_ATTRIBUTE **ec_point) +{ + CK_ATTRIBUTE *params_attr = NULL; + CK_ATTRIBUTE *point_attr = NULL; + + CK_BYTE *algid = NULL; + CK_ULONG algid_len; + CK_BYTE *algid_ECBase = NULL; + CK_BYTE *param = NULL; + CK_ULONG param_len; + CK_BYTE *point = NULL; + CK_ULONG point_len; + CK_BYTE *ecpoint = NULL; + CK_ULONG ecpoint_len; + CK_ULONG field_len, len; + CK_RV rc; + + UNUSED(data_len); // XXX can this parameter be removed ? + + rc = ber_decode_SPKI(data, &algid, &algid_len, ¶m, ¶m_len, + &point, &point_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_SPKI failed\n"); + return rc; + } + + /* + * Make sure we're dealing with an EC key. + * Extract base alg-id of DER encoded EC byte string + * and compare against the decoded alg-id from the inner sequence + */ + rc = ber_decode_SEQUENCE((CK_BYTE *)der_AlgIdECBase, &algid_ECBase, &len, + &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); + return rc; + } + + if (memcmp(algid, algid_ECBase, len) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + // build ec-parameter attribute + rc = build_attribute(CKA_EC_PARAMS, param, param_len, ¶ms_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + /* build ec-point attribute as BER encoded OCTET STRING */ + rc = ber_encode_OCTET_STRING(FALSE, &ecpoint, &ecpoint_len, + point, point_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_OCTET_STRING failed\n"); + goto cleanup; + } + rc = build_attribute(CKA_EC_POINT, ecpoint, ecpoint_len, &point_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + + free(ecpoint); + *ec_params = params_attr; + *ec_point = point_attr; + return CKR_OK; + +cleanup: + if (params_attr) + free(params_attr); + if (point_attr) + free(point_attr); + if (ecpoint) + free(ecpoint); + + return rc; +} + +// DH is a little different from RSA +// +// DHPrivateKey ::= INTEGER +// +// The 'parameters' field of the AlgorithmIdentifier are as follows: +// +// DSSParameters ::= SEQUENCE { +// prime INTEGER +// base INTEGER +// } +// +CK_RV ber_encode_DHPrivateKey(CK_BBOOL length_only, + CK_BYTE **data, + CK_ULONG *data_len, + CK_ATTRIBUTE *prime, + CK_ATTRIBUTE *base, CK_ATTRIBUTE *priv_key) +{ + CK_BYTE *param = NULL; + CK_BYTE *buf = NULL; + CK_BYTE *tmp = NULL; + CK_BYTE *alg = NULL; + CK_ULONG offset, len, param_len; + CK_ULONG alg_len; + CK_RV rc; + + // build the DSS parameters first + offset = 0; + rc = 0; + + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, prime->ulValueLen); + offset += len; + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, base->ulValueLen); + offset += len; + + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + return CKR_FUNCTION_FAILED; + } + if (length_only == TRUE) { + rc = ber_encode_SEQUENCE(TRUE, NULL, ¶m_len, NULL, offset); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); + return rc; + } + rc = ber_encode_INTEGER(TRUE, NULL, &len, NULL, priv_key->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + return rc; + } + rc = ber_encode_PrivateKeyInfo(TRUE, + NULL, data_len, + NULL, ber_idDHLen + param_len, + NULL, len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); + } + return rc; + } + // 'buf' will be the sequence data for the AlgorithmIdentifyer::parameter + buf = (CK_BYTE *) malloc(offset); + if (!buf) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + len = 0; + offset = 0; + + rc = ber_encode_INTEGER(FALSE, &tmp, &len, prime->pValue, + prime->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + goto error; + } + if (tmp != NULL) { + memcpy(buf + offset, tmp, len); + offset += len; + free(tmp); + tmp = NULL; + } + + rc = ber_encode_INTEGER(FALSE, &tmp, &len, base->pValue, base->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + goto error; + } + if (tmp != NULL) { + memcpy(buf + offset, tmp, len); + offset += len; + free(tmp); + tmp = NULL; + } + + rc = ber_encode_SEQUENCE(FALSE, ¶m, ¶m_len, buf, offset); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); + free(buf); + return rc; + } + + free(buf); + buf = NULL; + + // Build the DSA AlgorithmIdentifier + // + // AlgorithmIdentifier ::= SEQUENCE { + // algorithm OBJECT IDENTIFIER + // parameters ANY DEFINED BY algorithm OPTIONAL + // } + // + len = ber_idDHLen + param_len; + buf = (CK_BYTE *) malloc(len); + if (!buf) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto error; + } + memcpy(buf, ber_idDH, ber_idDHLen); + memcpy(buf + ber_idDHLen, param, param_len); + + free(param); + param = NULL; + + rc = ber_encode_SEQUENCE(FALSE, &alg, &alg_len, buf, len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); + goto error; + } + free(buf); + buf = NULL; + + // build the private key INTEGER + rc = ber_encode_INTEGER(FALSE, &buf, &len, priv_key->pValue, + priv_key->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_INTEGER failed\n"); + goto error; + } + + rc = ber_encode_PrivateKeyInfo(FALSE, + data, data_len, alg, alg_len, buf, len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); + goto error; + } + +error: + if (alg) + free(alg); + if (buf) + free(buf); + if (param) + free(param); + if (tmp) + free(tmp); + + return rc; +} + +// +// +CK_RV ber_decode_DHPrivateKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **prime, + CK_ATTRIBUTE **base, CK_ATTRIBUTE **priv_key) +{ + CK_ATTRIBUTE *p_attr = NULL; + CK_ATTRIBUTE *g_attr = NULL; + CK_ATTRIBUTE *x_attr = NULL; + CK_BYTE *alg = NULL; + CK_BYTE *buf = NULL; + CK_BYTE *dhkey = NULL; + CK_BYTE *tmp = NULL; + CK_ULONG buf_len, field_len, len, offset; + CK_RV rc; + + rc = ber_decode_PrivateKeyInfo(data, data_len, &alg, &len, &dhkey); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_PrivateKeyInfo failed\n"); + return rc; + } + // make sure we're dealing with a DH key. just compare the OBJECT + // IDENTIFIER + if (memcmp(alg, ber_idDH, ber_idDHLen) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + // extract the parameter data into ATTRIBUTES + // + rc = ber_decode_SEQUENCE(alg + ber_idDSALen, &buf, &buf_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); + return rc; + } + offset = 0; + + // prime + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } + offset += field_len; + + // base + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } + offset += field_len; + + if (offset > buf_len) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + // it looks okay. build the attributes + + offset = 0; + + // prime + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_PRIME, tmp, len, &p_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + offset += field_len; + } + + // base + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_BASE, tmp, len, &g_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + offset += field_len; + } + + // now get the private key + rc = ber_decode_INTEGER(dhkey, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_VALUE, tmp, len, &x_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + offset += field_len; + } + + *prime = p_attr; + *base = g_attr; + *priv_key = x_attr; + + return CKR_OK; + +cleanup: + if (p_attr) + free(p_attr); + if (g_attr) + free(g_attr); + if (x_attr) + free(x_attr); + + return rc; +} + +CK_RV ber_encode_DHPublicKey(CK_BBOOL length_only, CK_BYTE **data, + CK_ULONG *data_len, CK_ATTRIBUTE *prime, + CK_ATTRIBUTE *base, CK_ATTRIBUTE *value) +{ + CK_ULONG len, parm_len, id_len, pub_len, offset, total; + CK_RV rc = 0; + CK_BYTE *buf = NULL; + CK_BYTE *buf2 = NULL; + BerValue *val; + BerElement *ber; + + /* Calculate the BER container length + * + * SPKI := SEQUENCE { + * SEQUENCE { + * OID + * Parameters + * } + * BITSTRING public key + * } + */ + + offset = 0; + rc = 0; + total = 0; + parm_len = 0; + id_len = 0; + pub_len = 0; + + /* OID and parameters */ + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, prime->ulValueLen); + offset += len; + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, base->ulValueLen); + offset += len; + rc |= ber_encode_SEQUENCE(TRUE, NULL, &parm_len, NULL, offset); + rc |= + ber_encode_SEQUENCE(TRUE, NULL, &id_len, NULL, ber_idDHLen + parm_len); + + /* public key */ + rc |= + ber_encode_INTEGER(FALSE, &buf, &len, value->pValue, value->ulValueLen); + ber = ber_alloc_t(LBER_USE_DER); + rc = ber_put_bitstring(ber, (char *)buf, len * 8, 0x03); + rc = ber_flatten(ber, &val); + pub_len = val->bv_len; + ber_free(ber, 1); + free(buf); + + rc |= ber_encode_SEQUENCE(TRUE, NULL, &total, NULL, id_len + pub_len); + + if (rc != CKR_OK) { + TRACE_DEVEL("%s der_encode_sequence failed with rc=0x%lx\n", __func__, + rc); + return rc; + } + + if (length_only == TRUE) { + *data_len = total; + return rc; + } + + buf = (CK_BYTE *) malloc(id_len + pub_len); + if (!buf) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + return CKR_HOST_MEMORY; + } + + /* Parameters */ + offset = 0; + rc = ber_encode_INTEGER(FALSE, &buf2, &len, prime->pValue, + prime->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); + return rc; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + + rc = ber_encode_INTEGER(FALSE, &buf2, &len, base->pValue, base->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); + return rc; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + + rc = ber_encode_SEQUENCE(FALSE, &buf2, &parm_len, buf, offset); + if (rc != CKR_OK) { + TRACE_DEVEL("%s ber_encode_Seq failed with rc=0x%lx\n", __func__, rc); + return rc; + } + + /* OID and parameters */ + memcpy(buf, ber_idDH, ber_idDHLen); + memcpy(buf + ber_idDHLen, buf2, parm_len); + free(buf2); + + rc = ber_encode_SEQUENCE(FALSE, &buf2, &id_len, buf, + ber_idDHLen + parm_len); + if (rc != CKR_OK) { + TRACE_DEVEL("%s ber_encode_Seq failed with rc=0x%lx\n", __func__, rc); + return rc; + } + free(buf); + + /* public key */ + rc = ber_encode_INTEGER(FALSE, &buf, &len, value->pValue, + value->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); + return rc; + } + + ber = ber_alloc_t(LBER_USE_DER); + rc = ber_put_bitstring(ber, (char *)buf, len * 8, 0x03); + rc = ber_flatten(ber, &val); + free(buf); + + buf = (CK_BYTE *) malloc(id_len + val->bv_len); + if (!buf) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + return CKR_HOST_MEMORY; + } + memcpy(buf, buf2, id_len); + memcpy(buf + id_len, val->bv_val, val->bv_len); + free(buf2); + ber_free(ber, 1); + + /* outer sequence */ + rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf, id_len + pub_len); + if (rc != CKR_OK) { + TRACE_DEVEL("%s der_encode_Seq failed with rc=0x%lx\n", __func__, rc); + return rc; + } + free(buf); + + return rc; +} + + +CK_RV ber_decode_DHPublicKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **prime, + CK_ATTRIBUTE **base, + CK_ATTRIBUTE **value) +{ + CK_ATTRIBUTE *prime_attr = NULL; + CK_ATTRIBUTE *base_attr = NULL; + CK_ATTRIBUTE *value_attr = NULL; + + CK_BYTE *algid = NULL; + CK_ULONG algid_len; + CK_BYTE *param = NULL; + CK_ULONG param_len; + CK_BYTE *val = NULL; + CK_ULONG val_len; + CK_BYTE *seq; + CK_ULONG seq_len; + CK_BYTE *p; + CK_ULONG p_len; + CK_BYTE *b; + CK_ULONG b_len; + CK_ULONG field_len, offset; + CK_RV rc; + + UNUSED(data_len); // XXX can this parameter be removed ? + + rc = ber_decode_SPKI(data, &algid, &algid_len, ¶m, ¶m_len, + &val, &val_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_SPKI failed\n"); + return rc; + } + + /* + * Make sure we're dealing with an DH key. + */ + if (memcmp(algid, ber_idDH, ber_idDHLen) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + rc = ber_decode_SEQUENCE(param, &seq, &seq_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); + return rc; + } + + rc = ber_decode_INTEGER(seq, &p, &p_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + return rc; + } + + offset = field_len; + rc = ber_decode_INTEGER(seq + offset, &b, &b_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + return rc; + } + + // build prime attribute + rc = build_attribute(CKA_PRIME, p, p_len, &prime_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + // build base attribute + rc = build_attribute(CKA_BASE, b, b_len, &base_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + // build value attribute + rc = build_attribute(CKA_VALUE, val, val_len, &value_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + + *prime = prime_attr; + *base = base_attr; + *value = value_attr; + return CKR_OK; + +cleanup: + if (prime_attr) + free(prime_attr); + if (base_attr) + free(base_attr); + if (value_attr) + free(value_attr); + + return rc; +} + +/** + * An IBM Dilithium public key is given by: + * + * SEQUENCE (2 elem) + * SEQUENCE (2 elem) + * OBJECT IDENTIFIER 1.3.6.1.4.1.2.267.1.6.5 + * NULL + * BIT STRING (1 elem) + * SEQUENCE (2 elem) + * BIT STRING (256 bit) = 32 bytes + * BIT STRING (13824 bit) = 1728 bytes + */ +CK_RV ber_encode_IBM_DilithiumPublicKey(CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len, + CK_ATTRIBUTE *rho, CK_ATTRIBUTE *t1) +{ + CK_BYTE *buf = NULL, *buf2 = NULL, *buf3 = NULL, *buf4 = NULL; + CK_ULONG len, len4, offset, total, total_len; + CK_RV rc; + + UNUSED(length_only); + + offset = 0; + rc = 0; + total_len = ber_AlgIdDilithiumLen; + total = 0; + + /* Calculate storage for inner sequence */ + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, rho->ulValueLen); + offset += len; + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, t1->ulValueLen); + offset += len; + + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); + return rc; + } + + /* Allocate storage for inner sequence */ + buf = (CK_BYTE *) malloc(offset); + if (!buf) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + return CKR_HOST_MEMORY; + } + + /** + * SEQUENCE (2 elem) + * BIT STRING -> rho + * BIT STRING -> t + */ + offset = 0; + rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, + rho->pValue, rho->ulValueLen, 0); + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); + goto error; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + + rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, + t1->pValue, t1->ulValueLen, 0); + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); + goto error; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + + rc = ber_encode_SEQUENCE(FALSE, &buf2, &len, buf, offset); + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_encode_Seq failed with rc=0x%lx\n", __func__, rc); + goto error; + } + free(buf); + buf = NULL; + + /* Calculate length of outer sequence */ + rc = ber_encode_BIT_STRING(TRUE, NULL, &total, buf2, len, 0); + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_encode_Oct_Str failed with rc=0x%lx\n", __func__, rc); + goto error; + } else { + total_len += total; + } + + /* Allocate storage for outer sequence and bit string */ + buf3 = (CK_BYTE *) malloc(total_len); + if (!buf3) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + rc = CKR_HOST_MEMORY; + goto error; + } + + /* + * SEQUENCE (2 elem) + * OBJECT IDENTIFIER 1.3.6.1.4.1.2.267.1.6.5 + * NULL <- no parms for this oid + */ + total_len = 0; + memcpy(buf3 + total_len, ber_AlgIdDilithium, ber_AlgIdDilithiumLen); + total_len += ber_AlgIdDilithiumLen; + + /* + * BIT STRING (1 elem) + * SEQUENCE (2 elem) + * BIT STRING -> rho + * BIT STRING -> t1 + */ + rc = ber_encode_BIT_STRING(FALSE, &buf4, &len4, buf2, len, 0); + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_encode_BIT_STRING failed with rc=0x%lx\n", __func__, rc); + goto error; + } + memcpy(buf3 + total_len, buf4, len4); + total_len += len4; + free(buf4); + buf4 = NULL; + + /** + * SEQUENCE (2 elem) + * SEQUENCE (2 elem) + * OBJECT IDENTIFIER 1.3.6.1.4.1.2.267.1.6.5 + * NULL -> no parms for this oid + * BIT STRING (1 elem) + * SEQUENCE (2 elem) + * BIT STRING -> rho + * BIT STRING -> t1 + */ + rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf3, total_len); + if (rc != CKR_OK) + TRACE_ERROR("%s ber_encode_Seq failed with rc=0x%lx\n", __func__, rc); + +error: + + if (buf) + free(buf); + if (buf2) + free(buf2); + if (buf3) + free(buf3); + + return rc; +} + + +CK_RV ber_decode_IBM_DilithiumPublicKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **rho_attr, + CK_ATTRIBUTE **t1_attr) +{ + CK_ATTRIBUTE *rho_attr_temp = NULL; + CK_ATTRIBUTE *t1_attr_temp = NULL; + + CK_BYTE *algid_DilithiumBase = NULL; + CK_BYTE *algid = NULL; + CK_ULONG algid_len; + CK_BYTE *param = NULL; + CK_ULONG param_len; + CK_BYTE *val = NULL; + CK_ULONG val_len; + CK_BYTE *seq; + CK_ULONG seq_len; + CK_BYTE *rho; + CK_ULONG rho_len; + CK_BYTE *t1; + CK_ULONG t1_len; + CK_ULONG field_len, offset, len; + CK_RV rc; + + UNUSED(data_len); // XXX can this parameter be removed ? + + rc = ber_decode_SPKI(data, &algid, &algid_len, ¶m, ¶m_len, + &val, &val_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_SPKI failed\n"); + return rc; + } + + /* Make sure we're dealing with a Dilithium key */ + rc = ber_decode_SEQUENCE((CK_BYTE *)ber_AlgIdDilithium, &algid_DilithiumBase, &len, + &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); + return rc; + } + if (memcmp(algid, algid_DilithiumBase, len) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + /* Decode sequence: + * SEQUENCE (2 elem) + * BIT STRING = rho + * BIT STRING = t1 + */ + rc = ber_decode_SEQUENCE(val, &seq, &seq_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); + return rc; + } + + /* Decode rho */ + rc = ber_decode_BIT_STRING(seq, &rho, &rho_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + return rc; + } + + /* Decode t1 */ + offset = field_len; + rc = ber_decode_BIT_STRING(seq + offset, &t1, &t1_len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + return rc; + } + + /* Build rho attribute */ + rc = build_attribute(CKA_IBM_DILITHIUM_RHO, rho, rho_len, &rho_attr_temp); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + + /* Build t1 attribute */ + rc = build_attribute(CKA_IBM_DILITHIUM_T1, t1, t1_len, &t1_attr_temp); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + + *rho_attr = rho_attr_temp; + *t1_attr = t1_attr_temp; + + return CKR_OK; + +cleanup: + if (rho_attr_temp) + free(rho_attr_temp); + if (t1_attr_temp) + free(t1_attr_temp); + + return rc; +} + +/** + * An IBM Dilithium private key is given by: + * + * DilithiumPrivateKey ::= SEQUENCE { + * version INTEGER, -- v0, reserved 0 + * rho BIT STRING, -- nonce + * key BIT STRING, -- key/seed/D + * tr BIT STRING, -- PRF bytes ('CRH' in spec) + * s1 BIT STRING, -- vector(L) + * s2 BIT STRING, -- vector(K) + * t0 BIT STRING -- low bits(vector L) + * t1 [0] IMPLICIT OPTIONAL { + * t1 BIT STRING -- high bits(vector L) -- see also public key + * } + * } + */ +CK_RV ber_encode_IBM_DilithiumPrivateKey(CK_BBOOL length_only, + CK_BYTE **data, + CK_ULONG *data_len, + CK_ATTRIBUTE *rho, + CK_ATTRIBUTE *seed, + CK_ATTRIBUTE *tr, + CK_ATTRIBUTE *s1, + CK_ATTRIBUTE *s2, + CK_ATTRIBUTE *t0, + CK_ATTRIBUTE *t1, + CK_ATTRIBUTE *opaque) +{ + CK_BYTE *buf = NULL, *buf2 = NULL, *buf3 = NULL; + CK_ULONG len, len2, offset; + CK_BYTE version[] = { 0 }; + CK_RV rc; + + /* Calculate storage for sequence */ + offset = 0; + rc = 0; + + rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, sizeof(version)); + offset += len; + if (opaque != NULL) { + rc |= ber_encode_OCTET_STRING(TRUE, NULL, &len, NULL, opaque->ulValueLen); + offset += len; + } else { + rc |= ber_encode_BIT_STRING(TRUE, NULL, &len, NULL, rho->ulValueLen, 0); + offset += len; + rc |= ber_encode_BIT_STRING(TRUE, NULL, &len, NULL, seed->ulValueLen, 0); + offset += len; + rc |= ber_encode_BIT_STRING(TRUE, NULL, &len, NULL, tr->ulValueLen, 0); + offset += len; + rc |= ber_encode_BIT_STRING(TRUE, NULL, &len, NULL, s1->ulValueLen, 0); + offset += len; + rc |= ber_encode_BIT_STRING(TRUE, NULL, &len, NULL, s2->ulValueLen, 0); + offset += len; + rc |= ber_encode_BIT_STRING(TRUE, NULL, &len, NULL, t0->ulValueLen, 0); + offset += len; + if (t1) { + rc |= ber_encode_BIT_STRING(TRUE, NULL, &len2, NULL, t1->ulValueLen, 0); + rc |= ber_encode_CHOICE(TRUE, 0, NULL, &len, NULL, len2); + offset += len; + } + } + + if (rc != CKR_OK) { + TRACE_DEVEL("Calculate storage for sequence failed\n"); + return CKR_FUNCTION_FAILED; + } + + if (length_only == TRUE) { + rc = ber_encode_SEQUENCE(TRUE, NULL, &len, NULL, offset); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); + return rc; + } + rc = ber_encode_PrivateKeyInfo(TRUE, + NULL, data_len, + NULL, ber_AlgIdDilithiumLen, + NULL, len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); + return rc; + } + return rc; + } + + /* Allocate storage for sequence */ + buf = (CK_BYTE *) malloc(offset); + if (!buf) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + offset = 0; + rc = 0; + + /* Version */ + rc = ber_encode_INTEGER(FALSE, &buf2, &len, version, sizeof(version)); + if (rc != CKR_OK) { + TRACE_ERROR("ber_encode_INTEGER of version failed\n"); + goto error; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + + /* Check if key given as opaque blob */ + if (opaque != NULL) { + // the CKA_IBM_OPAQUE attrib + rc = ber_encode_OCTET_STRING(FALSE, &buf2, &len, + opaque->pValue, opaque->ulValueLen); + if (rc != CKR_OK) { + TRACE_ERROR("ber_encode_OCTET_STRING failed\n"); + goto error; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + } else { + /* rho */ + rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, + rho->pValue, rho->ulValueLen, 0); + if (rc != CKR_OK) { + TRACE_ERROR("ber_encode_BIT_STRING of rho failed\n"); + goto error; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + + /* seed */ + rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, + seed->pValue, seed->ulValueLen, 0); + if (rc != CKR_OK) { + TRACE_ERROR("ber_encode_BIT_STRING of seed failed\n"); + goto error; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + + /* tr */ + rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, + tr->pValue, tr->ulValueLen, 0); + if (rc != CKR_OK) { + TRACE_ERROR("ber_encode_BIT_STRING of (tr) failed\n"); + goto error; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + + /* s1 */ + rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, + s1->pValue, s1->ulValueLen, 0); + if (rc != CKR_OK) { + TRACE_ERROR("ber_encode_BIT_STRING of (s1) failed\n"); + goto error; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + + /* s2 */ + rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, + s2->pValue, s2->ulValueLen, 0); + if (rc != CKR_OK) { + TRACE_ERROR("ber_encode_BIT_STRING of (s2) failed\n"); + goto error; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + + /* t0 */ + rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, + t0->pValue, t0->ulValueLen, 0); + if (rc != CKR_OK) { + TRACE_ERROR("ber_encode_BIT_STRING of (t0) failed\n"); + goto error; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + + /* (t1) Optional bit-string of public key */ + if (t1 && t1->pValue) { + rc = ber_encode_BIT_STRING(FALSE, &buf3, &len2, t1->pValue, t1->ulValueLen, 0); + rc |= ber_encode_CHOICE(FALSE, 0, &buf2, &len, buf3, len2); + if (rc != CKR_OK) { + TRACE_ERROR("encoding of t1 value failed\n"); + goto error; + } + memcpy(buf + offset, buf2, len); + offset += len; + free(buf2); + buf2 = NULL; + } + } + + /* Encode sequence */ + rc = ber_encode_SEQUENCE(FALSE, &buf2, &len, buf, offset); + if (rc != CKR_OK) { + TRACE_ERROR("ber_encode_SEQUENCE failed\n"); + goto error; + } + rc = ber_encode_PrivateKeyInfo(FALSE, + data, data_len, + ber_AlgIdDilithium, + ber_AlgIdDilithiumLen, buf2, len); + if (rc != CKR_OK) { + TRACE_ERROR("ber_encode_PrivateKeyInfo failed\n"); + } + +error: + if (buf3) + free(buf3); + if (buf2) + free(buf2); + if (buf) + free(buf); + + return rc; +} + +/** + * decode an IBM Dilithium private key: + * + * DilithiumPrivateKey ::= SEQUENCE { + * version INTEGER, -- v0, reserved 0 + * rho BIT STRING, -- nonce + * key BIT STRING, -- key/seed/D + * tr BIT STRING, -- PRF bytes ('CRH' in spec) + * s1 BIT STRING, -- vector(L) + * s2 BIT STRING, -- vector(K) + * t0 BIT STRING -- low bits(vector L) + * t1 [0] IMPLICIT OPTIONAL { + * t1 BIT STRING -- high bits(vector L) -- see also public key + * } + * } + */ +CK_RV ber_decode_IBM_DilithiumPrivateKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **rho, + CK_ATTRIBUTE **seed, + CK_ATTRIBUTE **tr, + CK_ATTRIBUTE **s1, + CK_ATTRIBUTE **s2, + CK_ATTRIBUTE **t0, + CK_ATTRIBUTE **t1, + CK_ATTRIBUTE **opaque, + CK_BBOOL isopaque) +{ + CK_ATTRIBUTE *rho_attr = NULL, *seed_attr = NULL; + CK_ATTRIBUTE *tr_attr = NULL, *s1_attr = NULL, *s2_attr = NULL; + CK_ATTRIBUTE *t0_attr = NULL, *t1_attr = NULL; + CK_ATTRIBUTE *o_attr = NULL; + CK_BYTE *alg = NULL; + CK_BYTE *dilithium_priv_key = NULL; + CK_BYTE *buf = NULL; + CK_BYTE *tmp = NULL; + CK_ULONG offset, buf_len, field_len, len; + CK_RV rc; + + /* Check if this is a Dilithium private key */ + rc = ber_decode_PrivateKeyInfo(data, data_len, &alg, &len, + &dilithium_priv_key); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_PrivateKeyInfo failed\n"); + return rc; + } + + if (memcmp(alg, ber_AlgIdDilithium, ber_AlgIdDilithiumLen) != 0) { + // probably ought to use a different error + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + /* Decode private Dilithium key */ + rc = ber_decode_SEQUENCE(dilithium_priv_key, &buf, &buf_len, &field_len); + if (rc != CKR_OK) + return rc; + + /* Now build the attributes */ + offset = 0; + + /* Skip the version */ + rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_INTEGER failed\n"); + goto cleanup; + } + offset += field_len; + + /* Check if key given as opaque blob */ + if (isopaque) { + + /* Key is opaque */ + rc = ber_decode_OCTET_STRING(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_IBM_OPAQUE, tmp, len, &o_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + offset += field_len; + } + *opaque = o_attr; + + } else { + + /* rho */ + rc = ber_decode_BIT_STRING(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_BIT_STRING of (rho) failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_IBM_DILITHIUM_RHO, tmp, len, &rho_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute for (rho) failed\n"); + goto cleanup; + } + offset += field_len; + } + + /* seed */ + rc = ber_decode_BIT_STRING(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_BIT_STRING of (seed) failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_IBM_DILITHIUM_SEED, tmp, len, &seed_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute for (seed) failed\n"); + goto cleanup; + } + offset += field_len; + } + + /* tr */ + rc = ber_decode_BIT_STRING(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_BIT_STRING of (tr) failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_IBM_DILITHIUM_TR, tmp, len, &tr_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute for (tr) failed\n"); + goto cleanup; + } + offset += field_len; + } + + /* s1 */ + rc = ber_decode_BIT_STRING(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_BIT_STRING of (s1) failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_IBM_DILITHIUM_S1, tmp, len, &s1_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute for (s1) failed\n"); + goto cleanup; + } + offset += field_len; + } + + /* s2 */ + rc = ber_decode_BIT_STRING(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_BIT_STRING of (s2) failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_IBM_DILITHIUM_S2, tmp, len, &s2_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute for (s2) failed\n"); + goto cleanup; + } + offset += field_len; + } + + /* t0 */ + rc = ber_decode_BIT_STRING(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_BIT_STRING of (t0) failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_IBM_DILITHIUM_T0, tmp, len, &t0_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute for (t0) failed\n"); + goto cleanup; + } + offset += field_len; + } + + /* t1 */ + rc = ber_decode_BIT_STRING(buf + offset, &tmp, &len, &field_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_BIT_STRING of (t1) failed\n"); + goto cleanup; + } else { + rc = build_attribute(CKA_IBM_DILITHIUM_T1, tmp, len, &t1_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute for (t1) failed\n"); + goto cleanup; + } + offset += field_len; + } + } + + /* Check if buffer big enough */ + if (offset > buf_len) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + goto cleanup; + } + + *rho = rho_attr; + *seed = seed_attr; + *tr = tr_attr; + *s1 = s1_attr; + *s2 = s2_attr; + *t0 = t0_attr; + *t1 = t1_attr; + + return CKR_OK; + +cleanup: + + if (seed_attr) + free(seed_attr); + if (t1_attr) + free(t1_attr); + if (isopaque) { + if (o_attr) + free(o_attr); + } else { + if (rho_attr) + free(rho_attr); + if (seed_attr) + free(seed_attr); + if (tr_attr) + free(tr_attr); + if (s1_attr) + free(s1_attr); + if (s2_attr) + free(s2_attr); + if (t0_attr) + free(t0_attr); + } + + return rc; +} diff --git a/usr/lib/common/attributes.c b/usr/lib/common/attributes.c new file mode 100644 index 0000000..fcefbc1 --- /dev/null +++ b/usr/lib/common/attributes.c @@ -0,0 +1,155 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2012-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 + */ + +/* + * OpenCryptoki ICSF token - LDAP functions + * + * Author: Marcelo Cerri (mhcerri@br.ibm.com) + * + */ + +#include +#include +#include "attributes.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "trace.h" +#include + +static void __cleanse_and_free_attribute_array(CK_ATTRIBUTE_PTR attrs, + CK_ULONG attrs_len, + CK_BBOOL cleanse) +{ + CK_ULONG i; + + if (!attrs) + return; + + for (i = 0; i < attrs_len; i++) + if (attrs[i].pValue) { + if (cleanse) + OPENSSL_cleanse(attrs[i].pValue, attrs[i].ulValueLen); + free(attrs[i].pValue); + } + free(attrs); +} + +/* + * Free an array of attributes allocated with dup_attribute_array(). + */ +void free_attribute_array(CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len) +{ + __cleanse_and_free_attribute_array(attrs, attrs_len, FALSE); +} + +/* + * Free an array of attributes allocated with dup_attribute_array() and cleanse + * all attribute values. + */ +void cleanse_and_free_attribute_array(CK_ATTRIBUTE_PTR attrs, + CK_ULONG attrs_len) +{ + __cleanse_and_free_attribute_array(attrs, attrs_len, TRUE); +} + +/* + * Duplicate an array of attributes and all its values. + * + * The returned array must be freed with free_attribute_array(). + */ +CK_RV dup_attribute_array(CK_ATTRIBUTE_PTR orig, CK_ULONG orig_len, + CK_ATTRIBUTE_PTR *p_dest, CK_ULONG *p_dest_len) +{ + CK_RV rc = CKR_OK; + CK_ATTRIBUTE_PTR dest; + CK_ULONG dest_len; + CK_ATTRIBUTE_PTR it; + + /* Allocate the new array */ + dest_len = orig_len; + dest = malloc(dest_len * sizeof(*dest)); + if (dest == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + memset(dest, 0, dest_len); + + /* Copy each element */ + for (it = dest; it != (dest + orig_len); it++, orig++) { + it->type = orig->type; + it->ulValueLen = orig->ulValueLen; + it->pValue = malloc(it->ulValueLen); + if (it->pValue == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memcpy(it->pValue, orig->pValue, orig->ulValueLen); + } + +done: + if (rc == CKR_OK) { + *p_dest = dest; + *p_dest_len = dest_len; + } else { + free_attribute_array(dest, dest_len); + } + + return rc; +} + +/* + * Return the attribute structure for a given type. + */ +CK_ATTRIBUTE_PTR get_attribute_by_type(CK_ATTRIBUTE_PTR attrs, + CK_ULONG attrs_len, CK_ULONG type) +{ + CK_ATTRIBUTE_PTR it; + + for (it = attrs; it != attrs + attrs_len; it++) + if (it->type == type) + return it; + + return NULL; +} + +/* + * Reallocate the attribute array and add the new element. + */ +CK_RV add_to_attribute_array(CK_ATTRIBUTE_PTR *p_attrs, + CK_ULONG_PTR p_attrs_len, CK_ULONG type, + CK_BYTE_PTR value, CK_ULONG value_len) +{ + CK_ATTRIBUTE_PTR attrs; + CK_BYTE_PTR copied_value; + + copied_value = malloc(value_len); + if (copied_value == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + memcpy(copied_value, value, value_len); + + attrs = realloc(*p_attrs, sizeof(**p_attrs) * (*p_attrs_len + 1)); + if (attrs == NULL) { + free(copied_value); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + attrs[*p_attrs_len].type = type; + attrs[*p_attrs_len].pValue = copied_value; + attrs[*p_attrs_len].ulValueLen = value_len; + *p_attrs = attrs; + *p_attrs_len += 1; + + return CKR_OK; +} diff --git a/usr/lib/common/attributes.h b/usr/lib/common/attributes.h new file mode 100644 index 0000000..4e4c820 --- /dev/null +++ b/usr/lib/common/attributes.h @@ -0,0 +1,36 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2012-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 + */ + +/* + * OpenCryptoki ICSF token - LDAP functions + * Author: Marcelo Cerri (mhcerri@br.ibm.com) + * + */ + +#ifndef _ATTRIBUTES_H_ +#define _ATTRIBUTES_H_ + +#include "pkcs11types.h" + +void free_attribute_array(CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len); + +void cleanse_and_free_attribute_array(CK_ATTRIBUTE_PTR attrs, + CK_ULONG attrs_len); + +CK_RV dup_attribute_array(CK_ATTRIBUTE_PTR orig, CK_ULONG orig_len, + CK_ATTRIBUTE_PTR *p_dest, CK_ULONG *p_dest_len); + +CK_ATTRIBUTE_PTR get_attribute_by_type(CK_ATTRIBUTE_PTR attrs, + CK_ULONG attrs_len, CK_ULONG type); + +CK_RV add_to_attribute_array(CK_ATTRIBUTE_PTR *p_attrs, + CK_ULONG_PTR p_attrs_len, CK_ULONG type, + CK_BYTE_PTR value, CK_ULONG value_len); +#endif diff --git a/usr/lib/common/btree.c b/usr/lib/common/btree.c new file mode 100644 index 0000000..e6a0df4 --- /dev/null +++ b/usr/lib/common/btree.c @@ -0,0 +1,466 @@ +/* + * 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 "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) +{ + __transaction_atomic { /* start transaction */ + return __bt_get_node(t, node_num); + } /* end transaction */ +} + +/* + * 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; + + __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); + + if (v != NULL) + ((struct bt_ref_hdr *)v)->ref++; + } /* end transaction */ + + if (v != NULL) { + TRACE_DEBUG("bt_get_node_value: Btree: %p Value: %p Ref: %lu\n", + (void *)t, v, ((struct bt_ref_hdr *)v)->ref); + } + + 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; + 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 (warn) { + 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); + } + + 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) +{ + TRACE_DEBUG("bt_node_add: Btree: %p Value: %p Ref: 1\n", (void *)t, value); + + __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; + } + + 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; + } + + 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; + } + } 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; + } + } + + new_node_index >>= 1; + } + + t->size++; + + return t->size; + } /* end transaction */ +} + +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; +#ifdef DEBUG + unsigned long int ref; +#endif + + __transaction_atomic { /* start transaction */ + node = __bt_get_node(t, node_num); + + 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++; + +#ifdef DEBUG + ref = ((struct bt_ref_hdr *)value)->ref; +#endif + } + } /* end transaction */ + + if (value != NULL) { + TRACE_DEBUG("bt_node_free: Btree: %p Value: %p Ref: %lu\n", (void *)t, + value, ref); + } + + 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) +{ + __transaction_atomic { /* start transaction */ + return (t->free_nodes == t->size); + } /* end transaction */ +} + +/* 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) +{ + __transaction_atomic { /* start transaction */ + return (t->size - t->free_nodes); + } /* end transaction */ +} + +/* 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 transaction 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; + + 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; + } + } /* end transaction */ + + /* + * 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)) { + + 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); + } + + __transaction_atomic { /* start transaction */ + free(temp); + t->size--; + } /* end transaction */ + } + + __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 */ +} + +/* 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 *)) +{ + t->free_list = NULL; + t->top = NULL; + t->size = 0; + t->free_nodes = 0; + t->delete_func = delete_func; +} diff --git a/usr/lib/common/cert.c b/usr/lib/common/cert.c new file mode 100644 index 0000000..4748eca --- /dev/null +++ b/usr/lib/common/cert.c @@ -0,0 +1,212 @@ +/* + * 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: cert.c +// +// Functions contained within: +// +// cert_check_required_attributes +// cert_validate_attribute +// cert_x509_check_required_attributes +// cert_x509_set_default_attributes +// cert_x509_validate_attribute +// cert_vendor_check_required_attributes +// cert_vendor_validate_attribute +// + +#include +#include + +#include // for memcmp() et al + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "trace.h" + + +// cert_check_required_attributes +// +// Checks for required attributes for generic CKO_CERTIFICATE objects +// +// CKA_CERTIFICATE_TYPE : must be present on MODE_CREATE. +// +CK_RV cert_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + if (!tmpl) + return CKR_FUNCTION_FAILED; + + if (mode == MODE_CREATE) { + found = template_attribute_find(tmpl, CKA_CERTIFICATE_TYPE, &attr); + if (found == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + // don't bother checking the value. it was checked in the 'validate' + // routine. + } + + return template_check_required_base_attributes(tmpl, mode); +} + + +// cert_validate_attribute() +// +CK_RV cert_validate_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode) +{ + CK_CERTIFICATE_TYPE type; + + switch (attr->type) { + case CKA_CERTIFICATE_TYPE: + if (mode != MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + type = *(CK_CERTIFICATE_TYPE *) attr->pValue; + if (type == CKC_X_509 || type >= CKC_VENDOR_DEFINED) { + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + default: + return template_validate_base_attribute(tmpl, attr, mode); + } +} + + +// cert_x509_check_required_attributes() +// +CK_RV cert_x509_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_SUBJECT, &attr); + if (!found) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + return cert_check_required_attributes(tmpl, mode); +} + + +// cert_x509_set_default_attributes() +// +// Set the default attributes for X.509 certificates +// +// CKA_ID : empty string +// CKA_ISSUER : empty string +// CKA_SERIAL_NUMBER : empty string +// +CK_RV cert_x509_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *id_attr = NULL; + CK_ATTRIBUTE *issuer_attr = NULL; + CK_ATTRIBUTE *serial_attr = NULL; + + // satisfy compiler warning.... + // + if (mode) + id_attr = NULL; + + id_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + issuer_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + serial_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + + if (!id_attr || !issuer_attr || !serial_attr) { + if (id_attr) + free(id_attr); + if (issuer_attr) + free(issuer_attr); + if (serial_attr) + free(serial_attr); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + + return CKR_HOST_MEMORY; + } + + id_attr->type = CKA_ID; + id_attr->ulValueLen = 0; // empty string + id_attr->pValue = NULL; + + issuer_attr->type = CKA_ISSUER; + issuer_attr->ulValueLen = 0; // empty byte array + issuer_attr->pValue = NULL; + + serial_attr->type = CKA_SERIAL_NUMBER; + serial_attr->ulValueLen = 0; // empty byte array + serial_attr->pValue = NULL; + + template_update_attribute(tmpl, id_attr); + template_update_attribute(tmpl, issuer_attr); + template_update_attribute(tmpl, serial_attr); + + return CKR_OK; +} + + +// cert_x509_validate_attributes() +// +CK_RV cert_x509_validate_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode) +{ + switch (attr->type) { + case CKA_SUBJECT: + if (mode != MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + return CKR_OK; + case CKA_ID: + case CKA_ISSUER: + case CKA_SERIAL_NUMBER: + return CKR_OK; + case CKA_VALUE: + if (mode != MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + return CKR_OK; + default: + return cert_validate_attribute(tmpl, attr, mode); + } +} + + +// cert_vendor_check_required_attributes() +// +CK_RV cert_vendor_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + // CKC_VENDOR has no required attributes + // + return cert_check_required_attributes(tmpl, mode); +} + + +// cert_vendor_validate_attribute() +// +CK_RV cert_vendor_validate_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode) +{ + // cryptoki specifies no attributes for CKC_VENDOR certificates + // + return cert_validate_attribute(tmpl, attr, mode); +} diff --git a/usr/lib/common/common.mk b/usr/lib/common/common.mk new file mode 100644 index 0000000..31f1686 --- /dev/null +++ b/usr/lib/common/common.mk @@ -0,0 +1,8 @@ +noinst_HEADERS += \ + usr/lib/common/attributes.h usr/lib/common/ec_defs.h \ + usr/lib/common/host_defs.h usr/lib/common/ock_syslog.h \ + usr/lib/common/shared_memory.h usr/lib/common/tok_spec_struct.h \ + usr/lib/common/trace.h usr/lib/common/h_extern.h \ + usr/lib/common/sw_crypt.h usr/lib/common/defs.h \ + usr/lib/common/p11util.h \ + usr/lib/common/list.h usr/lib/common/tok_specific.h diff --git a/usr/lib/common/data_obj.c b/usr/lib/common/data_obj.c new file mode 100644 index 0000000..0cc6b0d --- /dev/null +++ b/usr/lib/common/data_obj.c @@ -0,0 +1,120 @@ +/* + * 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: data_obj.c +// +// Functions contained within: +// +// data_object_check_required_attributes +// data_object_set_default_attributes +// data_object_validate_attribute +// + +#include +#include + +#include // for memcmp() et al + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "trace.h" + + +// data_object_check_required_attributes() +// +CK_RV data_object_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + // CKO_DATA has no required attributes + // + + return template_check_required_base_attributes(tmpl, mode); +} + + +// data_object_set_default_attributes() +// +// Set the default attributes for data objects: +// +// CKA_APPLICATION : empty string +// CKA_VALUE : empty byte array +// +CK_RV data_object_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *class_attr = NULL; + CK_ATTRIBUTE *app_attr = NULL; + CK_ATTRIBUTE *value_attr = NULL; + + // satisfy the compiler + // + if (mode) + app_attr = NULL; + + // add the default CKO_DATA attributes + // + class_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_OBJECT_CLASS)); + app_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + + if (!class_attr || !app_attr || !value_attr) { + if (class_attr) + free(class_attr); + if (app_attr) + free(app_attr); + if (value_attr) + free(value_attr); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + app_attr->type = CKA_APPLICATION; + app_attr->ulValueLen = 0; // empty string + app_attr->pValue = NULL; + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; // empty byte array + value_attr->pValue = NULL; + + class_attr->type = CKA_CLASS; + class_attr->ulValueLen = sizeof(CK_OBJECT_CLASS); + class_attr->pValue = (CK_BYTE *) class_attr + sizeof(CK_ATTRIBUTE); + *(CK_OBJECT_CLASS *) class_attr->pValue = CKO_DATA; + + template_update_attribute(tmpl, class_attr); + template_update_attribute(tmpl, app_attr); + template_update_attribute(tmpl, value_attr); + + return CKR_OK; +} + + +// data_object_validate_attribute() +// +// Determine whether a CKO_DATA object's attribute are valid. +// +CK_RV data_object_validate_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode) +{ + if (!attr) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + switch (attr->type) { + case CKA_APPLICATION: + case CKA_VALUE: + return CKR_OK; + default: + return template_validate_base_attribute(tmpl, attr, mode); + } + + return CKR_OK; +} diff --git a/usr/lib/common/decr_mgr.c b/usr/lib/common/decr_mgr.c new file mode 100644 index 0000000..d0a7816 --- /dev/null +++ b/usr/lib/common/decr_mgr.c @@ -0,0 +1,1087 @@ +/* + * 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: decr_mgr.c +// +// Decryption manager routines +// + +#include +#include // for memcmp() et al +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "trace.h" + +// +// +CK_RV decr_mgr_init(STDLL_TokData_t *tokdata, + SESSION *sess, + ENCR_DECR_CONTEXT *ctx, + CK_ULONG operation, + CK_MECHANISM *mech, CK_OBJECT_HANDLE key_handle) +{ + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *ptr = NULL; + CK_KEY_TYPE keytype; + CK_BBOOL flag; + CK_RV rc; + + if (!sess) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (ctx->active != FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + return CKR_OPERATION_ACTIVE; + } + // key usage restrictions + // + if (operation == OP_DECRYPT_INIT) { + rc = object_mgr_find_in_map1(tokdata, key_handle, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle.\n"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + // is key allowed to do general decryption? + // + rc = template_attribute_find(key_obj->template, CKA_DECRYPT, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_ENCRYPT for the key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } else { + flag = *(CK_BBOOL *) attr->pValue; + if (flag != TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_FUNCTION_NOT_PERMITTED)); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + } + } else if (operation == OP_UNWRAP) { + rc = object_mgr_find_in_map1(tokdata, key_handle, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle.\n"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + rc = CKR_WRAPPING_KEY_HANDLE_INVALID; + goto done; + } + // is key allowed to unwrap other keys? + // + rc = template_attribute_find(key_obj->template, CKA_UNWRAP, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_UNWRAP for the key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } else { + flag = *(CK_BBOOL *) attr->pValue; + if (flag == FALSE) { + TRACE_ERROR("CKA_UNWRAP is set to FALSE.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + } + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + // is the mechanism supported? is the key type correct? is a + // parameter present if required? is the key size allowed? + // does the key support decryption? + // + // Will the FCV allow the operation? + // + switch (mech->mechanism) { + case CKM_DES_ECB: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // is the key type correct? + // + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_DES) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // Check FCV + // + // if ((nv_FCV.FunctionCntlBytes[DES_FUNCTION_BYTE] + // & FCV_56_BIT_DES) == 0) + // rc = CKR_MECHANISM_INVALID; + // goto done; + + ctx->context_len = sizeof(DES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(DES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(DES_CONTEXT)); + break; + case CKM_CDMF_ECB: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // is the key type correct? + // + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_CDMF) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // Check FCV + // + // if ((nv_FCV.FunctionCntlBytes[DES_FUNCTION_BYTE] + // & FCV_CDMF_DES) == 0) + // rc = CKR_MECHANISM_INVALID; + // goto done; + + ctx->context_len = sizeof(DES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(DES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(DES_CONTEXT)); + break; + case CKM_DES_CBC: + case CKM_DES_CBC_PAD: + if (mech->ulParameterLen != DES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // is the key type correct? + // + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_DES) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // Check FCV + // + // if ((nv_FCV.FunctionCntlBytes[DES_FUNCTION_BYTE] + // & FCV_56_BIT_DES) == 0) + // rc = CKR_MECHANISM_INVALID; + // goto done; + + ctx->context_len = sizeof(DES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(DES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(DES_CONTEXT)); + break; + case CKM_CDMF_CBC: + case CKM_CDMF_CBC_PAD: + if (mech->ulParameterLen != DES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // is the key type correct? + // + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_CDMF) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + + ctx->context_len = sizeof(DES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(DES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(DES_CONTEXT)); + break; + case CKM_DES_CFB8: + case CKM_DES_CFB64: + case CKM_DES_OFB64: + if (mech->ulParameterLen != DES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if ((keytype != CKK_DES3)) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + ctx->context_len = sizeof(DES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(DES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(DES_CONTEXT)); + break; + case CKM_DES3_ECB: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // is the key type correct? + // + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_DES3 && keytype != CKK_DES2) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // Check FCV + // + // if ((nv_FCV.FunctionCntlBytes[DES_FUNCTION_BYTE] + // & FCV_TRIPLE_DES) == 0) + // rc = CKR_MECHANISM_INVALID; + // goto done; + + ctx->context_len = sizeof(DES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(DES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(DES_CONTEXT)); + break; + case CKM_DES3_CBC: + case CKM_DES3_CBC_PAD: + if (mech->ulParameterLen != DES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // is the key type correct? + // + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_DES3 && keytype != CKK_DES2) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // Check FCV + // + // if ((nv_FCV.FunctionCntlBytes[DES_FUNCTION_BYTE] + // & FCV_TRIPLE_DES) == 0) + // rc = CKR_MECHANISM_INVALID; + // goto done; + + ctx->context_len = sizeof(DES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(DES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(DES_CONTEXT)); + break; + case CKM_RSA_PKCS_OAEP: + if (mech->ulParameterLen == 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_RSA) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + // RSA cannot be used for multi-part operations + // + ctx->context_len = 0; + ctx->context = NULL; + break; + case CKM_RSA_X_509: + case CKM_RSA_PKCS: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_RSA) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // RSA cannot be used for multi-part operations + // + ctx->context_len = 0; + ctx->context = NULL; + break; + case CKM_AES_ECB: + // XXX Copied from DES3, should be verified - KEY + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // is the key type correct? + // + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_AES) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + ctx->context_len = sizeof(AES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(AES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(AES_CONTEXT)); + break; + case CKM_AES_CBC: + case CKM_AES_CBC_PAD: + // XXX Copied from DES3, should be verified - KEY + if (mech->ulParameterLen != AES_INIT_VECTOR_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // is the key type correct? + // + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_AES) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + ctx->context_len = sizeof(AES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(AES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(AES_CONTEXT)); + break; + case CKM_AES_CTR: + if (mech->ulParameterLen != sizeof(CK_AES_CTR_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // is the key type correct? + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_AES) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + ctx->context_len = sizeof(AES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(AES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(AES_CONTEXT)); + break; + case CKM_AES_GCM: + if (mech->ulParameterLen != sizeof(CK_GCM_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_AES) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + ctx->context_len = sizeof(AES_GCM_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(AES_GCM_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(AES_GCM_CONTEXT)); + + rc = aes_gcm_init(tokdata, sess, ctx, mech, key_handle, 0); + if (rc) { + TRACE_ERROR("Could not initialize AES_GCM parms.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + break; + case CKM_AES_OFB: + case CKM_AES_CFB8: + case CKM_AES_CFB64: + case CKM_AES_CFB128: + if (mech->ulParameterLen != AES_INIT_VECTOR_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_AES) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + ctx->context_len = sizeof(AES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(AES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(AES_CONTEXT)); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + if ((mech->ulParameterLen > 0) || (mech->mechanism == CKM_AES_CTR) || + (mech->mechanism == CKM_AES_GCM)) { + ptr = (CK_BYTE *) malloc(mech->ulParameterLen); + if (!ptr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memcpy(ptr, mech->pParameter, mech->ulParameterLen); + } else if (mech->ulParameterLen > 0) { + ptr = (CK_BYTE *) malloc(mech->ulParameterLen); + if (!ptr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memcpy(ptr, mech->pParameter, mech->ulParameterLen); + } + + ctx->key = key_handle; + ctx->mech.ulParameterLen = mech->ulParameterLen; + ctx->mech.mechanism = mech->mechanism; + ctx->mech.pParameter = ptr; + ctx->multi_init = FALSE; + ctx->multi = FALSE; + ctx->active = TRUE; + + rc = CKR_OK; + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +// +// +CK_RV decr_mgr_cleanup(ENCR_DECR_CONTEXT *ctx) +{ + if (!ctx) { + TRACE_ERROR("Invalid function argument.\n"); + return CKR_FUNCTION_FAILED; + } + ctx->key = 0; + ctx->mech.ulParameterLen = 0; + ctx->mech.mechanism = 0; + ctx->multi_init = FALSE; + ctx->multi = FALSE; + ctx->active = FALSE; + ctx->init_pending = FALSE; + ctx->context_len = 0; + + if (ctx->mech.pParameter) { + free(ctx->mech.pParameter); + ctx->mech.pParameter = NULL; + } + + if (ctx->context) { + free(ctx->context); + ctx->context = NULL; + } + + return CKR_OK; +} + +// +// +CK_RV decr_mgr_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_KEY_TYPE keytype; + + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (ctx->active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->multi_init == FALSE) { + ctx->multi = FALSE; + ctx->multi_init = TRUE; + } + + // if the caller just wants the decrypted length, there is no reason to + // specify the input data. I just need the data length + // + if ((length_only == FALSE) && (!in_data || !out_data)) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + if (ctx->multi == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + return CKR_OPERATION_ACTIVE; + } + switch (ctx->mech.mechanism) { + case CKM_CDMF_ECB: + case CKM_DES_ECB: + return des_ecb_decrypt(tokdata, sess, length_only, + ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_CDMF_CBC: + case CKM_DES_CBC: + return des_cbc_decrypt(tokdata, sess, length_only, + ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_DES_CBC_PAD: + case CKM_CDMF_CBC_PAD: + return des_cbc_pad_decrypt(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_DES_OFB64: + get_keytype(tokdata, ctx->key, &keytype); + if (keytype == CKK_DES3) { + return des3_ofb_decrypt(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + case CKM_DES_CFB8: + get_keytype(tokdata, ctx->key, &keytype); + if (keytype == CKK_DES3) { + return des3_cfb_decrypt(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len, 0x01); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + case CKM_DES_CFB64: + get_keytype(tokdata, ctx->key, &keytype); + if (keytype == CKK_DES3) { + return des3_cfb_decrypt(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len, 0x08); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + case CKM_DES3_ECB: + return des3_ecb_decrypt(tokdata, sess, length_only, + ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_DES3_CBC: + return des3_cbc_decrypt(tokdata, sess, length_only, + ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_DES3_CBC_PAD: + return des3_cbc_pad_decrypt(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_RSA_PKCS: + return rsa_pkcs_decrypt(tokdata, sess, length_only, + ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_RSA_PKCS_OAEP: + return rsa_oaep_crypt(tokdata, sess, length_only, ctx, in_data, + in_data_len, out_data, out_data_len, DECRYPT); + case CKM_RSA_X_509: + return rsa_x509_decrypt(tokdata, sess, length_only, + ctx, + in_data, in_data_len, out_data, out_data_len); +#ifndef NOAES + case CKM_AES_CBC: + return aes_cbc_decrypt(tokdata, sess, length_only, + ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_AES_ECB: + return aes_ecb_decrypt(tokdata, sess, length_only, + ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_AES_CBC_PAD: + return aes_cbc_pad_decrypt(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_AES_CTR: + return aes_ctr_decrypt(tokdata, sess, length_only, + ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_AES_GCM: + return aes_gcm_decrypt(tokdata, sess, length_only, ctx, in_data, + in_data_len, out_data, out_data_len); + case CKM_AES_OFB: + return aes_ofb_decrypt(tokdata, sess, length_only, + ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_AES_CFB8: + return aes_cfb_decrypt(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len, 0x01); + case CKM_AES_CFB64: + return aes_cfb_decrypt(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len, 0x08); + case CKM_AES_CFB128: + return aes_cfb_decrypt(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len, 0x10); +#endif + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + +// +// +CK_RV decr_mgr_decrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_KEY_TYPE keytype; + + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + + if (!out_data && !length_only) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + if (ctx->active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->multi_init == FALSE) { + ctx->multi = TRUE; + ctx->multi_init = TRUE; + } + if (ctx->multi == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + return CKR_OPERATION_ACTIVE; + } + + switch (ctx->mech.mechanism) { + case CKM_CDMF_ECB: + case CKM_DES_ECB: + return des_ecb_decrypt_update(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_CDMF_CBC: + case CKM_DES_CBC: + return des_cbc_decrypt_update(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_DES_CBC_PAD: + case CKM_CDMF_CBC_PAD: + return des_cbc_pad_decrypt_update(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_DES_OFB64: + get_keytype(tokdata, ctx->key, &keytype); + if (keytype == CKK_DES3) { + return des3_ofb_decrypt_update(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + case CKM_DES_CFB8: + get_keytype(tokdata, ctx->key, &keytype); + if (keytype == CKK_DES3) { + return des3_cfb_decrypt_update(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len, 0x01); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + case CKM_DES_CFB64: + get_keytype(tokdata, ctx->key, &keytype); + if (keytype == CKK_DES3) { + return des3_cfb_decrypt_update(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len, 0x08); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + case CKM_DES3_ECB: + return des3_ecb_decrypt_update(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_DES3_CBC: + return des3_cbc_decrypt_update(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_DES3_CBC_PAD: + return des3_cbc_pad_decrypt_update(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len); +#ifndef NOAES + case CKM_AES_ECB: + return aes_ecb_decrypt_update(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_AES_CBC: + return aes_cbc_decrypt_update(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_AES_CBC_PAD: + return aes_cbc_pad_decrypt_update(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_AES_CTR: + return aes_ctr_decrypt_update(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_AES_GCM: + return aes_gcm_decrypt_update(tokdata, sess, length_only, ctx, + in_data, in_data_len, out_data, + out_data_len); + case CKM_AES_OFB: + return aes_ofb_decrypt_update(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_AES_CFB8: + return aes_cfb_decrypt_update(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len, 0x01); + case CKM_AES_CFB64: + return aes_cfb_decrypt_update(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len, 0x08); + case CKM_AES_CFB128: + return aes_cfb_decrypt_update(tokdata, sess, length_only, + ctx, + in_data, in_data_len, + out_data, out_data_len, 0x10); +#endif + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + +// +// +CK_RV decr_mgr_decrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_KEY_TYPE keytype; + + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (ctx->active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->multi_init == FALSE) { + ctx->multi = TRUE; + ctx->multi_init = TRUE; + } + if (ctx->multi == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + return CKR_OPERATION_ACTIVE; + } + + switch (ctx->mech.mechanism) { + case CKM_CDMF_ECB: + case CKM_DES_ECB: + return des_ecb_decrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_CDMF_CBC: + case CKM_DES_CBC: + return des_cbc_decrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_DES_CBC_PAD: + case CKM_CDMF_CBC_PAD: + return des_cbc_pad_decrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_DES_OFB64: + get_keytype(tokdata, ctx->key, &keytype); + if (keytype == CKK_DES3) { + return des3_ofb_decrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + case CKM_DES_CFB8: + get_keytype(tokdata, ctx->key, &keytype); + if (keytype == CKK_DES3) { + return des3_cfb_decrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len, 0x01); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + case CKM_DES_CFB64: + get_keytype(tokdata, ctx->key, &keytype); + if (keytype == CKK_DES3) { + return des3_cfb_decrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len, 0x08); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + case CKM_DES3_ECB: + return des3_ecb_decrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_DES3_CBC: + return des3_cbc_decrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_DES3_CBC_PAD: + return des3_cbc_pad_decrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); +#ifndef NOAES + case CKM_AES_ECB: + return aes_ecb_decrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_AES_CBC: + return aes_cbc_decrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_AES_CBC_PAD: + return aes_cbc_pad_decrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_AES_OFB: + return aes_ofb_decrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_AES_CFB8: + return aes_cfb_decrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len, 0x01); + case CKM_AES_CFB64: + return aes_cfb_decrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len, 0x08); + case CKM_AES_CFB128: + return aes_cfb_decrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len, 0x10); + case CKM_AES_CTR: + return aes_ctr_decrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_AES_GCM: + return aes_gcm_decrypt_final(tokdata, sess, length_only, ctx, + out_data, out_data_len); +#endif + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} diff --git a/usr/lib/common/defs.h b/usr/lib/common/defs.h new file mode 100644 index 0000000..7b5d15d --- /dev/null +++ b/usr/lib/common/defs.h @@ -0,0 +1,191 @@ +/* + * 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: defs.h +// +// Contains various definitions needed by both the host-side +// and coprocessor-side code. +// + +#ifndef _DEFS_H +#define _DEFS_H + +#define MAX_SESSION_COUNT 64 +#define MAX_PIN_LEN 8 +#define MIN_PIN_LEN 4 + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#define UNUSED(var) ((void)(var)) + +// the following constants are used for sccSignOn +// +#define PKCS_11_PRG_ID "pkcs11 2.01" +#define PKCS_11_DEVELOPER_ID 0xE +#define PKCS_11_VERSION 1 +#define PKCS_11_INSTANCE 0 +#define PKCS_11_QUEUE 0 + +// the following are "boolean" attributes +// +#define CKA_IBM_TWEAK_ALLOW_KEYMOD 0x80000001 +#define CKA_IBM_TWEAK_ALLOW_WEAK_DES 0x80000002 +#define CKA_IBM_TWEAK_DES_PARITY_CHK 0x80000003 +#define CKA_IBM_TWEAK_NETSCAPE 0x80000004 + +#define MODE_COPY (1 << 0) +#define MODE_CREATE (1 << 1) +#define MODE_KEYGEN (1 << 2) +#define MODE_MODIFY (1 << 3) +#define MODE_DERIVE (1 << 4) +#define MODE_UNWRAP (1 << 5) + +// RSA block formatting types +// +#define PKCS_BT_1 1 +#define PKCS_BT_2 2 + +#define OP_ENCRYPT_INIT 1 +#define OP_DECRYPT_INIT 2 +#define OP_WRAP 3 +#define OP_UNWRAP 4 +#define OP_SIGN_INIT 5 +#define OP_VERIFY_INIT 6 + +// saved-state identifiers +// +enum { + STATE_INVALID = 0, + STATE_ENCR, + STATE_DECR, + STATE_DIGEST, + STATE_SIGN, + STATE_VERIFY +}; + + +#define ENCRYPT 1 +#define DECRYPT 0 + +#define MAX_RSA_KEYLEN 1920 + +#define MAX_AES_KEY_SIZE 64 /* encompasses CCA key size */ +#define AES_KEY_SIZE_256 32 +#define AES_KEY_SIZE_192 24 +#define AES_KEY_SIZE_128 16 +#define AES_BLOCK_SIZE 16 +#define AES_INIT_VECTOR_SIZE AES_BLOCK_SIZE +#define AES_COUNTER_SIZE 16 + +#define MAX_DES_KEY_SIZE 64 /* encompasses CCA key size */ +#define DES_KEY_SIZE 8 +#define DES_BLOCK_SIZE 8 + +/* + * It should be able to keep any kind of key (AES, 3DES, etc) and also + * a PBKDF key + */ +#define MAX_KEY_SIZE 96 + +#define SHA1_HASH_SIZE 20 +#define SHA1_BLOCK_SIZE 64 +#define SHA1_BLOCK_SIZE_MASK (SHA1_BLOCK_SIZE - 1) +#define SHA224_HASH_SIZE 28 +#define SHA224_BLOCK_SIZE 64 +#define SHA224_BLOCK_SIZE_MASK (SHA224_BLOCK_SIZE - 1) +#define SHA256_HASH_SIZE 32 +#define SHA256_BLOCK_SIZE 64 +#define SHA256_BLOCK_SIZE_MASK (SHA256_BLOCK_SIZE - 1) +#define SHA384_HASH_SIZE 48 +#define SHA384_BLOCK_SIZE 128 +#define SHA384_BLOCK_SIZE_MASK (SHA384_BLOCK_SIZE - 1) +#define SHA512_HASH_SIZE 64 +#define SHA512_BLOCK_SIZE 128 +#define SHA512_BLOCK_SIZE_MASK (SHA512_BLOCK_SIZE - 1) +#define SHA3_224_HASH_SIZE SHA224_HASH_SIZE +#define SHA3_224_BLOCK_SIZE 144 +#define SHA3_224_BLOCK_SIZE_MASK (SHA3_224_BLOCK_SIZE - 1) +#define SHA3_256_HASH_SIZE SHA256_HASH_SIZE +#define SHA3_256_BLOCK_SIZE 136 +#define SHA3_256_BLOCK_SIZE_MASK (SHA3_256_BLOCK_SIZE - 1) +#define SHA3_384_HASH_SIZE SHA384_HASH_SIZE +#define SHA3_384_BLOCK_SIZE 104 +#define SHA3_384_BLOCK_SIZE_MASK (SHA3_384_BLOCK_SIZE - 1) +#define SHA3_512_HASH_SIZE SHA512_HASH_SIZE +#define SHA3_512_BLOCK_SIZE 72 +#define SHA3_512_BLOCK_SIZE_MASK (SHA3_512_BLOCK_SIZE - 1) +#define MAX_SHA_HASH_SIZE SHA512_HASH_SIZE +#define MAX_SHA_BLOCK_SIZE SHA3_224_BLOCK_SIZE + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +struct oc_sha_ctx { + unsigned char hash[MAX_SHA_HASH_SIZE + 1]; + unsigned int hash_len; + unsigned int hash_blksize; + unsigned int tail_len; + int message_part; + unsigned char tail[MAX_SHA_BLOCK_SIZE]; + unsigned int dev_ctx_offs; +}; + +#define MD2_HASH_SIZE 16 +#define MD2_BLOCK_SIZE 48 + +#define MD5_HASH_SIZE 16 +#define MD5_BLOCK_SIZE 64 + +#define DSA_SIGNATURE_SIZE 40 + +#define DEFAULT_SO_PIN "87654321" + +#define MAX_TOK_OBJS 2048 + + +typedef enum { + ALL = 1, + PRIVATE, + PUBLIC +} SESS_OBJ_TYPE; + +typedef enum { + NO_LOCK = 0, + READ_LOCK, + WRITE_LOCK, +} OBJ_LOCK_TYPE; + +typedef struct _DL_NODE { + struct _DL_NODE *next; + struct _DL_NODE *prev; + void *data; +} DL_NODE; + + +// Token local +// +#define PK_LITE_DIR token_specific.token_directory +#define PK_DIR PK_LITE_DIR +#define SUB_DIR token_specific.token_subdir +#define DBGTAG token_specific.token_debug_tag + +#define PK_LITE_NV "NVTOK.DAT" +#define PK_LITE_OBJ_DIR "TOK_OBJ" +#define PK_LITE_OBJ_IDX "OBJ.IDX" + +#define DEL_CMD "/bin/rm -f" + +#endif diff --git a/usr/lib/common/dig_mgr.c b/usr/lib/common/dig_mgr.c new file mode 100644 index 0000000..bd6c0ac --- /dev/null +++ b/usr/lib/common/dig_mgr.c @@ -0,0 +1,460 @@ +/* + * 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: dig_mgr.c +// +// Digest manager routines +// + +#include +#include // for memcmp() et al +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "trace.h" + + +// +// +CK_RV digest_mgr_init(STDLL_TokData_t *tokdata, + SESSION *sess, DIGEST_CONTEXT *ctx, CK_MECHANISM *mech) +{ + CK_RV rc = CKR_OK; + CK_BYTE *ptr = NULL; + + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (ctx->active != FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + return CKR_OPERATION_ACTIVE; + } + // is the mechanism supported? is the parameter present if required? + // + switch (mech->mechanism) { + case CKM_SHA_1: + case CKM_SHA224: + case CKM_SHA256: + case CKM_SHA384: + case CKM_SHA512: + case CKM_SHA512_224: + case CKM_SHA512_256: + case CKM_IBM_SHA3_224: + case CKM_IBM_SHA3_256: + case CKM_IBM_SHA3_384: + case CKM_IBM_SHA3_512: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + + ctx->context = NULL; + rc = sha_init(tokdata, sess, ctx, mech); + if (rc != CKR_OK) { + digest_mgr_cleanup(ctx); // to de-initialize context above + TRACE_ERROR("Failed to init sha context.\n"); + return rc; + } + break; + case CKM_MD2: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + ctx->context_len = sizeof(MD2_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(MD2_CONTEXT)); + if (!ctx->context) { + digest_mgr_cleanup(ctx); // to de-initialize context above + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + memset(ctx->context, 0x0, sizeof(MD2_CONTEXT)); + break; + case CKM_MD5: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + ctx->context = NULL; + rc = md5_init(tokdata, sess, ctx, mech); + if (rc != CKR_OK) { + digest_mgr_cleanup(ctx); // to de-initialize context above + TRACE_ERROR("Failed to init md5 context.\n"); + return rc; + } + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + if (mech->ulParameterLen > 0) { + ptr = (CK_BYTE *) malloc(mech->ulParameterLen); + if (!ptr) { + digest_mgr_cleanup(ctx); // to de-initialize context above + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + memcpy(ptr, mech->pParameter, mech->ulParameterLen); + } + ctx->mech.ulParameterLen = mech->ulParameterLen; + ctx->mech.mechanism = mech->mechanism; + ctx->mech.pParameter = ptr; + ctx->multi_init = FALSE; + ctx->multi = FALSE; + ctx->active = TRUE; + + return CKR_OK; +} + + +// +// +CK_RV digest_mgr_cleanup(DIGEST_CONTEXT *ctx) +{ + if (!ctx) { + TRACE_ERROR("Invalid function argument.\n"); + return CKR_FUNCTION_FAILED; + } + ctx->mech.ulParameterLen = 0; + ctx->mech.mechanism = 0; + ctx->multi_init = FALSE; + ctx->multi = FALSE; + ctx->active = FALSE; + ctx->context_len = 0; + + if (ctx->mech.pParameter) { + free(ctx->mech.pParameter); + ctx->mech.pParameter = NULL; + } + + if (ctx->context != NULL) { + free(ctx->context); + ctx->context = NULL; + } + + return CKR_OK; +} + + + +// +// +CK_RV digest_mgr_digest(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + DIGEST_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_RV rc; + + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (ctx->active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->multi_init == FALSE) { + ctx->multi = FALSE; + ctx->multi_init = TRUE; + } + + if (!in_data || !out_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto out; + } + + // if the caller just wants the encrypted length, there is no reason to + // specify the input data. I just need the data length + // + if ((length_only == FALSE) && (!in_data || !out_data)) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + goto out; + } + + if (ctx->multi == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto out; + } + switch (ctx->mech.mechanism) { + case CKM_SHA_1: + case CKM_SHA224: + case CKM_SHA256: + case CKM_SHA384: + case CKM_SHA512: + case CKM_SHA512_224: + case CKM_SHA512_256: + case CKM_IBM_SHA3_224: + case CKM_IBM_SHA3_256: + case CKM_IBM_SHA3_384: + case CKM_IBM_SHA3_512: + rc = sha_hash(tokdata, sess, length_only, ctx, in_data, in_data_len, + out_data, out_data_len); + break; +#if !(NOMD2 ) + case CKM_MD2: + rc = md2_hash(tokdata, sess, length_only, ctx, in_data, in_data_len, + out_data, out_data_len); + break; +#endif + case CKM_MD5: + rc = md5_hash(tokdata, sess, length_only, ctx, in_data, in_data_len, + out_data, out_data_len); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + } + +out: + if (!((rc == CKR_BUFFER_TOO_SMALL) || + (rc == CKR_OK && length_only == TRUE))) { + // "A call to C_Digest always terminates the active digest operation + // unless it returns CKR_BUFFER_TOO_SMALL or is a successful call (i.e., + // one which returns CKR_OK) to determine the length of the buffer + // needed to hold the message digest." + digest_mgr_cleanup(ctx); + } + + return rc; +} + + +// +// +CK_RV digest_mgr_digest_update(STDLL_TokData_t *tokdata, + SESSION *sess, + DIGEST_CONTEXT *ctx, + CK_BYTE *data, CK_ULONG data_len) +{ + CK_RV rc; + + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (ctx->active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->multi_init == FALSE) { + ctx->multi = TRUE; + ctx->multi_init = TRUE; + } + if (ctx->multi == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto out; + } + + if (!data && data_len != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto out; + } + + switch (ctx->mech.mechanism) { + case CKM_SHA_1: + case CKM_SHA224: + case CKM_SHA256: + case CKM_SHA384: + case CKM_SHA512: + case CKM_SHA512_224: + case CKM_SHA512_256: + case CKM_IBM_SHA3_224: + case CKM_IBM_SHA3_256: + case CKM_IBM_SHA3_384: + case CKM_IBM_SHA3_512: + rc = sha_hash_update(tokdata, sess, ctx, data, data_len); + break; +#if !(NOMD2) + case CKM_MD2: + rc = md2_hash_update(tokdata, sess, ctx, data, data_len); + break; +#endif + case CKM_MD5: + rc = md5_hash_update(tokdata, sess, ctx, data, data_len); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + } + +out: + if (rc != CKR_OK) { + digest_mgr_cleanup(ctx); + // "A call to C_DigestUpdate which results in an error + // terminates the current digest operation." + } + + return rc; +} + + +// +// +CK_RV digest_mgr_digest_key(STDLL_TokData_t *tokdata, + SESSION *sess, + DIGEST_CONTEXT *ctx, CK_OBJECT_HANDLE key_handle) +{ + CK_ATTRIBUTE *attr = NULL; + OBJECT *key_obj = NULL; + CK_OBJECT_CLASS class; + CK_RV rc; + + + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + + /* + * Secure keys can not be digested by digesting the CKA_VALUE attribute. + */ + if (is_secure_key_token()) { + TRACE_ERROR("%s because its a secure key token\n", + ock_err(CKR_KEY_INDIGESTIBLE)); + rc = CKR_KEY_INDIGESTIBLE; + goto out; + } + + rc = object_mgr_find_in_map1(tokdata, key_handle, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + rc = CKR_KEY_HANDLE_INVALID; + goto out; + } + // only allow digesting of CKO_SECRET keys + // + rc = template_attribute_find(key_obj->template, CKA_CLASS, &attr); + if (rc == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_INDIGESTIBLE)); + rc = CKR_KEY_INDIGESTIBLE; + goto out; + } else { + class = *(CK_OBJECT_CLASS *) attr->pValue; + } + + if (class != CKO_SECRET_KEY) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_INDIGESTIBLE)); + rc = CKR_KEY_INDIGESTIBLE; + goto out; + } + // every secret key has a CKA_VALUE attribute + // + rc = template_attribute_find(key_obj->template, CKA_VALUE, &attr); + if (!rc) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_INDIGESTIBLE)); + rc = CKR_KEY_INDIGESTIBLE; + goto out; + } + rc = digest_mgr_digest_update(tokdata, sess, ctx, + attr->pValue, attr->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("digest_mgr_digest_update failed\n"); + } + +out: + if (rc != CKR_OK) { + digest_mgr_cleanup(ctx); + } + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +// +// +CK_RV digest_mgr_digest_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + DIGEST_CONTEXT *ctx, + CK_BYTE *hash, CK_ULONG *hash_len) +{ + CK_RV rc; + + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (ctx->active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->multi_init == FALSE) { + ctx->multi = TRUE; + ctx->multi_init = TRUE; + } + if (ctx->multi == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto out; + } + + if (!hash_len) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto out; + } + + switch (ctx->mech.mechanism) { + case CKM_SHA_1: + case CKM_SHA224: + case CKM_SHA256: + case CKM_SHA384: + case CKM_SHA512: + case CKM_SHA512_224: + case CKM_SHA512_256: + case CKM_IBM_SHA3_224: + case CKM_IBM_SHA3_256: + case CKM_IBM_SHA3_384: + case CKM_IBM_SHA3_512: + rc = sha_hash_final(tokdata, sess, length_only, ctx, hash, hash_len); + break; +#if !(NOMD2) + case CKM_MD2: + rc = md2_hash_final(tokdata, sess, length_only, ctx, hash, hash_len); + break; +#endif + case CKM_MD5: + rc = md5_hash_final(tokdata, sess, length_only, ctx, hash, hash_len); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; // shouldn't happen + } + +out: + if (!((rc == CKR_BUFFER_TOO_SMALL) || + (rc == CKR_OK && length_only == TRUE))) { + // "A call to C_DigestFinal always terminates the active digest + // operation unless it returns CKR_BUFFER_TOO_SMALL or is a successful + // call (i.e., one which returns CKR_OK) to determine the length of the + // buffer needed to hold the message digest." + digest_mgr_cleanup(ctx); + } + + return rc; +} diff --git a/usr/lib/common/dp_obj.c b/usr/lib/common/dp_obj.c new file mode 100644 index 0000000..e23148e --- /dev/null +++ b/usr/lib/common/dp_obj.c @@ -0,0 +1,506 @@ +/* + * 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: dp_obj.c +// +// Domain Parameter Object functions + +#include +#include + +#include // for memcmp() et al + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "trace.h" + +#include "tok_spec_struct.h" + + +// dp_object_check_required_attributes() +// +// Check required common attributes for domain parameter objects +// +CK_RV dp_object_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_KEY_TYPE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return template_check_required_base_attributes(tmpl, mode); +} + +CK_RV dp_dsa_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + if (mode == MODE_CREATE) { + found = template_attribute_find(tmpl, CKA_PRIME, &attr); + if (!found) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + found = template_attribute_find(tmpl, CKA_SUBPRIME, &attr); + if (!found) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + found = template_attribute_find(tmpl, CKA_BASE, &attr); + if (!found) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } else if (mode == MODE_KEYGEN) { + found = template_attribute_find(tmpl, CKA_PRIME_BITS, &attr); + if (!found) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return dp_object_check_required_attributes(tmpl, mode); +} + +CK_RV dp_dh_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + if (mode == MODE_CREATE) { + found = template_attribute_find(tmpl, CKA_PRIME, &attr); + if (!found) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + found = template_attribute_find(tmpl, CKA_BASE, &attr); + if (!found) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } else if (mode == MODE_KEYGEN) { + found = template_attribute_find(tmpl, CKA_PRIME_BITS, &attr); + if (!found) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return dp_object_check_required_attributes(tmpl, mode); +} + +CK_RV dp_x9dh_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + if (mode == MODE_CREATE) { + found = template_attribute_find(tmpl, CKA_PRIME, &attr); + if (!found) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + found = template_attribute_find(tmpl, CKA_SUBPRIME, &attr); + if (!found) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + found = template_attribute_find(tmpl, CKA_BASE, &attr); + if (!found) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } else if (mode == MODE_KEYGEN) { + found = template_attribute_find(tmpl, CKA_PRIME_BITS, &attr); + if (!found) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + found = template_attribute_find(tmpl, CKA_SUBPRIME_BITS, &attr); + if (!found) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return dp_object_check_required_attributes(tmpl, mode); +} + + +// dp_object_set_default_attributes() +// +CK_RV dp_object_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *local_attr = NULL; + + UNUSED(mode); + + local_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + + if (!local_attr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + local_attr->type = CKA_LOCAL; + local_attr->ulValueLen = sizeof(CK_BBOOL); + local_attr->pValue = (CK_BYTE *) local_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) local_attr->pValue = FALSE; + + template_update_attribute(tmpl, local_attr); + + return CKR_OK; +} + + +// dp_object_validate_attribute() +// +CK_RV dp_object_validate_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode) +{ + switch (attr->type) { + case CKA_KEY_TYPE: + if (mode == MODE_CREATE) + return CKR_OK; + + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + case CKA_LOCAL: + if (mode == MODE_CREATE || mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID)); + return CKR_ATTRIBUTE_TYPE_INVALID; + } + return CKR_OK; + default: + return template_validate_base_attribute(tmpl, attr, mode); + } +} + +// +// +CK_RV dp_dsa_validate_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode) +{ + switch (attr->type) { + case CKA_PRIME: + if (mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_DOMAIN_PARAMS_INVALID)); + return CKR_DOMAIN_PARAMS_INVALID; + } + return CKR_OK; + case CKA_PRIME_BITS: + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_DOMAIN_PARAMS_INVALID)); + return CKR_DOMAIN_PARAMS_INVALID; + } + return CKR_OK; + case CKA_BASE: + if (mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_DOMAIN_PARAMS_INVALID)); + return CKR_DOMAIN_PARAMS_INVALID; + } + return CKR_OK; + case CKA_SUBPRIME: + if (mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_DOMAIN_PARAMS_INVALID)); + return CKR_DOMAIN_PARAMS_INVALID; + } + return CKR_OK; + default: + return dp_object_validate_attribute(tmpl, attr, mode); + } +} + +// +// +CK_RV dp_dh_validate_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode) +{ + switch (attr->type) { + case CKA_PRIME: + if (mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_DOMAIN_PARAMS_INVALID)); + return CKR_DOMAIN_PARAMS_INVALID; + } + return CKR_OK; + case CKA_PRIME_BITS: + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_DOMAIN_PARAMS_INVALID)); + return CKR_DOMAIN_PARAMS_INVALID; + } + return CKR_OK; + case CKA_BASE: + if (mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_DOMAIN_PARAMS_INVALID)); + return CKR_DOMAIN_PARAMS_INVALID; + } + return CKR_OK; + default: + return dp_object_validate_attribute(tmpl, attr, mode); + } +} + +// +// +CK_RV dp_x9dh_validate_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode) +{ + switch (attr->type) { + case CKA_PRIME: + if (mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_DOMAIN_PARAMS_INVALID)); + return CKR_DOMAIN_PARAMS_INVALID; + } + return CKR_OK; + case CKA_PRIME_BITS: + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_DOMAIN_PARAMS_INVALID)); + return CKR_DOMAIN_PARAMS_INVALID; + } + return CKR_OK; + case CKA_BASE: + if (mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_DOMAIN_PARAMS_INVALID)); + return CKR_DOMAIN_PARAMS_INVALID; + } + return CKR_OK; + case CKA_SUBPRIME: + if (mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_DOMAIN_PARAMS_INVALID)); + return CKR_DOMAIN_PARAMS_INVALID; + } + return CKR_OK; + case CKA_SUBPRIME_BITS: + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_DOMAIN_PARAMS_INVALID)); + return CKR_DOMAIN_PARAMS_INVALID; + } + return CKR_OK; + default: + return dp_object_validate_attribute(tmpl, attr, mode); + } +} + + +CK_RV dp_dsa_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_RV rc; + CK_ATTRIBUTE *prime_attr; + CK_ATTRIBUTE *subprime_attr; + CK_ATTRIBUTE *base_attr; + CK_ATTRIBUTE *primebits_attr; + CK_ATTRIBUTE *type_attr; + + rc = dp_object_set_default_attributes(tmpl, mode); + if (rc != CKR_OK) + return rc; + + prime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + subprime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + base_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + primebits_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + + if (!prime_attr || !subprime_attr || !base_attr || !primebits_attr + || !type_attr) { + if (prime_attr) + free(prime_attr); + if (subprime_attr) + free(subprime_attr); + if (base_attr) + free(base_attr); + if (primebits_attr) + free(primebits_attr); + if (type_attr) + free(type_attr); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + prime_attr->type = CKA_PRIME; + prime_attr->ulValueLen = 0; + prime_attr->pValue = NULL; + + subprime_attr->type = CKA_SUBPRIME; + subprime_attr->ulValueLen = 0; + subprime_attr->pValue = NULL; + + base_attr->type = CKA_BASE; + base_attr->ulValueLen = 0; + base_attr->pValue = NULL; + + primebits_attr->type = CKA_PRIME_BITS; + primebits_attr->ulValueLen = 0; + primebits_attr->pValue = NULL; +#if 0 + primebits_attr->ulValueLen = sizeof(CK_ULONG); + primebits_attr->pValue = (CK_ULONG *) primebits_attr + sizeof(CK_ATTRIBUTE); + *(CK_ULONG *) primebits_attr->pValue = 0; +#endif + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_DSA; + + template_update_attribute(tmpl, prime_attr); + template_update_attribute(tmpl, subprime_attr); + template_update_attribute(tmpl, base_attr); + template_update_attribute(tmpl, primebits_attr); + template_update_attribute(tmpl, type_attr); + + return CKR_OK; +} + +CK_RV dp_dh_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_RV rc; + CK_ATTRIBUTE *prime_attr; + CK_ATTRIBUTE *base_attr; + CK_ATTRIBUTE *primebits_attr; + CK_ATTRIBUTE *type_attr; + + rc = dp_object_set_default_attributes(tmpl, mode); + if (rc != CKR_OK) + return rc; + + prime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + base_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + primebits_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + + if (!prime_attr || !base_attr || !primebits_attr || !type_attr) { + if (prime_attr) + free(prime_attr); + if (base_attr) + free(base_attr); + if (primebits_attr) + free(primebits_attr); + if (type_attr) + free(type_attr); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + prime_attr->type = CKA_PRIME; + prime_attr->ulValueLen = 0; + prime_attr->pValue = NULL; + + base_attr->type = CKA_BASE; + base_attr->ulValueLen = 0; + base_attr->pValue = NULL; + + primebits_attr->type = CKA_PRIME_BITS; + primebits_attr->ulValueLen = 0; + primebits_attr->pValue = NULL; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_DH; + + template_update_attribute(tmpl, prime_attr); + template_update_attribute(tmpl, base_attr); + template_update_attribute(tmpl, primebits_attr); + template_update_attribute(tmpl, type_attr); + + return CKR_OK; +} + +CK_RV dp_x9dh_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_RV rc; + CK_ATTRIBUTE *prime_attr; + CK_ATTRIBUTE *subprime_attr; + CK_ATTRIBUTE *base_attr; + CK_ATTRIBUTE *primebits_attr; + CK_ATTRIBUTE *subprimebits_attr; + CK_ATTRIBUTE *type_attr; + + rc = dp_object_set_default_attributes(tmpl, mode); + if (rc != CKR_OK) + return rc; + + prime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + subprime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + base_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + primebits_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + subprimebits_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + + if (!prime_attr || !subprime_attr || !base_attr || + !primebits_attr || !subprimebits_attr || !type_attr) { + if (prime_attr) + free(prime_attr); + if (subprime_attr) + free(subprime_attr); + if (base_attr) + free(base_attr); + if (primebits_attr) + free(primebits_attr); + if (subprimebits_attr) + free(subprimebits_attr); + if (type_attr) + free(type_attr); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + prime_attr->type = CKA_PRIME; + prime_attr->ulValueLen = 0; + prime_attr->pValue = NULL; + + subprime_attr->type = CKA_SUBPRIME; + subprime_attr->ulValueLen = 0; + subprime_attr->pValue = NULL; + + base_attr->type = CKA_BASE; + base_attr->ulValueLen = 0; + base_attr->pValue = NULL; + + primebits_attr->type = CKA_PRIME_BITS; + primebits_attr->ulValueLen = 0; + primebits_attr->pValue = NULL; + + subprimebits_attr->type = CKA_SUBPRIME_BITS; + subprimebits_attr->ulValueLen = 0; + subprimebits_attr->pValue = NULL; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_DSA; + + template_update_attribute(tmpl, prime_attr); + template_update_attribute(tmpl, subprime_attr); + template_update_attribute(tmpl, base_attr); + template_update_attribute(tmpl, primebits_attr); + template_update_attribute(tmpl, subprimebits_attr); + template_update_attribute(tmpl, type_attr); + + return CKR_OK; +} diff --git a/usr/lib/common/ec_defs.h b/usr/lib/common/ec_defs.h new file mode 100644 index 0000000..0b13f03 --- /dev/null +++ b/usr/lib/common/ec_defs.h @@ -0,0 +1,99 @@ +/* + * 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 + */ + +#ifndef _EC_DEFS +#define _EC_DEFS + +#include "ec_curves.h" + +// Elliptic Curve type +// +#define PRIME_CURVE 0x00 +#define BRAINPOOL_CURVE 0x01 +#define MONTGOMERY_CURVE 0x02 +#define EDWARDS_CURVE 0x03 + +// Elliptic Curve length in bits +// +#define CURVE160 0x00A0 +#define CURVE192 0x00C0 +#define CURVE224 0x00E0 +#define CURVE256 0x0100 +#define CURVE320 0x0140 +#define CURVE384 0x0180 +#define CURVE456 0x01C8 +#define CURVE512 0x0200 +#define CURVE521 0x0209 + +/* Supported Elliptic Curves */ +#define NUMEC 24 /* number of supported curves */ +extern const CK_BYTE brainpoolP160r1[]; +extern const CK_BYTE brainpoolP160t1[]; +extern const CK_BYTE brainpoolP192r1[]; +extern const CK_BYTE brainpoolP192t1[]; +extern const CK_BYTE brainpoolP224r1[]; +extern const CK_BYTE brainpoolP224t1[]; +extern const CK_BYTE brainpoolP256r1[]; +extern const CK_BYTE brainpoolP256t1[]; +extern const CK_BYTE brainpoolP320r1[]; +extern const CK_BYTE brainpoolP320t1[]; +extern const CK_BYTE brainpoolP384r1[]; +extern const CK_BYTE brainpoolP384t1[]; +extern const CK_BYTE brainpoolP512r1[]; +extern const CK_BYTE brainpoolP512t1[]; +extern const CK_BYTE prime192v1[]; +extern const CK_BYTE secp224r1[]; +extern const CK_BYTE prime256v1[]; +extern const CK_BYTE secp384r1[]; +extern const CK_BYTE secp521r1[]; +extern const CK_BYTE secp256k1[]; +extern const CK_BYTE curve25519[]; +extern const CK_BYTE curve448[]; +extern const CK_BYTE ed25519[]; +extern const CK_BYTE ed448[]; + + +// structure of supported Elliptic Curves + +struct _ec { + uint8_t curve_type; /* uint8_t - prime or brainpool curve */ + uint16_t len_bits; /* uint16_t - len in bits */ + int nid; + CK_ULONG data_size; + void const *data; +} __attribute__ ((__packed__)); + +extern const struct _ec der_ec_supported[NUMEC]; + +#define MAX_ECDH_SHARED_SECRET_SIZE 66 +#define MAX_SUPPORTED_HASH_LENGTH 64 + +/* + * Refer to CCA Programmer's Guide, PKA Key Token Build + * Key value structure elements, ECC keys + */ +typedef struct { + uint8_t curve_type; /* 00 = prime, 01 = brainpool */ + uint8_t reserved; + uint16_t p_bitlen; + uint16_t d_length; + uint16_t q_length; + // followed by d || q +} __attribute__((packed)) ECC_PAIR; + +typedef struct { + uint8_t curve_type; /* 00 = prime, 01 = brainpool */ + uint8_t reserved; + uint16_t p_bitlen; + uint16_t q_length; + // followed by q +} __attribute__((packed)) ECC_PUBL; + +#endif diff --git a/usr/lib/common/encr_mgr.c b/usr/lib/common/encr_mgr.c new file mode 100644 index 0000000..6cd8d4c --- /dev/null +++ b/usr/lib/common/encr_mgr.c @@ -0,0 +1,1058 @@ +/* + * 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: encr_mgr.c +// +// Encryption manager routines +// + +#include +#include // for memcmp() et al +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "trace.h" + + +// +// +CK_RV encr_mgr_init(STDLL_TokData_t *tokdata, + SESSION *sess, + ENCR_DECR_CONTEXT *ctx, + CK_ULONG operation, + CK_MECHANISM *mech, CK_OBJECT_HANDLE key_handle) +{ + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *ptr = NULL; + CK_KEY_TYPE keytype; + CK_BBOOL flag; + CK_RV rc; + + + if (!sess || !ctx || !mech) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (ctx->active != FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + return CKR_OPERATION_ACTIVE; + } + // key usage restrictions + // + if (operation == OP_ENCRYPT_INIT) { + rc = object_mgr_find_in_map1(tokdata, key_handle, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle.\n"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + // is key allowed to do general encryption? + // + rc = template_attribute_find(key_obj->template, CKA_ENCRYPT, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_ENCRYPT for the key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } else { + flag = *(CK_BBOOL *) attr->pValue; + if (flag != TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_FUNCTION_NOT_PERMITTED)); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + } + } else if (operation == OP_WRAP) { + rc = object_mgr_find_in_map1(tokdata, key_handle, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle.\n"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_WRAPPING_KEY_HANDLE_INVALID; + else + return rc; + } + // is key allowed to wrap other keys? + // + rc = template_attribute_find(key_obj->template, CKA_WRAP, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_WRAP for the key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } else { + flag = *(CK_BBOOL *) attr->pValue; + if (flag == FALSE) { + TRACE_ERROR("CKA_WRAP is set to FALSE.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + } + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + // is the mechanism supported? is the key type correct? is a + // parameter present if required? is the key size allowed? + // does the key support encryption? + // + // Will the FCV allow the operation? + // + switch (mech->mechanism) { + case CKM_DES_ECB: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // is the key type correct? + // + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_DES) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // Check FCV + // + // if ((nv_FCV.FunctionCntlBytes[DES_FUNCTION_BYTE] + // & FCV_56_BIT_DES) == 0) + // rc = CKR_MECHANISM_INVALID; + // goto done; + + ctx->context_len = sizeof(DES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(DES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(DES_CONTEXT)); + break; + case CKM_CDMF_ECB: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // is the key type correct? + // + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_CDMF) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + ctx->context_len = sizeof(DES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(DES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(DES_CONTEXT)); + break; + case CKM_DES_CBC: + case CKM_DES_CBC_PAD: + if (mech->ulParameterLen != DES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // is the key type correct? + // + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_DES) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // Check FCV + // + // if ((nv_FCV.FunctionCntlBytes[DES_FUNCTION_BYTE] + // & FCV_56_BIT_DES) == 0) + // rc = CKR_MECHANISM_INVALID; + // goto done; + + ctx->context_len = sizeof(DES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(DES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(DES_CONTEXT)); + break; + case CKM_DES_CFB8: + case CKM_DES_CFB64: + case CKM_DES_OFB64: + if (mech->ulParameterLen != DES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if ((keytype != CKK_DES3)) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + ctx->context_len = sizeof(DES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(DES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(DES_CONTEXT)); + break; + case CKM_CDMF_CBC: + case CKM_CDMF_CBC_PAD: + if (mech->ulParameterLen != DES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // is the key type correct? + // + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_CDMF) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + + ctx->context_len = sizeof(DES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(DES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(DES_CONTEXT)); + break; + case CKM_DES3_ECB: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // is the key type correct? + // + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_DES3 && keytype != CKK_DES2) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // Check FCV + // + // if ((nv_FCV.FunctionCntlBytes[DES_FUNCTION_BYTE] + // & FCV_TRIPLE_DES) == 0) + // rc = CKR_MECHANISM_INVALID; + // goto done; + + ctx->context_len = sizeof(DES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(DES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(DES_CONTEXT)); + break; + case CKM_DES3_CBC: + case CKM_DES3_CBC_PAD: + if (mech->ulParameterLen != DES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // is the key type correct? + // + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_DES3 && keytype != CKK_DES2) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // Check FCV + // + // if ((nv_FCV.FunctionCntlBytes[DES_FUNCTION_BYTE] + // & FCV_TRIPLE_DES) == 0) + // rc = CKR_MECHANISM_INVALID; + // goto done; + + ctx->context_len = sizeof(DES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(DES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(DES_CONTEXT)); + break; + case CKM_RSA_PKCS_OAEP: + if (mech->ulParameterLen == 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_RSA) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + // RSA cannot be used for multi-part operations + // + ctx->context_len = 0; + ctx->context = NULL; + break; + case CKM_RSA_X_509: + case CKM_RSA_PKCS: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_RSA) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // RSA cannot be used for multi-part operations + // + ctx->context_len = 0; + ctx->context = NULL; + break; + case CKM_AES_ECB: + // XXX Copied in from DES3, should be verified - KEY + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // is the key type correct? + // + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_AES) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + ctx->context_len = sizeof(AES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(AES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(AES_CONTEXT)); + break; + case CKM_AES_CBC: + case CKM_AES_CBC_PAD: + // XXX Copied in from DES3, should be verified - KEY + if (mech->ulParameterLen != AES_INIT_VECTOR_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // is the key type correct? + // + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_AES) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + ctx->context_len = sizeof(AES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(AES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(AES_CONTEXT)); + break; + case CKM_AES_CTR: + if (mech->ulParameterLen != sizeof(CK_AES_CTR_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // is the key type correct + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_AES) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + ctx->context_len = sizeof(AES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(AES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(AES_CONTEXT)); + break; + case CKM_AES_GCM: + if (mech->ulParameterLen != sizeof(CK_GCM_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_AES) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + ctx->context_len = sizeof(AES_GCM_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(AES_GCM_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(AES_GCM_CONTEXT)); + + rc = aes_gcm_init(tokdata, sess, ctx, mech, key_handle, 1); + if (rc != CKR_OK) { + TRACE_ERROR("Could not initialize AES_GCM parms.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + break; + case CKM_AES_OFB: + case CKM_AES_CFB8: + case CKM_AES_CFB64: + case CKM_AES_CFB128: + if (mech->ulParameterLen != AES_INIT_VECTOR_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_AES) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + ctx->context_len = sizeof(AES_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(AES_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(AES_CONTEXT)); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + if ((mech->ulParameterLen > 0) || (mech->mechanism == CKM_AES_CTR) || + (mech->mechanism == CKM_AES_GCM)) { + ptr = (CK_BYTE *) malloc(mech->ulParameterLen); + if (!ptr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memcpy(ptr, mech->pParameter, mech->ulParameterLen); + } else if (mech->ulParameterLen > 0) { + ptr = (CK_BYTE *) malloc(mech->ulParameterLen); + if (!ptr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memcpy(ptr, mech->pParameter, mech->ulParameterLen); + } + + ctx->key = key_handle; + ctx->mech.ulParameterLen = mech->ulParameterLen; + ctx->mech.mechanism = mech->mechanism; + ctx->mech.pParameter = ptr; + ctx->multi_init = FALSE; + ctx->multi = FALSE; + ctx->active = TRUE; + + rc = CKR_OK; + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +// +// +CK_RV encr_mgr_cleanup(ENCR_DECR_CONTEXT *ctx) +{ + if (!ctx) { + TRACE_ERROR("Invalid function argument.\n"); + return CKR_FUNCTION_FAILED; + } + ctx->key = 0; + ctx->mech.ulParameterLen = 0; + ctx->mech.mechanism = 0; + ctx->multi_init = FALSE; + ctx->multi = FALSE; + ctx->active = FALSE; + ctx->init_pending = FALSE; + ctx->context_len = 0; + + if (ctx->mech.pParameter) { + free(ctx->mech.pParameter); + ctx->mech.pParameter = NULL; + } + + if (ctx->context) { + free(ctx->context); + ctx->context = NULL; + } + + return CKR_OK; +} + +// +// +CK_RV encr_mgr_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_KEY_TYPE keytype; + + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (ctx->active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->multi_init == FALSE) { + ctx->multi = FALSE; + ctx->multi_init = TRUE; + } + + // if the caller just wants the encrypted length, there is no reason to + // specify the input data. I just need the data length + // + if ((length_only == FALSE) && (!in_data || !out_data)) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + if (ctx->multi == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + return CKR_OPERATION_ACTIVE; + } + switch (ctx->mech.mechanism) { + case CKM_CDMF_ECB: + case CKM_DES_ECB: + return pk_des_ecb_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_CDMF_CBC: + case CKM_DES_CBC: + return pk_des_cbc_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_DES_CBC_PAD: + case CKM_CDMF_CBC_PAD: + return des_cbc_pad_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_DES_OFB64: + get_keytype(tokdata, ctx->key, &keytype); + if (keytype == CKK_DES3) { + return des3_ofb_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + case CKM_DES_CFB8: + get_keytype(tokdata, ctx->key, &keytype); + if (keytype == CKK_DES3) { + return des3_cfb_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len, 0x01); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + case CKM_DES_CFB64: + get_keytype(tokdata, ctx->key, &keytype); + if (keytype == CKK_DES3) { + return des3_cfb_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len, 0x08); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + case CKM_DES3_ECB: + return des3_ecb_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_DES3_CBC: + return des3_cbc_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_DES3_CBC_PAD: + return des3_cbc_pad_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_RSA_PKCS: + return rsa_pkcs_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_RSA_PKCS_OAEP: + return rsa_oaep_crypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len, ENCRYPT); + case CKM_RSA_X_509: + return rsa_x509_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); +#ifndef NOAES + case CKM_AES_CBC: + return aes_cbc_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + + case CKM_AES_ECB: + return aes_ecb_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + + case CKM_AES_CBC_PAD: + return aes_cbc_pad_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_AES_CTR: + return aes_ctr_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_AES_GCM: + return aes_gcm_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_AES_OFB: + return aes_ofb_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_AES_CFB8: + return aes_cfb_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len, 0x01); + case CKM_AES_CFB64: + return aes_cfb_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len, 0x08); + case CKM_AES_CFB128: + return aes_cfb_encrypt(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len, 0x10); +#endif + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + +// +// +CK_RV encr_mgr_encrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_KEY_TYPE keytype; + + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + + if (!out_data && !length_only) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + if (ctx->active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->multi_init == FALSE) { + ctx->multi = TRUE; + ctx->multi_init = TRUE; + } + if (ctx->multi == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + return CKR_OPERATION_ACTIVE; + } + + switch (ctx->mech.mechanism) { + case CKM_CDMF_ECB: + case CKM_DES_ECB: + return des_ecb_encrypt_update(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_CDMF_CBC: + case CKM_DES_CBC: + return des_cbc_encrypt_update(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_DES_CBC_PAD: + case CKM_CDMF_CBC_PAD: + return des_cbc_pad_encrypt_update(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_DES_OFB64: + get_keytype(tokdata, ctx->key, &keytype); + if (keytype == CKK_DES3) { + return des3_ofb_encrypt_update(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + case CKM_DES_CFB8: + get_keytype(tokdata, ctx->key, &keytype); + if (keytype == CKK_DES3) { + return des3_cfb_encrypt_update(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len, 0x01); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + case CKM_DES_CFB64: + get_keytype(tokdata, ctx->key, &keytype); + if (keytype == CKK_DES3) { + return des3_cfb_encrypt_update(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len, 0x08); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + case CKM_DES3_ECB: + return des3_ecb_encrypt_update(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_DES3_CBC: + return des3_cbc_encrypt_update(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_DES3_CBC_PAD: + return des3_cbc_pad_encrypt_update(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); +#ifndef NOAES + case CKM_AES_ECB: + return aes_ecb_encrypt_update(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_AES_CBC: + return aes_cbc_encrypt_update(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_AES_CBC_PAD: + return aes_cbc_pad_encrypt_update(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_AES_CTR: + return aes_ctr_encrypt_update(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_AES_GCM: + return aes_gcm_encrypt_update(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_AES_OFB: + return aes_ofb_encrypt_update(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len); + case CKM_AES_CFB8: + return aes_cfb_encrypt_update(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len, 0x01); + case CKM_AES_CFB64: + return aes_cfb_encrypt_update(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len, 0x08); + case CKM_AES_CFB128: + return aes_cfb_encrypt_update(tokdata, sess, length_only, ctx, + in_data, in_data_len, + out_data, out_data_len, 0x10); +#endif + default: + return CKR_MECHANISM_INVALID; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + +// +// +CK_RV +encr_mgr_encrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_KEY_TYPE keytype; + + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (ctx->active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->multi_init == FALSE) { + ctx->multi = TRUE; + ctx->multi_init = TRUE; + } + if (ctx->multi == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + return CKR_OPERATION_ACTIVE; + } + switch (ctx->mech.mechanism) { + case CKM_CDMF_ECB: + case CKM_DES_ECB: + return des_ecb_encrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_CDMF_CBC: + case CKM_DES_CBC: + return des_cbc_encrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_DES_CBC_PAD: + case CKM_CDMF_CBC_PAD: + return des_cbc_pad_encrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_DES_OFB64: + get_keytype(tokdata, ctx->key, &keytype); + if (keytype == CKK_DES3) { + return des3_ofb_encrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + case CKM_DES_CFB8: + get_keytype(tokdata, ctx->key, &keytype); + if (keytype == CKK_DES3) { + return des3_cfb_encrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len, 0x01); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + case CKM_DES_CFB64: + get_keytype(tokdata, ctx->key, &keytype); + if (keytype == CKK_DES3) { + return des3_cfb_encrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len, 0x08); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + return CKR_KEY_TYPE_INCONSISTENT; + } + case CKM_DES3_ECB: + return des3_ecb_encrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_DES3_CBC: + return des3_cbc_encrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_DES3_CBC_PAD: + return des3_cbc_pad_encrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); +#ifndef NOAES + case CKM_AES_ECB: + return aes_ecb_encrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_AES_CBC: + return aes_cbc_encrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_AES_CBC_PAD: + return aes_cbc_pad_encrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_AES_CTR: + return aes_ctr_encrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_AES_GCM: + return aes_gcm_encrypt_final(tokdata, sess, length_only, ctx, + out_data, out_data_len); + case CKM_AES_OFB: + return aes_ofb_encrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len); + case CKM_AES_CFB8: + return aes_cfb_encrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len, 0x01); + case CKM_AES_CFB64: + return aes_cfb_encrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len, 0x08); + case CKM_AES_CFB128: + return aes_cfb_encrypt_final(tokdata, sess, length_only, + ctx, out_data, out_data_len, 0x10); +#endif + default: + return CKR_MECHANISM_INVALID; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} diff --git a/usr/lib/common/globals.c b/usr/lib/common/globals.c new file mode 100644 index 0000000..6726b64 --- /dev/null +++ b/usr/lib/common/globals.c @@ -0,0 +1,231 @@ +/* + * 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 + */ + +/*************************************************************************** + Change Log + ========== + 4/25/03 Kapil Sood (kapil@corrent.com) + Added DH key pair generation and DH shared key derivation + functions. + + + +****************************************************************************/ + +#include +#include + +#include "pkcs11types.h" +#include "stdll.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" + +struct ST_FCN_LIST function_list; + + +// OBJECT IDENTIFIERs +// +const CK_BYTE ber_idDSA[] = + { 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x01 }; +const CK_BYTE ber_idEC[] = + { 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01 }; +const CK_BYTE ber_rsaEncryption[] = + { 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 }; +const CK_BYTE ber_md2WithRSAEncryption[] = + { 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x02 }; +const CK_BYTE ber_md4WithRSAEncryption[] = + { 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x03 }; +const CK_BYTE ber_md5WithRSAEncryption[] = + { 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04 }; +const CK_BYTE ber_sha1WithRSAEncryption[] = + { 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05 }; +const CK_BYTE ber_idDH[] = + { 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x03, 0x01 }; +const CK_BYTE ber_idDilithium[] = + { 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0B, 0x01, 0x06, 0x05 }; + +// Algorithm IDs. (Sequence of OID plus parms, usually NULL) +// +const CK_BYTE ber_AlgMd2[] = { + 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, + 0x86, 0xF7, 0x0D, 0x02, 0x02, 0x05, 0x00 +}; + +const CK_BYTE ber_AlgMd5[] = { + 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, + 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00 +}; + +const CK_BYTE ber_AlgSha1[] = { + 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, + 0x02, 0x1A, 0x05, 0x00 +}; + +const CK_BYTE ber_AlgSha224[] = { + 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, + 0x00 +}; + +const CK_BYTE ber_AlgSha256[] = { + 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, + 0x00 +}; + +const CK_BYTE ber_AlgSha384[] = { + 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, + 0x00 +}; + +const CK_BYTE ber_AlgSha512[] = { + 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, + 0x00 +}; + +const CK_BYTE ber_AlgIdRSAEncryption[] = { + 0x30, 0x0D, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, + 0x00 +}; + +const CK_BYTE der_AlgIdECBase[] = + { 0x30, 0x09, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 }; + +const CK_BYTE ber_AlgIdDilithium[] = + { 0x30, 0x0F, 0x06, 0x0B, 0x2B, 0x06, 0x01, + 0x04, 0x01, 0x02, 0x82, 0x0B, 0x01, 0x06, + 0x05, 0x05, 0x00 +}; + +// ID Lengths +// +const CK_ULONG ber_idDSALen = sizeof(ber_idDSA); +const CK_ULONG ber_idECLen = sizeof(ber_idEC); +const CK_ULONG ber_rsaEncryptionLen = sizeof(ber_rsaEncryption); +const CK_ULONG ber_md2WithRSAEncryptionLen = sizeof(ber_md2WithRSAEncryption); +const CK_ULONG ber_md4WithRSAEncryptionLen = sizeof(ber_md4WithRSAEncryption); +const CK_ULONG ber_md5WithRSAEncryptionLen = sizeof(ber_md5WithRSAEncryption); +const CK_ULONG ber_sha1WithRSAEncryptionLen = sizeof(ber_sha1WithRSAEncryption); +const CK_ULONG ber_idDHLen = sizeof(ber_idDH); +const CK_ULONG ber_idDilithiumLen = sizeof(ber_idDilithium); + +const CK_ULONG ber_AlgMd2Len = sizeof(ber_AlgMd2); +const CK_ULONG ber_AlgMd5Len = sizeof(ber_AlgMd5); +const CK_ULONG ber_AlgSha1Len = sizeof(ber_AlgSha1); +const CK_ULONG ber_AlgSha224Len = sizeof(ber_AlgSha224); +const CK_ULONG ber_AlgSha256Len = sizeof(ber_AlgSha256); +const CK_ULONG ber_AlgSha384Len = sizeof(ber_AlgSha384); +const CK_ULONG ber_AlgSha512Len = sizeof(ber_AlgSha512); +const CK_ULONG ber_AlgIdRSAEncryptionLen = sizeof(ber_AlgIdRSAEncryption); +const CK_ULONG der_AlgIdECBaseLen = sizeof(der_AlgIdECBase); +const CK_ULONG ber_AlgIdDilithiumLen = sizeof(ber_AlgIdDilithium); + +const CK_ULONG des_weak_count = 4; +const CK_ULONG des_semi_weak_count = 12; +const CK_ULONG des_possibly_weak_count = 48; + +const CK_BYTE des_weak_keys[4][8] = { + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, + {0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E}, + {0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1}, + {0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE} +}; + +const CK_BYTE des_semi_weak_keys[12][8] = { + {0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE}, + {0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01}, + {0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1}, + {0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E}, + {0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1}, + {0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01}, + {0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE}, + {0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E}, + {0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E}, + {0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01}, + {0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE}, + {0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1} +}; + +const CK_BYTE des_possibly_weak_keys[48][8] = { + {0x1F, 0x1F, 0x01, 0x01, 0x0E, 0x0E, 0x01, 0x01}, + {0x01, 0x1F, 0x1F, 0x01, 0x01, 0x0E, 0x0E, 0x01}, + {0x1F, 0x01, 0x01, 0x1F, 0x0E, 0x01, 0x01, 0x0E}, + {0x01, 0x01, 0x1F, 0x1F, 0x01, 0x01, 0x0E, 0x0E}, + {0xE0, 0xE0, 0x01, 0x01, 0xF1, 0xF1, 0x01, 0x01}, + {0xFE, 0xFE, 0x01, 0x01, 0xFE, 0xFE, 0x01, 0x01}, + {0xFE, 0xE0, 0x1F, 0x01, 0xFE, 0xF1, 0x0E, 0x01}, + {0xE0, 0xFE, 0x1F, 0x01, 0xF1, 0xFE, 0x0E, 0x01}, + {0xFE, 0xE0, 0x01, 0x1F, 0xFE, 0xF1, 0x01, 0x0E}, + {0xE0, 0xFE, 0x01, 0x1F, 0xF1, 0xFE, 0x01, 0x0E}, + {0xE0, 0xE0, 0x1F, 0x1F, 0xF1, 0xF1, 0x0E, 0x0E}, + {0xFE, 0xFE, 0x1F, 0x1F, 0xFE, 0xFE, 0x0E, 0x0E}, + {0xFE, 0x1F, 0xE0, 0x01, 0xFE, 0x0E, 0xF1, 0x01}, + {0xE0, 0x1F, 0xFE, 0x01, 0xF1, 0x0E, 0xFE, 0x01}, + {0xFE, 0x01, 0xE0, 0x1F, 0xFE, 0x01, 0xF1, 0x0E}, + {0xE0, 0x01, 0xFE, 0x1F, 0xF1, 0x01, 0xFE, 0x0E}, + {0x01, 0xE0, 0xE0, 0x01, 0x01, 0xF1, 0xF1, 0x01}, + {0x1F, 0xFE, 0xE0, 0x01, 0x0E, 0xFE, 0xF0, 0x01}, + {0x1F, 0xE0, 0xFE, 0x01, 0x0E, 0xF1, 0xFE, 0x01}, + {0x01, 0xFE, 0xFE, 0x01, 0x01, 0xFE, 0xFE, 0x01}, + {0x1F, 0xE0, 0xE0, 0x1F, 0x0E, 0xF1, 0xF1, 0x0E}, + {0x01, 0xFE, 0xE0, 0x1F, 0x01, 0xFE, 0xF1, 0x0E}, + {0x01, 0xE0, 0xFE, 0x1F, 0x01, 0xF1, 0xFE, 0x0E}, + {0x1F, 0xFE, 0xFE, 0x1F, 0x0E, 0xFE, 0xFE, 0x0E}, + {0xE0, 0x01, 0x01, 0xE0, 0xF1, 0x01, 0x01, 0xF1}, + {0xFE, 0x1F, 0x01, 0xE0, 0xFE, 0x0E, 0x01, 0xF1}, + {0xFE, 0x01, 0x1F, 0xE0, 0xFE, 0x01, 0x0E, 0xF1}, + {0xE0, 0x1F, 0x1F, 0xE0, 0xF1, 0x0E, 0x0E, 0xF1}, + {0xFE, 0x01, 0x01, 0xFE, 0xFE, 0x01, 0x01, 0xFE}, + {0xE0, 0x1F, 0x01, 0xFE, 0xF1, 0x0E, 0x01, 0xFE}, + {0xE0, 0x01, 0x1F, 0xFE, 0xF1, 0x01, 0x0E, 0xFE}, + {0xFE, 0x1F, 0x1F, 0xFE, 0xFE, 0x0E, 0x0E, 0xFE}, + {0x1F, 0xFE, 0x01, 0xE0, 0x0E, 0xFE, 0x01, 0xF1}, + {0x01, 0xFE, 0x1F, 0xE0, 0x01, 0xFE, 0x0E, 0xF1}, + {0x1F, 0xE0, 0x01, 0xFE, 0x0E, 0xF1, 0x01, 0xFE}, + {0x01, 0xE0, 0x1F, 0xFE, 0x01, 0xF1, 0x0E, 0xFE}, + {0x01, 0x01, 0xE0, 0xE0, 0x01, 0x01, 0xF1, 0xF1}, + {0x1F, 0x1F, 0xE0, 0xE0, 0x0E, 0x0E, 0xF1, 0xF1}, + {0x1F, 0x01, 0xFE, 0xE0, 0x0E, 0x01, 0xFE, 0xF1}, + {0x01, 0x1F, 0xFE, 0xE0, 0x01, 0x0E, 0xFE, 0xF1}, + {0x1F, 0x01, 0xE0, 0xFE, 0x0E, 0x01, 0xF1, 0xFE}, + {0x01, 0x1F, 0xE0, 0xFE, 0x01, 0x0E, 0xF1, 0xFE}, + {0x01, 0x01, 0xFE, 0xFE, 0x01, 0x01, 0xFE, 0xFE}, + {0x1F, 0x1F, 0xFE, 0xFE, 0x0E, 0x0E, 0xFE, 0xFE}, + {0xFE, 0xFE, 0xE0, 0xE0, 0xFE, 0xFE, 0xF1, 0xF1}, + {0xE0, 0xFE, 0xFE, 0xE0, 0xF1, 0xFE, 0xFE, 0xF1}, + {0xFE, 0xE0, 0xE0, 0xFE, 0xFE, 0xF1, 0xF1, 0xFE}, + {0xE0, 0xE0, 0xFE, 0xFE, 0xF1, 0xF1, 0xFE, 0xFE} +}; + +// default SO pin values +// + +const CK_BYTE default_so_pin_md5[MD5_HASH_SIZE] = { + 0x5E, 0x86, 0x67, 0xA4, 0x39, 0xC6, 0x8F, 0x51, + 0x45, 0xDD, 0x2F, 0xCB, 0xEC, 0xF0, 0x22, 0x09 +}; + +const CK_BYTE default_so_pin_sha[SHA1_HASH_SIZE] = { + 0xA7, 0xD5, 0x79, 0xBA, 0x76, 0x39, 0x80, 0x70, + 0xEA, 0xE6, 0x54, 0xC3, 0x0F, 0xF1, 0x53, 0xA4, + 0xC2, 0x73, 0x27, 0x2A +}; + +/* SHA-1 of "12345678" */ +const CK_BYTE default_user_pin_sha[SHA1_HASH_SIZE] = { + 0x7c, 0x22, 0x2f, 0xb2, 0x92, 0x7d, 0x82, 0x8a, + 0xf2, 0x2f, 0x59, 0x21, 0x34, 0xe8, 0x93, 0x24, + 0x80, 0x63, 0x7c, 0x0d +}; + diff --git a/usr/lib/common/h_extern.h b/usr/lib/common/h_extern.h new file mode 100644 index 0000000..2d65994 --- /dev/null +++ b/usr/lib/common/h_extern.h @@ -0,0 +1,2819 @@ +/* + * 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 + */ + +/*************************************************************************** + Change Log + ========== + 4/25/03 Kapil Sood (kapil@corrent.com) + Added DH key pair generation and DH shared key derivation + functions. + + + +****************************************************************************/ + + +#ifndef _H_EXTERN_H +#define _H_EXTERN_H + +#include + +// global variables +// +#define SO_PIN_DEFAULT "87654321" +#define SO_KDF_LOGIN_IT 100000ULL +#define SO_KDF_LOGIN_PURPOSE "so_login_purpose________________" +#define SO_KDF_WRAP_IT 100000ULL +#define SO_KDF_WRAP_PURPOSE "so_wrap_purpose_________________" + +#define USER_PIN_DEFAULT "12345678" +#define USER_KDF_LOGIN_IT 100000ULL +#define USER_KDF_LOGIN_PURPOSE "user_login_purpose______________" +#define USER_KDF_WRAP_IT 100000ULL +#define USER_KDF_WRAP_PURPOSE "user_wrap_purpose_______________" + +extern const CK_BYTE default_user_pin_sha[SHA1_HASH_SIZE]; +extern const CK_BYTE default_so_pin_sha[SHA1_HASH_SIZE]; +extern const CK_BYTE default_so_pin_md5[MD5_HASH_SIZE]; + +extern const CK_BYTE ber_AlgIdRSAEncryption[]; +extern const CK_ULONG ber_AlgIdRSAEncryptionLen; +extern const CK_BYTE ber_rsaEncryption[]; +extern const CK_ULONG ber_rsaEncryptionLen; +extern const CK_BYTE der_AlgIdECBase[]; +extern const CK_ULONG der_AlgIdECBaseLen; +extern const CK_BYTE ber_AlgIdDilithium[]; +extern const CK_ULONG ber_AlgIdDilithiumLen; +extern const CK_BYTE ber_idDSA[]; +extern const CK_ULONG ber_idDSALen; +extern const CK_BYTE ber_idDH[]; +extern const CK_ULONG ber_idDHLen; +extern const CK_BYTE ber_idEC[]; +extern const CK_ULONG ber_idECLen; + +extern const CK_BYTE ber_md2WithRSAEncryption[]; +extern const CK_ULONG ber_md2WithRSAEncryptionLen; +extern const CK_BYTE ber_md4WithRSAEncryption[]; +extern const CK_ULONG ber_md4WithRSAEncryptionLen; +extern const CK_BYTE ber_md5WithRSAEncryption[]; +extern const CK_ULONG ber_md5WithRSAEncryptionLen; +extern const CK_BYTE ber_sha1WithRSAEncryption[]; +extern const CK_ULONG ber_sha1WithRSAEncryptionLen; +extern const CK_BYTE ber_AlgMd2[]; +extern const CK_ULONG ber_AlgMd2Len; +extern const CK_BYTE ber_AlgMd5[]; +extern const CK_ULONG ber_AlgMd5Len; +extern const CK_BYTE ber_AlgSha1[]; +extern const CK_ULONG ber_AlgSha1Len; +extern const CK_BYTE ber_AlgSha224[]; +extern const CK_ULONG ber_AlgSha224Len; +extern const CK_BYTE ber_AlgSha256[]; +extern const CK_ULONG ber_AlgSha256Len; +extern const CK_BYTE ber_AlgSha384[]; +extern const CK_ULONG ber_AlgSha384Len; +extern const CK_BYTE ber_AlgSha512[]; +extern const CK_ULONG ber_AlgSha512Len; + +extern const CK_ULONG des_weak_count; +extern const CK_ULONG des_semi_weak_count; +extern const CK_ULONG des_possibly_weak_count; +extern const CK_BYTE des_weak_keys[4][8]; +extern const CK_BYTE des_semi_weak_keys[12][8]; +extern const CK_BYTE des_possibly_weak_keys[48][8]; + +extern struct ST_FCN_LIST function_list; + +// General-purpose functions +// +CK_RV C_Initialize(CK_VOID_PTR pInitArgs); +CK_RV C_Finalize(CK_VOID_PTR pReserved); +CK_RV C_GetInfo(CK_INFO_PTR pInfo); +CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList); + +// Slot and token management functions +// +CK_RV C_GetSlotList(CK_BBOOL tokenPresent, + CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount); + +CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo); + +CK_RV C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo); + +CK_RV C_WaitForSlotEvent(CK_FLAGS flags, + CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved); + +CK_RV C_GetMechanismList(CK_SLOT_ID slotID, + CK_MECHANISM_TYPE_PTR pMechanismList, + CK_ULONG_PTR pulCount); + +CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID, + CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo); + +CK_RV C_InitToken(CK_SLOT_ID slotID, + CK_CHAR_PTR pPin, CK_ULONG ulPinLen, CK_CHAR_PTR pLabel); + +CK_RV C_InitPIN(CK_SESSION_HANDLE hSession, + CK_CHAR_PTR pPin, CK_ULONG ulPinLen); + +CK_RV C_SetPIN(CK_SESSION_HANDLE hSession, + CK_CHAR_PTR pOldPin, + CK_ULONG ulOldLen, CK_CHAR_PTR pNewPin, CK_ULONG ulNewLen); + +// Session management functions +// +CK_RV C_OpenSession(CK_SLOT_ID slotID, + CK_FLAGS flags, + CK_VOID_PTR pApplication, + CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession); + +CK_RV C_CloseSession(CK_SESSION_HANDLE hSession); + +CK_RV C_CloseAllSessions(CK_SLOT_ID slotID); + +CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo); + +CK_RV C_GetOperationState(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pOperationState, + CK_ULONG_PTR pulOperationStateLen); + +CK_RV C_SetOperationState(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pOperationState, + CK_ULONG ulOperationStateLen, + CK_OBJECT_HANDLE hEncryptionKey, + CK_OBJECT_HANDLE hAuthenticationKey); + +CK_RV C_Login(CK_SESSION_HANDLE hSession, + CK_USER_TYPE userType, CK_CHAR_PTR pPin, CK_ULONG uPinLen); + +CK_RV C_Logout(CK_SESSION_HANDLE hSession); + + +// Object management functions +// +CK_RV C_CreateObject(CK_SESSION_HANDLE hSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject); + +CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject); + +CK_RV C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject); + +CK_RV C_GetObjectSize(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize); + +CK_RV C_GetAttributeValue(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount); + +CK_RV C_SetAttributeValue(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount); + +CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount); + +CK_RV C_FindObjects(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE_PTR phObject, + CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount); + +CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE hSession); + + +// Encryption functions +// +CK_RV C_EncryptInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); + +CK_RV C_Encrypt(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pData, + CK_ULONG ulDataLen, + CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen); + +CK_RV C_EncryptUpdate(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, + CK_ULONG ulPartLen, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen); + +CK_RV C_EncryptFinal(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pLastEncryptedPart, + CK_ULONG_PTR pulLastEncryptedPartLen); + + +// Decryption functions +// +CK_RV C_DecryptInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); + +CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedData, + CK_ULONG ulEncryptedDataLen, + CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen); + +CK_RV C_DecryptUpdate(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, + CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen); + +CK_RV C_DecryptFinal(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen); + + +// Message digesting functions +// +CK_RV C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism); + +CK_RV C_Digest(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pData, + CK_ULONG ulDataLen, + CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen); + +CK_RV C_DigestUpdate(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen); + +CK_RV C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey); + +CK_RV C_DigestFinal(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen); + + +// Signing and MAC functions +// +CK_RV C_SignInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); + +CK_RV C_Sign(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pData, + CK_ULONG ulDataLen, + CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen); + +CK_RV C_SignUpdate(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen); + +CK_RV C_SignFinal(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen); + +CK_RV C_SignRecoverInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); + +CK_RV C_SignRecover(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pData, + CK_ULONG ulDataLen, + CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen); + + +// Signature/MAC verification functions +// +CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); + +CK_RV C_Verify(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pData, + CK_ULONG ulDataLen, + CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen); + +CK_RV C_VerifyUpdate(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen); + +CK_RV C_VerifyFinal(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen); + +CK_RV C_VerifyRecoverInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); + +CK_RV C_VerifyRecover(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pSignature, + CK_ULONG ulSignatureLen, + CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen); + + +// Dual-function cryptographics functions +// +CK_RV C_DigestEncryptUpdate(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, + CK_ULONG ulPartLen, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen); + +CK_RV C_DecryptDigestUpdate(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, + CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen); + +CK_RV C_SignEncryptUpdate(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pPart, + CK_ULONG ulPartLen, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen); + +CK_RV C_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, + CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen); + + +// Key management functions +// +CK_RV C_GenerateKey(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey); + +CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_ATTRIBUTE_PTR pPublicKeyTemplate, + CK_ULONG ulPublicKeyAttributeCount, + CK_ATTRIBUTE_PTR pPrivateKeyTemplate, + CK_ULONG ulPrivateKeyAttributeCount, + CK_OBJECT_HANDLE_PTR phPublicKey, + CK_OBJECT_HANDLE_PTR phPrivateKey); + +CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hWrappingKey, + CK_OBJECT_HANDLE hKey, + CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen); + +CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hUnwrappingKey, + CK_BYTE_PTR pWrappedKey, + CK_ULONG ulWrappedKeyLen, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey); + +CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hBaseKey, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey); + + +// Random number generation functions +// +CK_RV C_SeedRandom(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen); + +CK_RV C_GenerateRandom(CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen); + +// Parallel function management functions +// +CK_RV C_GetFunctionStatus(CK_SESSION_HANDLE hSession); + +CK_RV C_CancelFunction(CK_SESSION_HANDLE hSession); + + +// +// internal routines are below this point +// +CK_RV clock_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV clock_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV clock_validate_attribute(TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + +CK_RV counter_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV counter_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV counter_validate_attribute(TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + +CK_RV dp_dsa_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV dp_dsa_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV dp_dsa_validate_attribute(TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + +CK_RV dp_dh_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV dp_dh_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV dp_dh_validate_attribute(TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + +CK_RV dp_x9dh_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV dp_x9dh_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV dp_x9dh_validate_attribute(TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + +CK_RV communicate(CK_ULONG cmd_id, + CK_VOID_PTR pReq, CK_ULONG req_len, + CK_VOID_PTR pRep, CK_ULONG_PTR repl_len, + CK_BYTE_PTR pOut, CK_ULONG out_len, + CK_BYTE_PTR pIn, CK_ULONG in_len); + +CK_RV compute_next_token_obj_name(CK_BYTE *current, CK_BYTE *next); + +CK_RV save_token_object(STDLL_TokData_t *tokdata, OBJECT *obj); +CK_RV save_private_token_object(STDLL_TokData_t *tokdata, OBJECT *obj); +CK_RV save_public_token_object(STDLL_TokData_t *tokdata, OBJECT *obj); + +CK_RV load_public_token_objects(STDLL_TokData_t *tokdata); +CK_RV load_private_token_objects(STDLL_TokData_t *tokdata); + +CK_RV reload_token_object(STDLL_TokData_t *tokdata, OBJECT *obj); + +CK_RV restore_private_token_object(STDLL_TokData_t *tokdata, + CK_BYTE *header, + CK_BYTE *data, CK_ULONG len, + CK_BYTE *footer, + OBJECT *pObj); + +CK_RV delete_token_object(STDLL_TokData_t *tokdata, OBJECT *ptr); +CK_RV delete_token_data(STDLL_TokData_t *tokdata); + +char *get_pk_dir(STDLL_TokData_t *tokdata, char *); + +CK_RV init_token_data(STDLL_TokData_t *, CK_SLOT_ID); +CK_RV load_token_data(STDLL_TokData_t *, CK_SLOT_ID); +CK_RV save_token_data(STDLL_TokData_t *, CK_SLOT_ID); + +CK_RV load_masterkey_so(STDLL_TokData_t *tokdata); +CK_RV load_masterkey_user(STDLL_TokData_t *tokdata); +CK_RV save_masterkey_so(STDLL_TokData_t *tokdata); +CK_RV save_masterkey_user(STDLL_TokData_t *tokdata); + +CK_RV generate_master_key(STDLL_TokData_t *tokdata, CK_BYTE *key); + +void init_data_store(STDLL_TokData_t *tokdata, char *directory, + char *data_store); +void final_data_store(STDLL_TokData_t * tokdata); + +void copy_token_contents_sensibly(CK_TOKEN_INFO_PTR pInfo, + TOKEN_DATA *nv_token_data); + +CK_RV compute_md5(STDLL_TokData_t *tokdata, CK_BYTE *data, CK_ULONG len, + CK_BYTE *hash); +CK_RV compute_sha1(STDLL_TokData_t *tokdata, CK_BYTE *data, CK_ULONG len, + CK_BYTE *hash); +CK_RV compute_sha(STDLL_TokData_t *tokdata, CK_BYTE *data, CK_ULONG len, + CK_BYTE *hash, CK_ULONG mech); +CK_RV get_sha_size(CK_ULONG mech, CK_ULONG *hsize); +CK_RV get_sha_block_size(CK_ULONG mech, CK_ULONG *bsize); + +CK_RV mgf1(STDLL_TokData_t *tokdata, 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); + +//CK_RV load_FCV( void ); +//CK_RV save_FCV( FUNCTION_CTRL_VEC_RECORD *new_FCV ); + +//CK_RV update_tweak_values( void *attributes, CK_ULONG count ); +//CK_RV query_tweak_values( CK_ATTRIBUTE_TYPE * attributes, +// CK_ULONG count, +// CK_BYTE ** reply, +// CK_ULONG * reply_len ); + +void init_slotInfo(CK_SLOT_INFO *); +void init_tokenInfo(TOKEN_DATA *nv_token_data); + +CK_BYTE parity_adjust(CK_BYTE b); +CK_RV parity_is_odd(CK_BYTE b); + +CK_RV build_attribute(CK_ATTRIBUTE_TYPE type, + CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **attr); + +CK_RV find_bbool_attribute(CK_ATTRIBUTE *attrs, CK_ULONG attrs_len, + CK_ATTRIBUTE_TYPE type, CK_BBOOL *value); + +CK_RV add_pkcs_padding(CK_BYTE *ptr, // where to start appending + CK_ULONG block_size, + CK_ULONG data_len, CK_ULONG total_len); + +CK_RV strip_pkcs_padding(CK_BYTE *ptr, + CK_ULONG total_len, CK_ULONG *data_len); + + +// RNG routines +// +CK_RV rng_generate(STDLL_TokData_t *tokdata, CK_BYTE *output, CK_ULONG bytes); + + +// SSL3 routines +// +CK_RV ssl3_mac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV ssl3_mac_sign_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV ssl3_mac_sign_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV ssl3_mac_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len); + +CK_RV ssl3_mac_verify_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV ssl3_mac_verify_final(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG sig_len); + +CK_RV ssl3_master_key_derive(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_MECHANISM *mech, + CK_OBJECT_HANDLE base_key, + CK_ATTRIBUTE *attributes, + CK_ULONG count, CK_OBJECT_HANDLE *handle); + +CK_RV ssl3_key_and_mac_derive(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_MECHANISM *mech, + CK_OBJECT_HANDLE base_key, + CK_ATTRIBUTE *attributes, CK_ULONG count); + +CK_RV ckm_ssl3_pre_master_key_gen(STDLL_TokData_t *tokdata, + TEMPLATE *tmpl, CK_MECHANISM *mech); + + +// RSA routines +// +CK_RV rsa_pkcs_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV rsa_pkcs_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV rsa_pkcs_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG *sig_len); + +CK_RV rsa_pkcs_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len); + +CK_RV rsa_pkcs_verify_recover(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, + CK_ULONG sig_len, + CK_BYTE *out_data, CK_ULONG *out_len); + +CK_RV rsa_oaep_crypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_BBOOL encrypt); + +CK_RV rsa_x509_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV rsa_x509_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV rsa_x509_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG *sig_len); + +CK_RV rsa_x509_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len); + +CK_RV rsa_x509_verify_recover(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, + CK_ULONG sig_len, + CK_BYTE *out_data, CK_ULONG *out_len); + +CK_RV rsa_hash_pkcs_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG *sig_len); + +CK_RV rsa_hash_pkcs_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len); + +CK_RV rsa_hash_pkcs_sign_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV rsa_hash_pkcs_verify_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV rsa_hash_pkcs_sign_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG *sig_len); + +CK_RV rsa_hash_pkcs_verify_final(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG sig_len); + +CK_RV rsa_pss_sign(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len); + +CK_RV rsa_hash_pss_sign(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *sig, + CK_ULONG *sig_len); + +CK_RV rsa_hash_pss_update(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV rsa_hash_pss_sign_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *signature, + CK_ULONG *sig_len); + +CK_RV rsa_pss_verify(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *signature, + CK_ULONG sig_len); + +CK_RV rsa_hash_pss_verify(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len); + +CK_RV rsa_hash_pss_verify_final(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG sig_len); + +CK_RV rsa_format_block(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG out_data_len, CK_ULONG type); + +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); + +// RSA mechanisms +// +CK_RV ckm_rsa_key_pair_gen(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, + TEMPLATE *priv_tmpl); + +CK_RV ckm_rsa_encrypt(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, OBJECT *key_obj); + +CK_RV ckm_rsa_decrypt(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, OBJECT *key_obj); + +CK_RV ckm_rsa_compute_priv_exp(STDLL_TokData_t *tokdata, TEMPLATE *tmpl); + +CK_RV ckm_rsa_sign(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, OBJECT *key_obj); + +CK_RV ckm_rsa_verify(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG out_data_len, OBJECT *key_obj); + +// RSA mechanism - EME-OAEP encoding +// +CK_RV encode_eme_oaep(STDLL_TokData_t *tokdata, CK_BYTE *mData, CK_ULONG mLen, + CK_BYTE *emData, CK_ULONG modLength, + CK_RSA_PKCS_MGF_TYPE mgf, CK_BYTE *hash, CK_ULONG hlen); + +CK_RV decode_eme_oaep(STDLL_TokData_t *tokdata, CK_BYTE *emData, + CK_ULONG emLen, CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_RSA_PKCS_MGF_TYPE mgf, + CK_BYTE *hash, CK_ULONG hlen); + +CK_RV emsa_pss_encode(STDLL_TokData_t *tokdata, + CK_RSA_PKCS_PSS_PARAMS_PTR pssParms, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *emData, + CK_ULONG *modbytes); + +CK_RV emsa_pss_verify(STDLL_TokData_t *tokdata, + CK_RSA_PKCS_PSS_PARAMS_PTR pssParms, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *sig, CK_ULONG modbytes); + +CK_RV check_pss_params(CK_MECHANISM *mechanism, CK_ULONG); + +#ifndef NODSA +// DSA routines +// +CK_RV dsa_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG *sig_len); + +CK_RV dsa_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG sig_len); + + +// DSA mechanisms +// +CK_RV ckm_dsa_key_pair_gen(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, + TEMPLATE *priv_tmpl); + +CK_RV ckm_dsa_sign(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, // must be 20 bytes + CK_BYTE *signature, // must be 40 bytes + OBJECT *priv_key); + +CK_RV ckm_dsa_verify(STDLL_TokData_t *tokdata, + CK_BYTE *signature, // must be 40 bytes + CK_BYTE *data, // must be 20 bytes + OBJECT *publ_key); + +#endif + +/* Begin code contributed by Corrent corp. */ +// DH routines +// +#ifndef NODH + +CK_RV dh_pkcs_derive(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_MECHANISM *mech, + CK_OBJECT_HANDLE base_key, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, CK_OBJECT_HANDLE *handle); + +// DH mechanisms +// +CK_RV ckm_dh_pkcs_derive(STDLL_TokData_t *tokdata, + CK_VOID_PTR other_pubkey, + CK_ULONG other_pubkey_len, + CK_OBJECT_HANDLE base_key, + CK_BYTE *secret, CK_ULONG *secret_len); + +CK_RV ckm_dh_key_pair_gen(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, + TEMPLATE *priv_tmpl); + +CK_RV ckm_dh_pkcs_key_pair_gen(STDLL_TokData_t *tokdata, + TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl); +#endif +/* End code contributed by Corrent corp. */ + +CK_RV ecdh_pkcs_derive(STDLL_TokData_t *tokdata, SESSION *sess, + CK_MECHANISM *mech, CK_OBJECT_HANDLE base_key, + CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, + CK_OBJECT_HANDLE *derived_key_obj); + +// DES routines - I have to provide two different versions of these +// because encryption routines are also used internally +// so we can't assume that external-to-external buffering +// will be possible and combining them into a single +// function is messy. +// +CK_RV pk_des_ecb_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des_ecb_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV pk_des_cbc_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des_cbc_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des_cbc_pad_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des_cbc_pad_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des_ecb_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des_ecb_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des_cbc_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des_cbc_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des_cbc_pad_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des_cbc_pad_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des_ecb_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des_ecb_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des_cbc_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des_cbc_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des_cbc_pad_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des_cbc_pad_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des_ecb_wrap_key(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, CK_MECHANISM *mech, + OBJECT *key, OBJECT *encr_key, + CK_BYTE *data, CK_ULONG *data_len); + + +// DES mechanisms +// +CK_RV ckm_des_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl); +CK_RV ckm_cdmf_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl); + +CK_RV ckm_des_ecb_encrypt(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len, + OBJECT *key); + +CK_RV ckm_des_ecb_decrypt(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len, + OBJECT *key); + +CK_RV ckm_des_cbc_encrypt(STDLL_TokData_t *tokdata, + 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_des_cbc_decrypt(STDLL_TokData_t *tokdata, + 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_des_wrap_format(STDLL_TokData_t *tokdata, CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len); + + +// DES3 routines +// +CK_RV des3_ecb_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_ecb_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_cbc_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_cbc_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_cbc_pad_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_cbc_pad_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_ecb_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_ecb_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_cbc_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_cbc_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_cbc_pad_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_cbc_pad_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_ecb_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_ecb_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_cbc_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_cbc_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_cbc_pad_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_cbc_pad_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_mac_sign(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_mac_sign_update(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV des3_mac_sign_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_mac_verify(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG out_data_len); + +CK_RV des3_mac_verify_update(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV des3_mac_verify_final(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG signature_len); + +CK_RV des3_cmac_sign(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_cmac_sign_update(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV des3_cmac_sign_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_cmac_verify(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG out_data_len); + +CK_RV des3_cmac_verify_update(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV des3_cmac_verify_final(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG signature_len); + + +// DES3 mechanisms +// +CK_RV ckm_des3_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl); + +CK_RV ckm_des3_ecb_encrypt(STDLL_TokData_t *tokdata, CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len, + OBJECT *key); + +CK_RV ckm_des3_ecb_decrypt(STDLL_TokData_t *tokdata, CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len, + OBJECT *key); + +CK_RV ckm_des3_cbc_encrypt(STDLL_TokData_t *tokdata, 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_des3_cbc_decrypt(STDLL_TokData_t *tokdata, 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 des3_ofb_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len); + +CK_RV des3_ofb_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len); + +CK_RV des3_ofb_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len); + +CK_RV des3_ofb_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len); + + +CK_RV des3_ofb_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_ofb_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV des3_cfb_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len, + CK_ULONG cfb_len); + +CK_RV des3_cfb_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len, + CK_ULONG cfb_len); + +CK_RV des3_cfb_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len, + CK_ULONG cfb_len); + +CK_RV des3_cfb_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len, + CK_ULONG cfb_len); + +CK_RV des3_cfb_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len, + CK_ULONG cfb_len); + +CK_RV des3_cfb_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len, + CK_ULONG cfb_len); + +// AES routines +// +CK_RV aes_ecb_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_ecb_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_cbc_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_cbc_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_cbc_pad_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_cbc_pad_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_ctr_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_ctr_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_ecb_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_ecb_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_cbc_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_cbc_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_cbc_pad_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len); + +CK_RV aes_cbc_pad_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len); + +CK_RV aes_ctr_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_ctr_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_ecb_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_ecb_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_cbc_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_cbc_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_cbc_pad_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, CK_BYTE *out_data, + CK_ULONG *out_data_len); + +CK_RV aes_cbc_pad_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *context, CK_BYTE *out_data, + CK_ULONG *out_data_len); + +CK_RV aes_ctr_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_ctr_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_mac_sign(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_mac_sign_update(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV aes_mac_sign_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_mac_verify(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG out_data_len); + +CK_RV aes_mac_verify_update(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV aes_mac_verify_final(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG signature_len); + +CK_RV aes_cmac_sign(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_cmac_sign_update(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV aes_cmac_sign_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_cmac_verify(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG out_data_len); + +CK_RV aes_cmac_verify_update(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV aes_cmac_verify_final(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG signature_len); + + +// AES mechanisms +// +CK_RV ckm_aes_key_gen(STDLL_TokData_t *, TEMPLATE *tmpl); + +CK_RV ckm_aes_ecb_encrypt(STDLL_TokData_t *, 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_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_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_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len, + CK_BYTE *init_v, OBJECT *key); + +CK_RV ckm_aes_ctr_encrypt(STDLL_TokData_t *, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_BYTE *counterblock, + CK_ULONG counter_width, OBJECT *key); + +CK_RV ckm_aes_ctr_decrypt(STDLL_TokData_t *, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_BYTE *counterblock, + CK_ULONG counter_width, OBJECT *key); + +CK_RV ckm_aes_wrap_format(STDLL_TokData_t *, CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len); + +CK_RV aes_gcm_init(STDLL_TokData_t *tokdata, SESSION *, ENCR_DECR_CONTEXT *, + CK_MECHANISM *, CK_OBJECT_HANDLE, CK_BYTE); + +CK_RV aes_gcm_encrypt(STDLL_TokData_t *tokdata, SESSION *, CK_BBOOL, + ENCR_DECR_CONTEXT *, CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG *); + +CK_RV aes_gcm_encrypt_update(STDLL_TokData_t *tokdata, SESSION *, CK_BBOOL, + ENCR_DECR_CONTEXT *, + CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); + +CK_RV aes_gcm_encrypt_final(STDLL_TokData_t *tokdata, SESSION *, CK_BBOOL, + ENCR_DECR_CONTEXT *, CK_BYTE *, CK_ULONG *); + +CK_RV aes_gcm_decrypt(STDLL_TokData_t *tokdata, SESSION *, CK_BBOOL, + ENCR_DECR_CONTEXT *, CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG *); + +CK_RV aes_gcm_decrypt_update(STDLL_TokData_t *tokdata, SESSION *, CK_BBOOL, + ENCR_DECR_CONTEXT *, + CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); + +CK_RV aes_gcm_decrypt_final(STDLL_TokData_t *tokdata, SESSION *, CK_BBOOL, + ENCR_DECR_CONTEXT *, CK_BYTE *, CK_ULONG *); + +CK_RV aes_ofb_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len); + +CK_RV aes_ofb_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len); + +CK_RV aes_ofb_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, + CK_ULONG *out_data_len); + +CK_RV aes_ofb_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV aes_ofb_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len); + +CK_RV aes_ofb_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, + CK_ULONG *out_data_len); + +CK_RV aes_cfb_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_ULONG cfb_len); + +CK_RV aes_cfb_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len, + CK_ULONG cfb_len); + +CK_RV aes_cfb_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_ULONG cfb_len); + +CK_RV aes_cfb_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len, + CK_ULONG cfb_len); + +CK_RV aes_cfb_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_ULONG cfb_len); + +CK_RV aes_cfb_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_ULONG cfb_len); + +// SHA mechanisms +// + +void sw_sha1_init(DIGEST_CONTEXT *ctx); + +CK_RV sw_sha1_hash(DIGEST_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len); + +CK_RV sha_init(STDLL_TokData_t *tokdata, SESSION *sess, DIGEST_CONTEXT *ctx, + CK_MECHANISM *mech); + +CK_RV sha_hash(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, + DIGEST_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV sha_hash_update(STDLL_TokData_t *tokdata, SESSION *sess, + DIGEST_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len); + +CK_RV sha_hash_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, DIGEST_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV hmac_sign_init(STDLL_TokData_t *tokdata, SESSION *sess, + CK_MECHANISM *mech, CK_OBJECT_HANDLE key); + +CK_RV hmac_sign_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV hmac_sign_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BYTE *in_data, CK_ULONG *in_data_len); + +CK_RV hmac_verify_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV hmac_verify_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV hmac_verify_init(STDLL_TokData_t *tokdata, SESSION *sess, + CK_MECHANISM *mech, CK_OBJECT_HANDLE key); + +CK_RV sha1_hmac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV sha1_hmac_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len); + +CK_RV sha224_hmac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV sha224_hmac_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len); + +CK_RV sha256_hmac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV sha256_hmac_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len); + +CK_RV sha384_hmac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len); + +CK_RV sha384_hmac_verify(STDLL_TokData_t *tokdata, + SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len); + +CK_RV sha512_hmac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len); + +CK_RV sha512_hmac_verify(STDLL_TokData_t *tokdata, + SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len); + +//adding the hmac secret key generation here +CK_RV ckm_generic_secret_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl); + +// MD2 mechanisms +// +CK_RV md2_hash(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, + DIGEST_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV md2_hash_update(STDLL_TokData_t *tokdata, SESSION *sess, + DIGEST_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV md2_hash_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, DIGEST_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV md2_hmac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV md2_hmac_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len); + +CK_RV ckm_md2_update(STDLL_TokData_t *tokdata, MD2_CONTEXT *context, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV ckm_md2_final(STDLL_TokData_t *tokdata, MD2_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG out_data_len); + +void ckm_md2_transform(STDLL_TokData_t *tokdata, CK_BYTE *state, + CK_BYTE *checksum, CK_BYTE *block); + + +// MD5 mechanisms +// +CK_RV md5_hash(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, DIGEST_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV md5_hash_update(STDLL_TokData_t *tokdata, SESSION *sess, + DIGEST_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV md5_hash_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, DIGEST_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV md5_hmac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV md5_hmac_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len); + +void sw_md5_init(DIGEST_CONTEXT *ctx); + +CK_RV sw_md5_hash(DIGEST_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len); + +CK_RV md5_init(STDLL_TokData_t *tokdata, SESSION *sess, DIGEST_CONTEXT *ctx, + CK_MECHANISM *mech); + +//Elliptic curve (EC) mechanisms +// +CK_RV ckm_ec_key_pair_gen(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, + TEMPLATE *priv_tmpl); + +CK_RV ckm_ec_sign(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_RV ec_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV ckm_ec_verify(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_RV ec_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG sig_len); + +CK_RV ec_hash_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG *sig_len); + +CK_RV ec_hash_sign_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV ec_hash_sign_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG *sig_len); + +CK_RV ec_hash_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len); + +CK_RV ec_hash_verify_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len); + + +CK_RV ec_hash_verify_final(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG sig_len); + +CK_RV ec_uncompress_public_key(CK_BYTE *curve, CK_ULONG curve_len, + CK_BYTE *pubkey, CK_ULONG pubkey_len, + CK_ULONG privkey_len, + CK_BYTE *out_pubkey, CK_ULONG *out_len); + +// linked-list routines +// +DL_NODE *dlist_add_as_first(DL_NODE *list, void *data); +DL_NODE *dlist_add_as_last(DL_NODE *list, void *data); +DL_NODE *dlist_find(DL_NODE *list, void *data); +DL_NODE *dlist_get_first(DL_NODE *list); +DL_NODE *dlist_get_last(DL_NODE *list); +CK_ULONG dlist_length(DL_NODE *list); +DL_NODE *dlist_next(DL_NODE *list); +DL_NODE *dlist_prev(DL_NODE *list); +void dlist_purge(DL_NODE *list); +DL_NODE *dlist_remove_node(DL_NODE *list, DL_NODE *node); + +CK_RV attach_shm(STDLL_TokData_t *tokdata, CK_SLOT_ID slot_id); +CK_RV detach_shm(STDLL_TokData_t *tokdata, CK_BBOOL ignore_ref_count); + +//get keytype +CK_RV get_keytype(STDLL_TokData_t *tokdata, CK_OBJECT_HANDLE hkey, + CK_KEY_TYPE *keytype); +CK_RV check_user_and_group(); + +//lock and unlock routines +CK_RV XProcLock(STDLL_TokData_t *tokdata); +CK_RV XProcUnLock(STDLL_TokData_t *tokdata); +CK_RV XThreadLock(STDLL_TokData_t *tokdata); +CK_RV XThreadUnLock(STDLL_TokData_t *tokdata); +CK_RV CreateXProcLock(char *tokname, STDLL_TokData_t *tokdata); +CK_RV XProcLock_Init(STDLL_TokData_t *tokdata); +void CloseXProcLock(STDLL_TokData_t *tokdata); + +//list mechanisms +// +void mechanism_list_transformations(CK_MECHANISM_TYPE_PTR mech_arr_ptr, + CK_ULONG_PTR count_ptr); + +// encryption manager routines +// +CK_RV encr_mgr_init(STDLL_TokData_t *tokdata, + SESSION *sess, + ENCR_DECR_CONTEXT *ctx, + CK_ULONG operation, + CK_MECHANISM *mech, CK_OBJECT_HANDLE key_handle); + +CK_RV encr_mgr_cleanup(ENCR_DECR_CONTEXT *ctx); + +CK_RV encr_mgr_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV encr_mgr_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV encr_mgr_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +// decryption manager routines +// +CK_RV decr_mgr_init(STDLL_TokData_t *tokdata, + SESSION *sess, + ENCR_DECR_CONTEXT *ctx, + CK_ULONG operation, + CK_MECHANISM *mech, CK_OBJECT_HANDLE key_handle); + +CK_RV decr_mgr_cleanup(ENCR_DECR_CONTEXT *ctx); + +CK_RV decr_mgr_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV decr_mgr_decrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV decr_mgr_decrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV decr_mgr_update_des_ecb(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV decr_mgr_update_des_cbc(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV decr_mgr_update_des3_ecb(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV decr_mgr_update_des3_cbc(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +// digest manager routines +// +CK_RV digest_mgr_cleanup(DIGEST_CONTEXT *ctx); + +CK_RV digest_mgr_init(STDLL_TokData_t *tokdata, + SESSION *sess, + DIGEST_CONTEXT *ctx, CK_MECHANISM *mech); + +CK_RV digest_mgr_digest(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + DIGEST_CONTEXT *ctx, + CK_BYTE *data, CK_ULONG data_len, + CK_BYTE *hash, CK_ULONG *hash_len); + +CK_RV digest_mgr_digest_update(STDLL_TokData_t *tokdata, + SESSION *sess, + DIGEST_CONTEXT *ctx, + CK_BYTE *data, CK_ULONG data_len); + +CK_RV digest_mgr_digest_key(STDLL_TokData_t *tokdata, + SESSION *sess, + DIGEST_CONTEXT *ctx, CK_OBJECT_HANDLE key_handle); + +CK_RV digest_mgr_digest_final(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + DIGEST_CONTEXT *ctx, + CK_BYTE *hash, CK_ULONG *hash_len); + + +// key manager routines +// +CK_RV key_mgr_generate_key(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_MECHANISM *mech, + CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, + CK_OBJECT_HANDLE *key_handle); + +CK_RV key_mgr_generate_key_pair(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_MECHANISM *mech, + CK_ATTRIBUTE *publ_tmpl, CK_ULONG publ_count, + CK_ATTRIBUTE *priv_tmpl, CK_ULONG priv_count, + CK_OBJECT_HANDLE *publ_key_handle, + CK_OBJECT_HANDLE *priv_key_handle); + +CK_RV key_mgr_get_private_key_type(CK_BYTE *keydata, + CK_ULONG keylen, CK_KEY_TYPE *keytype); + +CK_RV key_mgr_derive_key(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_MECHANISM *mech, + CK_OBJECT_HANDLE base_key, + CK_OBJECT_HANDLE *derived_key, + CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount); + +CK_RV key_mgr_wrap_key(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + CK_MECHANISM *mech, + CK_OBJECT_HANDLE h_wrapping_key, + CK_OBJECT_HANDLE h_key, + CK_BYTE *wrapped_key, CK_ULONG *wrapped_key_len); + +CK_RV key_mgr_unwrap_key(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_MECHANISM *mech, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, + CK_BYTE *wrapped_key, + CK_ULONG wrapped_key_len, + CK_OBJECT_HANDLE unwrapping_key, + CK_OBJECT_HANDLE *unwrapped_key); + +CK_RV key_mgr_derive_prolog(SESSION *sess, + CK_ATTRIBUTE *attributes, + CK_ULONG attrcount, + CK_OBJECT_HANDLE base_key, + OBJECT *base_key_obj, + CK_BYTE *base_key_value, + CK_KEY_TYPE base_key_type, + ATTRIBUTE_PARSE_LIST *parselist, CK_ULONG plcount); + + +// signature manager routines +// +CK_RV sign_mgr_init(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_MECHANISM *mech, + CK_BBOOL recover_mode, CK_OBJECT_HANDLE key_handle); + +CK_RV sign_mgr_cleanup(SIGN_VERIFY_CONTEXT *ctx); + +CK_RV sign_mgr_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV sign_mgr_sign_recover(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV sign_mgr_sign_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len); + +CK_RV sign_mgr_sign_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len); + +// signature verify manager routines +// +CK_RV verify_mgr_init(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_MECHANISM *mech, + CK_BBOOL recover_mode, CK_OBJECT_HANDLE key_handle); + +CK_RV verify_mgr_cleanup(SIGN_VERIFY_CONTEXT *ctx); + +CK_RV verify_mgr_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len); + +CK_RV verify_mgr_verify_recover(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, + CK_ULONG sig_len, + CK_BYTE *out_data, CK_ULONG *out_len); + +CK_RV verify_mgr_verify_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len); + +CK_RV verify_mgr_verify_final(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG sig_len); + + +// session manager routines +// +CK_RV session_mgr_close_all_sessions(STDLL_TokData_t *tokdata); +CK_RV session_mgr_close_session(STDLL_TokData_t *tokdata, CK_SESSION_HANDLE); +CK_RV session_mgr_new(STDLL_TokData_t *tokdata, CK_ULONG flags, + CK_SLOT_ID slot_id, CK_SESSION_HANDLE_PTR phSession); +SESSION *session_mgr_find(STDLL_TokData_t *tokdata, CK_SESSION_HANDLE handle); +void session_mgr_put(STDLL_TokData_t *tokdata, SESSION *session); +CK_RV session_mgr_login_all(STDLL_TokData_t *tokdata, CK_USER_TYPE user_type); +CK_RV session_mgr_logout_all(STDLL_TokData_t *tokdata); + +CK_BBOOL session_mgr_readonly_session_exists(STDLL_TokData_t *tokdata); +CK_BBOOL session_mgr_so_session_exists(STDLL_TokData_t *tokdata); +CK_BBOOL session_mgr_user_session_exists(STDLL_TokData_t *tokdata); +CK_BBOOL session_mgr_public_session_exists(STDLL_TokData_t *tokdata); + +CK_RV session_mgr_get_op_state(SESSION *sess, CK_BBOOL length_only, + CK_BYTE *data, CK_ULONG *data_len); + +CK_RV session_mgr_set_op_state(SESSION *sess, + CK_OBJECT_HANDLE encr_key, + CK_OBJECT_HANDLE auth_key, CK_BYTE *data, + CK_ULONG data_len); +CK_BBOOL pin_expired(CK_SESSION_INFO *, CK_FLAGS); +CK_BBOOL pin_locked(CK_SESSION_INFO *, CK_FLAGS); +void set_login_flags(CK_USER_TYPE, CK_FLAGS_32 *); + + +// object manager routines +// +CK_RV object_mgr_add(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, CK_OBJECT_HANDLE *handle); + +CK_RV object_mgr_add_to_map(STDLL_TokData_t *tokdata, + SESSION *sess, + OBJECT *obj, + unsigned long obj_handle, + CK_OBJECT_HANDLE *handle); + +void object_mgr_add_to_shm(OBJECT *obj, LW_SHM_TYPE *shm); +CK_RV object_mgr_del_from_shm(OBJECT *obj, LW_SHM_TYPE *shm); +CK_RV object_mgr_check_shm(STDLL_TokData_t *tokdata, OBJECT *obj); +CK_RV object_mgr_search_shm_for_obj(TOK_OBJ_ENTRY *list, + CK_ULONG lo, + CK_ULONG hi, + OBJECT *obj, CK_ULONG *index); +CK_RV object_mgr_sort_priv_shm(void); +CK_RV object_mgr_sort_publ_shm(void); +CK_RV object_mgr_update_from_shm(STDLL_TokData_t *tokdata); +CK_RV object_mgr_update_publ_tok_obj_from_shm(STDLL_TokData_t *tokdata); +CK_RV object_mgr_update_priv_tok_obj_from_shm(STDLL_TokData_t *tokdata); + +CK_RV object_mgr_copy(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, + CK_OBJECT_HANDLE old_obj, CK_OBJECT_HANDLE *new_obj); + +CK_RV object_mgr_create_final(STDLL_TokData_t *tokdata, + SESSION *sess, + OBJECT *obj, CK_OBJECT_HANDLE *handle); + +CK_RV object_mgr_create_skel(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, + CK_ULONG mode, + CK_ULONG class, CK_ULONG subclass, OBJECT **obj); + +CK_RV object_mgr_destroy_object(STDLL_TokData_t *tokdata, + SESSION *sess, CK_OBJECT_HANDLE handle); + +CK_RV object_mgr_destroy_token_objects(STDLL_TokData_t *tokdata); + +CK_RV object_mgr_find_in_map_nocache(STDLL_TokData_t *tokdata, + CK_OBJECT_HANDLE handle, OBJECT **ptr, + OBJ_LOCK_TYPE lock_type); + +CK_RV object_mgr_find_in_map1(STDLL_TokData_t *tokdata, + CK_OBJECT_HANDLE handle, OBJECT **ptr, + OBJ_LOCK_TYPE lock_type); + +CK_RV object_mgr_find_in_map2(STDLL_TokData_t *tokdata, + OBJECT *ptr, CK_OBJECT_HANDLE *handle); + +CK_RV object_mgr_find_init(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount); + +CK_RV object_mgr_find_build_list(SESSION *sess, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, + DL_NODE *obj_list, CK_BBOOL public_only); + +CK_RV object_mgr_find_final(SESSION *sess); + +CK_RV object_mgr_get_attribute_values(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_OBJECT_HANDLE handle, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount); + +CK_RV object_mgr_get_object_size(STDLL_TokData_t *tokdata, + CK_OBJECT_HANDLE handle, CK_ULONG *size); + +CK_BBOOL object_mgr_purge_session_objects(STDLL_TokData_t *tokdata, + SESSION *sess, SESS_OBJ_TYPE type); + +CK_BBOOL object_mgr_purge_token_objects(STDLL_TokData_t *tokdata); + +CK_BBOOL object_mgr_purge_private_token_objects(STDLL_TokData_t *tokdata); + +CK_RV object_mgr_restore_obj(STDLL_TokData_t *tokdata, CK_BYTE *data, + OBJECT *oldObj); + +CK_RV object_mgr_restore_obj_withSize(STDLL_TokData_t *tokdata, + CK_BYTE *data, OBJECT *oldObj, + int data_size); + +CK_RV object_mgr_set_attribute_values(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_OBJECT_HANDLE handle, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount); + +// SAB FIXME FIXME +CK_BBOOL object_mgr_purge_map(STDLL_TokData_t *tokdata, + SESSION *sess, SESS_OBJ_TYPE type); + +CK_RV object_put(STDLL_TokData_t *tokdata, OBJECT *obj, CK_BBOOL unlock); + +/* structures used to hold arguments to callback functions triggered by either + * bt_for_each_node or bt_node_free */ +struct find_args { + int done; + OBJECT *obj; + CK_OBJECT_HANDLE map_handle; +}; + +struct find_by_name_args { + int done; + char *name; +}; + +struct find_build_list_args { + CK_ATTRIBUTE *pTemplate; + SESSION *sess; + CK_ULONG ulCount; + CK_BBOOL hw_feature; + CK_BBOOL hidden_object; + CK_BBOOL public_only; +}; + +struct purge_args { + SESSION *sess; + SESS_OBJ_TYPE type; +}; + +struct update_tok_obj_args { + TOK_OBJ_ENTRY *entries; + CK_ULONG_32 *num_entries; + struct btree *t; +}; + + +// object routines +// +CK_RV object_create(STDLL_TokData_t *tokdata, + CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, OBJECT **obj); + +CK_RV object_create_skel(STDLL_TokData_t *tokdata, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, + CK_ULONG mode, + CK_ULONG class, CK_ULONG subclass, OBJECT **key); + +CK_RV object_copy(STDLL_TokData_t *tokdata, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, OBJECT *old_obj, OBJECT **new_obj); + +CK_RV object_flatten(OBJECT *obj, CK_BYTE **data, CK_ULONG *len); + +void object_free(OBJECT *obj); + +void call_object_free(void *ptr); + +CK_RV object_get_attribute_values(OBJECT *obj, + CK_ATTRIBUTE *pTemplate, CK_ULONG count); + +CK_ULONG object_get_size(OBJECT *obj); + +CK_RV object_restore(CK_BYTE *data, OBJECT **obj, CK_BBOOL replace); + +CK_RV object_restore_withSize(CK_BYTE *data, + OBJECT **obj, CK_BBOOL replace, int data_size); + +CK_RV object_set_attribute_values(STDLL_TokData_t *tokdata, + OBJECT *obj, + CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount); + +CK_BBOOL object_is_modifiable(OBJECT *obj); +CK_BBOOL object_is_private(OBJECT *obj); +CK_BBOOL object_is_public(OBJECT *obj); +CK_BBOOL object_is_token_object(OBJECT *obj); +CK_BBOOL object_is_session_object(OBJECT *obj); + +CK_RV object_init_lock(OBJECT *obj); +CK_RV object_destroy_lock(OBJECT *obj); +CK_RV object_lock(OBJECT *obj, OBJ_LOCK_TYPE type); +CK_RV object_unlock(OBJECT *obj); + +// object attribute template routines +// + +CK_RV template_add_attributes(TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG ulCount); + +CK_RV template_add_default_attributes(TEMPLATE *tmpl, + TEMPLATE *basetmpl, + CK_ULONG class, + CK_ULONG subclass, CK_ULONG mode); + +CK_BBOOL template_attribute_find(TEMPLATE *tmpl, + CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE **attr); + +void template_attribute_find_multiple(TEMPLATE *tmpl, + ATTRIBUTE_PARSE_LIST *parselist, + CK_ULONG plcount); + +CK_BBOOL template_check_exportability(TEMPLATE *tmpl, CK_ATTRIBUTE_TYPE type); + +CK_RV template_check_required_attributes(TEMPLATE *tmpl, + CK_ULONG class, + CK_ULONG subclass, CK_ULONG mode); + +CK_RV template_check_required_base_attributes(TEMPLATE *tmpl, CK_ULONG mode); + +CK_BBOOL template_compare(CK_ATTRIBUTE *t1, CK_ULONG ulCount, TEMPLATE *t2); + +CK_RV template_copy(TEMPLATE *dest, TEMPLATE *src); + +CK_RV template_flatten(TEMPLATE *tmpl, CK_BYTE *dest); + +CK_RV template_free(TEMPLATE *tmpl); + +CK_BBOOL template_get_class(TEMPLATE *tmpl, + CK_ULONG *class, CK_ULONG *subclass); + +CK_ULONG template_get_count(TEMPLATE *tmpl); + +CK_ULONG template_get_size(TEMPLATE *tmpl); + +CK_ULONG template_get_compressed_size(TEMPLATE *tmpl); + +CK_RV template_set_default_common_attributes(TEMPLATE *tmpl); + +CK_RV template_merge(TEMPLATE *dest, TEMPLATE **src); + +CK_RV template_update_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr); + +CK_RV template_unflatten(TEMPLATE **tmpl, CK_BYTE *data, CK_ULONG count); + +CK_RV template_unflatten_withSize(TEMPLATE **new_tmpl, + CK_BYTE *buf, CK_ULONG count, int buf_size); + +CK_RV template_validate_attribute(STDLL_TokData_t *tokdata, + TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, + CK_ULONG class, + CK_ULONG subclass, CK_ULONG mode); + +CK_RV template_validate_attributes(STDLL_TokData_t *tokdata, + TEMPLATE *tmpl, + CK_ULONG class, + CK_ULONG subclass, CK_ULONG mode); + +CK_RV template_validate_base_attribute(TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + + + +// DATA OBJECT ROUTINES +// +CK_RV data_object_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV data_object_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV data_object_validate_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode); + +// CERTIFICATE ROUTINES +// +CK_RV cert_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV cert_validate_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode); + +CK_RV cert_x509_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV cert_x509_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV cert_x509_validate_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode); +CK_RV cert_vendor_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV cert_vendor_validate_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode); + +// +// KEY ROUTINES +// + +CK_RV key_object_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV key_object_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV key_object_validate_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode); + +CK_RV publ_key_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV publ_key_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV publ_key_validate_attribute(STDLL_TokData_t *tokdata, + TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + +CK_RV priv_key_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV priv_key_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV priv_key_unwrap(TEMPLATE *tmpl, CK_ULONG keytype, CK_BYTE *data, + CK_ULONG data_len, CK_BBOOL isopaque); +CK_RV priv_key_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + +CK_BBOOL secret_key_check_exportability(CK_ATTRIBUTE_TYPE type); +CK_RV secret_key_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV secret_key_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV secret_key_unwrap(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ULONG keytype, CK_BYTE *data, CK_ULONG data_len, + CK_BBOOL fromend, CK_BBOOL isopaque); +CK_RV secret_key_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + +// rsa routines +// +CK_RV rsa_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV rsa_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); +CK_RV rsa_publ_set_default_attributes(TEMPLATE *tmpl, TEMPLATE *basetmpl, + CK_ULONG mode); +CK_BBOOL rsa_priv_check_exportability(CK_ATTRIBUTE_TYPE type); +CK_RV rsa_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV rsa_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV rsa_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); +CK_RV rsa_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len); +CK_RV rsa_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG data_len, + CK_BBOOL isopaque); +CK_RV rsa_priv_unwrap_get_data(TEMPLATE *tmpl, + CK_BYTE *data, CK_ULONG total_length); + +// dsa routines +// +CK_RV dsa_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV dsa_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV dsa_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); +CK_BBOOL dsa_priv_check_exportability(CK_ATTRIBUTE_TYPE type); +CK_RV dsa_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV dsa_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV dsa_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); +CK_RV dsa_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len); +CK_RV dsa_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG data_len); +CK_RV dsa_priv_unwrap_get_data(TEMPLATE *tmpl, + CK_BYTE *data, CK_ULONG total_length); + +// ecdsa routines +// +CK_RV ecdsa_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV ecdsa_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV ecdsa_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); +CK_BBOOL ecdsa_priv_check_exportability(CK_ATTRIBUTE_TYPE type); +CK_RV ecdsa_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV ecdsa_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV ecdsa_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); +CK_RV ecdsa_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len); +CK_RV ecdsa_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data, + CK_ULONG data_len); +CK_RV ec_priv_unwrap(TEMPLATE *tmpl, + CK_BYTE *data, CK_ULONG data_len, CK_BBOOL isOpaque); + +// Dilithium routines +// +CK_RV ibm_dilithium_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV ibm_dilithium_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV ibm_dilithium_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); +CK_RV ibm_dilithium_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV ibm_dilithium_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV ibm_dilithium_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); +CK_RV ibm_dilithium_priv_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len); +CK_RV ibm_dilithium_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, + CK_ULONG total_length, CK_BBOOL isOpaque); +CK_RV ibm_dilithium_priv_unwrap_get_data(TEMPLATE *tmpl, + CK_BYTE *data, CK_ULONG total_length); + +// diffie-hellman routines +// +CK_RV dh_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV dh_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV dh_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); +CK_BBOOL dh_priv_check_exportability(CK_ATTRIBUTE_TYPE type); +CK_RV dh_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV dh_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV dh_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); +CK_RV dh_priv_wrap_get_data(TEMPLATE *tmpl, + CK_BBOOL length_only, CK_BYTE **data, + CK_ULONG *data_len); +CK_RV dh_priv_unwrap_get_data(TEMPLATE *tmpl, + CK_BYTE *data, CK_ULONG total_length); +CK_RV dh_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG data_len); + +// KEA routines +// +CK_RV kea_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV kea_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV kea_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); +CK_BBOOL kea_priv_check_exportability(CK_ATTRIBUTE_TYPE type); +CK_RV kea_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV kea_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV kea_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + + +// Generic secret key routines +CK_RV generic_secret_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV generic_secret_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV generic_secret_validate_attribute(STDLL_TokData_t *tokdata, + TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode); +CK_RV generic_secret_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len); +CK_RV generic_secret_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG data_len, + CK_BBOOL fromend, CK_BBOOL isopaque); + +// RC2 routines +CK_RV rc2_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV rc2_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV rc2_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + +// RC4 routines +CK_RV rc4_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV rc4_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV rc4_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + +// RC5 routines +CK_RV rc5_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV rc5_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV rc5_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + +// DES routines +CK_RV des_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_BBOOL des_check_weak_key(CK_BYTE *key); +CK_RV des_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV des_unwrap(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_BYTE *data, + CK_ULONG data_len, CK_BBOOL fromend, CK_BBOOL isopaque); +CK_RV des_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); +CK_RV des_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, + CK_ULONG *data_len); + +// DES2 routines +CK_RV des2_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV des2_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV des2_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + +// DES3 routines +CK_RV des3_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV des3_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV des3_unwrap(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_BYTE *data, + CK_ULONG data_len, CK_BBOOL fromend, CK_BBOOL isopaque); +CK_RV des3_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); +CK_RV des3_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, + CK_ULONG *data_len); + +// AES routines +CK_RV aes_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV aes_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV aes_unwrap(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, CK_BYTE *data, + CK_ULONG data_len, CK_BBOOL fromend, CK_BBOOL isopaque); +CK_RV aes_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); +CK_RV aes_wrap_get_data(TEMPLATE *tmpl, CK_BBOOL length_only, CK_BYTE **data, + CK_ULONG *data_len); + +// CAST routines +CK_RV cast_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV cast_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV cast_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + +// CAST3 routines +CK_RV cast3_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV cast3_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV cast3_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + +// CAST5 routines +CK_RV cast5_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV cast5_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV cast5_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + +// IDEA routines +CK_RV idea_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV idea_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV idea_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + +// CDMF routines +CK_RV cdmf_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV cdmf_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV cdmf_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + +// SKIPJACK routines +CK_RV skipjack_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV skipjack_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV skipjack_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + +// BATON routines +CK_RV baton_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV baton_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV baton_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + +// JUNIPER routines +CK_RV juniper_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV juniper_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode); +CK_RV juniper_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode); + + +// modular math routines +// +CK_RV mp_subtract(CK_BYTE *bigint, CK_ULONG val, CK_ULONG len); + +CK_RV mp_mult(CK_BYTE *bigint_a, CK_ULONG a_len, + CK_BYTE *bigint_b, CK_ULONG b_len, + CK_BYTE *bigint_c, CK_ULONG c_len, + CK_BYTE *result, CK_ULONG *result_len); + +CK_RV mp_exp(CK_BYTE *bigint_a, CK_ULONG a_len, + CK_BYTE *bigint_b, CK_ULONG b_len, + CK_BYTE *bigint_c, CK_ULONG c_len, + CK_BYTE *result, CK_ULONG *result_len); + +// ASN.1 routines +// +CK_ULONG ber_encode_INTEGER(CK_BBOOL length_only, + CK_BYTE **ber_int, + CK_ULONG *ber_int_len, + CK_BYTE *data, CK_ULONG data_len); + +CK_RV ber_decode_INTEGER(CK_BYTE *ber_int, + CK_BYTE **data, + CK_ULONG *data_len, CK_ULONG *field_len); + +CK_RV ber_decode_BIT_STRING(CK_BYTE *str, + CK_BYTE **data, + CK_ULONG *data_len, CK_ULONG *field_len); + +CK_RV ber_encode_OCTET_STRING(CK_BBOOL length_only, + CK_BYTE **str, + CK_ULONG *str_len, + CK_BYTE *data, CK_ULONG data_len); + +CK_RV ber_decode_OCTET_STRING(CK_BYTE *str, + CK_BYTE **data, + CK_ULONG *data_len, CK_ULONG *field_len); + +CK_RV ber_encode_SEQUENCE(CK_BBOOL length_only, + CK_BYTE **seq, + CK_ULONG *seq_len, + CK_BYTE *data, CK_ULONG data_len); + +CK_RV ber_decode_SEQUENCE(CK_BYTE *seq, + CK_BYTE **data, + CK_ULONG *data_len, CK_ULONG *field_len); + +CK_RV ber_encode_PrivateKeyInfo(CK_BBOOL length_only, + CK_BYTE **data, + CK_ULONG *data_len, + const CK_BYTE *algorithm_id, + const CK_ULONG algorithm_id_len, + CK_BYTE *priv_key, CK_ULONG priv_key_len); + +CK_RV ber_decode_PrivateKeyInfo(CK_BYTE *data, + CK_ULONG data_len, + CK_BYTE **algorithm_id, + CK_ULONG *alg_len, CK_BYTE **priv_key); + +CK_RV ber_decode_SPKI(CK_BYTE *spki, CK_BYTE **alg_oid, CK_ULONG *alg_oid_len, + CK_BYTE **param, CK_ULONG *param_len, + CK_BYTE **key, CK_ULONG *key_len); + +CK_RV ber_encode_RSAPrivateKey(CK_BBOOL length_only, + CK_BYTE **data, + CK_ULONG *data_len, + CK_ATTRIBUTE *modulus, + CK_ATTRIBUTE *publ_exp, + CK_ATTRIBUTE *priv_exp, + CK_ATTRIBUTE *prime1, + CK_ATTRIBUTE *prime2, + CK_ATTRIBUTE *exponent1, + CK_ATTRIBUTE *exponent2, + CK_ATTRIBUTE *coeff, CK_ATTRIBUTE *opaque); + +CK_RV ber_decode_RSAPrivateKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **modulus, + CK_ATTRIBUTE **publ_exp, + CK_ATTRIBUTE **priv_exp, + CK_ATTRIBUTE **prime1, + CK_ATTRIBUTE **prime2, + CK_ATTRIBUTE **exponent1, + CK_ATTRIBUTE **exponent2, + CK_ATTRIBUTE **coeff, + CK_ATTRIBUTE **opaque, CK_BBOOL isopaque); + +CK_RV ber_encode_RSAPublicKey(CK_BBOOL length_only, CK_BYTE **data, + CK_ULONG *data_len, CK_ATTRIBUTE *modulus, + CK_ATTRIBUTE *publ_exp); + +CK_RV ber_decode_RSAPublicKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **modulus, + CK_ATTRIBUTE **publ_exp); + +CK_RV der_encode_ECPrivateKey(CK_BBOOL length_only, + CK_BYTE **data, + CK_ULONG *data_len, + CK_ATTRIBUTE *params, + CK_ATTRIBUTE *point, + CK_ATTRIBUTE *opaque, CK_ATTRIBUTE *pubkey); + +CK_RV der_decode_ECPrivateKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **params, + CK_ATTRIBUTE **pub_key, + CK_ATTRIBUTE **priv_key, + CK_ATTRIBUTE **opaque_key, CK_BBOOL isOpaque); + +CK_RV ber_encode_ECPublicKey(CK_BBOOL length_only, CK_BYTE **data, + CK_ULONG *data_len, CK_ATTRIBUTE *params, + CK_ATTRIBUTE *point); + +CK_RV der_decode_ECPublicKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **params, CK_ATTRIBUTE **point); + +CK_RV ber_encode_DSAPrivateKey(CK_BBOOL length_only, + CK_BYTE **data, + CK_ULONG *data_len, + CK_ATTRIBUTE *prime1, + CK_ATTRIBUTE *prime2, + CK_ATTRIBUTE *base, CK_ATTRIBUTE *priv_key); + +CK_RV ber_decode_DSAPrivateKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **prime, + CK_ATTRIBUTE **subprime, + CK_ATTRIBUTE **base, CK_ATTRIBUTE **priv_key); + +CK_RV ber_encode_DSAPublicKey(CK_BBOOL length_only, CK_BYTE **data, + CK_ULONG *data_len, CK_ATTRIBUTE *prime, + CK_ATTRIBUTE *subprime, CK_ATTRIBUTE *base, + CK_ATTRIBUTE *value); + +CK_RV ber_decode_DSAPublicKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **prime, + CK_ATTRIBUTE **subprime, + CK_ATTRIBUTE **base, + CK_ATTRIBUTE **value); + +CK_RV ber_encode_DHPrivateKey(CK_BBOOL length_only, + CK_BYTE **data, + CK_ULONG *data_len, + CK_ATTRIBUTE *prime, + CK_ATTRIBUTE *base, CK_ATTRIBUTE *priv_key); + +CK_RV ber_decode_DHPrivateKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **prime, + CK_ATTRIBUTE **base, CK_ATTRIBUTE **priv_key); + +CK_RV ber_encode_DHPublicKey(CK_BBOOL length_only, CK_BYTE **data, + CK_ULONG *data_len, CK_ATTRIBUTE *prime, + CK_ATTRIBUTE *base, CK_ATTRIBUTE *value); + +CK_RV ber_decode_DHPublicKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **prime, + CK_ATTRIBUTE **base, + CK_ATTRIBUTE **value); + +CK_RV ber_decode_ECDHPrivateKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **ecparam, + CK_ATTRIBUTE **pub_key, + CK_ATTRIBUTE **priv_key); + +CK_RV ber_encode_IBM_DilithiumPublicKey(CK_BBOOL length_only, CK_BYTE **data, + CK_ULONG *data_len, CK_ATTRIBUTE *rho, + CK_ATTRIBUTE *t1); + +CK_RV ber_decode_IBM_DilithiumPublicKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **rho_attr, + CK_ATTRIBUTE **t1_attr); + +CK_RV ber_encode_IBM_DilithiumPrivateKey(CK_BBOOL length_only, + CK_BYTE **data, + CK_ULONG *data_len, + CK_ATTRIBUTE *rho, + CK_ATTRIBUTE *seed, + CK_ATTRIBUTE *tr, + CK_ATTRIBUTE *s1, + CK_ATTRIBUTE *s2, + CK_ATTRIBUTE *t0, + CK_ATTRIBUTE *t1, + CK_ATTRIBUTE *opaque); + +CK_RV ber_decode_IBM_DilithiumPrivateKey(CK_BYTE *data, + CK_ULONG data_len, + CK_ATTRIBUTE **rho, + CK_ATTRIBUTE **seed, + CK_ATTRIBUTE **tr, + CK_ATTRIBUTE **s1, + CK_ATTRIBUTE **s2, + CK_ATTRIBUTE **t0, + CK_ATTRIBUTE **t1, + CK_ATTRIBUTE **opaque, + CK_BBOOL isopaque); + +#include "tok_spec_struct.h" +extern token_spec_t token_specific; + +CK_BBOOL is_secure_key_token(); + + +/* CKA_HIDDEN will be used to filter return results on a C_FindObjects call. + * Used for objects internal to a token for management of that token */ +#define CKA_HIDDEN CKA_VENDOR_DEFINED + 0x01000000 + +#endif diff --git a/usr/lib/common/host_defs.h b/usr/lib/common/host_defs.h new file mode 100644 index 0000000..19d6e55 --- /dev/null +++ b/usr/lib/common/host_defs.h @@ -0,0 +1,364 @@ +/* + * 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 + */ + +#include +#ifndef _HOST_DEFS_H +#define _HOST_DEFS_H + +#include +#include + +#include "pkcs32.h" +#include +#include + +#include "local_types.h" + +typedef struct _ENCR_DECR_CONTEXT { + CK_OBJECT_HANDLE key; + CK_MECHANISM mech; + CK_BYTE *context; + CK_ULONG context_len; + CK_BBOOL multi; + CK_BBOOL active; + CK_BBOOL init_pending; // indicate init request pending + CK_BBOOL multi_init; // multi field is initialized + // on first call *after* init +} ENCR_DECR_CONTEXT; + +typedef struct _DIGEST_CONTEXT { + CK_MECHANISM mech; + CK_BYTE *context; + CK_ULONG context_len; + CK_BBOOL multi; + CK_BBOOL active; + CK_BBOOL multi_init; // multi field is initialized + // on first call *after* init +} DIGEST_CONTEXT; + +typedef struct _SIGN_VERIFY_CONTEXT { + CK_OBJECT_HANDLE key; + CK_MECHANISM mech; // current sign mechanism + CK_BYTE *context; // temporary work area + CK_ULONG context_len; + CK_BBOOL multi; // is this a multi-part operation? + CK_BBOOL recover; // are we in recover mode? + CK_BBOOL active; + CK_BBOOL init_pending; // indicate init request pending + CK_BBOOL multi_init; // multi field is initialized + // on first call *after* init +} SIGN_VERIFY_CONTEXT; + + +typedef struct _SESSION { + struct bt_ref_hdr hdr; + CK_SESSION_HANDLE handle; + CK_SESSION_INFO session_info; + + CK_OBJECT_HANDLE *find_list; // array of CK_OBJECT_HANDLE + CK_ULONG_32 find_count; // # handles in the list + CK_ULONG_32 find_len; // max # of handles in the list + CK_ULONG_32 find_idx; // current position + CK_BBOOL find_active; + + ENCR_DECR_CONTEXT encr_ctx; + ENCR_DECR_CONTEXT decr_ctx; + DIGEST_CONTEXT digest_ctx; + SIGN_VERIFY_CONTEXT sign_ctx; + SIGN_VERIFY_CONTEXT verify_ctx; + + void *private_data; +} SESSION; + +/* TODO: + * Add compile-time checking that sizeof(void *) == sizeof(CK_SESSION_HANDLE) + * */ + + +typedef struct _DES_CONTEXT { + CK_BYTE data[DES_BLOCK_SIZE]; + CK_ULONG len; + CK_BBOOL cbc_pad; // is this a CKM_DES_CBC_PAD operation? +} DES_CONTEXT; + +typedef struct _DES_DATA_CONTEXT { + CK_BYTE data[DES_BLOCK_SIZE]; + CK_ULONG len; + CK_BYTE iv[DES_BLOCK_SIZE]; +} DES_DATA_CONTEXT; + +typedef struct _AES_CONTEXT { + CK_BYTE data[AES_BLOCK_SIZE]; + CK_ULONG len; + CK_BBOOL cbc_pad; +} AES_CONTEXT; + +typedef struct _AES_DATA_CONTEXT { + CK_BYTE data[AES_BLOCK_SIZE]; + CK_ULONG len; + CK_BYTE iv[AES_BLOCK_SIZE]; +} AES_DATA_CONTEXT; + +typedef struct _AES_GCM_CONTEXT { + /* Data buffer for DecryptUpdate needs space + * for tag data and remaining tail data */ + CK_BYTE data[2 * AES_BLOCK_SIZE]; + CK_ULONG len; + CK_BYTE icb[AES_BLOCK_SIZE]; + CK_BYTE ucb[AES_BLOCK_SIZE]; + CK_BYTE hash[AES_BLOCK_SIZE]; + CK_BYTE subkey[AES_BLOCK_SIZE]; + CK_ULONG ulAlen; + CK_ULONG ulClen; +} AES_GCM_CONTEXT; + +typedef struct _SHA1_CONTEXT { + unsigned int buf[16]; + unsigned int hash_value[5]; + unsigned int bits_hi, bits_lo; // # bits processed so far + +} SHA1_CONTEXT; + +typedef SHA1_CONTEXT SHA2_CONTEXT; + + +typedef struct _MD2_CONTEXT { + CK_BYTE state[16]; // state + CK_BYTE checksum[16]; // checksum + CK_ULONG count; // number of bytes, modulo 16 + CK_BYTE buffer[16]; // input buffer +} MD2_CONTEXT; + + +typedef struct _MD5_CONTEXT { + CK_ULONG i[2]; // number of _bits_ handled mod 2^64 + CK_ULONG buf[4]; // scratch buffer + CK_BYTE in[64]; // input buffer + CK_BYTE digest[16]; // actual digest after MD5Final call + +} MD5_CONTEXT; + +typedef struct _DES_CMAC_CONTEXT { + CK_BYTE data[DES_BLOCK_SIZE]; + CK_ULONG len; + CK_BYTE iv[DES_BLOCK_SIZE]; + CK_BBOOL initialized; + CK_VOID_PTR ctx; +} DES_CMAC_CONTEXT; + +typedef struct _AES_CMAC_CONTEXT { + CK_BYTE data[AES_BLOCK_SIZE]; + CK_ULONG len; + CK_BYTE iv[AES_BLOCK_SIZE]; + CK_BBOOL initialized; + CK_VOID_PTR ctx; +} AES_CMAC_CONTEXT; + +// linux +typedef pthread_mutex_t MUTEX; + +// This is actualy wrong... XPROC will be with spinlocks + +typedef struct _TEMPLATE { + DL_NODE *attribute_list; +} TEMPLATE; + + +typedef struct _OBJECT { + struct bt_ref_hdr hdr; + CK_OBJECT_CLASS class; + CK_BYTE name[8]; // for token objects + + SESSION *session; // creator; only for session objects + TEMPLATE *template; + pthread_rwlock_t template_rwlock; // Lock for object's template + CK_ULONG count_hi; // only significant for token objects + CK_ULONG count_lo; // only significant for token objects + CK_ULONG index; // SAB Index into the SHM + CK_OBJECT_HANDLE map_handle; +} OBJECT; + + +typedef struct _OBJECT_MAP { + struct bt_ref_hdr hdr; + CK_OBJECT_HANDLE obj_handle; + CK_BBOOL is_private; + CK_BBOOL is_session_obj; + SESSION *session; +} OBJECT_MAP; + +/* FIXME: Compile-time check that sizeof(void *) == sizeof(CK_OBJECT_HANDLE) */ + + +typedef struct _ATTRIBUTE_PARSE_LIST { + CK_ATTRIBUTE_TYPE type; + void *ptr; + CK_ULONG len; + CK_BBOOL found; +} ATTRIBUTE_PARSE_LIST; + + +typedef struct _OP_STATE_DATA { + CK_STATE session_state; + CK_ULONG active_operation; + CK_ULONG data_len; + // state data gets appended here + // + + // mechanism parameter gets appended here + // +} OP_STATE_DATA; + + +// this is our internal "tweak" vector (not the FCV) used to tweak various +// aspects of the PKCS #11 implementation. Some of these tweaks deviate from +// the PKCS #11 specification but are needed to support Netscape. Others +// are left as token-defined values by PKCS #11. +// +// - whether or not to allow weak/semi-weak DES keys to be imported +// - whether to insist imported DES keys have proper parity +// - whether the CKA_ENCRYPT/DECRYPT/SIGN/VERIFY attributes are modifiable +// after key creation +// +typedef struct _TWEAK_VEC { + int allow_weak_des; + int check_des_parity; + int allow_key_mods; + int netscape_mods; +} TWEAK_VEC; + +typedef struct _TOKEN_DATA_VERSION { + uint32_t version; /* major<<16|minor */ + /* --- PBKDF2 --- */ + /* SO login */ + uint64_t so_login_it; + unsigned char so_login_salt[64]; + unsigned char so_login_key[32]; + /* User login */ + uint64_t user_login_it; + unsigned char user_login_salt[64]; + unsigned char user_login_key[32]; + /* SO MK wrap */ + uint64_t so_wrap_it; + unsigned char so_wrap_salt[64]; + /* User MK wrap */ + uint64_t user_wrap_it; + unsigned char user_wrap_salt[64]; +} TOKEN_DATA_VERSION; + +typedef struct _TOKEN_DATA { + CK_TOKEN_INFO_32 token_info; + + CK_BYTE user_pin_sha[3 * DES_BLOCK_SIZE]; + CK_BYTE so_pin_sha[3 * DES_BLOCK_SIZE]; + CK_BYTE next_token_object_name[8]; + TWEAK_VEC tweak_vector; + + /* new for tokversion >= 3.12 */ + TOKEN_DATA_VERSION dat; +} TOKEN_DATA; + +typedef struct _TOKEN_DATA_OLD { + CK_TOKEN_INFO_32 token_info; + + CK_BYTE user_pin_sha[3 * DES_BLOCK_SIZE]; + CK_BYTE so_pin_sha[3 * DES_BLOCK_SIZE]; + CK_BYTE next_token_object_name[8]; + TWEAK_VEC tweak_vector; +} TOKEN_DATA_OLD; + +typedef struct _SSL3_MAC_CONTEXT { + DIGEST_CONTEXT hash_context; + CK_BBOOL flag; +} SSL3_MAC_CONTEXT; + + +typedef struct _RSA_DIGEST_CONTEXT { + DIGEST_CONTEXT hash_context; + CK_BBOOL flag; +} RSA_DIGEST_CONTEXT; + + +typedef struct _MECH_LIST_ELEMENT { + CK_MECHANISM_TYPE mech_type; + CK_MECHANISM_INFO mech_info; +} MECH_LIST_ELEMENT; + +struct mech_list_item; + +struct mech_list_item { + struct mech_list_item *next; + MECH_LIST_ELEMENT element; +}; + +struct mech_list_item *find_mech_list_item_for_type(CK_MECHANISM_TYPE type, + struct mech_list_item + *head); + +/* mech_list.c */ +CK_RV ock_generic_get_mechanism_list(STDLL_TokData_t * tokdata, + CK_MECHANISM_TYPE_PTR pMechanismList, + CK_ULONG_PTR pulCount); + +/* mech_list.c */ +CK_RV ock_generic_get_mechanism_info(STDLL_TokData_t * tokdata, + CK_MECHANISM_TYPE type, + CK_MECHANISM_INFO_PTR pInfo); + +typedef struct _TOK_OBJ_ENTRY { + CK_BBOOL deleted; + char name[8]; + CK_ULONG_32 count_lo; + CK_ULONG_32 count_hi; +} TOK_OBJ_ENTRY; + +struct _LW_SHM_TYPE { + TOKEN_DATA nv_token_data; + CK_ULONG_32 num_priv_tok_obj; + CK_ULONG_32 num_publ_tok_obj; + CK_BBOOL priv_loaded; + CK_BBOOL publ_loaded; + TOK_OBJ_ENTRY publ_tok_objs[MAX_TOK_OBJS]; + TOK_OBJ_ENTRY priv_tok_objs[MAX_TOK_OBJS]; +}; + +struct _STDLL_TokData_t { + CK_SLOT_INFO slot_info; + int spinxplfd; // token specific lock + unsigned int spinxplfd_count; // counter for recursive file lock + pthread_mutex_t spinxplfd_mutex; // token specific pthread lock + char *pk_dir; + char data_store[256]; // path information of the token directory + CK_BYTE user_pin_md5[MD5_HASH_SIZE]; + CK_BYTE so_pin_md5[MD5_HASH_SIZE]; + CK_BYTE master_key[MAX_KEY_SIZE]; + CK_BBOOL initialized; + CK_ULONG ro_session_count; + CK_STATE global_login_state; + LW_SHM_TYPE *global_shm; + TOKEN_DATA *nv_token_data; + void *private_data; + uint32_t version; /* major<<16|minor */ + unsigned char so_wrap_key[32]; + 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; + struct btree priv_token_obj_btree; + MECH_LIST_ELEMENT *mech_list; + CK_ULONG mech_list_len; +}; + +#endif diff --git a/usr/lib/common/hwf_obj.c b/usr/lib/common/hwf_obj.c new file mode 100644 index 0000000..176a39d --- /dev/null +++ b/usr/lib/common/hwf_obj.c @@ -0,0 +1,251 @@ +/* + * 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: hwf_obj.c +// +// Hardware Feature Object functions + +#include +#include + +#include // for memcmp() et al + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "trace.h" + +#include "tok_spec_struct.h" + + +// hwf_object_check_required_attributes() +// +// Check required common attributes for hardware feature objects +// +CK_RV hwf_object_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_HW_FEATURE_TYPE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return template_check_required_base_attributes(tmpl, mode); +} + +CK_RV clock_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + if (mode == MODE_CREATE) { + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return hwf_object_check_required_attributes(tmpl, mode); +} + +CK_RV counter_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + if (mode == MODE_CREATE) { + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + found = template_attribute_find(tmpl, CKA_HAS_RESET, &attr); + if (!found) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + found = template_attribute_find(tmpl, CKA_RESET_ON_INIT, &attr); + if (!found) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return hwf_object_check_required_attributes(tmpl, mode); +} + + +// hwf_object_set_default_attributes() +// +CK_RV hwf_object_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ +#if 0 + CK_ATTRIBUTE *local_attr = NULL; + + local_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + + if (!local_attr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + local_attr->type = CKA_LOCAL; + local_attr->ulValueLen = sizeof(CK_BBOOL); + local_attr->pValue = (CK_BYTE *) local_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) local_attr->pValue = FALSE; + + template_update_attribute(tmpl, local_attr); +#endif + UNUSED(tmpl); + UNUSED(mode); + + return CKR_OK; +} + + +// hwf_object_validate_attribute() +// +CK_RV hwf_validate_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode) +{ + switch (attr->type) { + case CKA_HW_FEATURE_TYPE: + if (mode == MODE_CREATE) + return CKR_OK; + + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + default: + return template_validate_base_attribute(tmpl, attr, mode); + } + + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID)); + return CKR_ATTRIBUTE_TYPE_INVALID; +} + +// +// +CK_RV clock_validate_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode) +{ + UNUSED(mode); + + switch (attr->type) { + case CKA_VALUE: + return CKR_OK; + default: + return hwf_validate_attribute(tmpl, attr, mode); + } +} + +// +// +CK_RV counter_validate_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode) +{ + switch (attr->type) { + case CKA_VALUE: + /* Fall Through */ + case CKA_HAS_RESET: + /* Fall Through */ + case CKA_RESET_ON_INIT: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + default: + return hwf_validate_attribute(tmpl, attr, mode); + } +} + + +CK_RV clock_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_RV rc; + CK_ATTRIBUTE *value_attr; + + rc = hwf_object_set_default_attributes(tmpl, mode); + if (rc != CKR_OK) + return rc; + + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + + if (!value_attr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + template_update_attribute(tmpl, value_attr); + + return CKR_OK; +} + +CK_RV counter_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_RV rc; + CK_ATTRIBUTE *value_attr; + CK_ATTRIBUTE *hasreset_attr; + CK_ATTRIBUTE *resetoninit_attr; + + rc = hwf_object_set_default_attributes(tmpl, mode); + if (rc != CKR_OK) + return rc; + + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + hasreset_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + resetoninit_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + + if (!value_attr || !hasreset_attr || !resetoninit_attr) { + if (value_attr) + free(value_attr); + if (hasreset_attr) + free(hasreset_attr); + if (resetoninit_attr) + free(resetoninit_attr); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + hasreset_attr->type = CKA_HAS_RESET; + hasreset_attr->ulValueLen = sizeof(CK_BBOOL); + hasreset_attr->pValue = (CK_BYTE *) hasreset_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) hasreset_attr->pValue = FALSE; + + /* Hmm... Not sure if we should be setting this here. */ + resetoninit_attr->type = CKA_RESET_ON_INIT; + resetoninit_attr->ulValueLen = sizeof(CK_BBOOL); + resetoninit_attr->pValue = + (CK_BYTE *) resetoninit_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) resetoninit_attr->pValue = FALSE; + + template_update_attribute(tmpl, value_attr); + template_update_attribute(tmpl, hasreset_attr); + template_update_attribute(tmpl, resetoninit_attr); + + return CKR_OK; +} diff --git a/usr/lib/common/key.c b/usr/lib/common/key.c new file mode 100644 index 0000000..36da163 --- /dev/null +++ b/usr/lib/common/key.c @@ -0,0 +1,6044 @@ +/* + * 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: key.c +// +// Functions contained within: +// +// key_object_check_required_attributes +// key_object_set_default_attributes +// key_object_validate_attribute +// +// publ_key_check_required_attributes +// publ_key_set_default_attributes +// publ_key_validate_attribute +// +// priv_key_check_required_attributes +// priv_key_set_default_attributes +// priv_key_validate_attribute +// +// secret_key_check_required_attributes +// secret_key_set_default_attributes +// secret_key_validate_attribute +// +// rsa_publ_check_required_attributes +// rsa_publ_validate_attribute +// rsa_priv_check_required_attributes +// rsa_priv_validate_attribute +// rsa_priv_check_exportability +// +// dsa_publ_check_required_attributes +// dsa_publ_validate_attribute +// dsa_priv_check_required_attributes +// dsa_priv_validate_attribute +// dsa_priv_check_exportability +// +// ecdsa_publ_check_required_attributes +// ecdsa_publ_validate_attribute +// ecdsa_priv_checK_required_attributes +// ecdsa_priv_validate_attribute +// ecdsa_priv_check_exportability +// +// dh_publ_check_required_attributes +// dh_publ_validate_attribute +// dh_priv_check_required_attributes +// dh_priv_validate_attribute +// dh_priv_check_exportability +// +// kea_publ_check_required_attributes +// kea_publ_validate_attribute +// kea_priv_check_required_attributes +// kea_priv_validate_attribute +// kea_priv_check_exportability +// +// generic_secret_check_required_attributes +// generic_secret_validate_attribute +// generic_secret_set_default_attributes +// +// rc2_check_required_attributes +// rc2_validate_attribute +// rc2_priv_check_exportability +// +// rc4_check_required_attributes +// rc4_validate_attribute +// rc4_priv_check_exportability +// +// rc5_check_required_attributes +// rc5_validate_attribute +// rc5_priv_check_exportability +// +// des_check_required_attributes +// des_validate_attribute +// des_priv_check_exportability +// +// des2_check_required_attributes +// des2_validate_attribute +// des2_priv_check_exportability +// +// des3_check_required_attributes +// des3_validate_attribute +// des3_priv_check_exportability +// +// cast_check_required_attributes +// cast_validate_attribute +// cast_priv_check_exportability +// +// cast3_check_required_attributes +// cast3_validate_attribute +// cast3_priv_check_exportability +// +// cast5_check_required_attributes +// cast5_validate_attribute +// cast5_priv_check_exportability +// +// idea_check_required_attributes +// idea_validate_attribute +// idea_priv_check_exportability +// +// cdmf_check_required_attributes +// cdmf_validate_attribute +// cdmf_priv_check_exportability +// +// skipjack_check_required_attributes +// skipjack_validate_attribute +// skipjack_priv_check_exportability +// +// baton_check_required_attributes +// baton_validate_attribute +// baton_priv_check_exportability +// +// juniper_check_required_attributes +// juniper_validate_attribute +// juniper_priv_check_exportability +// + +#include +#include + +#include // for memcmp() et al + +#include "pkcs11types.h" +#include "p11util.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "trace.h" + +#include "tok_spec_struct.h" + + +// key_object_check_required_attributes() +// +// Check required common attributes for key objects +// +CK_RV key_object_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_KEY_TYPE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return template_check_required_base_attributes(tmpl, mode); +} + + +// key_object_set_default_attributes() +// +CK_RV key_object_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *id_attr = NULL; + CK_ATTRIBUTE *sdate_attr = NULL; + CK_ATTRIBUTE *edate_attr = NULL; + CK_ATTRIBUTE *derive_attr = NULL; + CK_ATTRIBUTE *local_attr = NULL; + CK_ATTRIBUTE *keygenmech_attr = NULL; + + // satisfy the compiler + // + if (mode) + id_attr = NULL; + + id_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + sdate_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + edate_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + derive_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + local_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + keygenmech_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + + sizeof(CK_MECHANISM_TYPE)); + + if (!id_attr || !sdate_attr || !edate_attr || !derive_attr || !local_attr + || !keygenmech_attr) { + if (id_attr) + free(id_attr); + if (sdate_attr) + free(sdate_attr); + if (edate_attr) + free(edate_attr); + if (derive_attr) + free(derive_attr); + if (local_attr) + free(local_attr); + if (keygenmech_attr) + free(keygenmech_attr); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + id_attr->type = CKA_ID; + id_attr->ulValueLen = 0; + id_attr->pValue = NULL; + + sdate_attr->type = CKA_START_DATE; + sdate_attr->ulValueLen = 0; + sdate_attr->pValue = NULL; + + edate_attr->type = CKA_END_DATE; + edate_attr->ulValueLen = 0; + edate_attr->pValue = NULL; + + derive_attr->type = CKA_DERIVE; + derive_attr->ulValueLen = sizeof(CK_BBOOL); + derive_attr->pValue = (CK_BYTE *) derive_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) derive_attr->pValue = FALSE; + + local_attr->type = CKA_LOCAL; + local_attr->ulValueLen = sizeof(CK_BBOOL); + local_attr->pValue = (CK_BYTE *) local_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) local_attr->pValue = FALSE; + + keygenmech_attr->type = CKA_KEY_GEN_MECHANISM; + keygenmech_attr->ulValueLen = sizeof(CK_MECHANISM_TYPE); + keygenmech_attr->pValue = (CK_BYTE *) keygenmech_attr + sizeof(CK_ATTRIBUTE); + *(CK_MECHANISM_TYPE *) keygenmech_attr->pValue = CK_UNAVAILABLE_INFORMATION; + + template_update_attribute(tmpl, id_attr); + template_update_attribute(tmpl, sdate_attr); + template_update_attribute(tmpl, edate_attr); + template_update_attribute(tmpl, derive_attr); + template_update_attribute(tmpl, local_attr); + template_update_attribute(tmpl, keygenmech_attr); + return CKR_OK; +} + + +// key_object_validate_attribute() +// +CK_RV key_object_validate_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode) +{ + switch (attr->type) { + case CKA_KEY_TYPE: + if (mode == MODE_CREATE || mode == MODE_DERIVE || + mode == MODE_KEYGEN || mode == MODE_UNWRAP) + return CKR_OK; + + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + case CKA_ID: + case CKA_START_DATE: + case CKA_END_DATE: + case CKA_DERIVE: + return CKR_OK; + case CKA_LOCAL: + // CKA_LOCAL is only set by the key-generate routine + // + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + default: + return template_validate_base_attribute(tmpl, attr, mode); + } + + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID)); + + return CKR_ATTRIBUTE_TYPE_INVALID; +} + + +// publ_key_check_required_attributes() +// +CK_RV publ_key_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + // CKO_PUBLIC_KEY has no required attributes + // + return key_object_check_required_attributes(tmpl, mode); +} + + +// publ_key_set_default_attributes() +// +// some of the common public key attributes have defaults but none of the +// specific public keytypes have default attributes +// +CK_RV publ_key_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *class_attr = NULL; + CK_ATTRIBUTE *subject_attr = NULL; + CK_ATTRIBUTE *encrypt_attr = NULL; + CK_ATTRIBUTE *verify_attr = NULL; + CK_ATTRIBUTE *verify_recover_attr = NULL; + CK_ATTRIBUTE *wrap_attr = NULL; + + CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; + CK_RV rc; + + + rc = key_object_set_default_attributes(tmpl, mode); + if (rc != CKR_OK) { + TRACE_DEVEL("key_object_set_default_attributes failed\n"); + return rc; + } + // add the default CKO_PUBLIC_KEY attributes + // + class_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_OBJECT_CLASS)); + subject_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + encrypt_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + verify_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + verify_recover_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + wrap_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + + if (!class || !subject_attr || !encrypt_attr || + !verify_attr || !verify_recover_attr || !wrap_attr) { + if (class_attr) + free(class_attr); + if (subject_attr) + free(subject_attr); + if (encrypt_attr) + free(encrypt_attr); + if (verify_attr) + free(verify_attr); + if (verify_recover_attr) + free(verify_recover_attr); + if (wrap_attr) + free(wrap_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + class_attr->type = CKA_CLASS; + class_attr->ulValueLen = sizeof(CK_OBJECT_CLASS); + class_attr->pValue = (CK_BYTE *) class_attr + sizeof(CK_ATTRIBUTE); + *(CK_OBJECT_CLASS *) class_attr->pValue = CKO_PUBLIC_KEY; + + subject_attr->type = CKA_SUBJECT; + subject_attr->ulValueLen = 0; // empty string + subject_attr->pValue = NULL; + + encrypt_attr->type = CKA_ENCRYPT; + encrypt_attr->ulValueLen = sizeof(CK_BBOOL); + encrypt_attr->pValue = (CK_BYTE *) encrypt_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) encrypt_attr->pValue = TRUE; + + verify_attr->type = CKA_VERIFY; + verify_attr->ulValueLen = sizeof(CK_BBOOL); + verify_attr->pValue = (CK_BYTE *) verify_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) verify_attr->pValue = TRUE; + + verify_recover_attr->type = CKA_VERIFY_RECOVER; + verify_recover_attr->ulValueLen = sizeof(CK_BBOOL); + verify_recover_attr->pValue = + (CK_BYTE *) verify_recover_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) verify_recover_attr->pValue = TRUE; + + wrap_attr->type = CKA_WRAP; + wrap_attr->ulValueLen = sizeof(CK_BBOOL); + wrap_attr->pValue = (CK_BYTE *) wrap_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) wrap_attr->pValue = TRUE; + + template_update_attribute(tmpl, class_attr); + template_update_attribute(tmpl, subject_attr); + template_update_attribute(tmpl, encrypt_attr); + template_update_attribute(tmpl, verify_attr); + template_update_attribute(tmpl, verify_recover_attr); + template_update_attribute(tmpl, wrap_attr); + + return CKR_OK; +} + + +// publ_key_validate_attribute +// +CK_RV publ_key_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_SUBJECT: + return CKR_OK; + case CKA_ENCRYPT: + case CKA_VERIFY: + case CKA_VERIFY_RECOVER: + case CKA_WRAP: + if (mode == MODE_MODIFY) { + if (tokdata->nv_token_data->tweak_vector.allow_key_mods == TRUE) + return CKR_OK; + + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + return CKR_OK; + default: + return key_object_validate_attribute(tmpl, attr, mode); + } + + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID)); + + return CKR_ATTRIBUTE_TYPE_INVALID; +} + + +// priv_key_check_required_attributes() +// +CK_RV priv_key_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + // CKO_PRIVATE_KEY has no required attributes + // + return key_object_check_required_attributes(tmpl, mode); +} + + +// priv_key_set_default_attributes() +// +// some of the common private key attributes have defaults but none of the +// specific private keytypes have default attributes +// +CK_RV priv_key_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *class_attr = NULL; + CK_ATTRIBUTE *subject_attr = NULL; + CK_ATTRIBUTE *sensitive_attr = NULL; + CK_ATTRIBUTE *decrypt_attr = NULL; + CK_ATTRIBUTE *sign_attr = NULL; + CK_ATTRIBUTE *sign_recover_attr = NULL; + CK_ATTRIBUTE *unwrap_attr = NULL; + CK_ATTRIBUTE *extractable_attr = NULL; + CK_ATTRIBUTE *never_extr_attr = NULL; + CK_ATTRIBUTE *always_sens_attr = NULL; + CK_ATTRIBUTE *always_auth_attr = NULL; + CK_RV rc; + + + rc = key_object_set_default_attributes(tmpl, mode); + if (rc != CKR_OK) { + TRACE_DEVEL("key_object_set_default_attributes failed\n"); + return rc; + } + // add the default CKO_PUBLIC_KEY attributes + // + class_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_OBJECT_CLASS)); + subject_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + sensitive_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + decrypt_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + sign_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + sign_recover_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + unwrap_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + extractable_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + never_extr_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + always_sens_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + always_auth_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + + if (!class_attr || !subject_attr || !sensitive_attr || !decrypt_attr || + !sign_attr || !sign_recover_attr || !unwrap_attr || !extractable_attr || + !never_extr_attr || !always_sens_attr || !always_auth_attr) { + if (class_attr) + free(class_attr); + if (subject_attr) + free(subject_attr); + if (sensitive_attr) + free(sensitive_attr); + if (decrypt_attr) + free(decrypt_attr); + if (sign_attr) + free(sign_attr); + if (sign_recover_attr) + free(sign_recover_attr); + if (unwrap_attr) + free(unwrap_attr); + if (extractable_attr) + free(extractable_attr); + if (always_sens_attr) + free(always_sens_attr); + if (never_extr_attr) + free(never_extr_attr); + if (always_auth_attr) + free(always_auth_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + class_attr->type = CKA_CLASS; + class_attr->ulValueLen = sizeof(CK_OBJECT_CLASS); + class_attr->pValue = (CK_BYTE *) class_attr + sizeof(CK_ATTRIBUTE); + *(CK_OBJECT_CLASS *) class_attr->pValue = CKO_PRIVATE_KEY; + + subject_attr->type = CKA_SUBJECT; + subject_attr->ulValueLen = 0; // empty string + subject_attr->pValue = NULL; + + sensitive_attr->type = CKA_SENSITIVE; + sensitive_attr->ulValueLen = sizeof(CK_BBOOL); + sensitive_attr->pValue = (CK_BYTE *) sensitive_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) sensitive_attr->pValue = FALSE; + + decrypt_attr->type = CKA_DECRYPT; + decrypt_attr->ulValueLen = sizeof(CK_BBOOL); + decrypt_attr->pValue = (CK_BYTE *) decrypt_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) decrypt_attr->pValue = TRUE; + + sign_attr->type = CKA_SIGN; + sign_attr->ulValueLen = sizeof(CK_BBOOL); + sign_attr->pValue = (CK_BYTE *) sign_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) sign_attr->pValue = TRUE; + + sign_recover_attr->type = CKA_SIGN_RECOVER; + sign_recover_attr->ulValueLen = sizeof(CK_BBOOL); + sign_recover_attr->pValue = + (CK_BYTE *) sign_recover_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) sign_recover_attr->pValue = TRUE; + + unwrap_attr->type = CKA_UNWRAP; + unwrap_attr->ulValueLen = sizeof(CK_BBOOL); + unwrap_attr->pValue = (CK_BYTE *) unwrap_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) unwrap_attr->pValue = TRUE; + + extractable_attr->type = CKA_EXTRACTABLE; + extractable_attr->ulValueLen = sizeof(CK_BBOOL); + extractable_attr->pValue = + (CK_BYTE *) extractable_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) extractable_attr->pValue = TRUE; + + // by default, we'll set NEVER_EXTRACTABLE == FALSE and + // ALWAYS_SENSITIVE == FALSE + // If the key is being created with KEYGEN, it will adjust as necessary. + // + never_extr_attr->type = CKA_NEVER_EXTRACTABLE; + never_extr_attr->ulValueLen = sizeof(CK_BBOOL); + never_extr_attr->pValue = + (CK_BYTE *) never_extr_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) never_extr_attr->pValue = FALSE; + + always_sens_attr->type = CKA_ALWAYS_SENSITIVE; + always_sens_attr->ulValueLen = sizeof(CK_BBOOL); + always_sens_attr->pValue = + (CK_BYTE *) always_sens_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) always_sens_attr->pValue = FALSE; + + always_auth_attr->type = CKA_ALWAYS_AUTHENTICATE; + always_auth_attr->ulValueLen = sizeof(CK_BBOOL); + always_auth_attr->pValue = + (CK_BYTE *) always_auth_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) always_auth_attr->pValue = FALSE; + + template_update_attribute(tmpl, class_attr); + template_update_attribute(tmpl, subject_attr); + template_update_attribute(tmpl, sensitive_attr); + template_update_attribute(tmpl, decrypt_attr); + template_update_attribute(tmpl, sign_attr); + template_update_attribute(tmpl, sign_recover_attr); + template_update_attribute(tmpl, unwrap_attr); + template_update_attribute(tmpl, extractable_attr); + template_update_attribute(tmpl, never_extr_attr); + template_update_attribute(tmpl, always_sens_attr); + template_update_attribute(tmpl, always_auth_attr); + + return CKR_OK; +} + + +// +// +CK_RV priv_key_unwrap(TEMPLATE *tmpl, + CK_ULONG keytype, + CK_BYTE *data, CK_ULONG data_len, CK_BBOOL isopaque) +{ + CK_ATTRIBUTE *extractable = NULL; + CK_ATTRIBUTE *always_sens = NULL; + CK_ATTRIBUTE *never_extract = NULL; + CK_ATTRIBUTE *sensitive = NULL; + CK_ATTRIBUTE *local = NULL; + CK_BBOOL true = TRUE; + CK_BBOOL false = FALSE; + CK_RV rc; + + switch (keytype) { + case CKK_RSA: + rc = rsa_priv_unwrap(tmpl, data, data_len, isopaque); + break; + case CKK_DSA: + rc = dsa_priv_unwrap(tmpl, data, data_len); + break; + case CKK_DH: + rc = dh_priv_unwrap(tmpl, data, data_len); + break; + case CKK_EC: + rc = ec_priv_unwrap(tmpl, data, data_len, isopaque); + break; + case CKK_IBM_PQC_DILITHIUM: + rc = ibm_dilithium_priv_unwrap(tmpl, data, data_len, isopaque); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_WRAPPED_KEY_INVALID)); + return CKR_WRAPPED_KEY_INVALID; + } + + if (rc != CKR_OK) { + TRACE_DEVEL("priv unwrap failed\n"); + return rc; + } + // make sure + // CKA_LOCAL == FALSE + // CKA_ALWAYS_SENSITIVE == FALSE + // CKA_EXTRACTABLE == TRUE + // CKA_NEVER_EXTRACTABLE == FALSE + // + rc = build_attribute(CKA_LOCAL, &false, 1, &local); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + + rc = build_attribute(CKA_ALWAYS_SENSITIVE, &false, 1, &always_sens); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + + rc = build_attribute(CKA_SENSITIVE, &false, 1, &sensitive); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + + rc = build_attribute(CKA_EXTRACTABLE, &true, 1, &extractable); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + + rc = build_attribute(CKA_NEVER_EXTRACTABLE, &false, 1, &never_extract); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + + template_update_attribute(tmpl, local); + template_update_attribute(tmpl, always_sens); + template_update_attribute(tmpl, sensitive); + template_update_attribute(tmpl, extractable); + template_update_attribute(tmpl, never_extract); + + return CKR_OK; + +cleanup: + if (local) + free(local); + if (always_sens) + free(always_sens); + if (extractable) + free(extractable); + if (never_extract) + free(never_extract); + + return rc; +} + + +// priv_key_validate_attribute() +// +CK_RV priv_key_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_SUBJECT: + return CKR_OK; + case CKA_DECRYPT: + case CKA_SIGN: + case CKA_SIGN_RECOVER: + case CKA_UNWRAP: + // we might want to do this for MODE_COPY too + // + if (mode == MODE_MODIFY) { + if (tokdata->nv_token_data->tweak_vector.allow_key_mods == TRUE) + return CKR_OK; + + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + return CKR_OK; + // after key creation, CKA_SENSITIVE may only be set to TRUE + // + case CKA_SENSITIVE: + { + CK_BBOOL value; + + if (mode == MODE_CREATE || mode == MODE_KEYGEN) + return CKR_OK; + + value = *(CK_BBOOL *) attr->pValue; + if (value != TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + return CKR_OK; + } + // after key creation, CKA_EXTRACTABLE may only be set to FALSE + // + case CKA_EXTRACTABLE: + { + CK_BBOOL value; + + value = *(CK_BBOOL *) attr->pValue; + if ((mode != MODE_CREATE && mode != MODE_KEYGEN) && + value != FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + if (value == FALSE) { + CK_ATTRIBUTE *attr; + + attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + + sizeof(CK_BBOOL)); + if (!attr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + attr->type = CKA_NEVER_EXTRACTABLE; + attr->ulValueLen = sizeof(CK_BBOOL); + attr->pValue = (CK_BYTE *) attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) attr->pValue = FALSE; + + template_update_attribute(tmpl, attr); + } + return CKR_OK; + } + case CKA_ALWAYS_SENSITIVE: + case CKA_NEVER_EXTRACTABLE: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + default: + return key_object_validate_attribute(tmpl, attr, mode); + } + + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID)); + + return CKR_ATTRIBUTE_TYPE_INVALID; +} + + + + +// secret_key_check_required_attributes() +// +CK_RV secret_key_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + return key_object_check_required_attributes(tmpl, mode); +} + + +// secret_key_set_default_attributes() +// +// some of the common secret key attributes have defaults but none of the +// specific secret keytypes have default attributes +// +CK_RV secret_key_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *class_attr = NULL; + CK_ATTRIBUTE *sensitive_attr = NULL; + CK_ATTRIBUTE *encrypt_attr = NULL; + CK_ATTRIBUTE *decrypt_attr = NULL; + CK_ATTRIBUTE *sign_attr = NULL; + CK_ATTRIBUTE *verify_attr = NULL; + CK_ATTRIBUTE *wrap_attr = NULL; + CK_ATTRIBUTE *unwrap_attr = NULL; + CK_ATTRIBUTE *extractable_attr = NULL; + CK_ATTRIBUTE *never_extr_attr = NULL; + CK_ATTRIBUTE *always_sens_attr = NULL; + CK_RV rc; + + + rc = key_object_set_default_attributes(tmpl, mode); + if (rc != CKR_OK) + return rc; + + // add the default CKO_DATA attributes + // + class_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_OBJECT_CLASS)); + sensitive_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + encrypt_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + decrypt_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + sign_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + verify_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + wrap_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + unwrap_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + extractable_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + never_extr_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + always_sens_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + + if (!class_attr || !sensitive_attr || !encrypt_attr || !decrypt_attr || + !sign_attr || !verify_attr || !wrap_attr || + !unwrap_attr || !extractable_attr || !never_extr_attr + || !always_sens_attr) { + if (class_attr) + free(class_attr); + if (sensitive_attr) + free(sensitive_attr); + if (encrypt_attr) + free(encrypt_attr); + if (decrypt_attr) + free(decrypt_attr); + if (sign_attr) + free(sign_attr); + if (verify_attr) + free(verify_attr); + if (wrap_attr) + free(wrap_attr); + if (unwrap_attr) + free(unwrap_attr); + if (extractable_attr) + free(extractable_attr); + if (never_extr_attr) + free(never_extr_attr); + if (always_sens_attr) + free(always_sens_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + class_attr->type = CKA_CLASS; + class_attr->ulValueLen = sizeof(CK_OBJECT_CLASS); + class_attr->pValue = (CK_BYTE *) class_attr + sizeof(CK_ATTRIBUTE); + *(CK_OBJECT_CLASS *) class_attr->pValue = CKO_SECRET_KEY; + + sensitive_attr->type = CKA_SENSITIVE; + sensitive_attr->ulValueLen = sizeof(CK_BBOOL); + sensitive_attr->pValue = (CK_BYTE *) sensitive_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) sensitive_attr->pValue = FALSE; + + encrypt_attr->type = CKA_ENCRYPT; + encrypt_attr->ulValueLen = sizeof(CK_BBOOL); + encrypt_attr->pValue = (CK_BYTE *) encrypt_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) encrypt_attr->pValue = TRUE; + + decrypt_attr->type = CKA_DECRYPT; + decrypt_attr->ulValueLen = sizeof(CK_BBOOL); + decrypt_attr->pValue = (CK_BYTE *) decrypt_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) decrypt_attr->pValue = TRUE; + + sign_attr->type = CKA_SIGN; + sign_attr->ulValueLen = sizeof(CK_BBOOL); + sign_attr->pValue = (CK_BYTE *) sign_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) sign_attr->pValue = TRUE; + + verify_attr->type = CKA_VERIFY; + verify_attr->ulValueLen = sizeof(CK_BBOOL); + verify_attr->pValue = (CK_BYTE *) verify_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) verify_attr->pValue = TRUE; + + wrap_attr->type = CKA_WRAP; + wrap_attr->ulValueLen = sizeof(CK_BBOOL); + wrap_attr->pValue = (CK_BYTE *) wrap_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) wrap_attr->pValue = TRUE; + + unwrap_attr->type = CKA_UNWRAP; + unwrap_attr->ulValueLen = sizeof(CK_BBOOL); + unwrap_attr->pValue = (CK_BYTE *) unwrap_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) unwrap_attr->pValue = TRUE; + + extractable_attr->type = CKA_EXTRACTABLE; + extractable_attr->ulValueLen = sizeof(CK_BBOOL); + extractable_attr->pValue = + (CK_BYTE *) extractable_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) extractable_attr->pValue = TRUE; + + // by default, we'll set NEVER_EXTRACTABLE == FALSE and + // ALWAYS_SENSITIVE == FALSE + // If the key is being created with KEYGEN, it will adjust as necessary. + // + always_sens_attr->type = CKA_ALWAYS_SENSITIVE; + always_sens_attr->ulValueLen = sizeof(CK_BBOOL); + always_sens_attr->pValue = + (CK_BYTE *) always_sens_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) always_sens_attr->pValue = FALSE; + + never_extr_attr->type = CKA_NEVER_EXTRACTABLE; + never_extr_attr->ulValueLen = sizeof(CK_BBOOL); + never_extr_attr->pValue = + (CK_BYTE *) never_extr_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) never_extr_attr->pValue = FALSE; + + template_update_attribute(tmpl, class_attr); + template_update_attribute(tmpl, sensitive_attr); + template_update_attribute(tmpl, encrypt_attr); + template_update_attribute(tmpl, decrypt_attr); + template_update_attribute(tmpl, sign_attr); + template_update_attribute(tmpl, verify_attr); + template_update_attribute(tmpl, wrap_attr); + template_update_attribute(tmpl, unwrap_attr); + template_update_attribute(tmpl, extractable_attr); + template_update_attribute(tmpl, never_extr_attr); + template_update_attribute(tmpl, always_sens_attr); + + return CKR_OK; +} + + +// +// +CK_RV secret_key_unwrap(STDLL_TokData_t *tokdata, + TEMPLATE *tmpl, + CK_ULONG keytype, + CK_BYTE *data, + CK_ULONG data_len, CK_BBOOL fromend, CK_BBOOL isopaque) +{ + CK_ATTRIBUTE *local = NULL; + CK_ATTRIBUTE *always_sens = NULL; + CK_ATTRIBUTE *sensitive = NULL; + CK_ATTRIBUTE *extractable = NULL; + CK_ATTRIBUTE *never_extract = NULL; + CK_BBOOL true = TRUE; + CK_BBOOL false = FALSE; + CK_RV rc; + + switch (keytype) { + case CKK_CDMF: + case CKK_DES: + rc = des_unwrap(tokdata, tmpl, data, data_len, fromend, isopaque); + break; + case CKK_DES3: + rc = des3_unwrap(tokdata, tmpl, data, data_len, fromend, isopaque); + break; + case CKK_AES: + rc = aes_unwrap(tokdata, tmpl, data, data_len, fromend, isopaque); + break; + case CKK_GENERIC_SECRET: + case CKK_RC2: + case CKK_RC4: + case CKK_RC5: + case CKK_CAST: + case CKK_CAST3: + case CKK_CAST5: + rc = generic_secret_unwrap(tmpl, data, data_len, fromend, isopaque); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_WRAPPED_KEY_INVALID)); + return CKR_WRAPPED_KEY_INVALID; + } + + if (rc != CKR_OK) + return rc; + + // make sure + // CKA_LOCAL == FALSE + // CKA_ALWAYS_SENSITIVE == FALSE + // CKA_EXTRACTABLE == TRUE + // CKA_NEVER_EXTRACTABLE == FALSE + // + rc = build_attribute(CKA_LOCAL, &false, 1, &local); + if (rc != CKR_OK) { + TRACE_DEVEL("build attribute failed\n"); + goto cleanup; + } + rc = build_attribute(CKA_ALWAYS_SENSITIVE, &false, 1, &always_sens); + if (rc != CKR_OK) { + TRACE_DEVEL("build attribute failed\n"); + goto cleanup; + } + rc = build_attribute(CKA_SENSITIVE, &false, 1, &sensitive); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + rc = build_attribute(CKA_EXTRACTABLE, &true, 1, &extractable); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + rc = build_attribute(CKA_NEVER_EXTRACTABLE, &false, 1, &never_extract); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto cleanup; + } + template_update_attribute(tmpl, local); + template_update_attribute(tmpl, always_sens); + template_update_attribute(tmpl, sensitive); + template_update_attribute(tmpl, extractable); + template_update_attribute(tmpl, never_extract); + + return CKR_OK; + +cleanup: + if (local) + free(local); + if (extractable) + free(extractable); + if (always_sens) + free(always_sens); + if (never_extract) + free(never_extract); + + return rc; +} + + + + +// secret_key_validate_attribute() +// +CK_RV secret_key_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_ENCRYPT: + case CKA_DECRYPT: + case CKA_SIGN: + case CKA_VERIFY: + case CKA_WRAP: + case CKA_UNWRAP: + if (mode == MODE_MODIFY) { + if (tokdata->nv_token_data->tweak_vector.allow_key_mods == TRUE) + return CKR_OK; + + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + return CKR_OK; + // after key creation, CKA_SENSITIVE may only be set to TRUE + // + case CKA_SENSITIVE: + { + CK_BBOOL value; + + value = *(CK_BBOOL *) attr->pValue; + if ((mode != MODE_CREATE && mode != MODE_DERIVE && + mode != MODE_KEYGEN) && (value != TRUE)) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + return CKR_OK; + } + // after key creation, CKA_EXTRACTABLE may only be set to FALSE + // + case CKA_EXTRACTABLE: + { + CK_BBOOL value; + + // the unwrap routine will automatically set extractable to TRUE + // + value = *(CK_BBOOL *) attr->pValue; + if ((mode != MODE_CREATE && mode != MODE_DERIVE && + mode != MODE_KEYGEN) && (value != FALSE)) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + if (value == FALSE) { + CK_ATTRIBUTE *attr; + + attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + + sizeof(CK_BBOOL)); + if (!attr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + attr->type = CKA_NEVER_EXTRACTABLE; + attr->ulValueLen = sizeof(CK_BBOOL); + attr->pValue = (CK_BYTE *) attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) attr->pValue = FALSE; + + template_update_attribute(tmpl, attr); + } + return CKR_OK; + } + case CKA_ALWAYS_SENSITIVE: + case CKA_NEVER_EXTRACTABLE: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + default: + return key_object_validate_attribute(tmpl, attr, mode); + } + + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID)); + + return CKR_ATTRIBUTE_TYPE_INVALID; +} + + +// secret_key_check_exportability() +// +CK_BBOOL secret_key_check_exportability(CK_ATTRIBUTE_TYPE type) +{ + switch (type) { + case CKA_VALUE: + TRACE_ERROR("%s\n", ock_err(ERR_KEY_UNEXTRACTABLE)); + return FALSE; + } + + return TRUE; +} + + +// rsa_publ_check_required_attributes() +// +CK_RV rsa_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + + found = template_attribute_find(tmpl, CKA_MODULUS, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_MODULUS_BITS, &attr); + if (!found) { + if (mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_PUBLIC_EXPONENT, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return publ_key_check_required_attributes(tmpl, mode); +} + + +// rsa_publ_set_default_attributes() +// +CK_RV rsa_publ_set_default_attributes(TEMPLATE *tmpl, TEMPLATE *basetmpl, + CK_ULONG mode) +{ + CK_ATTRIBUTE *type_attr = NULL; + CK_ATTRIBUTE *modulus_attr = NULL; + CK_ATTRIBUTE *modulus_bits_attr = NULL; + CK_ATTRIBUTE *public_exp_attr = NULL; + CK_ATTRIBUTE *tmpattr = NULL; + CK_ULONG bits = 0L; + CK_BYTE pubExp[3] = { 0x01, 0x00, 0x01 }; + + publ_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + modulus_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + modulus_bits_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG)); + public_exp_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(pubExp)); + + if (!type_attr || !modulus_attr || !modulus_bits_attr || !public_exp_attr) { + if (type_attr) + free(type_attr); + if (modulus_attr) + free(modulus_attr); + if (modulus_bits_attr) + free(modulus_bits_attr); + if (public_exp_attr) + free(public_exp_attr); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + + return CKR_HOST_MEMORY; + } + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_RSA; + + modulus_attr->type = CKA_MODULUS; + modulus_attr->ulValueLen = 0; + modulus_attr->pValue = NULL; + + modulus_bits_attr->type = CKA_MODULUS_BITS; + modulus_bits_attr->ulValueLen = sizeof(CK_ULONG); + modulus_bits_attr->pValue = + (CK_BYTE *) modulus_bits_attr + sizeof(CK_ATTRIBUTE); + + if (template_attribute_find(basetmpl, CKA_MODULUS, &tmpattr)) { + *(CK_ULONG *) modulus_bits_attr->pValue = 8 * tmpattr->ulValueLen; + } else { + *(CK_ULONG *) modulus_bits_attr->pValue = bits; + } + + public_exp_attr->type = CKA_PUBLIC_EXPONENT; + public_exp_attr->ulValueLen = sizeof(pubExp); + public_exp_attr->pValue = + (CK_BYTE *) public_exp_attr + sizeof(CK_ATTRIBUTE); + memcpy(public_exp_attr->pValue, pubExp, sizeof(pubExp)); + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, modulus_attr); + template_update_attribute(tmpl, modulus_bits_attr); + template_update_attribute(tmpl, public_exp_attr); + + return CKR_OK; +} + + +// rsa_publ_validate_attributes() +// +CK_RV rsa_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_MODULUS_BITS: + if (mode == MODE_KEYGEN) { + if (attr->ulValueLen != sizeof(CK_ULONG)) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } else { + CK_ULONG mod_bits = *(CK_ULONG *) attr->pValue; + + if (mod_bits < 512 || mod_bits > 4096) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + if (mod_bits % 8 != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + } + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + case CKA_MODULUS: + if (mode == MODE_CREATE) { + p11_attribute_trim(attr); + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + case CKA_PUBLIC_EXPONENT: + if (mode == MODE_CREATE || mode == MODE_KEYGEN) { + p11_attribute_trim(attr); + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + default: + return publ_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// rsa_priv_check_required_attributes() +// +CK_RV rsa_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + + found = template_attribute_find(tmpl, CKA_MODULUS, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + // + // PKCS #11 is flexible with respect to which attributes must be present + // in an RSA key. Keys can be specified in Chinese-Remainder format or + // they can be specified in modular-exponent format. Right now, I only + // support keys created in Chinese-Remainder format. That is, we return + // CKR_TEMPLATE_INCOMPLETE if a modular-exponent key is specified. This + // is allowed by PKCS #11. + // + // In the future, we should allow for creation of keys in modular-exponent + // format too. This raises some issues. It's easy enough to recognize + // when a key has been specified in modular-exponent format. And it's + // easy enough to recognize when all attributes have been specified + // (which is what we require right now). What's trickier to handle is + // the "middle" cases in which more than the minimum yet less than the + // full number of attributes have been specified. Do we revert back to + // modular-exponent representation? Do we compute the missing attributes + // ourselves? Do we simply return CKR_TEMPLATE_INCOMPLETE? + // + + found = template_attribute_find(tmpl, CKA_PUBLIC_EXPONENT, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_PRIVATE_EXPONENT, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_PRIME_1, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_PRIME_2, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_EXPONENT_1, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_EXPONENT_2, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_COEFFICIENT, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + // we should probably verify that the (e != p) and (e != q). + // ie. gcd(e,n) == 1 + // + + return priv_key_check_required_attributes(tmpl, mode); +} + + +// rsa_priv_set_default_attributes() +// +CK_RV rsa_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *modulus_attr = NULL; + CK_ATTRIBUTE *public_exp_attr = NULL; + CK_ATTRIBUTE *private_exp_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + + // satisfy the compiler + // + if (mode) + modulus_attr = NULL; + + priv_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + modulus_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + public_exp_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + private_exp_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + + if (!type_attr || !modulus_attr || !public_exp_attr || !private_exp_attr) { + if (type_attr) + free(type_attr); + if (modulus_attr) + free(modulus_attr); + if (public_exp_attr) + free(public_exp_attr); + if (private_exp_attr) + free(private_exp_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + modulus_attr->type = CKA_MODULUS; + modulus_attr->ulValueLen = 0; + modulus_attr->pValue = NULL; + + public_exp_attr->type = CKA_PUBLIC_EXPONENT; + public_exp_attr->ulValueLen = 0; + public_exp_attr->pValue = NULL; + + private_exp_attr->type = CKA_PRIVATE_EXPONENT; + private_exp_attr->ulValueLen = 0; + private_exp_attr->pValue = NULL; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_RSA; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, modulus_attr); + template_update_attribute(tmpl, public_exp_attr); + template_update_attribute(tmpl, private_exp_attr); + + return CKR_OK; +} + + +// rsa_priv_validate_attributes() +// +CK_RV rsa_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_MODULUS: + case CKA_PRIVATE_EXPONENT: + if (mode == MODE_CREATE) { + p11_attribute_trim(attr); + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + case CKA_PUBLIC_EXPONENT: + case CKA_PRIME_1: + case CKA_PRIME_2: + case CKA_EXPONENT_1: + case CKA_EXPONENT_2: + case CKA_COEFFICIENT: + if (mode == MODE_CREATE) { + p11_attribute_trim(attr); + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + default: + return priv_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// rsa_priv_check_exportability() +// +CK_BBOOL rsa_priv_check_exportability(CK_ATTRIBUTE_TYPE type) +{ + switch (type) { + case CKA_PRIVATE_EXPONENT: + case CKA_PRIME_1: + case CKA_PRIME_2: + case CKA_EXPONENT_1: + case CKA_EXPONENT_2: + case CKA_COEFFICIENT: + TRACE_ERROR("%s\n", ock_err(ERR_KEY_UNEXTRACTABLE)); + return FALSE; + } + + return TRUE; +} + + +// create the ASN.1 encoding for the private key for wrapping as defined +// in PKCS #8 +// +// ASN.1 type PrivateKeyInfo ::= SEQUENCE { +// version Version +// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier +// privateKey PrivateKey +// attributes OPTIONAL +// } +// +// Where PrivateKey is defined as follows for RSA: +// +// ASN.1 type RSAPrivateKey +// +// RSAPrivateKey ::= SEQUENCE { +// version Version +// modulus INTEGER +// publicExponent INTEGER +// privateExponent INTEGER +// prime1 INTEGER +// prime2 INTEGER +// exponent1 INTEGER +// exponent2 INTEGER +// coefficient INTEGER +// } +// +CK_RV rsa_priv_wrap_get_data(TEMPLATE *tmpl, + CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len) +{ + CK_ATTRIBUTE *modulus = NULL; + CK_ATTRIBUTE *publ_exp = NULL, *priv_exp = NULL; + CK_ATTRIBUTE *prime1 = NULL, *prime2 = NULL; + CK_ATTRIBUTE *exponent1 = NULL, *exponent2 = NULL; + CK_ATTRIBUTE *coeff = NULL; + CK_ATTRIBUTE *opaque = NULL; + CK_RV rc; + + + // compute the total length of the BER-encoded data + // + if (template_attribute_find(tmpl, CKA_MODULUS, &modulus) == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + return CKR_FUNCTION_FAILED; + } + if (template_attribute_find(tmpl, CKA_PUBLIC_EXPONENT, &publ_exp) == FALSE) { + TRACE_ERROR("Could not find CKA_PUBLIC_EXPONENT for the key.\n"); + return CKR_FUNCTION_FAILED; + } + // CKA_IBM_OPAQUE is used for secure key, if it is not available, then + // assume using clear key and get rest of attributes required for clear key. + + if (template_attribute_find(tmpl, CKA_IBM_OPAQUE, &opaque) == FALSE) { + if (template_attribute_find(tmpl, CKA_PRIVATE_EXPONENT, &priv_exp) == + FALSE) { + TRACE_ERROR("Could not find private exponent for the key.\n"); + return CKR_FUNCTION_FAILED; + } + if (template_attribute_find(tmpl, CKA_PRIME_1, &prime1) == FALSE) { + TRACE_ERROR("Could not find CKA_PRIME_1 for the key.\n"); + return CKR_FUNCTION_FAILED; + } + if (template_attribute_find(tmpl, CKA_PRIME_2, &prime2) == FALSE) { + TRACE_ERROR("Could not find CKA_PRIME_2 for the key.\n"); + return CKR_FUNCTION_FAILED; + } + if (template_attribute_find(tmpl, CKA_EXPONENT_1, &exponent1) == FALSE) { + TRACE_ERROR("Could not find CKA_EXPONENT_1 for the key.\n"); + return CKR_FUNCTION_FAILED; + } + if (template_attribute_find(tmpl, CKA_EXPONENT_2, &exponent2) == FALSE) { + TRACE_ERROR("Could not find CKA_EXPONENT_2 for the key.\n"); + return CKR_FUNCTION_FAILED; + } + if (template_attribute_find(tmpl, CKA_COEFFICIENT, &coeff) == FALSE) { + TRACE_ERROR("Could not find CKA_COEFFICIENT for the key.\n"); + return CKR_FUNCTION_FAILED; + } + } + + rc = ber_encode_RSAPrivateKey(length_only, data, data_len, modulus, + publ_exp, priv_exp, prime1, prime2, + exponent1, exponent2, coeff, opaque); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_RSAPrivateKey failed\n"); + } + + return rc; +} + + +// +// +CK_RV rsa_priv_unwrap(TEMPLATE *tmpl, + CK_BYTE *data, CK_ULONG total_length, CK_BBOOL isopaque) +{ + CK_ATTRIBUTE *modulus = NULL; + CK_ATTRIBUTE *publ_exp = NULL; + CK_ATTRIBUTE *priv_exp = NULL; + CK_ATTRIBUTE *prime1 = NULL; + CK_ATTRIBUTE *prime2 = NULL; + CK_ATTRIBUTE *exponent1 = NULL; + CK_ATTRIBUTE *exponent2 = NULL; + CK_ATTRIBUTE *coeff = NULL; + CK_ATTRIBUTE *opaque = NULL; + CK_RV rc; + + rc = ber_decode_RSAPrivateKey(data, + total_length, + &modulus, + &publ_exp, + &priv_exp, + &prime1, + &prime2, + &exponent1, + &exponent2, &coeff, &opaque, isopaque); + + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_RSAPrivateKey failed\n"); + return rc; + } + p11_attribute_trim(modulus); + p11_attribute_trim(publ_exp); + if (isopaque) { + p11_attribute_trim(opaque); + } else { + p11_attribute_trim(priv_exp); + p11_attribute_trim(prime1); + p11_attribute_trim(prime2); + p11_attribute_trim(exponent1); + p11_attribute_trim(exponent2); + p11_attribute_trim(coeff); + } + + template_update_attribute(tmpl, modulus); + template_update_attribute(tmpl, publ_exp); + if (isopaque) { + template_update_attribute(tmpl, opaque); + } else { + template_update_attribute(tmpl, priv_exp); + template_update_attribute(tmpl, prime1); + template_update_attribute(tmpl, prime2); + template_update_attribute(tmpl, exponent1); + template_update_attribute(tmpl, exponent2); + template_update_attribute(tmpl, coeff); + } + + return CKR_OK; +} + + +CK_RV rsa_priv_unwrap_get_data(TEMPLATE *tmpl, + CK_BYTE *data, CK_ULONG total_length) +{ + CK_ATTRIBUTE *modulus = NULL; + CK_ATTRIBUTE *publ_exp = NULL; + CK_RV rc; + + rc = ber_decode_RSAPublicKey(data, total_length, &modulus, &publ_exp); + + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_RSAPublicKey failed\n"); + return rc; + } + + p11_attribute_trim(modulus); + p11_attribute_trim(publ_exp); + + rc = template_update_attribute(tmpl, modulus); + if (rc != CKR_OK) + TRACE_DEVEL("template_update_attribute(CKA_MODULUS) failed\n"); + rc = template_update_attribute(tmpl, publ_exp); + if (rc != CKR_OK) + TRACE_DEVEL("template_update_attribute(CKA_PUBLIC_EXPONENT) failed\n"); + + return CKR_OK; +} + +CK_RV ibm_dilithium_priv_wrap_get_data(TEMPLATE *tmpl, + CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len) +{ + CK_ATTRIBUTE *keyform, *rho = NULL, *seed = NULL; + CK_ATTRIBUTE *tr = NULL, *s1 = NULL, *s2 = NULL; + CK_ATTRIBUTE *t0 = NULL, *t1 = NULL; + CK_ATTRIBUTE *opaque = NULL; + CK_RV rc; + + /* A private Dilithium key must have a keyform value */ + if (!template_attribute_find(tmpl, CKA_IBM_DILITHIUM_KEYFORM, &keyform)) { + TRACE_ERROR("Could not find CKA_IBM_DILITHIUM_KEYFORM for the key.\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + + /* Check if it's an expected keyform */ + if (*(CK_ULONG *) keyform->pValue != IBM_DILITHIUM_KEYFORM_ROUND2) { + TRACE_ERROR("This key has an unexpected CKA_IBM_DILITHIUM_KEYFORM: %ld \n", + *(CK_ULONG *) keyform->pValue); + return CKR_TEMPLATE_INCONSISTENT; + } + + /* Check if key given as opaque blob */ + if (template_attribute_find(tmpl, CKA_IBM_OPAQUE, &opaque) == FALSE) { + + if (template_attribute_find(tmpl, CKA_IBM_DILITHIUM_RHO, &rho) == FALSE) { + TRACE_ERROR("Could not find CKA_IBM_DILITHIUM_RHO for the key.\n"); + return CKR_TEMPLATE_INCONSISTENT; + } + + if (template_attribute_find(tmpl, CKA_IBM_DILITHIUM_SEED, &seed) == FALSE) { + TRACE_ERROR("Could not find CKA_IBM_DILITHIUM_SEED for the key.\n"); + return CKR_TEMPLATE_INCONSISTENT; + } + + if (template_attribute_find(tmpl, CKA_IBM_DILITHIUM_TR, &tr) == FALSE) { + TRACE_ERROR("Could not find CKA_IBM_DILITHIUM_TR for the key.\n"); + return CKR_TEMPLATE_INCONSISTENT; + } + + if (template_attribute_find(tmpl, CKA_IBM_DILITHIUM_S1, &s1) == FALSE) { + TRACE_ERROR("Could not find CKA_IBM_DILITHIUM_S1 for the key.\n"); + return CKR_TEMPLATE_INCONSISTENT; + } + + if (template_attribute_find(tmpl, CKA_IBM_DILITHIUM_S2, &s2) == FALSE) { + TRACE_ERROR("Could not find CKA_IBM_DILITHIUM_S2 for the key.\n"); + return CKR_TEMPLATE_INCONSISTENT; + } + + if (template_attribute_find(tmpl, CKA_IBM_DILITHIUM_T0, &t0) == FALSE) { + TRACE_ERROR("Could not find CKA_IBM_DILITHIUM_T0 for the key.\n"); + return CKR_TEMPLATE_INCONSISTENT; + } + + if (template_attribute_find(tmpl, CKA_IBM_DILITHIUM_T1, &t1) == FALSE) { + TRACE_ERROR("Could not find CKA_IBM_DILITHIUM_T1 for the key.\n"); + return CKR_TEMPLATE_INCONSISTENT; + } + } + + rc = ber_encode_IBM_DilithiumPrivateKey(length_only, data, data_len, + rho, seed, tr, s1, s2, t0, t1, + opaque); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_IBM_DilithiumPrivateKey failed\n"); + } + + return rc; +} + +CK_RV ibm_dilithium_priv_unwrap_get_data(TEMPLATE *tmpl, CK_BYTE *data, + CK_ULONG total_length) +{ + CK_ATTRIBUTE *rho = NULL; + CK_ATTRIBUTE *t1 = NULL; + CK_RV rc; + + rc = ber_decode_IBM_DilithiumPublicKey(data, total_length, &rho, &t1); + if (rc != CKR_OK) { + TRACE_ERROR("ber_decode_DilithiumPublicKey failed\n"); + return rc; + } + + rc = template_update_attribute(tmpl, rho); + if (rc != CKR_OK) { + TRACE_ERROR("template_update_attribute(CKA_IBM_DILITHIUM_RHO) failed\n"); + return rc; + } + rc = template_update_attribute(tmpl, t1); + if (rc != CKR_OK) { + TRACE_ERROR("template_update_attribute(CKA_IBM_DILITHIUM_T1) failed\n"); + return rc; + } + + return CKR_OK; +} + +// +// +CK_RV ibm_dilithium_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, + CK_ULONG total_length, CK_BBOOL isOpaque) +{ + CK_ATTRIBUTE *rho = NULL, *seed = NULL, *tr = NULL; + CK_ATTRIBUTE *s1 = NULL, *s2 = NULL, *t0 = NULL, *t1 = NULL; + CK_ATTRIBUTE *opaque = NULL; + CK_RV rc; + + rc = ber_decode_IBM_DilithiumPrivateKey(data, total_length, + &rho, &seed, &tr, &s1, &s2, &t0, &t1, + &opaque, isOpaque); + if (rc != CKR_OK) { + TRACE_ERROR("der_decode_IBM_DilithiumPrivateKey failed\n"); + return rc; + } + + if (isOpaque) + rc |= template_update_attribute(tmpl, opaque); + + rc |= template_update_attribute(tmpl, rho); + rc |= template_update_attribute(tmpl, seed); + rc |= template_update_attribute(tmpl, tr); + rc |= template_update_attribute(tmpl, s1); + rc |= template_update_attribute(tmpl, s2); + rc |= template_update_attribute(tmpl, t0); + rc |= template_update_attribute(tmpl, t1); + + if (rc != CKR_OK) { + TRACE_ERROR("template_update_attribute failed\n"); + return rc; + } + + return CKR_OK; +} + +// dsa_publ_check_required_attributes() +// +CK_RV dsa_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + + found = template_attribute_find(tmpl, CKA_PRIME, &attr); + if (!found) { + if (mode == MODE_CREATE || mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + found = template_attribute_find(tmpl, CKA_SUBPRIME, &attr); + if (!found) { + if (mode == MODE_CREATE || mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_BASE, &attr); + if (!found) { + if (mode == MODE_CREATE || mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return publ_key_check_required_attributes(tmpl, mode); +} + + +// dsa_publ_set_default_attributes() +// +CK_RV dsa_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *prime_attr = NULL; + CK_ATTRIBUTE *subprime_attr = NULL; + CK_ATTRIBUTE *base_attr = NULL; + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + + if (mode) + prime_attr = NULL; + + publ_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + prime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + subprime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + base_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + + if (!type_attr || !prime_attr || !subprime_attr || !base_attr + || !value_attr) { + if (type_attr) + free(type_attr); + if (prime_attr) + free(prime_attr); + if (subprime_attr) + free(subprime_attr); + if (base_attr) + free(base_attr); + if (value_attr) + free(value_attr); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + + return CKR_HOST_MEMORY; + } + + prime_attr->type = CKA_PRIME; + prime_attr->ulValueLen = 0; + prime_attr->pValue = NULL; + + subprime_attr->type = CKA_SUBPRIME; + subprime_attr->ulValueLen = 0; + subprime_attr->pValue = NULL; + + base_attr->type = CKA_BASE; + base_attr->ulValueLen = 0; + base_attr->pValue = NULL; + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_DSA; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, prime_attr); + template_update_attribute(tmpl, subprime_attr); + template_update_attribute(tmpl, base_attr); + template_update_attribute(tmpl, value_attr); + + return CKR_OK; +} + + +// dsa_publ_validate_attributes() +// +CK_RV dsa_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_PRIME: + { + CK_ULONG size; + + if (mode != MODE_CREATE && mode != MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + // must be between [512, 1024] bits, and a multiple of 64 bits + // + size = attr->ulValueLen; + if (size < 64 || size > 128 || (size % 8 != 0)) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + p11_attribute_trim(attr); + return CKR_OK; + } + case CKA_SUBPRIME: + if (mode != MODE_CREATE && mode != MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + // subprime must be 160 bits + // + if (attr->ulValueLen != 20) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + p11_attribute_trim(attr); + return CKR_OK; + case CKA_BASE: + if (mode == MODE_CREATE || mode == MODE_KEYGEN) { + p11_attribute_trim(attr); + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + case CKA_VALUE: + if (mode == MODE_CREATE) { + p11_attribute_trim(attr); + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + default: + return publ_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// dsa_priv_check_required_attributes() +// +CK_RV dsa_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + + found = template_attribute_find(tmpl, CKA_PRIME, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_SUBPRIME, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_BASE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return priv_key_check_required_attributes(tmpl, mode); +} + + +// dsa_priv_set_default_attributes() +// +CK_RV dsa_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *prime_attr = NULL; + CK_ATTRIBUTE *subprime_attr = NULL; + CK_ATTRIBUTE *base_attr = NULL; + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + + if (mode) + prime_attr = NULL; + + priv_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + prime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + subprime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + base_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + + if (!type_attr || !prime_attr || !subprime_attr || !base_attr + || !value_attr) { + if (type_attr) + free(type_attr); + if (prime_attr) + free(prime_attr); + if (subprime_attr) + free(subprime_attr); + if (base_attr) + free(base_attr); + if (value_attr) + free(value_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + + return CKR_HOST_MEMORY; + } + + prime_attr->type = CKA_PRIME; + prime_attr->ulValueLen = 0; + prime_attr->pValue = NULL; + + subprime_attr->type = CKA_SUBPRIME; + subprime_attr->ulValueLen = 0; + subprime_attr->pValue = NULL; + + base_attr->type = CKA_BASE; + base_attr->ulValueLen = 0; + base_attr->pValue = NULL; + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_DSA; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, prime_attr); + template_update_attribute(tmpl, subprime_attr); + template_update_attribute(tmpl, base_attr); + template_update_attribute(tmpl, value_attr); + + return CKR_OK; +} + + +// dsa_priv_validate_attributes() +// +CK_RV dsa_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_PRIME: + { + CK_ULONG size; + + if (mode != MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + // must be between [512, 1024] bits, and a multiple of 64 bits + // + size = attr->ulValueLen; + if (size < 64 || size > 128 || (size % 8 != 0)) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + p11_attribute_trim(attr); + return CKR_OK; + } + case CKA_SUBPRIME: + if (mode != MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + // subprime must be 160 bits + // + if (attr->ulValueLen != 20) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + p11_attribute_trim(attr); + return CKR_OK; + case CKA_BASE: + case CKA_VALUE: + if (mode == MODE_CREATE) { + p11_attribute_trim(attr); + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + default: + return priv_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// dsa_priv_check_exportability() +// +CK_BBOOL dsa_priv_check_exportability(CK_ATTRIBUTE_TYPE type) +{ + switch (type) { + case CKA_VALUE: + return FALSE; + } + + return TRUE; +} + + +// create the ASN.1 encoding for the private key for wrapping as defined +// in PKCS #8 +// +// ASN.1 type PrivateKeyInfo ::= SEQUENCE { +// version Version +// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier +// privateKey PrivateKey +// attributes OPTIONAL +// } +// +// PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier +// +// AlgorithmIdentifier ::= SEQUENCE { +// algorithm OBJECT IDENTIFIER +// parameters ANY DEFINED BY algorithm OPTIONAL +// } +// +// paramters ::= SEQUENCE { +// p INTEGER +// q INTEGER +// g INTEGER +// } +// +// privateKey ::= INTEGER +// +// +CK_RV dsa_priv_wrap_get_data(TEMPLATE *tmpl, + CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len) +{ + CK_ATTRIBUTE *prime = NULL; + CK_ATTRIBUTE *subprime = NULL; + CK_ATTRIBUTE *base = NULL; + CK_ATTRIBUTE *value = NULL; + CK_RV rc; + + + // compute the total length of the BER-encoded data + // + if (template_attribute_find(tmpl, CKA_PRIME, &prime) == FALSE) { + TRACE_ERROR("Could not find CKA_PRIME for the key.\n"); + return CKR_FUNCTION_FAILED; + } + if (template_attribute_find(tmpl, CKA_SUBPRIME, &subprime) == FALSE) { + TRACE_ERROR("Could not find CKA_SUBPRIME for the key.\n"); + return CKR_FUNCTION_FAILED; + } + if (template_attribute_find(tmpl, CKA_BASE, &base) == FALSE) { + TRACE_ERROR("Could not find CKA_BASE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + if (template_attribute_find(tmpl, CKA_VALUE, &value) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + rc = ber_encode_DSAPrivateKey(length_only, data, data_len, + prime, subprime, base, value); + if (rc != CKR_OK) + TRACE_DEVEL("ber_encode_DSAPrivateKey failed\n"); + + return rc; +} + + +// +// +CK_RV dsa_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length) +{ + CK_ATTRIBUTE *prime = NULL; + CK_ATTRIBUTE *subprime = NULL; + CK_ATTRIBUTE *base = NULL; + CK_ATTRIBUTE *value = NULL; + CK_RV rc; + + rc = ber_decode_DSAPrivateKey(data, total_length, + &prime, &subprime, &base, &value); + + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_DSAPrivateKey failed\n"); + return rc; + } + p11_attribute_trim(prime); + p11_attribute_trim(subprime); + p11_attribute_trim(base); + p11_attribute_trim(value); + + template_update_attribute(tmpl, prime); + template_update_attribute(tmpl, subprime); + template_update_attribute(tmpl, base); + template_update_attribute(tmpl, value); + + return CKR_OK; +} + +CK_RV dsa_priv_unwrap_get_data(TEMPLATE *tmpl, + CK_BYTE *data, CK_ULONG total_length) +{ + CK_ATTRIBUTE *prime = NULL; + CK_ATTRIBUTE *subprime = NULL; + CK_ATTRIBUTE *base = NULL; + CK_ATTRIBUTE *value = NULL; + CK_RV rc; + + rc = ber_decode_DSAPublicKey(data, total_length, &prime, &subprime, + &base, &value); + + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_DSAPublicKey failed\n"); + return rc; + } + + p11_attribute_trim(prime); + p11_attribute_trim(subprime); + p11_attribute_trim(base); + p11_attribute_trim(value); + + rc = template_update_attribute(tmpl, prime); + if (rc != CKR_OK) + TRACE_DEVEL("template_update_attribute(CKA_PRIME) failed\n"); + rc = template_update_attribute(tmpl, subprime); + if (rc != CKR_OK) + TRACE_DEVEL("template_update_attribute(CKA_SUBPRIME) failed\n"); + rc = template_update_attribute(tmpl, base); + if (rc != CKR_OK) + TRACE_DEVEL("template_update_attribute(CKA_BASE) failed\n"); + rc = template_update_attribute(tmpl, value); + if (rc != CKR_OK) + TRACE_DEVEL("template_update_attribute(CKA_VALUE) failed\n"); + + return CKR_OK; +} + + +// ecdsa_publ_check_required_attributes() +// +CK_RV ecdsa_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + + found = template_attribute_find(tmpl, CKA_ECDSA_PARAMS, &attr); + if (!found) { + if (mode == MODE_CREATE || mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_EC_POINT, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return publ_key_check_required_attributes(tmpl, mode); +} + + +// ecdsa_publ_set_default_attributes() +// +CK_RV ecdsa_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *params_attr = NULL; + CK_ATTRIBUTE *ec_point_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + + if (mode) + params_attr = NULL; + + publ_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + params_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + ec_point_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + + if (!type_attr || !params_attr || !ec_point_attr) { + if (type_attr) + free(type_attr); + if (params_attr) + free(params_attr); + if (ec_point_attr) + free(ec_point_attr); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + + return CKR_HOST_MEMORY; + } + + params_attr->type = CKA_ECDSA_PARAMS; + params_attr->ulValueLen = 0; + params_attr->pValue = NULL; + + ec_point_attr->type = CKA_EC_POINT; + ec_point_attr->ulValueLen = 0; + ec_point_attr->pValue = NULL; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_ECDSA; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, params_attr); + template_update_attribute(tmpl, ec_point_attr); + + return CKR_OK; +} + + +// ecdsa_publ_validate_attributes() +// +CK_RV ecdsa_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_ECDSA_PARAMS: + if (mode == MODE_CREATE || mode == MODE_KEYGEN) + return CKR_OK; + + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + case CKA_EC_POINT: + if (mode == MODE_CREATE) + return CKR_OK; + + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + default: + return publ_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// ecdsa_priv_check_required_attributes() +// +CK_RV ecdsa_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + + found = template_attribute_find(tmpl, CKA_ECDSA_PARAMS, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return priv_key_check_required_attributes(tmpl, mode); +} + + +// ecdsa_priv_set_default_attributes() +// +CK_RV ecdsa_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *params_attr = NULL; + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + + if (mode) + params_attr = NULL; + + priv_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + params_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + + if (!type_attr || !params_attr || !value_attr) { + if (type_attr) + free(type_attr); + if (params_attr) + free(params_attr); + if (value_attr) + free(value_attr); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + + return CKR_HOST_MEMORY; + } + + params_attr->type = CKA_ECDSA_PARAMS; + params_attr->ulValueLen = 0; + params_attr->pValue = NULL; + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_ECDSA; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, params_attr); + template_update_attribute(tmpl, value_attr); + + return CKR_OK; +} + + +// ecdsa_priv_validate_attributes() +// +CK_RV ecdsa_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_ECDSA_PARAMS: + if (mode == MODE_CREATE) + return CKR_OK; + + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + case CKA_VALUE: + if (mode == MODE_CREATE) { + p11_attribute_trim(attr); + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + case CKA_EC_POINT: + if (mode == MODE_CREATE) { + p11_attribute_trim(attr); + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + default: + return priv_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// ecdsa_priv_check_exportability() +// +CK_BBOOL ecdsa_priv_check_exportability(CK_ATTRIBUTE_TYPE type) +{ + switch (type) { + case CKA_VALUE: + return FALSE; + } + + return TRUE; +} + +/* + * create the ASN.1 encoding for the private key for wrapping as defined + * in PKCS #8 + * + * ASN.1 type PrivateKeyInfo ::= SEQUENCE { + * version Version + * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier + * privateKey PrivateKey + * attributes OPTIONAL + * } + * + * Where PrivateKey is defined as follows for EC: + * + * ASN.1 type RSAPrivateKey + * + * ECPrivateKey ::= SEQUENCE { + * version Version + * privateKey OCTET STRING + * parameters [0] ECParameters (OPTIONAL) + * publicKey [1] BIT STRING (OPTIONAL) + * } + */ +CK_RV ecdsa_priv_wrap_get_data(TEMPLATE *tmpl, + CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len) +{ + CK_ATTRIBUTE *params = NULL; + CK_ATTRIBUTE *point = NULL; + CK_ATTRIBUTE *opaque = NULL; + CK_ATTRIBUTE *pubkey = NULL; + CK_RV rc; + + + // compute the total length of the BER-encoded data + // + if (template_attribute_find(tmpl, CKA_EC_PARAMS, ¶ms) == FALSE) { + TRACE_ERROR("Could not find CKA_EC_PARAMS for the key.\n"); + return CKR_FUNCTION_FAILED; + } + if (template_attribute_find(tmpl, CKA_VALUE, &point) == FALSE) { + TRACE_ERROR("Could not find CKA_EC_POINT for the key.\n"); + return CKR_FUNCTION_FAILED; + } + // CKA_IBM_OPAQUE is used for secure key, if it is not available, then + // assume using clear key and get rest of attributes required for clear key. + + if (template_attribute_find(tmpl, CKA_IBM_OPAQUE, &opaque) == FALSE) { + if (template_attribute_find(tmpl, CKA_VALUE, &point) == FALSE) { + TRACE_ERROR("Could not find EC Point for the key.\n"); + return CKR_FUNCTION_FAILED; + } + } + + /* check if optional public-key part was defined */ + template_attribute_find(tmpl, CKA_EC_POINT, &pubkey); + + rc = der_encode_ECPrivateKey(length_only, data, data_len, params, + point, opaque, pubkey); + if (rc != CKR_OK) { + TRACE_DEVEL("der_encode_ECPrivateKey failed\n"); + } + + return rc; +} + +CK_RV ecdsa_priv_unwrap_get_data(TEMPLATE *tmpl, + CK_BYTE *data, CK_ULONG total_length) +{ + CK_ATTRIBUTE *params = NULL; + CK_ATTRIBUTE *point = NULL; + CK_RV rc; + + rc = der_decode_ECPublicKey(data, total_length, ¶ms, &point); + + if (rc != CKR_OK) { + TRACE_DEVEL("der_decode_ECPublicKey failed\n"); + return rc; + } + + p11_attribute_trim(params); + p11_attribute_trim(point); + + rc = template_update_attribute(tmpl, params); + if (rc != CKR_OK) + TRACE_DEVEL("template_update_attribute(CKA_EC_PARAMS) failed\n"); + rc = template_update_attribute(tmpl, point); + if (rc != CKR_OK) + TRACE_DEVEL("template_update_attribute(CKA_EC_POINT) failed\n"); + + return CKR_OK; +} + +// +// +CK_RV ec_priv_unwrap(TEMPLATE *tmpl, + CK_BYTE *data, CK_ULONG total_length, CK_BBOOL isOpaque) +{ + CK_ATTRIBUTE *pubkey = NULL; + CK_ATTRIBUTE *privkey = NULL; + CK_ATTRIBUTE *opaque = NULL; + CK_ATTRIBUTE *ecparam = NULL; + CK_RV rc; + + rc = der_decode_ECPrivateKey(data, total_length, &ecparam, + &pubkey, &privkey, &opaque, isOpaque); + + if (rc != CKR_OK) { + TRACE_DEVEL("der_decode_ECPrivateKey failed\n"); + return rc; + } + p11_attribute_trim(pubkey); + p11_attribute_trim(privkey); + + if (isOpaque) + template_update_attribute(tmpl, opaque); + if (pubkey) + template_update_attribute(tmpl, pubkey); + if (privkey) + template_update_attribute(tmpl, privkey); + template_update_attribute(tmpl, ecparam); + + return CKR_OK; +} + +// dh_publ_check_required_attributes() +// +CK_RV dh_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + + found = template_attribute_find(tmpl, CKA_PRIME, &attr); + if (!found) { + if (mode == MODE_CREATE || mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_BASE, &attr); + if (!found) { + if (mode == MODE_CREATE || mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return publ_key_check_required_attributes(tmpl, mode); +} + + +// dh_publ_set_default_attributes() +// +CK_RV dh_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *prime_attr = NULL; + CK_ATTRIBUTE *base_attr = NULL; + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + + if (mode) + prime_attr = NULL; + + publ_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + prime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + base_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + + if (!type_attr || !prime_attr || !base_attr || !value_attr) { + if (type_attr) + free(type_attr); + if (prime_attr) + free(prime_attr); + if (base_attr) + free(base_attr); + if (value_attr) + free(value_attr); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + + return CKR_HOST_MEMORY; + } + + prime_attr->type = CKA_PRIME; + prime_attr->ulValueLen = 0; + prime_attr->pValue = NULL; + + base_attr->type = CKA_BASE; + base_attr->ulValueLen = 0; + base_attr->pValue = NULL; + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_DH; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, prime_attr); + template_update_attribute(tmpl, base_attr); + template_update_attribute(tmpl, value_attr); + + return CKR_OK; +} + + + + +// dh_publ_validate_attribute() +// +CK_RV dh_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_PRIME: + case CKA_BASE: + if (mode == MODE_CREATE || mode == MODE_KEYGEN) { + p11_attribute_trim(attr); + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + case CKA_VALUE: + if (mode == MODE_CREATE) { + p11_attribute_trim(attr); + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + default: + return publ_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// dh_priv_check_required_attributes() +// +CK_RV dh_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + + found = template_attribute_find(tmpl, CKA_PRIME, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_BASE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_VALUE_BITS, &attr); + if (found) { + if (mode == MODE_CREATE || mode == MODE_UNWRAP) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + } + + return priv_key_check_required_attributes(tmpl, mode); +} + + +// dh_priv_set_default_attributes() +// +CK_RV dh_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *prime_attr = NULL; + CK_ATTRIBUTE *base_attr = NULL; + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *value_bits_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + CK_ULONG bits = 0L; + + priv_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + prime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + base_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + value_bits_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG)); + + if (!type_attr || !prime_attr || !base_attr || !value_attr + || !value_bits_attr) { + if (type_attr) + free(type_attr); + if (prime_attr) + free(prime_attr); + if (base_attr) + free(base_attr); + if (value_attr) + free(value_attr); + if (value_bits_attr) + free(value_bits_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + prime_attr->type = CKA_PRIME; + prime_attr->ulValueLen = 0; + prime_attr->pValue = NULL; + + base_attr->type = CKA_BASE; + base_attr->ulValueLen = 0; + base_attr->pValue = NULL; + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + value_bits_attr->type = CKA_VALUE_BITS; + value_bits_attr->ulValueLen = sizeof(CK_ULONG); + value_bits_attr->pValue = + (CK_BYTE *) value_bits_attr + sizeof(CK_ATTRIBUTE); + *(CK_ULONG *) value_bits_attr->pValue = bits; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_DH; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, prime_attr); + template_update_attribute(tmpl, base_attr); + template_update_attribute(tmpl, value_attr); + template_update_attribute(tmpl, value_bits_attr); + + return CKR_OK; +} + + +// dh_priv_validate_attribute() +// +CK_RV dh_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_PRIME: + case CKA_BASE: + case CKA_VALUE: + if (mode == MODE_CREATE || mode == MODE_KEYGEN) { + p11_attribute_trim(attr); + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + // I'm not sure what to do about VALUE_BITS...we don't really support + // Diffie-Hellman keys other than for storage...when the object is + // created, we're supposed to add CKA_VALUE_BITS outselves...which we + // don't do at this time. (we'd need to add code in C_CreateObject to + // call some sort of objecttype-specific callback) + // + // kapil 05/08/03 : Commented out error flagging, as CKA_VALUE_BITS is + // valid attribute for creating DH priv object. The + // above is an older comment. + case CKA_VALUE_BITS: + // TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + // return CKR_ATTRIBUTE_READ_ONLY; + return CKR_OK; + break; + default: + return priv_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// dh_priv_check_exportability() +// +CK_BBOOL dh_priv_check_exportability(CK_ATTRIBUTE_TYPE type) +{ + switch (type) { + case CKA_VALUE: + return FALSE; + } + + return TRUE; +} + +// +// +CK_RV dh_priv_unwrap(TEMPLATE *tmpl, CK_BYTE *data, CK_ULONG total_length) +{ + CK_ATTRIBUTE *prime = NULL; + CK_ATTRIBUTE *base = NULL; + CK_ATTRIBUTE *value = NULL; + CK_RV rc; + + rc = ber_decode_DHPrivateKey(data, total_length, &prime, &base, &value); + + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_DHPrivateKey failed\n"); + return rc; + } + p11_attribute_trim(prime); + p11_attribute_trim(base); + p11_attribute_trim(value); + + template_update_attribute(tmpl, prime); + template_update_attribute(tmpl, base); + template_update_attribute(tmpl, value); + + return CKR_OK; +} + +CK_RV dh_priv_unwrap_get_data(TEMPLATE *tmpl, + CK_BYTE *data, CK_ULONG total_length) +{ + CK_ATTRIBUTE *prime = NULL; + CK_ATTRIBUTE *base = NULL; + CK_ATTRIBUTE *value = NULL; + CK_RV rc; + + rc = ber_decode_DHPublicKey(data, total_length, &prime, &base, &value); + + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_DHPublicKey failed\n"); + return rc; + } + + p11_attribute_trim(prime); + p11_attribute_trim(base); + p11_attribute_trim(value); + + rc = template_update_attribute(tmpl, prime); + if (rc != CKR_OK) + TRACE_DEVEL("template_update_attribute(CKA_PRIME) failed\n"); + rc = template_update_attribute(tmpl, base); + if (rc != CKR_OK) + TRACE_DEVEL("template_update_attribute(CKA_BASE) failed\n"); + rc = template_update_attribute(tmpl, value); + if (rc != CKR_OK) + TRACE_DEVEL("template_update_attribute(CKA_VALUE) failed\n"); + + return CKR_OK; +} + +// create the ASN.1 encoding for the private key for wrapping as defined +// in PKCS #8 +// +// ASN.1 type PrivateKeyInfo ::= SEQUENCE { +// version Version +// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier +// privateKey PrivateKey +// attributes OPTIONAL +// } +// +// PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier +// +// AlgorithmIdentifier ::= SEQUENCE { +// algorithm OBJECT IDENTIFIER +// parameters ANY DEFINED BY algorithm OPTIONAL +// } +// +// paramters ::= SEQUENCE { +// p INTEGER +// g INTEGER +// } +// +// privateKey ::= INTEGER +// +// +CK_RV dh_priv_wrap_get_data(TEMPLATE *tmpl, + CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len) +{ + CK_ATTRIBUTE *prime = NULL; + CK_ATTRIBUTE *base = NULL; + CK_ATTRIBUTE *value = NULL; + CK_RV rc; + + // compute the total length of the BER-encoded data + if (template_attribute_find(tmpl, CKA_PRIME, &prime) == FALSE) { + TRACE_ERROR("Could not find CKA_PRIME for the key.\n"); + return CKR_FUNCTION_FAILED; + } + if (template_attribute_find(tmpl, CKA_BASE, &base) == FALSE) { + TRACE_ERROR("Could not find CKA_BASE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + if (template_attribute_find(tmpl, CKA_VALUE, &value) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + rc = ber_encode_DHPrivateKey(length_only, data, data_len, + prime, base, value); + if (rc != CKR_OK) + TRACE_DEVEL("ber_encode_DHPrivateKey failed\n"); + + return rc; +} + + +// kea_publ_check_required_attributes() +// +CK_RV kea_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + + found = template_attribute_find(tmpl, CKA_PRIME, &attr); + if (!found) { + if (mode == MODE_CREATE || mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_SUBPRIME, &attr); + if (!found) { + if (mode == MODE_CREATE || mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_BASE, &attr); + if (!found) { + if (mode == MODE_CREATE || mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return publ_key_check_required_attributes(tmpl, mode); +} + + +// kea_publ_set_default_attributes() +// +CK_RV kea_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *prime_attr = NULL; + CK_ATTRIBUTE *subprime_attr = NULL; + CK_ATTRIBUTE *base_attr = NULL; + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + + if (mode) + prime_attr = NULL; + + + publ_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + prime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + subprime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + base_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + + if (!type_attr || !prime_attr || !subprime_attr || !base_attr + || !value_attr) { + if (type_attr) + free(type_attr); + if (prime_attr) + free(prime_attr); + if (subprime_attr) + free(subprime_attr); + if (base_attr) + free(base_attr); + if (value_attr) + free(value_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + prime_attr->type = CKA_PRIME; + prime_attr->ulValueLen = 0; + prime_attr->pValue = NULL; + + subprime_attr->type = CKA_SUBPRIME; + subprime_attr->ulValueLen = 0; + subprime_attr->pValue = NULL; + + base_attr->type = CKA_BASE; + base_attr->ulValueLen = 0; + base_attr->pValue = NULL; + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_KEA; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, prime_attr); + template_update_attribute(tmpl, subprime_attr); + template_update_attribute(tmpl, base_attr); + template_update_attribute(tmpl, value_attr); + + return CKR_OK; +} + + +// kea_publ_validate_attribute() +// +CK_RV kea_publ_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_PRIME: + case CKA_SUBPRIME: + case CKA_BASE: + if (mode == MODE_CREATE || mode == MODE_KEYGEN) { + p11_attribute_trim(attr); + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + case CKA_VALUE: + if (mode == MODE_CREATE) { + p11_attribute_trim(attr); + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + default: + return publ_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// kea_priv_check_required_attributes() +// +CK_RV kea_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + + found = template_attribute_find(tmpl, CKA_PRIME, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_SUBPRIME, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_BASE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return priv_key_check_required_attributes(tmpl, mode); +} + + +// kea_priv_set_default_attributes() +// +CK_RV kea_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *prime_attr = NULL; + CK_ATTRIBUTE *subprime_attr = NULL; + CK_ATTRIBUTE *base_attr = NULL; + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + + if (mode) + prime_attr = NULL; + + priv_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + prime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + subprime_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + base_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + + if (!type_attr || !prime_attr || !base_attr || !value_attr + || !subprime_attr) { + if (type_attr) + free(type_attr); + if (prime_attr) + free(prime_attr); + if (subprime_attr) + free(subprime_attr); + if (base_attr) + free(base_attr); + if (value_attr) + free(value_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + prime_attr->type = CKA_PRIME; + prime_attr->ulValueLen = 0; + prime_attr->pValue = NULL; + + subprime_attr->type = CKA_SUBPRIME; + subprime_attr->ulValueLen = 0; + subprime_attr->pValue = NULL; + + base_attr->type = CKA_BASE; + base_attr->ulValueLen = 0; + base_attr->pValue = NULL; + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_KEA; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, prime_attr); + template_update_attribute(tmpl, subprime_attr); + template_update_attribute(tmpl, base_attr); + template_update_attribute(tmpl, value_attr); + + return CKR_OK; +} + + +// kea_priv_validate_attribute() +// +CK_RV kea_priv_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_PRIME: + case CKA_SUBPRIME: + case CKA_BASE: + case CKA_VALUE: + if (mode == MODE_CREATE) { + p11_attribute_trim(attr); + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + default: + return priv_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// kea_priv_check_exportability() +// +CK_BBOOL kea_priv_check_exportability(CK_ATTRIBUTE_TYPE type) +{ + switch (type) { + case CKA_VALUE: + return FALSE; + } + + return TRUE; +} + +// ibm_dilithium_publ_set_default_attributes() +// +CK_RV ibm_dilithium_publ_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *type_attr = NULL; + CK_ATTRIBUTE *rho_attr = NULL; + CK_ATTRIBUTE *t1_attr = NULL; + CK_ATTRIBUTE *keyform_attr = NULL; + + publ_key_set_default_attributes(tmpl, mode); + + type_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + keyform_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG)); + rho_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + t1_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + + if (!type_attr || !rho_attr || !t1_attr || !keyform_attr) { + if (type_attr) + free(type_attr); + if (rho_attr) + free(rho_attr); + if (t1_attr) + free(t1_attr); + if (keyform_attr) + free(keyform_attr); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + + return CKR_HOST_MEMORY; + } + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_IBM_PQC_DILITHIUM; + + keyform_attr->type = CKA_IBM_DILITHIUM_KEYFORM; + keyform_attr->ulValueLen = sizeof(CK_ULONG); + keyform_attr->pValue = (CK_BYTE *) keyform_attr + sizeof(CK_ATTRIBUTE); + *(CK_ULONG *) keyform_attr->pValue = 1; + + rho_attr->type = CKA_IBM_DILITHIUM_RHO; + rho_attr->ulValueLen = 0; + rho_attr->pValue = NULL; + + t1_attr->type = CKA_IBM_DILITHIUM_T1; + t1_attr->ulValueLen = 0; + t1_attr->pValue = NULL; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, rho_attr); + template_update_attribute(tmpl, t1_attr); + template_update_attribute(tmpl, keyform_attr); + + return CKR_OK; +} + +// ibm_dilithium_priv_set_default_attributes() +// +CK_RV ibm_dilithium_priv_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *type_attr = NULL; + CK_ATTRIBUTE *rho_attr = NULL; + CK_ATTRIBUTE *seed_attr = NULL; + CK_ATTRIBUTE *tr_attr = NULL; + CK_ATTRIBUTE *s1_attr = NULL; + CK_ATTRIBUTE *s2_attr = NULL; + CK_ATTRIBUTE *t0_attr = NULL; + CK_ATTRIBUTE *t1_attr = NULL; + CK_ATTRIBUTE *keyform_attr = NULL; + + priv_key_set_default_attributes(tmpl, mode); + + type_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + keyform_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG)); + rho_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + seed_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + tr_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + s1_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + s2_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + t0_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + t1_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + + if (!type_attr || !rho_attr || !seed_attr || !tr_attr || !s1_attr + || !s2_attr || !t0_attr || !t1_attr || !keyform_attr) { + if (type_attr) + free(type_attr); + if (rho_attr) + free(rho_attr); + if (seed_attr) + free(seed_attr); + if (tr_attr) + free(tr_attr); + if (s1_attr) + free(s1_attr); + if (s2_attr) + free(s2_attr); + if (t0_attr) + free(t0_attr); + if (t1_attr) + free(t1_attr); + if (keyform_attr) + free(keyform_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_IBM_PQC_DILITHIUM; + + keyform_attr->type = CKA_IBM_DILITHIUM_KEYFORM; + keyform_attr->ulValueLen = sizeof(CK_ULONG); + keyform_attr->pValue = (CK_BYTE *) keyform_attr + sizeof(CK_ATTRIBUTE); + *(CK_ULONG *) keyform_attr->pValue = 1; + + rho_attr->type = CKA_IBM_DILITHIUM_RHO; + rho_attr->ulValueLen = 0; + rho_attr->pValue = NULL; + + seed_attr->type = CKA_IBM_DILITHIUM_SEED; + seed_attr->ulValueLen = 0; + seed_attr->pValue = NULL; + + tr_attr->type = CKA_IBM_DILITHIUM_TR; + tr_attr->ulValueLen = 0; + tr_attr->pValue = NULL; + + s1_attr->type = CKA_IBM_DILITHIUM_S1; + s1_attr->ulValueLen = 0; + s1_attr->pValue = NULL; + + s2_attr->type = CKA_IBM_DILITHIUM_S2; + s2_attr->ulValueLen = 0; + s2_attr->pValue = NULL; + + t0_attr->type = CKA_IBM_DILITHIUM_T0; + t0_attr->ulValueLen = 0; + t0_attr->pValue = NULL; + + t1_attr->type = CKA_IBM_DILITHIUM_T1; + t1_attr->ulValueLen = 0; + t1_attr->pValue = NULL; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, keyform_attr); + template_update_attribute(tmpl, rho_attr); + template_update_attribute(tmpl, seed_attr); + template_update_attribute(tmpl, tr_attr); + template_update_attribute(tmpl, s1_attr); + template_update_attribute(tmpl, s2_attr); + template_update_attribute(tmpl, t0_attr); + template_update_attribute(tmpl, t1_attr); + + return CKR_OK; +} + +// ibm_dilithium_publ_check_required_attributes() +// +CK_RV ibm_dilithium_publ_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + static CK_ULONG req_attrs[] = { + CKA_IBM_DILITHIUM_KEYFORM, + CKA_IBM_DILITHIUM_RHO, + CKA_IBM_DILITHIUM_T1, + }; + CK_ULONG i; + + /* MODE_KEYGEN: attrs are added during keygen */ + if (mode == MODE_KEYGEN || mode == MODE_UNWRAP) + return publ_key_check_required_attributes(tmpl, mode); + + /* MODE_CREATE (key import) or MODE_COPY: check if all attrs present */ + for (i = 0; i < sizeof(req_attrs) / sizeof(req_attrs[0]); i++) { + if (!(template_attribute_find(tmpl, req_attrs[i], &attr))) { + TRACE_ERROR("%s, attribute %08lX missing.\n", + ock_err(ERR_TEMPLATE_INCOMPLETE), req_attrs[i]); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + /* All required attrs found, check them */ + return publ_key_check_required_attributes(tmpl, mode); +} + +// ibm_dilithium_priv_check_required_attributes() +// +CK_RV ibm_dilithium_priv_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + static CK_ULONG req_attrs[] = { + CKA_IBM_DILITHIUM_KEYFORM, + CKA_IBM_DILITHIUM_RHO, + CKA_IBM_DILITHIUM_SEED, + CKA_IBM_DILITHIUM_TR, + CKA_IBM_DILITHIUM_S1, + CKA_IBM_DILITHIUM_S2, + CKA_IBM_DILITHIUM_T0, + CKA_IBM_DILITHIUM_T1, + }; + CK_ULONG i; + + /* MODE_KEYGEN: attrs are added during keygen */ + if (mode == MODE_KEYGEN || mode == MODE_UNWRAP) + return priv_key_check_required_attributes(tmpl, mode); + + /* MODE_CREATE (key import) or MODE_COPY: check if all attrs present */ + for (i = 0; i < sizeof(req_attrs) / sizeof(req_attrs[0]); i++) { + if (!(template_attribute_find(tmpl, req_attrs[i], &attr))) { + TRACE_ERROR("%s, attribute %08lX missing.\n", + ock_err(ERR_TEMPLATE_INCOMPLETE), req_attrs[i]); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + /* All required attrs found, check them */ + return priv_key_check_required_attributes(tmpl, mode); +} + +// ibm_dilithium_publ_validate_attribute() +// +CK_RV ibm_dilithium_publ_validate_attribute(STDLL_TokData_t *tokdata, + TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode) +{ + switch (attr->type) { + case CKA_IBM_DILITHIUM_RHO: + case CKA_IBM_DILITHIUM_T1: + if (mode == MODE_CREATE) + return CKR_OK; + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + case CKA_IBM_DILITHIUM_KEYFORM: + if (mode == MODE_CREATE || mode == MODE_KEYGEN) { + switch (*((CK_ULONG *)attr->pValue)) { + case IBM_DILITHIUM_KEYFORM_ROUND2: + return CKR_OK; + default: + TRACE_ERROR("%s\n", ock_err(CKR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + default: + return publ_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + +// ibm_dilithium_priv_validate_attribute() +// +CK_RV ibm_dilithium_priv_validate_attribute(STDLL_TokData_t *tokdata, + TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode) +{ + switch (attr->type) { + case CKA_IBM_DILITHIUM_RHO: + case CKA_IBM_DILITHIUM_SEED: + case CKA_IBM_DILITHIUM_TR: + case CKA_IBM_DILITHIUM_S1: + case CKA_IBM_DILITHIUM_S2: + case CKA_IBM_DILITHIUM_T0: + case CKA_IBM_DILITHIUM_T1: + if (mode == MODE_CREATE) + return CKR_OK; + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + case CKA_IBM_DILITHIUM_KEYFORM: + if (mode == MODE_CREATE || mode == MODE_KEYGEN) { + switch (*((CK_ULONG *)attr->pValue)) { + case IBM_DILITHIUM_KEYFORM_ROUND2: + return CKR_OK; + default: + TRACE_ERROR("%s\n", ock_err(CKR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + default: + return priv_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + +// generic_secret_check_required_attributes() +// +CK_RV generic_secret_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + + found = template_attribute_find(tmpl, CKA_VALUE_LEN, &attr); + if (!found) { + // here's another place where PKCS #11 deviates from its own + // specification. + // the spec states that VALUE_LEN must be present for KEYGEN but later + // it's merely optional if the mechanism is CKM_SSL3_PRE_MASTER_KEY_GEN. + // Unfortunately, we can't check the mechanism at this point + // + return CKR_OK; + } else { + // Another contradiction within the spec: When describing the key types + // the spec says that VALUE_LEN must not be specified when unwrapping + // a key. In the section describing the mechanisms, though, it's allowed + // for most unwrapping mechanisms. Netscape DOES does specify this + // attribute when unwrapping. + // + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + } + + return secret_key_check_required_attributes(tmpl, mode); +} + + +// generic_secret_set_default_attributes() +// +CK_RV generic_secret_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *value_len_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + CK_ATTRIBUTE *class_attr = NULL; + CK_ATTRIBUTE *sensitive_attr = NULL; + CK_ATTRIBUTE *encrypt_attr = NULL; + CK_ATTRIBUTE *decrypt_attr = NULL; + CK_ATTRIBUTE *sign_attr = NULL; + CK_ATTRIBUTE *verify_attr = NULL; + CK_ATTRIBUTE *wrap_attr = NULL; + CK_ATTRIBUTE *unwrap_attr = NULL; + CK_ATTRIBUTE *extractable_attr = NULL; + CK_ATTRIBUTE *never_extr_attr = NULL; + CK_ATTRIBUTE *always_sens_attr = NULL; + CK_ATTRIBUTE *id_attr = NULL; + CK_ATTRIBUTE *sdate_attr = NULL; + CK_ATTRIBUTE *edate_attr = NULL; + CK_ATTRIBUTE *derive_attr = NULL; + CK_ATTRIBUTE *local_attr = NULL; + CK_ULONG len = 0L; + + if (mode) { + value_attr = NULL; + id_attr = NULL; + } + + /* First set the Common Key Attributes's defaults for Generic Secret Keys */ + + id_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + sdate_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + edate_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + derive_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + local_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + + if (!id_attr || !sdate_attr || !edate_attr || !derive_attr || !local_attr) { + if (id_attr) + free(id_attr); + if (sdate_attr) + free(sdate_attr); + if (edate_attr) + free(edate_attr); + if (derive_attr) + free(derive_attr); + if (local_attr) + free(local_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + id_attr->type = CKA_ID; + id_attr->ulValueLen = 0; + id_attr->pValue = NULL; + + sdate_attr->type = CKA_START_DATE; + sdate_attr->ulValueLen = 0; + sdate_attr->pValue = NULL; + + edate_attr->type = CKA_END_DATE; + edate_attr->ulValueLen = 0; + edate_attr->pValue = NULL; + + derive_attr->type = CKA_DERIVE; + derive_attr->ulValueLen = sizeof(CK_BBOOL); + derive_attr->pValue = (CK_BYTE *) derive_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) derive_attr->pValue = TRUE; + + /* should be safe to set CKA_LOCAL here... */ + local_attr->type = CKA_LOCAL; + local_attr->ulValueLen = sizeof(CK_BBOOL); + local_attr->pValue = (CK_BYTE *) local_attr + sizeof(CK_ATTRIBUTE); + if (mode == MODE_KEYGEN) + *(CK_BBOOL *) local_attr->pValue = TRUE; + else + *(CK_BBOOL *) local_attr->pValue = FALSE; + + template_update_attribute(tmpl, id_attr); + template_update_attribute(tmpl, sdate_attr); + template_update_attribute(tmpl, edate_attr); + template_update_attribute(tmpl, derive_attr); + template_update_attribute(tmpl, local_attr); + + /* Next, set the Common Secret Key Attributes and defaults for + * Generic Secret Keys. + */ + + class_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_OBJECT_CLASS)); + sensitive_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + encrypt_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + decrypt_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + sign_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + verify_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + wrap_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + unwrap_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + extractable_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + never_extr_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + always_sens_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + if (!class_attr || !sensitive_attr || !encrypt_attr || !decrypt_attr + || !sign_attr || !verify_attr | !wrap_attr || !unwrap_attr + || !extractable_attr || !never_extr_attr || !always_sens_attr) { + if (class_attr) + free(class_attr); + if (sensitive_attr) + free(sensitive_attr); + if (encrypt_attr) + free(encrypt_attr); + if (decrypt_attr) + free(decrypt_attr); + if (sign_attr) + free(sign_attr); + if (verify_attr) + free(verify_attr); + if (wrap_attr) + free(wrap_attr); + if (unwrap_attr) + free(unwrap_attr); + if (extractable_attr) + free(extractable_attr); + if (never_extr_attr) + free(never_extr_attr); + if (always_sens_attr) + free(always_sens_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + class_attr->type = CKA_CLASS; + class_attr->ulValueLen = sizeof(CK_OBJECT_CLASS); + class_attr->pValue = (CK_BYTE *) class_attr + sizeof(CK_ATTRIBUTE); + *(CK_OBJECT_CLASS *) class_attr->pValue = CKO_SECRET_KEY; + + sensitive_attr->type = CKA_SENSITIVE; + sensitive_attr->ulValueLen = sizeof(CK_BBOOL); + sensitive_attr->pValue = (CK_BYTE *) sensitive_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) sensitive_attr->pValue = FALSE; + + encrypt_attr->type = CKA_ENCRYPT; + encrypt_attr->ulValueLen = sizeof(CK_BBOOL); + encrypt_attr->pValue = (CK_BYTE *) encrypt_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) encrypt_attr->pValue = FALSE; + + decrypt_attr->type = CKA_DECRYPT; + decrypt_attr->ulValueLen = sizeof(CK_BBOOL); + decrypt_attr->pValue = (CK_BYTE *) decrypt_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) decrypt_attr->pValue = FALSE; + + sign_attr->type = CKA_SIGN; + sign_attr->ulValueLen = sizeof(CK_BBOOL); + sign_attr->pValue = (CK_BYTE *) sign_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) sign_attr->pValue = TRUE; + + verify_attr->type = CKA_VERIFY; + verify_attr->ulValueLen = sizeof(CK_BBOOL); + verify_attr->pValue = (CK_BYTE *) verify_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) verify_attr->pValue = TRUE; + + wrap_attr->type = CKA_WRAP; + wrap_attr->ulValueLen = sizeof(CK_BBOOL); + wrap_attr->pValue = (CK_BYTE *) wrap_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) wrap_attr->pValue = FALSE; + + unwrap_attr->type = CKA_UNWRAP; + unwrap_attr->ulValueLen = sizeof(CK_BBOOL); + unwrap_attr->pValue = (CK_BYTE *) unwrap_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) unwrap_attr->pValue = FALSE; + + extractable_attr->type = CKA_EXTRACTABLE; + extractable_attr->ulValueLen = sizeof(CK_BBOOL); + extractable_attr->pValue = + (CK_BYTE *) extractable_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) extractable_attr->pValue = TRUE; + + /* by default, we'll set NEVER_EXTRACTABLE == FALSE and + * ALWAYS_SENSITIVE == FALSE + * If the key is being created with KEYGEN, it will adjust as necessary. + */ + always_sens_attr->type = CKA_ALWAYS_SENSITIVE; + always_sens_attr->ulValueLen = sizeof(CK_BBOOL); + always_sens_attr->pValue = + (CK_BYTE *) always_sens_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) always_sens_attr->pValue = FALSE; + + never_extr_attr->type = CKA_NEVER_EXTRACTABLE; + never_extr_attr->ulValueLen = sizeof(CK_BBOOL); + never_extr_attr->pValue = + (CK_BYTE *) never_extr_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) never_extr_attr->pValue = FALSE; + + template_update_attribute(tmpl, class_attr); + template_update_attribute(tmpl, sensitive_attr); + template_update_attribute(tmpl, encrypt_attr); + template_update_attribute(tmpl, decrypt_attr); + template_update_attribute(tmpl, sign_attr); + template_update_attribute(tmpl, verify_attr); + template_update_attribute(tmpl, wrap_attr); + template_update_attribute(tmpl, unwrap_attr); + template_update_attribute(tmpl, extractable_attr); + template_update_attribute(tmpl, never_extr_attr); + template_update_attribute(tmpl, always_sens_attr); + + /* Now set the type, value and value_len */ + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + value_len_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG)); + + if (!type_attr || !value_attr || !value_len_attr) { + if (type_attr) + free(type_attr); + if (value_attr) + free(value_attr); + if (value_len_attr) + free(value_len_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + value_len_attr->type = CKA_VALUE_LEN; + value_len_attr->ulValueLen = sizeof(CK_ULONG); + value_len_attr->pValue = (CK_BYTE *) value_len_attr + sizeof(CK_ATTRIBUTE); + *(CK_ULONG *) value_len_attr->pValue = len; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_GENERIC_SECRET; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, value_attr); + template_update_attribute(tmpl, value_len_attr); + + return CKR_OK; +} + +// generic_secret_validate_attribute() +// +CK_RV generic_secret_validate_attribute(STDLL_TokData_t *tokdata, + TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode) +{ + switch (attr->type) { + case CKA_VALUE: + if (mode == MODE_CREATE) + return CKR_OK; + + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + // Another contradiction within the spec: When describing the key types + // the spec says that VALUE_LEN must not be specified when unwrapping + // a key. In the section describing the mechanisms, though, it's allowed + // for most unwrapping mechanisms. Netscape DOES does specify this + // attribute when unwrapping. + // + case CKA_VALUE_LEN: + if (mode == MODE_KEYGEN || mode == MODE_DERIVE) + return CKR_OK; + if (mode == MODE_UNWRAP) { + if (tokdata->nv_token_data->tweak_vector.netscape_mods == TRUE) + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + default: + return secret_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// generic_secret_check_exportability() +// +CK_BBOOL generic_secret_check_exportability(CK_ATTRIBUTE_TYPE type) +{ + switch (type) { + case CKA_VALUE: + return FALSE; + } + + return TRUE; +} + + +// +// +CK_RV generic_secret_wrap_get_data(TEMPLATE *tmpl, + CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *ptr = NULL; + CK_RV rc; + + + if (!tmpl || !data_len) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + + rc = template_attribute_find(tmpl, CKA_IBM_OPAQUE, &attr); + if (rc == FALSE) { + rc = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_NOT_WRAPPABLE)); + return CKR_KEY_NOT_WRAPPABLE; + } + } + *data_len = attr->ulValueLen; + + if (length_only == FALSE) { + ptr = (CK_BYTE *) malloc(attr->ulValueLen); + if (!ptr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + memcpy(ptr, attr->pValue, attr->ulValueLen); + + *data = ptr; + } + + return CKR_OK; +} + + +// +// +CK_RV generic_secret_unwrap(TEMPLATE *tmpl, + CK_BYTE *data, + CK_ULONG data_len, + CK_BBOOL fromend, CK_BBOOL isopaque) +{ + CK_ATTRIBUTE *attr = NULL; + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *value_len_attr = NULL; + CK_BYTE *ptr = NULL; + CK_ULONG rc, len = 0; + + + if (fromend == TRUE) + ptr = data + data_len; + else + ptr = data; + + // it's possible that the user specified CKA_VALUE_LEN in the + // template. if so, try to use it. by default, CKA_VALUE_LEN is 0 + // + rc = template_attribute_find(tmpl, CKA_VALUE_LEN, &attr); + if (rc) { + len = *(CK_ULONG *) attr->pValue; + if (len > data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + rc = CKR_ATTRIBUTE_VALUE_INVALID; + goto error; + } + + if (len != 0) + data_len = len; + } + + if (fromend == TRUE) + ptr -= data_len; + + if (isopaque) + rc = build_attribute(CKA_IBM_OPAQUE, ptr, data_len, &value_attr); + else + rc = build_attribute(CKA_VALUE, ptr, data_len, &value_attr); + + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto error; + } + if (data_len != len) { + rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE *) & data_len, + sizeof(CK_ULONG), &value_len_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto error; + } + } + + template_update_attribute(tmpl, value_attr); + + if (data_len != len) + template_update_attribute(tmpl, value_len_attr); + + return CKR_OK; + +error: + if (value_attr) + free(value_attr); + if (value_len_attr) + free(value_len_attr); + + return rc; +} + + +// rc2_check_required_attributes() +// +CK_RV rc2_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_VALUE_LEN, &attr); + if (!found) { + if (mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return secret_key_check_required_attributes(tmpl, mode); +} + + +// rc2_set_default_attributes() +// +CK_RV rc2_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *value_len_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + CK_ULONG len = 0L; + + secret_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + value_len_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG)); + + if (!type_attr || !value_attr || !value_len_attr) { + if (type_attr) + free(type_attr); + if (value_attr) + free(value_attr); + if (value_len_attr) + free(value_len_attr); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + + return CKR_HOST_MEMORY; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + value_len_attr->type = CKA_VALUE_LEN; + value_len_attr->ulValueLen = sizeof(CK_ULONG); + value_len_attr->pValue = (CK_BYTE *) value_len_attr + sizeof(CK_ATTRIBUTE); + *(CK_ULONG *) value_len_attr->pValue = len; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_RC2; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, value_attr); + template_update_attribute(tmpl, value_len_attr); + + return CKR_OK; +} + + +// rc2_validate_attribute() +// +CK_RV rc2_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_VALUE: + if (mode != MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + // rc2 key length <= 128 bytes + // + if (attr->ulValueLen > 128) + return CKR_ATTRIBUTE_VALUE_INVALID; + + return CKR_OK; + case CKA_VALUE_LEN: + { + CK_ULONG len; + + if (mode != MODE_KEYGEN && mode != MODE_DERIVE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + len = *(CK_ULONG *) attr->pValue; + if (len > 128) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + } + default: + return secret_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// rc4_set_default_attributes() +// +CK_RV rc4_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *value_len_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + CK_ULONG len = 0L; + + secret_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + value_len_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG)); + + if (!type_attr || !value_attr || !value_len_attr) { + if (type_attr) + free(type_attr); + if (value_attr) + free(value_attr); + if (value_len_attr) + free(value_len_attr); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + + return CKR_HOST_MEMORY; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + value_len_attr->type = CKA_VALUE_LEN; + value_len_attr->ulValueLen = sizeof(CK_ULONG); + value_len_attr->pValue = (CK_BYTE *) value_len_attr + sizeof(CK_ATTRIBUTE); + *(CK_ULONG *) value_len_attr->pValue = len; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_RC4; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, value_attr); + template_update_attribute(tmpl, value_len_attr); + + return CKR_OK; +} + + +// rc4_check_required_attributes() +// +CK_RV rc4_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_VALUE_LEN, &attr); + if (!found) { + if (mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return secret_key_check_required_attributes(tmpl, mode); +} + + +// rc4_validate_attribute() +// +CK_RV rc4_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_VALUE: + if (mode != MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + // key length <= 256 bytes + // + if (attr->ulValueLen > 256) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + case CKA_VALUE_LEN: + { + CK_ULONG len; + + if (mode != MODE_KEYGEN && mode != MODE_DERIVE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + len = *(CK_ULONG *) attr->pValue; + if (len > 255) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + } + default: + return secret_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// rc5_check_required_attributes() +// +CK_RV rc5_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_VALUE_LEN, &attr); + if (!found) { + if (mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return secret_key_check_required_attributes(tmpl, mode); +} + + +// rc5_set_default_attributes() +// +CK_RV rc5_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *value_len_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + CK_ULONG len = 0L; + + secret_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + value_len_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG)); + + if (!type_attr || !value_attr || !value_len_attr) { + if (type_attr) + free(type_attr); + if (value_attr) + free(value_attr); + if (value_len_attr) + free(value_len_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + value_len_attr->type = CKA_VALUE_LEN; + value_len_attr->ulValueLen = sizeof(CK_ULONG); + value_len_attr->pValue = (CK_BYTE *) value_len_attr + sizeof(CK_ATTRIBUTE); + *(CK_ULONG *) value_len_attr->pValue = len; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_RC5; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, value_attr); + template_update_attribute(tmpl, value_len_attr); + + return CKR_OK; +} + + +// rc5_validate_attribute() +// +CK_RV rc5_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_VALUE: + if (mode != MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + // key length <= 256 bytes + // + if (attr->ulValueLen > 255) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + case CKA_VALUE_LEN: + { + CK_ULONG len; + + if (mode != MODE_KEYGEN && mode != MODE_DERIVE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + len = *(CK_ULONG *) attr->pValue; + if (len > 255) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + } + default: + return secret_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// +// +CK_RV des_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return secret_key_check_required_attributes(tmpl, mode); +} + + +// +// +CK_BBOOL des_check_weak_key(CK_BYTE *key) +{ + CK_ULONG i; + + for (i = 0; i < des_weak_count; i++) { + if (memcmp(key, des_weak_keys[i], DES_KEY_SIZE) == 0) + return TRUE; + } + + for (i = 0; i < des_semi_weak_count; i++) { + if (memcmp(key, des_semi_weak_keys[i], DES_KEY_SIZE) == 0) + return TRUE; + } + + for (i = 0; i < des_possibly_weak_count; i++) { + if (memcmp(key, des_possibly_weak_keys[i], DES_KEY_SIZE) == 0) + return TRUE; + } + + return FALSE; +} + + + +// +// +CK_RV des_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + + if (mode) + value_attr = NULL; + + secret_key_set_default_attributes(tmpl, mode); + + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + + if (!value_attr || !type_attr) { + if (value_attr) + free(value_attr); + if (type_attr) + free(type_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_DES; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, value_attr); + + return CKR_OK; +} + + +// +// +CK_RV des_unwrap(STDLL_TokData_t *tokdata, + TEMPLATE *tmpl, + CK_BYTE *data, + CK_ULONG data_len, CK_BBOOL fromend, CK_BBOOL isopaque) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_BYTE *ptr = NULL; + CK_ULONG i; + + + if (data_len < DES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_WRAPPED_KEY_INVALID)); + return CKR_WRAPPED_KEY_INVALID; + } + if (fromend == TRUE) { + if (isopaque) + ptr = data + data_len; + else + ptr = data + data_len - DES_BLOCK_SIZE; + } else { + ptr = data; + } + + if (isopaque) { + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + data_len); + } else { + if (tokdata->nv_token_data->tweak_vector.check_des_parity == TRUE) { + for (i = 0; i < DES_KEY_SIZE; i++) { + if (parity_is_odd(ptr[i]) == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + } + } + value_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + DES_BLOCK_SIZE); + } + + if (!value_attr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + if (isopaque) { + value_attr->type = CKA_IBM_OPAQUE; + value_attr->ulValueLen = data_len; + value_attr->pValue = (CK_BYTE *) value_attr + sizeof(CK_ATTRIBUTE); + memcpy(value_attr->pValue, ptr, data_len); + } else { + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = DES_BLOCK_SIZE; + value_attr->pValue = (CK_BYTE *) value_attr + sizeof(CK_ATTRIBUTE); + memcpy(value_attr->pValue, ptr, DES_BLOCK_SIZE); + } + + template_update_attribute(tmpl, value_attr); + + return CKR_OK; +} + + +// des_validate_attribute() +// +CK_RV des_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + CK_BYTE *ptr = NULL; + CK_ULONG i; + + switch (attr->type) { + case CKA_VALUE: + // key length always 8 bytes + // + if (mode == MODE_CREATE) { + if (attr->ulValueLen != DES_KEY_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + if (tokdata->nv_token_data->tweak_vector.check_des_parity == TRUE) { + ptr = attr->pValue; + for (i = 0; i < DES_KEY_SIZE; i++) { + if (parity_is_odd(ptr[i]) == FALSE) { + TRACE_ERROR("%s\n", + ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + } + } + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + case CKA_VALUE_LEN: + // Cryptoki doesn't allow this but Netscape tries uses it + // + if (tokdata->nv_token_data->tweak_vector.netscape_mods == TRUE) { + if (mode == MODE_CREATE || mode == MODE_DERIVE || + mode == MODE_KEYGEN || mode == MODE_UNWRAP) { + CK_ULONG len = *(CK_ULONG *) attr->pValue; + if (len != DES_KEY_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + default: + return secret_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// +// +CK_RV des_wrap_get_data(TEMPLATE *tmpl, + CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *ptr = NULL; + CK_RV rc; + + + if (!tmpl || !data_len) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + + rc = template_attribute_find(tmpl, CKA_IBM_OPAQUE, &attr); + if (rc == FALSE) { + rc = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_NOT_WRAPPABLE)); + return CKR_KEY_NOT_WRAPPABLE; + } + } + *data_len = attr->ulValueLen; + + if (length_only == FALSE) { + ptr = (CK_BYTE *) malloc(attr->ulValueLen); + if (!ptr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + memcpy(ptr, attr->pValue, attr->ulValueLen); + + *data = ptr; + } + + return CKR_OK; +} + + +// des2_check_required_attributes() +// +CK_RV des2_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return secret_key_check_required_attributes(tmpl, mode); +} + + +// des2_set_default_attributes() +// +CK_RV des2_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + + if (mode) + value_attr = NULL; + + secret_key_set_default_attributes(tmpl, mode); + + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + + if (!value_attr || !type_attr) { + if (value_attr) + free(value_attr); + if (type_attr) + free(type_attr); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + + return CKR_HOST_MEMORY; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_DES2; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, value_attr); + + return CKR_OK; +} + + +// des2_validate_attribute() +// +CK_RV des2_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + CK_BYTE *ptr = NULL; + CK_ULONG i; + + switch (attr->type) { + case CKA_VALUE: + // key length always 16 bytes + // + if (mode == MODE_CREATE) { + if (attr->ulValueLen != (2 * DES_KEY_SIZE)) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + if (tokdata->nv_token_data->tweak_vector.check_des_parity == TRUE) { + ptr = attr->pValue; + for (i = 0; i < 2 * DES_KEY_SIZE; i++) { + if (parity_is_odd(ptr[i]) == FALSE) { + TRACE_ERROR("%s\n", + ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + } + } + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + case CKA_VALUE_LEN: + // Cryptoki doesn't allow this but Netscape tries uses it + // + if (tokdata->nv_token_data->tweak_vector.netscape_mods == TRUE) { + if (mode == MODE_CREATE || mode == MODE_DERIVE || + mode == MODE_KEYGEN || mode == MODE_UNWRAP) { + CK_ULONG len = *(CK_ULONG *) attr->pValue; + if (len != (2 * DES_KEY_SIZE)) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + default: + return secret_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// des3_check_required_attributes() +// +CK_RV des3_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return secret_key_check_required_attributes(tmpl, mode); +} + + +// des3_set_default_attributes() +// +CK_RV des3_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + + if (mode) + value_attr = NULL; + + secret_key_set_default_attributes(tmpl, mode); + + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + + if (!value_attr || !type_attr) { + if (value_attr) + free(value_attr); + if (type_attr) + free(type_attr); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + + return CKR_HOST_MEMORY; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_DES3; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, value_attr); + + return CKR_OK; +} + + +// +// +CK_RV des3_unwrap(STDLL_TokData_t *tokdata, + TEMPLATE *tmpl, + CK_BYTE *data, + CK_ULONG data_len, CK_BBOOL fromend, CK_BBOOL isopaque) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_BYTE *ptr = NULL; + CK_ULONG i; + + + if (data_len < 3 * DES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_WRAPPED_KEY_INVALID)); + return CKR_WRAPPED_KEY_INVALID; + } + if (fromend == TRUE) { + if (isopaque) + ptr = data + data_len; + else + ptr = data + data_len - (3 * DES_BLOCK_SIZE); + } else { + ptr = data; + } + + if (isopaque) { + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + data_len); + } else { + if (tokdata->nv_token_data->tweak_vector.check_des_parity == TRUE) { + for (i = 0; i < 3 * DES_KEY_SIZE; i++) { + if (parity_is_odd(ptr[i]) == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + } + } + value_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + + (3 * DES_BLOCK_SIZE)); + } + + if (!value_attr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + if (isopaque) { + value_attr->type = CKA_IBM_OPAQUE; + value_attr->ulValueLen = data_len; + value_attr->pValue = (CK_BYTE *) value_attr + sizeof(CK_ATTRIBUTE); + memcpy(value_attr->pValue, ptr, data_len); + } else { + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 3 * DES_BLOCK_SIZE; + value_attr->pValue = (CK_BYTE *) value_attr + sizeof(CK_ATTRIBUTE); + memcpy(value_attr->pValue, ptr, 3 * DES_BLOCK_SIZE); + } + + template_update_attribute(tmpl, value_attr); + + return CKR_OK; +} + + +// +// +CK_RV des3_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + CK_BYTE *ptr = NULL; + CK_ULONG i; + + switch (attr->type) { + case CKA_VALUE: + // key length always 24 bytes + // + if (mode == MODE_CREATE) { + if (attr->ulValueLen != (3 * DES_KEY_SIZE)) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + if (tokdata->nv_token_data->tweak_vector.check_des_parity == TRUE) { + ptr = attr->pValue; + for (i = 0; i < 3 * DES_KEY_SIZE; i++) { + if (parity_is_odd(ptr[i]) == FALSE) { + TRACE_ERROR("%s\n", + ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + } + } + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + case CKA_VALUE_LEN: + // Cryptoki doesn't allow this but Netscape tries uses it + // + if (tokdata->nv_token_data->tweak_vector.netscape_mods == TRUE) { + if (mode == MODE_CREATE || mode == MODE_DERIVE || + mode == MODE_KEYGEN || mode == MODE_UNWRAP) { + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + default: + return secret_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// +// +CK_RV des3_wrap_get_data(TEMPLATE *tmpl, + CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *ptr = NULL; + CK_RV rc; + + + if (!tmpl || !data_len) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + // try secure key first, if not found then try clear key... + rc = template_attribute_find(tmpl, CKA_IBM_OPAQUE, &attr); + if (rc == FALSE) { + rc = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_NOT_WRAPPABLE)); + return CKR_KEY_NOT_WRAPPABLE; + } + } + *data_len = attr->ulValueLen; + + if (length_only == FALSE) { + ptr = (CK_BYTE *) malloc(attr->ulValueLen); + if (!ptr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + memcpy(ptr, attr->pValue, attr->ulValueLen); + + *data = ptr; + } + + return CKR_OK; +} + + +// cast_check_required_attributes() +// +CK_RV cast_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_VALUE_LEN, &attr); + if (!found) { + if (mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return secret_key_check_required_attributes(tmpl, mode); +} + + +// cast_set_default_attributes() +// +CK_RV cast_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *value_len_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + CK_ULONG len = 0L; + + + secret_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + value_len_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG)); + + if (!type_attr || !value_attr || !value_len_attr) { + if (type_attr) + free(type_attr); + if (value_attr) + free(value_attr); + if (value_len_attr) + free(value_len_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + value_len_attr->type = CKA_VALUE_LEN; + value_len_attr->ulValueLen = sizeof(CK_ULONG); + value_len_attr->pValue = (CK_BYTE *) value_len_attr + sizeof(CK_ATTRIBUTE); + *(CK_ULONG *) value_len_attr->pValue = len; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_CAST; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, value_attr); + template_update_attribute(tmpl, value_len_attr); + + return CKR_OK; +} + + +// cast_validate_attribute() +// +CK_RV cast_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + CK_ULONG len; + + switch (attr->type) { + case CKA_VALUE: + if (mode != MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + if (attr->ulValueLen > 8 || attr->ulValueLen < 1) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + case CKA_VALUE_LEN: + if (mode != MODE_KEYGEN && mode != MODE_DERIVE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + len = *(CK_ULONG *) attr->pValue; + if (len > 8 || len < 1) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + default: + return secret_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// cast3_check_required_attributes() +// +CK_RV cast3_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + found = template_attribute_find(tmpl, CKA_VALUE_LEN, &attr); + if (!found) { + if (mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return secret_key_check_required_attributes(tmpl, mode); +} + + +// cast3_set_default_attributes() +// +CK_RV cast3_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *value_len_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + CK_ULONG len = 0L; + + if (mode) + value_attr = NULL; + + secret_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + value_len_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG)); + + if (!type_attr || !value_attr || !value_len_attr) { + if (type_attr) + free(type_attr); + if (value_attr) + free(value_attr); + if (value_len_attr) + free(value_len_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + value_len_attr->type = CKA_VALUE_LEN; + value_len_attr->ulValueLen = sizeof(CK_ULONG); + value_len_attr->pValue = (CK_BYTE *) value_len_attr + sizeof(CK_ATTRIBUTE); + *(CK_ULONG *) value_len_attr->pValue = len; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_CAST3; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, value_attr); + template_update_attribute(tmpl, value_len_attr); + + return CKR_OK; +} + + +// cast3_validate_attribute() +// +CK_RV cast3_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + CK_ULONG len; + + switch (attr->type) { + case CKA_VALUE: + if (mode != MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + if (attr->ulValueLen > 8 || attr->ulValueLen < 1) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + case CKA_VALUE_LEN: + if (mode != MODE_KEYGEN && mode != MODE_DERIVE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + len = *(CK_ULONG *) attr->pValue; + if (len > 8 || len < 1) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + default: + return secret_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// cast5_check_required_attributes() +// +CK_RV cast5_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + found = template_attribute_find(tmpl, CKA_VALUE_LEN, &attr); + if (!found) { + if (mode == MODE_KEYGEN) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return secret_key_check_required_attributes(tmpl, mode); +} + + +// cast5_set_default_attributes() +// +CK_RV cast5_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *value_len_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + CK_ULONG len = 0L; + + secret_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + value_len_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG)); + + if (!type_attr || !value_attr || !value_len_attr) { + if (type_attr) + free(type_attr); + if (value_attr) + free(value_attr); + if (value_len_attr) + free(value_len_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + value_len_attr->type = CKA_VALUE_LEN; + value_len_attr->ulValueLen = sizeof(CK_ULONG); + value_len_attr->pValue = (CK_BYTE *) value_len_attr + sizeof(CK_ATTRIBUTE); + *(CK_ULONG *) value_len_attr->pValue = len; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_CAST5; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, value_attr); + template_update_attribute(tmpl, value_len_attr); + + return CKR_OK; +} + + +// cast5_validate_attribute() +// +CK_RV cast5_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + CK_ULONG len; + + switch (attr->type) { + case CKA_VALUE: + if (mode != MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + if (attr->ulValueLen > 16 || attr->ulValueLen < 1) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + case CKA_VALUE_LEN: + if (mode != MODE_KEYGEN && mode != MODE_DERIVE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + len = *(CK_ULONG *) attr->pValue; + if (len < 1 || len > 16) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + default: + return secret_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// idea_check_required_attributes() +// +CK_RV idea_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return secret_key_check_required_attributes(tmpl, mode); +} + + +// idea_set_default_attributes() +// +CK_RV idea_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + + if (mode) + value_attr = NULL; + + secret_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + if (!type_attr || !value_attr) { + if (type_attr) + free(type_attr); + if (value_attr) + free(value_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_IDEA; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, value_attr); + + return CKR_OK; +} + + +// idea_validate_attribute() +// +CK_RV idea_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_VALUE: + if (mode != MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + if (attr->ulValueLen != 16) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + default: + return secret_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// cdmf_check_required_attributes() +// +CK_RV cdmf_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return secret_key_check_required_attributes(tmpl, mode); +} + + +#if !(NOCDMF) +// cdmf_set_default_attributes() +// +CK_RV cdmf_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + + if (mode) + value_attr = NULL; + + secret_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + + if (!type_attr || !value_attr) { + if (type_attr) + free(type_attr); + if (value_attr) + free(value_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_CDMF; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, value_attr); + + return CKR_OK; +} + + +// cdmf_validate_attribute() +// +CK_RV cdmf_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + CK_ULONG len; + + switch (attr->type) { + case CKA_VALUE: +#if 0 + CDMF_Transform_Args args; +#endif + CK_ULONG req_len, repl_len; + CK_BYTE cdmf_key[DES_KEY_SIZE]; + CK_RV rc; + + if (mode != MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + if (attr->ulValueLen != DES_KEY_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } +#if 0 + req_len = sizeof(args); + repl_len = DES_KEY_SIZE; + + memcpy(args.des_key, attr->pValue, DES_KEY_SIZE); + + rc = communicate(PK_CDMF_TRANSFORM_KEY, + &args, req_len, cdmf_key, &repl_len, NULL, 0, NULL, 0); + + if (rc != CKR_OK) + return rc; + + if (rc == CKR_OK) { + if (repl_len != DES_KEY_SIZE) + return CKR_GENERAL_ERROR; + + memcpy(attr->pValue, cdmf_key, DES_KEY_SIZE); + } + + return CKR_OK; +#else + return tok_cdmf_transform(attr->pValue, DES_KEY_SIZE); +#endif + case CKA_VALUE_LEN: + if (tokdata->nv_token_data->tweak_vector.netscape_mods == TRUE) { + if (mode == MODE_CREATE || mode == MODE_KEYGEN) { + len = *(CK_ULONG *) attr->pValue; + if (len != DES_KEY_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + default: + return secret_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + +#endif + +// skipjack_check_required_attributes() +// +CK_RV skipjack_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return secret_key_check_required_attributes(tmpl, mode); +} + + +// skipjack_set_default_attributes() +// +CK_RV skipjack_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + + if (mode) + value_attr = NULL; + + secret_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + + if (!type_attr || !value_attr) { + if (type_attr) + free(type_attr); + if (value_attr) + free(value_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_SKIPJACK; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, value_attr); + + return CKR_OK; +} + + +// skipjack_validate_attribute() +// +CK_RV skipjack_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_VALUE: + if (mode != MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + if (attr->ulValueLen != 20) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + default: + return secret_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// baton_check_required_attributes() +// +CK_RV baton_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return secret_key_check_required_attributes(tmpl, mode); +} + + +// baton_set_default_attributes() +// +CK_RV baton_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + + if (mode) + value_attr = NULL; + + secret_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + + if (!type_attr || !value_attr) { + if (type_attr) + free(type_attr); + if (value_attr) + free(value_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_BATON; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, value_attr); + + return CKR_OK; +} + + +// baton_validate_attribute() +// +CK_RV baton_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_VALUE: + if (mode != MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + if (attr->ulValueLen != 40) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + default: + return secret_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// juniper_check_required_attributes() +// +CK_RV juniper_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return secret_key_check_required_attributes(tmpl, mode); +} + + +// juniper_set_default_attributes() +// +CK_RV juniper_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + + if (mode) + value_attr = NULL; + + secret_key_set_default_attributes(tmpl, mode); + + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + + if (!type_attr || !value_attr) { + if (type_attr) + free(type_attr); + if (value_attr) + free(value_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_JUNIPER; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, value_attr); + + return CKR_OK; +} + + +// juniper_validate_attribute() +// +CK_RV juniper_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + switch (attr->type) { + case CKA_VALUE: + if (mode != MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + } + if (attr->ulValueLen != 40) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + default: + return secret_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// aes_set_default_attributes() +// +CK_RV aes_set_default_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *type_attr = NULL; + + if (mode) + value_attr = NULL; + + secret_key_set_default_attributes(tmpl, mode); + + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE)); + type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + + if (!value_attr || !type_attr) { + if (value_attr) + free(value_attr); + if (type_attr) + free(type_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 0; + value_attr->pValue = NULL; + + type_attr->type = CKA_KEY_TYPE; + type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + type_attr->pValue = (CK_BYTE *) type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) type_attr->pValue = CKK_AES; + + template_update_attribute(tmpl, type_attr); + template_update_attribute(tmpl, value_attr); + + return CKR_OK; +} + +// aes_check_required_attributes() +// +CK_RV aes_check_required_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (!found) { + if (mode == MODE_CREATE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + } + + return secret_key_check_required_attributes(tmpl, mode); +} + +// +// +CK_RV aes_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG mode) +{ + CK_ULONG val; + + switch (attr->type) { + case CKA_VALUE: + // key length is either 16, 24 or 32 bytes + // + if (mode == MODE_CREATE) { + if (attr->ulValueLen != AES_KEY_SIZE_128 && + attr->ulValueLen != AES_KEY_SIZE_192 && + attr->ulValueLen != AES_KEY_SIZE_256) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_ATTRIBUTE_READ_ONLY; + case CKA_VALUE_LEN: + if (mode == MODE_CREATE || mode == MODE_DERIVE || + mode == MODE_KEYGEN || mode == MODE_UNWRAP) { + val = *(CK_ULONG *) attr->pValue; + if (val != AES_KEY_SIZE_128 && + val != AES_KEY_SIZE_192 && val != AES_KEY_SIZE_256) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + return CKR_TEMPLATE_INCONSISTENT; + } + return CKR_OK; + } + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + default: + return secret_key_validate_attribute(tokdata, tmpl, attr, mode); + } +} + + +// +// +CK_RV aes_wrap_get_data(TEMPLATE *tmpl, + CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *ptr = NULL; + CK_RV rc; + + + if (!tmpl || !data_len) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + + rc = template_attribute_find(tmpl, CKA_IBM_OPAQUE, &attr); + if (rc == FALSE) { + rc = template_attribute_find(tmpl, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_NOT_WRAPPABLE)); + return CKR_KEY_NOT_WRAPPABLE; + } + } + *data_len = attr->ulValueLen; + + if (length_only == FALSE) { + ptr = (CK_BYTE *) malloc(attr->ulValueLen); + if (!ptr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + memcpy(ptr, attr->pValue, attr->ulValueLen); + + *data = ptr; + } + + return CKR_OK; +} + +// +// +CK_RV aes_unwrap(STDLL_TokData_t *tokdata, + TEMPLATE *tmpl, + CK_BYTE *data, + CK_ULONG data_len, CK_BBOOL fromend, CK_BBOOL isopaque) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *val_len_attr = NULL; + CK_BYTE *ptr = NULL; + CK_ULONG key_size; + CK_BBOOL found = FALSE; + + UNUSED(tokdata); + + /* accept CKA_VALUE_LEN. pkcs11v2.20 doesn't want this attribute when + * unwrapping an AES key, but we need it for several reasons: + * - because some mechanisms may have added padding + * - AES keys come in several sizes + * - secure key size depends on token specifics + * If not a secure key, try datalen and see if matches an aes key size. + * Otherwise, fail because we need to return CKA_VALUE_LEN and we cannot + * unless user tells us what it is for secure key. + * + * Note: since cca token has secure key size of 64, which is a multiple of + * aes blocksize, can assume datalen will always be 64. + * However, a better solution is to create a token specific wrap and + * unwrap and do this kind of stuff in the token. + */ + found = template_attribute_find(tmpl, CKA_VALUE_LEN, &val_len_attr); + if (found) { + key_size = *(CK_ULONG *) val_len_attr->pValue; + } else { + if (isopaque) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } else { + key_size = data_len; + } + } + + /* key_size should be one of AES's possible sizes */ + if (key_size != AES_KEY_SIZE_128 && + key_size != AES_KEY_SIZE_192 && key_size != AES_KEY_SIZE_256) { + TRACE_ERROR("%s\n", ock_err(ERR_WRAPPED_KEY_LEN_RANGE)); + return CKR_WRAPPED_KEY_LEN_RANGE; + } + + if (fromend == TRUE) { + if (isopaque) + ptr = data + data_len; + else + ptr = data + data_len - key_size; + } else { + ptr = data; + } + + /* reset key_size for secure key, assuming datalen is the token's secure key + * size */ + if (isopaque) + key_size = data_len; + + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + key_size); + + if (!value_attr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + if (isopaque) + value_attr->type = CKA_IBM_OPAQUE; + else + value_attr->type = CKA_VALUE; + + value_attr->ulValueLen = key_size; + value_attr->pValue = (CK_BYTE *) value_attr + sizeof(CK_ATTRIBUTE); + memcpy(value_attr->pValue, ptr, key_size); + + template_update_attribute(tmpl, value_attr); + + + /* pkcs11v2-20: CKA_VALUE and CKA_VALUE_LEN given for aes key object. */ + if (!found) { + val_len_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG)); + if (!val_len_attr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + val_len_attr->type = CKA_VALUE_LEN; + val_len_attr->ulValueLen = sizeof(CK_ULONG); + val_len_attr->pValue = (CK_BYTE *) val_len_attr + sizeof(CK_ATTRIBUTE); + *((CK_ULONG *) val_len_attr->pValue) = key_size; + + template_update_attribute(tmpl, val_len_attr); + } + + return CKR_OK; +} diff --git a/usr/lib/common/key_mgr.c b/usr/lib/common/key_mgr.c new file mode 100644 index 0000000..9ed6bcb --- /dev/null +++ b/usr/lib/common/key_mgr.c @@ -0,0 +1,1189 @@ +/* + * 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 + */ + +/*************************************************************************** + Change Log + ========== + 4/25/03 Kapil Sood (kapil@corrent.com) + Added DH key pair generation and DH shared key derivation + functions. + + + +****************************************************************************/ + + +// File: key_mgr.c +// + +#include +#include + +#include // for memcmp() et al + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "trace.h" + +#include + +static CK_BBOOL true = TRUE, false = FALSE; + +// +// +CK_RV key_mgr_generate_key(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_MECHANISM *mech, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, CK_OBJECT_HANDLE *handle) +{ + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_ATTRIBUTE *new_attr = NULL; + CK_ULONG i, keyclass, subclass = 0; + CK_BBOOL flag; + CK_RV rc; + + + if (!sess || !mech || !handle) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (!pTemplate && (ulCount != 0)) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // it's silly but Cryptoki allows the user to specify the CKA_CLASS + // in the template. so we have to iterate through the provided template + // and make sure that if CKA_CLASS is CKO_SECRET_KEY, if it is present. + // + // it would have been more logical for Cryptoki to forbid specifying + // the CKA_CLASS attribute when generating a key + // + for (i = 0; i < ulCount; i++) { + if (pTemplate[i].type == CKA_CLASS) { + keyclass = *(CK_OBJECT_CLASS *) pTemplate[i].pValue; + if (keyclass != CKO_SECRET_KEY) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + } + } + + if (pTemplate[i].type == CKA_KEY_TYPE) + subclass = *(CK_ULONG *) pTemplate[i].pValue; + } + + + switch (mech->mechanism) { + case CKM_DES_KEY_GEN: + if (subclass != 0 && subclass != CKK_DES) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + } + + subclass = CKK_DES; + break; + case CKM_DES3_KEY_GEN: + if (subclass != 0 && subclass != CKK_DES3) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + } + + subclass = CKK_DES3; + break; +#if !(NOCDMF) + case CKM_CDMF_KEY_GEN: + if (subclass != 0 && subclass != CKK_CDMF) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + } + + subclass = CKK_CDMF; + break; +#endif + case CKM_SSL3_PRE_MASTER_KEY_GEN: + if (subclass != 0 && subclass != CKK_GENERIC_SECRET) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + } + if (mech->ulParameterLen != sizeof(CK_VERSION)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + + subclass = CKK_GENERIC_SECRET; + break; + case CKM_AES_KEY_GEN: + if (subclass != 0 && subclass != CKK_AES) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + } + + subclass = CKK_AES; + break; + case CKM_GENERIC_SECRET_KEY_GEN: + if (subclass != 0 && subclass != CKK_GENERIC_SECRET) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + } + + subclass = CKK_GENERIC_SECRET; + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + + rc = object_mgr_create_skel(tokdata, sess, + pTemplate, ulCount, + MODE_KEYGEN, + CKO_SECRET_KEY, subclass, &key_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_create_skel failed.\n"); + goto error; + } + // at this point, 'key_obj' should contain a skeleton key. depending on + // the key type, we may need to extract one or more attributes from + // the object prior to generating the key data (ie. variable key length) + // + + switch (mech->mechanism) { + case CKM_DES_KEY_GEN: + rc = ckm_des_key_gen(tokdata, key_obj->template); + break; + case CKM_DES3_KEY_GEN: + rc = ckm_des3_key_gen(tokdata, key_obj->template); + break; +#if !(NOCDMF) + case CKM_CDMF_KEY_GEN: + rc = ckm_cdmf_key_gen(tokdata, key_obj->template); + break; +#endif + case CKM_SSL3_PRE_MASTER_KEY_GEN: + rc = ckm_ssl3_pre_master_key_gen(tokdata, key_obj->template, mech); + break; +#ifndef NOAES + case CKM_AES_KEY_GEN: + rc = ckm_aes_key_gen(tokdata, key_obj->template); + break; +#endif + case CKM_GENERIC_SECRET_KEY_GEN: + rc = ckm_generic_secret_key_gen(tokdata, key_obj->template); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + } + + if (rc != CKR_OK) { + TRACE_ERROR("Key generation failed.\n"); + goto error; + } + // we can now set CKA_ALWAYS_SENSITIVE and CKA_NEVER_EXTRACTABLE + // to their appropriate values. this only applies to CKO_SECRET_KEY + // and CKO_PRIVATE_KEY objects + // + flag = template_attribute_find(key_obj->template, CKA_SENSITIVE, &attr); + if (flag == TRUE) { + flag = *(CK_BBOOL *) attr->pValue; + + rc = build_attribute(CKA_ALWAYS_SENSITIVE, &flag, sizeof(CK_BBOOL), + &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build attribute failed.\n"); + goto error; + } + template_update_attribute(key_obj->template, new_attr); + + } else { + rc = CKR_FUNCTION_FAILED; + TRACE_ERROR("Failed to find CKA_SENSITIVE in key object template.\n"); + goto error; + } + + + flag = template_attribute_find(key_obj->template, CKA_EXTRACTABLE, &attr); + if (flag == TRUE) { + flag = *(CK_BBOOL *) attr->pValue; + + rc = build_attribute(CKA_NEVER_EXTRACTABLE, &true, sizeof(CK_BBOOL), + &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto error; + } + if (flag == TRUE) + *(CK_BBOOL *) new_attr->pValue = FALSE; + + template_update_attribute(key_obj->template, new_attr); + + } else { + rc = CKR_FUNCTION_FAILED; + TRACE_ERROR("Failed to find CKA_EXTRACTABLE in key object template.\n"); + goto error; + } + + /* add/update CKA_LOCAL with value true to the template */ + rc = build_attribute(CKA_LOCAL, &true, sizeof(CK_BBOOL), &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto error; + } + template_update_attribute(key_obj->template, new_attr); + + // at this point, the key should be fully constructed...assign + // an object handle and store the key + // + rc = object_mgr_create_final(tokdata, sess, key_obj, handle); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_create_final failed.\n"); + goto error; + } + + return rc; + +error: + if (key_obj) + object_free(key_obj); + + *handle = 0; + + return rc; +} + + +// +// +CK_RV key_mgr_generate_key_pair(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_MECHANISM *mech, + CK_ATTRIBUTE *publ_tmpl, + CK_ULONG publ_count, + CK_ATTRIBUTE *priv_tmpl, + CK_ULONG priv_count, + CK_OBJECT_HANDLE *publ_key_handle, + CK_OBJECT_HANDLE *priv_key_handle) +{ + OBJECT *publ_key_obj = NULL; + OBJECT *priv_key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_ATTRIBUTE *new_attr = NULL; + CK_ULONG i, keyclass, subclass = 0; + CK_BBOOL flag; + CK_RV rc; + + if (!sess || !mech || !publ_key_handle || !priv_key_handle) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (!publ_tmpl && (publ_count != 0)) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (!priv_tmpl && (priv_count != 0)) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // it's silly but Cryptoki allows the user to specify the CKA_CLASS + // in the template. so we have to iterate through the provided template + // and make sure that if CKA_CLASS is valid, if it is present. + // + // it would have been more logical for Cryptoki to forbid specifying + // the CKA_CLASS attribute when generating a key + // + for (i = 0; i < publ_count; i++) { + if (publ_tmpl[i].type == CKA_CLASS) { + keyclass = *(CK_OBJECT_CLASS *) publ_tmpl[i].pValue; + if (keyclass != CKO_PUBLIC_KEY) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + } + } + + if (publ_tmpl[i].type == CKA_KEY_TYPE) + subclass = *(CK_ULONG *) publ_tmpl[i].pValue; + } + + + for (i = 0; i < priv_count; i++) { + if (priv_tmpl[i].type == CKA_CLASS) { + keyclass = *(CK_OBJECT_CLASS *) priv_tmpl[i].pValue; + if (keyclass != CKO_PRIVATE_KEY) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + } + } + + if (priv_tmpl[i].type == CKA_KEY_TYPE) { + CK_ULONG temp = *(CK_ULONG *) priv_tmpl[i].pValue; + if (temp != subclass) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + } + } + } + + + switch (mech->mechanism) { + case CKM_RSA_PKCS_KEY_PAIR_GEN: + if (subclass != 0 && subclass != CKK_RSA) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + } + + subclass = CKK_RSA; + break; + case CKM_EC_KEY_PAIR_GEN: + if (subclass != 0 && subclass != CKK_EC) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + } + + subclass = CKK_EC; + break; +#if !(NODSA) + case CKM_DSA_KEY_PAIR_GEN: + if (subclass != 0 && subclass != CKK_DSA) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + } + subclass = CKK_DSA; + break; +#endif +/* Begin code contributed by Corrent corp. */ +#if !(NODH) + case CKM_DH_PKCS_KEY_PAIR_GEN: + if (subclass != 0 && subclass != CKK_DH) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + } + subclass = CKK_DH; + break; +#endif +/* End code contributed by Corrent corp. */ + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + + rc = object_mgr_create_skel(tokdata, sess, + publ_tmpl, publ_count, + MODE_KEYGEN, + CKO_PUBLIC_KEY, subclass, &publ_key_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_create_skel failed.\n"); + goto error; + } + rc = object_mgr_create_skel(tokdata, sess, + priv_tmpl, priv_count, + MODE_KEYGEN, + CKO_PRIVATE_KEY, subclass, &priv_key_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_create_skel failed.\n"); + goto error; + } + // at this point, 'key_obj' should contain a skeleton key. depending on + // the key type, we may need to extract one or more attributes from + // the object prior to generating the key data (ie. variable key length) + // + + switch (mech->mechanism) { + case CKM_RSA_PKCS_KEY_PAIR_GEN: + rc = ckm_rsa_key_pair_gen(tokdata, publ_key_obj->template, + priv_key_obj->template); + break; + case CKM_EC_KEY_PAIR_GEN: + rc = ckm_ec_key_pair_gen(tokdata, publ_key_obj->template, + priv_key_obj->template); + break; +#if !(NODSA) + case CKM_DSA_KEY_PAIR_GEN: + rc = ckm_dsa_key_pair_gen(tokdata, publ_key_obj->template, + priv_key_obj->template); + break; +#endif + +/* Begin code contributed by Corrent corp. */ +#if !(NODH) + case CKM_DH_PKCS_KEY_PAIR_GEN: + rc = ckm_dh_pkcs_key_pair_gen(tokdata, publ_key_obj->template, + priv_key_obj->template); + break; +#endif +/* End code contributed by Corrent corp. */ + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + break; + } + + if (rc != CKR_OK) { + TRACE_DEVEL("Key Generation failed.\n"); + goto error; + } + // we can now set CKA_ALWAYS_SENSITIVE and CKA_NEVER_EXTRACTABLE + // to their appropriate values. this only applies to CKO_SECRET_KEY + // and CKO_PRIVATE_KEY objects + // + flag = + template_attribute_find(priv_key_obj->template, CKA_SENSITIVE, &attr); + if (flag == TRUE) { + flag = *(CK_BBOOL *) attr->pValue; + + rc = build_attribute(CKA_ALWAYS_SENSITIVE, &flag, sizeof(CK_BBOOL), + &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed.\n"); + goto error; + } + template_update_attribute(priv_key_obj->template, new_attr); + + } else { + TRACE_ERROR("Failed to find CKA_SENSITIVE in key object template.\n"); + rc = CKR_FUNCTION_FAILED; + goto error; + } + + + flag = + template_attribute_find(priv_key_obj->template, CKA_EXTRACTABLE, &attr); + if (flag == TRUE) { + flag = *(CK_BBOOL *) attr->pValue; + + rc = build_attribute(CKA_NEVER_EXTRACTABLE, &true, sizeof(CK_BBOOL), + &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed.\n"); + goto error; + } + if (flag == TRUE) + *(CK_BBOOL *) new_attr->pValue = false; + + template_update_attribute(priv_key_obj->template, new_attr); + + } else { + TRACE_ERROR("Failed to find CKA_EXTRACTABLE in key object template.\n"); + rc = CKR_FUNCTION_FAILED; + goto error; + } + + /* add/update CKA_LOCAL with value true to the keypair templates */ + rc = build_attribute(CKA_LOCAL, &true, sizeof(CK_BBOOL), &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto error; + } + template_update_attribute(publ_key_obj->template, new_attr); + rc = build_attribute(CKA_LOCAL, &true, sizeof(CK_BBOOL), &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto error; + } + template_update_attribute(priv_key_obj->template, new_attr); + + // at this point, the keys should be fully constructed...assign + // object handles and store the keys + // + rc = object_mgr_create_final(tokdata, sess, publ_key_obj, publ_key_handle); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_create_final failed.\n"); + goto error; + } + rc = object_mgr_create_final(tokdata, sess, priv_key_obj, priv_key_handle); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_create_final failed.\n"); + object_mgr_destroy_object(tokdata, sess, *publ_key_handle); + publ_key_obj = NULL; + goto error; + } + + return rc; + +error: + if (publ_key_obj) + object_free(publ_key_obj); + if (priv_key_obj) + object_free(priv_key_obj); + + *publ_key_handle = 0; + *priv_key_handle = 0; + + return rc; +} + + +// +// +CK_RV key_mgr_wrap_key(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + CK_MECHANISM *mech, + CK_OBJECT_HANDLE h_wrapping_key, + CK_OBJECT_HANDLE h_key, + CK_BYTE *wrapped_key, CK_ULONG *wrapped_key_len) +{ + ENCR_DECR_CONTEXT *ctx = NULL; + OBJECT *key1_obj = NULL; + OBJECT *key2_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *data = NULL; + CK_ULONG data_len; + CK_OBJECT_CLASS class; + CK_KEY_TYPE keytype; + CK_BBOOL flag; + CK_RV rc; + + + if (!sess || !wrapped_key_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + rc = object_mgr_find_in_map1(tokdata, h_wrapping_key, &key1_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("%s\n", ock_err(ERR_WRAPPING_KEY_HANDLE_INVALID)); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_WRAPPING_KEY_HANDLE_INVALID; + + return rc; + } + + object_put(tokdata, key1_obj, TRUE); + key1_obj = NULL; + + rc = object_mgr_find_in_map1(tokdata, h_key, &key2_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + + return rc; + } + // is the key-to-be-wrapped EXTRACTABLE? + // + rc = template_attribute_find(key2_obj->template, CKA_EXTRACTABLE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Failed to find CKA_EXTRACTABLE in key template.\n"); + // could happen if user tries to wrap a public key + rc = CKR_KEY_NOT_WRAPPABLE; + goto done; + } else { + flag = *(CK_BBOOL *) attr->pValue; + if (flag == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_UNEXTRACTABLE)); + rc = CKR_KEY_UNEXTRACTABLE; + goto done; + } + } + + // what kind of key are we trying to wrap? make sure the mechanism is + // allowed to wrap this kind of key + // + rc = template_attribute_find(key2_obj->template, CKA_CLASS, &attr); + if (rc == FALSE) { + TRACE_DEVEL("CKA_CLASS is missing for key to be wrapped.\n"); + rc = CKR_KEY_NOT_WRAPPABLE; + goto done; + } else { + class = *(CK_OBJECT_CLASS *) attr->pValue; + } + + // pkcs11v2-20rc3, page 178 + // C_WrapKey can be used in following situations: + // - To wrap any secret key with a public key that supports encryption + // and decryption. + // - To wrap any secret key with any other secret key. Consideration + // must be given to key size and mechanism strength or the token may + // not allow the operation. + // - To wrap a private key with any secret key. + // + // These can be deduced to: + // A public key or a secret key can be used to wrap a secret key. + // A secret key can be used to wrap a private key. + + switch (mech->mechanism) { +#if !(NOCDMF) + case CKM_CDMF_CBC: + case CKM_CDMF_CBC_PAD: +#endif + case CKM_DES_CBC: + case CKM_DES3_ECB: + case CKM_DES3_CBC: + case CKM_AES_CTR: + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC_PAD: + case CKM_AES_CBC_PAD: + case CKM_AES_OFB: + case CKM_AES_CFB8: + case CKM_AES_CFB64: + case CKM_AES_CFB128: + if ((class != CKO_SECRET_KEY) && (class != CKO_PRIVATE_KEY)) { + TRACE_ERROR + ("Specified mechanism only wraps secret & private keys.\n"); + rc = CKR_KEY_NOT_WRAPPABLE; + goto done; + } + break; + case CKM_CDMF_ECB: + case CKM_DES_ECB: + case CKM_AES_ECB: + case CKM_AES_CBC: + case CKM_RSA_PKCS_OAEP: + case CKM_RSA_PKCS: + case CKM_RSA_X_509: + if (class != CKO_SECRET_KEY) { + TRACE_ERROR("Specified mechanism only wraps secret keys.\n"); + rc = CKR_KEY_NOT_WRAPPABLE; + goto done; + } + break; + default: + TRACE_ERROR("The mechanism does not support wrapping keys.\n"); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + + // extract the secret data to be wrapped + // + rc = template_attribute_find(key2_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Failed to find CKA_KEY_TYPE in key template.\n"); + rc = CKR_KEY_NOT_WRAPPABLE; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + } + + switch (keytype) { +#if !(NOCDMF) + case CKK_CDMF: +#endif + case CKK_DES: + rc = des_wrap_get_data(key2_obj->template, length_only, &data, + &data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("des_wrap_get_data failed.\n"); + goto done; + } + break; + case CKK_DES3: + rc = des3_wrap_get_data(key2_obj->template, length_only, &data, + &data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("des3_wrap_get_data failed.\n"); + goto done; + } + break; + case CKK_RSA: + rc = rsa_priv_wrap_get_data(key2_obj->template, length_only, &data, + &data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("rsa_priv_wrap_get_data failed.\n"); + goto done; + } + break; +#if !(NODSA) + case CKK_DSA: + rc = dsa_priv_wrap_get_data(key2_obj->template, length_only, &data, + &data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("dsa_priv_wrap_get_data failed.\n"); + goto done; + } + break; +#endif + case CKK_GENERIC_SECRET: + rc = generic_secret_wrap_get_data(key2_obj->template, length_only, + &data, &data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("generic_secret_wrap_get_data failed.\n"); + goto done; + } + break; +#ifndef NOAES + case CKK_AES: + rc = aes_wrap_get_data(key2_obj->template, length_only, &data, + &data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("aes_wrap_get_data failed.\n"); + goto done; + } + break; +#endif + case CKK_EC: + rc = ecdsa_priv_wrap_get_data(key2_obj->template, length_only, &data, + &data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ecdsa_priv_wrap_get_data failed with rc=%s.\n", + ock_err(rc)); + goto done; + } + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_KEY_NOT_WRAPPABLE)); + rc = CKR_KEY_NOT_WRAPPABLE; + goto done; + } + + // we might need to format the wrapped data based on the mechanism + // + switch (mech->mechanism) { +#if !(NOCMF) + case CKM_CDMF_ECB: + case CKM_CDMF_CBC: +#endif + case CKM_DES_ECB: + case CKM_DES_CBC: + case CKM_DES3_ECB: + case CKM_DES3_CBC: + rc = ckm_des_wrap_format(tokdata, length_only, &data, &data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ckm_des_wrap_format failed.\n"); + if (data) { + OPENSSL_cleanse(data, data_len); + free(data); + } + goto done; + } + break; +#ifndef NOAES + case CKM_AES_ECB: + case CKM_AES_CBC: + case CKM_AES_CTR: + case CKM_AES_OFB: + case CKM_AES_CFB8: + case CKM_AES_CFB64: + case CKM_AES_CFB128: + rc = ckm_aes_wrap_format(tokdata, length_only, &data, &data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ckm_aes_wrap_format failed.\n"); + if (data) { + OPENSSL_cleanse(data, data_len); + free(data); + } + goto done; + } + break; +#endif +#if !(NOCMF) + case CKM_CDMF_CBC_PAD: +#endif + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC_PAD: + case CKM_AES_CBC_PAD: + // these mechanisms pad themselves + // + break; + + case CKM_RSA_PKCS_OAEP: + case CKM_RSA_PKCS: + case CKM_RSA_X_509: + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + if (data) { + OPENSSL_cleanse(data, data_len); + free(data); + } + rc = CKR_MECHANISM_INVALID; + goto done; + } + + ctx = (ENCR_DECR_CONTEXT *) malloc(sizeof(ENCR_DECR_CONTEXT)); + if (!ctx) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + if (data) { + OPENSSL_cleanse(data, data_len); + free(data); + } + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx, 0x0, sizeof(ENCR_DECR_CONTEXT)); + + // prepare to do the encryption + // + rc = encr_mgr_init(tokdata, sess, ctx, OP_WRAP, mech, h_wrapping_key); + if (rc != CKR_OK) { + TRACE_DEVEL("encr_mgr_init failed.\n"); + free(ctx); + if (data) { + OPENSSL_cleanse(data, data_len); + free(data); + } + goto done; + } + // do the encryption and clean up. at this point, 'value' may or may not + // be NULL depending on 'length_only' + // + rc = encr_mgr_encrypt(tokdata, sess, length_only, + ctx, data, data_len, wrapped_key, wrapped_key_len); + if (data != NULL) { + OPENSSL_cleanse(data, data_len); + free(data); + } + encr_mgr_cleanup(ctx); + free(ctx); + +done: + object_put(tokdata, key2_obj, TRUE); + key2_obj = NULL; + + return rc; +} + + +// +// +CK_RV key_mgr_unwrap_key(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_MECHANISM *mech, + CK_ATTRIBUTE *attributes, + CK_ULONG attrib_count, + CK_BYTE *wrapped_key, + CK_ULONG wrapped_key_len, + CK_OBJECT_HANDLE h_unwrapping_key, + CK_OBJECT_HANDLE *h_unwrapped_key) +{ + ENCR_DECR_CONTEXT *ctx = NULL; + OBJECT *key_obj = NULL, *tmp_obj = NULL; + CK_BYTE *data = NULL; + CK_ULONG data_len; + CK_ULONG keyclass = 0, keytype = 0; + CK_ULONG i; + CK_BBOOL found_class, found_type, fromend, isopaque = FALSE; + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + + + if (!sess || !wrapped_key || !h_unwrapped_key) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + rc = object_mgr_find_in_map1(tokdata, h_unwrapping_key, &tmp_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_WRAPPING_KEY_HANDLE_INVALID; + else + return rc; + } + + if (template_attribute_find(tmp_obj->template, CKA_IBM_OPAQUE, &attr) == + TRUE) { + isopaque = TRUE; + } + + object_put(tokdata, tmp_obj, TRUE); + tmp_obj = NULL; + + found_class = FALSE; + found_type = FALSE; + + /* + * pkcs11v2-20 + * C_WrapKey can be used in following situations: + * - To wrap any secret key with a public key that supports encryption + * and decryption. + * - To wrap any secret key with any other secret key. Consideration + * must be given to key size and mechanism strength or the token may + * not allow the operation. + * - To wrap a private key with any secret key. + * + * extract key type and key class from the passed in attributes + */ + + for (i = 0; i < attrib_count; i++) { + switch (attributes[i].type) { + case CKA_CLASS: + keyclass = *(CK_OBJECT_CLASS *) attributes[i].pValue; + found_class = TRUE; + break; + case CKA_KEY_TYPE: + keytype = *(CK_KEY_TYPE *) attributes[i].pValue; + found_type = TRUE; + break; + } + } + + // we need both key class and key type in template. + // we can be a bit lenient for private key since can extract key type + // from BER-encoded information. + + if (found_class == FALSE || + (found_type == FALSE && keyclass != CKO_PRIVATE_KEY)) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + switch (mech->mechanism) { + case CKM_CDMF_ECB: + case CKM_DES_ECB: + case CKM_AES_ECB: + case CKM_AES_CBC: + case CKM_RSA_PKCS_OAEP: + case CKM_RSA_PKCS: + case CKM_RSA_X_509: + if (keyclass != CKO_SECRET_KEY) { + TRACE_ERROR("The specified mechanism unwraps secret keys only.\n"); + return CKR_ARGUMENTS_BAD; + } + break; +#if !(NOCMF) + case CKM_CDMF_CBC: + case CKM_CDMF_CBC_PAD: +#endif + case CKM_DES_CBC: + case CKM_DES3_ECB: + case CKM_DES3_CBC: + case CKM_AES_CTR: + case CKM_AES_OFB: + case CKM_AES_CFB8: + case CKM_AES_CFB64: + case CKM_AES_CFB128: + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC_PAD: + case CKM_AES_CBC_PAD: + if ((keyclass != CKO_SECRET_KEY) && (keyclass != CKO_PRIVATE_KEY)) { + TRACE_ERROR("Specified mech unwraps secret & private keys only.\n"); + return CKR_ARGUMENTS_BAD; + } + break; + default: + TRACE_ERROR("The specified mechanism cannot unwrap keys.\n"); + return CKR_MECHANISM_INVALID; + } + + // looks okay... do the decryption + ctx = (ENCR_DECR_CONTEXT *) malloc(sizeof(ENCR_DECR_CONTEXT)); + if (!ctx) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + memset(ctx, 0x0, sizeof(ENCR_DECR_CONTEXT)); + + rc = decr_mgr_init(tokdata, sess, ctx, OP_UNWRAP, mech, h_unwrapping_key); + if (rc != CKR_OK) + return rc; + + rc = decr_mgr_decrypt(tokdata, sess, + TRUE, + ctx, wrapped_key, wrapped_key_len, data, &data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("decr_mgr_decrypt failed.\n"); + goto error; + } + data = (CK_BYTE *) malloc(data_len); + if (!data) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto error; + } + + rc = decr_mgr_decrypt(tokdata, sess, + FALSE, + ctx, wrapped_key, wrapped_key_len, data, &data_len); + + decr_mgr_cleanup(ctx); + free(ctx); + + if (rc != CKR_OK) { + TRACE_DEVEL("decr_mgr_decrypt failed.\n"); + goto error; + } + // if we use X.509, the data will be padded from the front with zeros. + // PKCS #11 specifies that for this mechanism, CK_VALUE is to be read + // from the end of the data. + // + // Note: the PKCS #11 reference implementation gets this wrong. + // + if (mech->mechanism == CKM_RSA_X_509) + fromend = TRUE; + else + fromend = FALSE; + + // extract the key type from the PrivateKeyInfo::AlgorithmIndicator + // + if (keyclass == CKO_PRIVATE_KEY) { + rc = key_mgr_get_private_key_type(data, data_len, &keytype); + if (rc != CKR_OK) { + TRACE_DEVEL("key_mgr_get_private_key_type failed.\n"); + goto error; + } + } + // we have decrypted the wrapped key data. we also + // know what type of key it is. now we need to construct a new key + // object... + // + + rc = object_mgr_create_skel(tokdata, sess, + attributes, attrib_count, + MODE_UNWRAP, keyclass, keytype, &key_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_create_skel failed.\n"); + goto error; + } + // at this point, 'key_obj' should contain a skeleton key. depending on + // the key type. we're now ready to plug in the decrypted key data. + // in some cases, the data will be BER-encoded so we'll need to decode it. + // + // this routine also ensires that CKA_EXTRACTABLE == FALSE, + // CKA_ALWAYS_SENSITIVE == FALSE and CKA_LOCAL == FALSE + // + switch (keyclass) { + case CKO_SECRET_KEY: + rc = secret_key_unwrap(tokdata, key_obj->template, keytype, data, + data_len, fromend, isopaque); + break; + case CKO_PRIVATE_KEY: + rc = priv_key_unwrap(key_obj->template, keytype, data, data_len, + isopaque); + break; + default: + rc = CKR_WRAPPED_KEY_INVALID; + break; + } + + if (rc != CKR_OK) { + TRACE_DEVEL("key_unwrap failed.\n"); + goto error; + } + // at this point, the key should be fully constructed...assign + // an object handle and store the key + // + rc = object_mgr_create_final(tokdata, sess, key_obj, h_unwrapped_key); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_create_final failed.\n"); + goto error; + } + if (data) { + OPENSSL_cleanse(data, data_len); + free(data); + } + + return rc; + +error: + if (key_obj) + object_free(key_obj); + if (data) { + OPENSSL_cleanse(data, data_len); + free(data); + } + + return rc; +} + + +CK_RV key_mgr_get_private_key_type(CK_BYTE *keydata, + CK_ULONG keylen, CK_KEY_TYPE *keytype) +{ + CK_BYTE *alg = NULL; + CK_BYTE *priv_key = NULL; + CK_ULONG alg_len; + CK_RV rc; + + rc = ber_decode_PrivateKeyInfo(keydata, keylen, &alg, &alg_len, &priv_key); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_decode_PrivateKeyInfo failed.\n"); + return rc; + } + // check the entire AlgorithmIdentifier for RSA + // + if (alg_len >= ber_rsaEncryptionLen) { + if (memcmp(alg, ber_rsaEncryption, ber_rsaEncryptionLen) == 0) { + *keytype = CKK_RSA; + return CKR_OK; + } + } + // Check only the OBJECT IDENTIFIER for DSA + // + if (alg_len >= ber_idDSALen) { + if (memcmp(alg, ber_idDSA, ber_idDSALen) == 0) { + *keytype = CKK_DSA; + return CKR_OK; + } + } + // Check only the OBJECT IDENTIFIER for EC + // + if (alg_len >= der_AlgIdECBaseLen) { + if (memcmp(alg, ber_idEC, ber_idECLen) == 0) { + *keytype = CKK_EC; + return CKR_OK; + } + } + + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; +} + + +// +// +CK_RV key_mgr_derive_key(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_MECHANISM *mech, + CK_OBJECT_HANDLE base_key, + CK_OBJECT_HANDLE *derived_key, + CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount) +{ + if (!sess || !mech) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (!pTemplate && (ulCount != 0)) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + switch (mech->mechanism) { + case CKM_SSL3_MASTER_KEY_DERIVE: + if (!derived_key) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + return ssl3_master_key_derive(tokdata, sess, mech, base_key, + pTemplate, ulCount, derived_key); + break; + case CKM_SSL3_KEY_AND_MAC_DERIVE: + return ssl3_key_and_mac_derive(tokdata, sess, mech, base_key, + pTemplate, ulCount); + break; +/* Begin code contributed by Corrent corp. */ +#ifndef NODH + case CKM_DH_PKCS_DERIVE: + if (!derived_key) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + return dh_pkcs_derive(tokdata, sess, mech, base_key, + pTemplate, ulCount, derived_key); + break; +#endif +/* End code contributed by Corrent corp. */ + case CKM_ECDH1_DERIVE: + if (!derived_key) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + return ecdh_pkcs_derive(tokdata, sess, mech, base_key, pTemplate, + ulCount, derived_key); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } +} diff --git a/usr/lib/common/list.h b/usr/lib/common/list.h new file mode 100644 index 0000000..899cb14 --- /dev/null +++ b/usr/lib/common/list.h @@ -0,0 +1,147 @@ +/* + * 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 + */ + +/* + * Very small linked list implementation. + * + * For simplicity and portability it doesn't use GCC extensions and sticks with + * C89. That means there's no hidden variable declaration or type inference + * inside the macros. + */ + +#ifndef _LIST_H_ +#define _LIST_H_ + +#include /* for offsetof */ + +/* + * Typedefs for lists and list entries. + * + * List entry should be defined as a member in an application-specific + * structure. + */ +typedef struct _list list_t; +typedef struct _list_entry list_entry_t; + +struct _list { + list_entry_t *head; + list_entry_t *tail; +}; + +struct _list_entry { + list_entry_t *next; + list_entry_t *prev; + list_t *list; +}; + +/* A helper macro */ +#ifndef container_of +#define container_of(_pt, _type, _field) \ + ((_type *) (!(_pt) ? NULL : (((char *) (_pt)) - offsetof(_type, _field)))) +#endif + +/* + * Macro to iterate over a list. + * + * It can *NOT* be used to remove entries while iterating. + * + */ +#define for_each_list_entry(_head, _type, _var, _field) \ + for (_var = container_of((_head)->head, _type, _field); \ + (_var) && &((_var)->_field); \ + _var = container_of((_var)->_field.next, _type, _field)) + +/* + * Similar to for_each_list_entry but it's possible to remove an entry while + * iterating. + * + * It uses an additional list_entry_t* to hold the value of the next element. + */ +#define for_each_list_entry_safe(_head, _type, _var, _field, _next) \ + for (_var = container_of((_head)->head, _type, _field); \ + (_var) && &((_var)->_field) && \ + ((_next = (_var)->_field.next) || 1); \ + _var = container_of(_next, _type, _field)) + +/* + * Assignment initialization macro. + */ +#define LIST_INIT() \ + { NULL, NULL } + +/* + * Initialize a list. + */ +static inline void list_init(list_t *list) +{ + list->head = list->tail = NULL; +} + +static inline int list_is_empty(list_t *list) +{ + return (list->head == NULL); +} + +/* + * Insert a element at the head. + */ +static inline void list_insert_head(list_t *list, list_entry_t *new) +{ + if (!list->head) { + new->next = new->prev = NULL; + list->head = list->tail = new; + } else { + new->prev = NULL; + new->next = list->head; + list->head->prev = new; + list->head = new; + } + new->list = list; +} + +/* + * Insert a element at the end. + * (currently unused) +static inline void list_insert_tail(list_t *list, list_entry_t *new) +{ + if (!list->tail) { + new->next = new->prev = NULL; + list->head = list->tail = new; + } else { + new->next = NULL; + new->prev = list->tail; + list->tail->next = new; + list->tail = new; + } + new->list = list; +} + */ + +/* + * Remove an element. + */ +static inline void list_remove(list_entry_t *entry) +{ + list_t *list = entry->list; + + if (list->head == entry) + list->head = entry->next; + + if (list->tail == entry) + list->tail = entry->prev; + + if (entry->next) + entry->next->prev = entry->prev; + + if (entry->prev) + entry->prev->next = entry->next; +} + +#endif diff --git a/usr/lib/common/loadsave.c b/usr/lib/common/loadsave.c new file mode 100644 index 0000000..c30dd1a --- /dev/null +++ b/usr/lib/common/loadsave.c @@ -0,0 +1,2768 @@ +/* + * 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 + */ + +// loadsave.c +// +// routines associated with loading/saving files +// +// +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "pkcs32.h" +#include "sw_crypt.h" +#include "trace.h" +#include "ock_syslog.h" + +extern void set_perm(int); + +CK_RV restore_private_token_object_old(STDLL_TokData_t *tokdata, CK_BYTE *data, + CK_ULONG len, OBJECT *pObj); +CK_RV reload_token_object_old(STDLL_TokData_t *tokdata, OBJECT *obj); +CK_RV save_public_token_object_old(STDLL_TokData_t *tokdata, OBJECT *obj); +CK_RV load_public_token_objects_old(STDLL_TokData_t *tokdata); + +char *get_pk_dir(STDLL_TokData_t *tokdata, char *fname) +{ + struct passwd *pw = NULL; + + if (token_specific.data_store.per_user && (pw = getpwuid(getuid())) != NULL) + sprintf(fname, "%s/%s", tokdata->pk_dir, pw->pw_name); + else + sprintf(fname, "%s", tokdata->pk_dir); + + return fname; +} + +void set_perm(int file) +{ + struct group *grp; + + if (token_specific.data_store.per_user) { + /* In the TPM token, with per user data stores, we don't share + * the token object amongst a group. In fact, we want to + * restrict access to a single user */ + fchmod(file, S_IRUSR | S_IWUSR); + } else { + // Set absolute permissions or rw-rw---- + fchmod(file, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + grp = getgrnam("pkcs11"); // Obtain the group id + if (grp) { + // set ownership to root, and pkcs11 group + if (fchown(file, getuid(), grp->gr_gid) != 0) { + goto error; + } + } else { + goto error; + } + } + + return; + +error: + TRACE_DEVEL("Unable to set permissions on file.\n"); +} + +// +// Note: The token lock (XProcLock) must be held when calling this function. +// The object must hold the READ lock when this function is called. +// +CK_RV save_token_object(STDLL_TokData_t *tokdata, OBJECT *obj) +{ + FILE *fp = NULL; + char line[256]; + char fname[PATH_MAX]; + CK_RV rc; + + // write token object + if (object_is_private(obj) == TRUE) + rc = save_private_token_object(tokdata, obj); + else + rc = save_public_token_object(tokdata, obj); + if (rc != CKR_OK) + return rc; + + // update the index file if it exists + sprintf(fname, "%s/%s/%s", tokdata->data_store, PK_LITE_OBJ_DIR, + PK_LITE_OBJ_IDX); + fp = fopen(fname, "r"); + if (fp) { + set_perm(fileno(fp)); + while (fgets(line, 50, fp)) { + line[strlen(line) - 1] = 0; + if (strcmp(line, (char *)obj->name) == 0) { + fclose(fp); + // object is already in the list + return CKR_OK; + } + } + fclose(fp); + } + // we didn't find it...either the index file doesn't exist or this + // is a new object... + // + fp = fopen(fname, "a"); + if (!fp) { + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + return CKR_FUNCTION_FAILED; + } + + set_perm(fileno(fp)); + fprintf(fp, "%s\n", obj->name); + fclose(fp); + + return CKR_OK; +} + +// +// Note: The token lock (XProcLock) must be held when calling this function. +// +CK_RV delete_token_object(STDLL_TokData_t *tokdata, OBJECT *obj) +{ + FILE *fp1, *fp2; + char objidx[PATH_MAX], idxtmp[PATH_MAX], fname[PATH_MAX], line[256]; + + sprintf(objidx, "%s/%s/%s", tokdata->data_store, + PK_LITE_OBJ_DIR, PK_LITE_OBJ_IDX); + sprintf(idxtmp, "%s/%s/%s", tokdata->data_store, + PK_LITE_OBJ_DIR, "IDX.TMP"); + + // FIXME: on UNIX, we need to make sure these guys aren't symlinks + // before we blindly write to these files... + // + + // remove the object from the index file + // + + fp1 = fopen(objidx, "r"); + fp2 = fopen(idxtmp, "w"); + if (!fp1 || !fp2) { + if (fp1) + fclose(fp1); + if (fp2) + fclose(fp2); + TRACE_ERROR("fopen failed\n"); + return CKR_FUNCTION_FAILED; + } + + set_perm(fileno(fp2)); + + while (fgets(line, 50, fp1)) { + line[strlen(line) - 1] = 0; + if (strcmp(line, (char *)obj->name) == 0) + continue; + else + fprintf(fp2, "%s\n", line); + } + + fclose(fp1); + fclose(fp2); + fp2 = fopen(objidx, "w"); + fp1 = fopen(idxtmp, "r"); + if (!fp1 || !fp2) { + if (fp1) + fclose(fp1); + if (fp2) + fclose(fp2); + TRACE_ERROR("fopen failed\n"); + return CKR_FUNCTION_FAILED; + } + + set_perm(fileno(fp2)); + + while (fgets(line, 50, fp1)) { + fprintf(fp2, "%s", line); + } + + fclose(fp1); + fclose(fp2); + + sprintf(fname, "%s/%s/%s", tokdata->data_store, + PK_LITE_OBJ_DIR, (char *) obj->name); + unlink(fname); + + return CKR_OK; +} + +CK_RV delete_token_data(STDLL_TokData_t *tokdata) +{ + CK_RV rc = CKR_OK; + char *cmd = NULL; + + // Construct a string to delete the token objects. + // + // META This should be fine since the open session checking + // should occur at the API not the STDLL + // + // TODO: Implement delete_all_files_in_dir() */ + if (asprintf(&cmd, "%s %s/%s/* > /dev/null 2>&1", DEL_CMD, + tokdata->data_store, PK_LITE_OBJ_DIR) < 0) { + rc = CKR_HOST_MEMORY; + goto done; + } + + if (system(cmd)) + TRACE_ERROR("system() failed.\n"); + +done: + free(cmd); + + return rc; +} + +void init_data_store(STDLL_TokData_t *tokdata, char *directory, + char *data_store) +{ + char *pkdir; + + if (tokdata->pk_dir != NULL) { + free(tokdata->pk_dir); + tokdata->pk_dir = NULL; + } + + if ((pkdir = getenv("PKCS_APP_STORE")) != NULL) { + tokdata->pk_dir = (char *) malloc(strlen(pkdir) + 1024); + memset(tokdata->pk_dir, 0, strlen(pkdir) + 1024); + sprintf(tokdata->pk_dir, "%s/%s", pkdir, SUB_DIR); + get_pk_dir(tokdata, data_store); + return; + } + + if (directory) { + tokdata->pk_dir = (char *) malloc(strlen(directory) + 25); + memset(tokdata->pk_dir, 0, strlen(directory) + 25); + sprintf(tokdata->pk_dir, "%s", directory); + } else { + tokdata->pk_dir = (char *) malloc(strlen(PK_DIR) + 25); + memset(tokdata->pk_dir, 0, strlen(PK_DIR) + 25); + sprintf(tokdata->pk_dir, "%s", PK_DIR); + } + get_pk_dir(tokdata, data_store); + + return; +} + +void final_data_store(STDLL_TokData_t * tokdata) +{ + if (tokdata->pk_dir != NULL) { + free(tokdata->pk_dir); + tokdata->pk_dir = NULL; + } +} + +/****************************************************************************** + * tokversion < 3.12 object store + */ + +static CK_RV get_encryption_info_for_clear_key(CK_ULONG *p_key_len, + CK_ULONG *p_block_size) +{ + CK_ULONG key_len = 0L; + CK_ULONG block_size = 0L; + + switch (token_specific.data_store.encryption_algorithm) { + case CKM_DES3_CBC: + key_len = 3 * DES_KEY_SIZE; + block_size = DES_BLOCK_SIZE; + break; + case CKM_AES_CBC: + key_len = AES_KEY_SIZE_256; + block_size = AES_BLOCK_SIZE; + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return ERR_MECHANISM_INVALID; + } + + if (p_key_len) + *p_key_len = key_len; + if (p_block_size) + *p_block_size = block_size; + + return CKR_OK; +} + +static CK_RV get_encryption_info(CK_ULONG *p_key_len, CK_ULONG *p_block_size) +{ + CK_RV rc; + + rc = get_encryption_info_for_clear_key(p_key_len, p_block_size); + if (rc != CKR_OK) + return rc; + + /* Tokens that use a secure key have a different size for key because + * it's just an indentifier not a real key. + */ + if (is_secure_key_token()) { + if (p_key_len) + *p_key_len = token_specific.token_keysize; + } + + return CKR_OK; +} + +static CK_BYTE *duplicate_initial_vector(const CK_BYTE *iv) +{ + CK_ULONG block_size = 0L; + CK_BYTE *initial_vector = NULL; + + if (iv == NULL) + goto done; + + if (get_encryption_info(NULL, &block_size) != CKR_OK) + goto done; + + initial_vector = malloc(block_size); + if (initial_vector == NULL) { + goto done; + } + memcpy(initial_vector, iv, block_size); + +done: + return initial_vector; +} + +static CK_RV encrypt_data(STDLL_TokData_t *tokdata, CK_BYTE *key, + CK_ULONG keylen, const CK_BYTE *iv, + CK_BYTE *clear, CK_ULONG clear_len, + CK_BYTE *cipher, CK_ULONG *p_cipher_len) +{ +#ifndef CLEARTEXT + CK_RV rc = CKR_OK; + CK_BYTE *initial_vector = NULL; + OBJECT *keyobj = NULL; + CK_KEY_TYPE keyType; + CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; + CK_ATTRIBUTE key_tmpl[] = { + {CKA_CLASS, &keyClass, sizeof(keyClass)} + , + {CKA_KEY_TYPE, &keyType, sizeof(keyType)} + , + {CKA_VALUE, key, keylen} + }; + + switch (token_specific.data_store.encryption_algorithm) { + case CKM_DES3_CBC: + keyType = CKK_DES3; + break; + case CKM_AES_CBC: + keyType = CKK_AES; + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return ERR_MECHANISM_INVALID; + } + rc = object_create_skel(tokdata, key_tmpl, 3, MODE_CREATE, + CKO_SECRET_KEY, keyType, &keyobj); + if (rc != CKR_OK) { + TRACE_DEVEL("object_create_skel failed.\n"); + return rc; + } + + initial_vector = duplicate_initial_vector(iv); + if (initial_vector == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return ERR_HOST_MEMORY; + } + + switch (token_specific.data_store.encryption_algorithm) { + case CKM_DES3_CBC: + rc = ckm_des3_cbc_encrypt(tokdata, clear, clear_len, + cipher, p_cipher_len, initial_vector, keyobj); + break; + case CKM_AES_CBC: + rc = ckm_aes_cbc_encrypt(tokdata, clear, clear_len, + cipher, p_cipher_len, initial_vector, keyobj); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = ERR_MECHANISM_INVALID; + } + + if (initial_vector) + free(initial_vector); + + return rc; + +#else + memcpy(cipher, clear, clear_len); + return CKR_OK; +#endif +} + +static CK_RV encrypt_data_with_clear_key(STDLL_TokData_t *tokdata, + CK_BYTE *key, CK_ULONG keylen, + const CK_BYTE *iv, + CK_BYTE *clear, CK_ULONG clear_len, + CK_BYTE *cipher, + CK_ULONG *p_cipher_len) +{ +#ifndef CLEARTEXT + CK_RV rc = CKR_OK; + CK_BYTE *initial_vector = NULL; + + if (!is_secure_key_token() && + token_specific.data_store.encryption_algorithm != CKM_DES3_CBC) { + return encrypt_data(tokdata, key, keylen, iv, clear, clear_len, + cipher, p_cipher_len); + } + + /* Fall back to a software alternative if key is secure, or + * if token's data store encryption algorithm is 3DES_CBC */ + initial_vector = duplicate_initial_vector(iv); + if (initial_vector == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return ERR_HOST_MEMORY; + } + + switch (token_specific.data_store.encryption_algorithm) { + case CKM_DES3_CBC: + rc = sw_des3_cbc_encrypt(clear, clear_len, + cipher, p_cipher_len, initial_vector, key); + break; + case CKM_AES_CBC: + rc = sw_aes_cbc_encrypt(clear, clear_len, cipher, p_cipher_len, + initial_vector, key, keylen); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = ERR_MECHANISM_INVALID; + } + + if (initial_vector) + free(initial_vector); + + return rc; + +#else + memcpy(cipher, clear, clear_len); + return CKR_OK; +#endif +} + +static CK_RV decrypt_data(STDLL_TokData_t *tokdata, + CK_BYTE *key, CK_ULONG keylen, const CK_BYTE *iv, + CK_BYTE *cipher, CK_ULONG cipher_len, + CK_BYTE *clear, CK_ULONG *p_clear_len) +{ +#ifndef CLEARTEXT + CK_RV rc = CKR_OK; + CK_BYTE *initial_vector = NULL; + OBJECT *keyobj = NULL; + CK_KEY_TYPE keyType; + CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; + CK_ATTRIBUTE key_tmpl[] = { + { CKA_CLASS, &keyClass, sizeof(keyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_VALUE, key, keylen } + }; + + switch (token_specific.data_store.encryption_algorithm) { + case CKM_DES3_CBC: + keyType = CKK_DES3; + break; + case CKM_AES_CBC: + keyType = CKK_AES; + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return ERR_MECHANISM_INVALID; + } + rc = object_create_skel(tokdata, key_tmpl, 3, MODE_CREATE, + CKO_SECRET_KEY, keyType, &keyobj); + if (rc != CKR_OK) { + TRACE_DEVEL("object_create_skel failed.\n"); + return rc; + } + + initial_vector = duplicate_initial_vector(iv); + if (initial_vector == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return ERR_HOST_MEMORY; + } + + switch (token_specific.data_store.encryption_algorithm) { + case CKM_DES3_CBC: + rc = ckm_des3_cbc_decrypt(tokdata, cipher, cipher_len, + clear, p_clear_len, initial_vector, keyobj); + break; + case CKM_AES_CBC: + rc = ckm_aes_cbc_decrypt(tokdata, cipher, cipher_len, + clear, p_clear_len, initial_vector, keyobj); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = ERR_MECHANISM_INVALID; + } + + if (initial_vector) + free(initial_vector); + + return rc; + +#else + memcpy(clear, cipher, cipher_len); + return CKR_OK; +#endif +} + +static CK_RV decrypt_data_with_clear_key(STDLL_TokData_t *tokdata, + CK_BYTE *key, CK_ULONG keylen, + const CK_BYTE *iv, + CK_BYTE *cipher, CK_ULONG cipher_len, + CK_BYTE *clear, + CK_ULONG *p_clear_len) +{ +#ifndef CLEARTEXT + CK_RV rc = CKR_OK; + CK_BYTE *initial_vector = NULL; + + if (!is_secure_key_token() && + token_specific.data_store.encryption_algorithm != CKM_DES3_CBC) { + return decrypt_data(tokdata, key, keylen, iv, cipher, + cipher_len, clear, p_clear_len); + } + + /* Fall back to a software alternative if key is secure, or + * if token's data store encryption algorithm is 3DES_CBC */ + initial_vector = duplicate_initial_vector(iv); + if (initial_vector == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return ERR_HOST_MEMORY; + } + + switch (token_specific.data_store.encryption_algorithm) { + case CKM_DES3_CBC: + rc = sw_des3_cbc_decrypt(cipher, cipher_len, clear, p_clear_len, + initial_vector, key); + break; + case CKM_AES_CBC: + rc = sw_aes_cbc_decrypt(cipher, cipher_len, clear, p_clear_len, + initial_vector, key, keylen); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = ERR_MECHANISM_INVALID; + } + + if (initial_vector) + free(initial_vector); + + return rc; + +#else + memcpy(clear, cipher, cipher_len); + return CKR_OK; +#endif +} + +// +// +CK_RV load_token_data_old(STDLL_TokData_t *tokdata, CK_SLOT_ID slot_id) +{ + FILE *fp = NULL; + char fname[PATH_MAX]; + TOKEN_DATA td; + CK_RV rc; + + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get Process Lock.\n"); + goto out_nolock; + } + + sprintf(fname, "%s/%s", tokdata->data_store, PK_LITE_NV); + fp = fopen(fname, "r"); + if (!fp) { + /* Better error checking added */ + if (errno == ENOENT) { + init_token_data(tokdata, slot_id); + + fp = fopen(fname, "r"); + if (!fp) { + // were really hosed here since the created + // did not occur + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto out_unlock; + } + } else { + /* Could not open file for some unknown reason */ + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto out_unlock; + } + } + set_perm(fileno(fp)); + + /* Load generic token data */ + if (!fread(&td, sizeof(TOKEN_DATA_OLD), 1, fp)) { + TRACE_ERROR("fread(%s): %s\n", fname, + ferror(fp) ? strerror(errno) : "failed"); + rc = CKR_FUNCTION_FAILED; + goto out_unlock; + } + memcpy(tokdata->nv_token_data, &td, sizeof(TOKEN_DATA_OLD)); + + /* Load token-specific data */ + if (token_specific.t_load_token_data) { + rc = token_specific.t_load_token_data(tokdata, slot_id, fp); + if (rc) + goto out_unlock; + } + + rc = CKR_OK; + +out_unlock: + if (fp) + fclose(fp); + + if (rc == CKR_OK) { + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) + TRACE_ERROR("Failed to release Process Lock.\n"); + } else { + /* return error that occurred first */ + XProcUnLock(tokdata); + } + +out_nolock: + return rc; +} + +// +// +CK_RV save_token_data_old(STDLL_TokData_t *tokdata, CK_SLOT_ID slot_id) +{ + FILE *fp = NULL; + TOKEN_DATA td; + CK_RV rc; + char fname[PATH_MAX]; + + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get Process Lock.\n"); + goto out_nolock; + } + + sprintf(fname, "%s/%s", tokdata->data_store, PK_LITE_NV); + fp = fopen(fname, "w"); + if (!fp) { + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + set_perm(fileno(fp)); + + /* Write generic token data */ + memcpy(&td, tokdata->nv_token_data, sizeof(TOKEN_DATA_OLD)); + if (!fwrite(&td, sizeof(TOKEN_DATA_OLD), 1, fp)) { + TRACE_ERROR("fwrite(%s): %s\n", fname, + ferror(fp) ? strerror(errno) : "failed"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Write token-specific data */ + if (token_specific.t_save_token_data) { + rc = token_specific.t_save_token_data(tokdata, slot_id, fp); + if (rc) + goto done; + } + + rc = CKR_OK; + +done: + if (fp) + fclose(fp); + + if (rc == CKR_OK) { + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) + TRACE_ERROR("Failed to release Process Lock.\n"); + } else { + /* return error that occurred first */ + XProcUnLock(tokdata); + } + +out_nolock: + return rc; +} + + +// +// Note: The token lock (XProcLock) must be held when calling this function. +// +static CK_RV save_private_token_object_old(STDLL_TokData_t *tokdata, OBJECT *obj) +{ + FILE *fp = NULL; + CK_BYTE *obj_data = NULL; + CK_BYTE *clear = NULL; + CK_BYTE *cipher = NULL; + CK_BYTE *ptr = NULL; + char fname[PATH_MAX]; + CK_BYTE hash_sha[SHA1_HASH_SIZE]; + CK_BYTE *key = NULL; + CK_ULONG key_len = 0L; + CK_ULONG block_size = 0L; + CK_ULONG obj_data_len, clear_len, cipher_len; + CK_ULONG padded_len; + CK_BBOOL flag; + CK_RV rc; + CK_ULONG_32 obj_data_len_32; + CK_ULONG_32 total_len; + + rc = object_flatten(obj, &obj_data, &obj_data_len); + obj_data_len_32 = obj_data_len; + if (rc != CKR_OK) { + goto error; + } + // + // format for the object file: + // private flag + // ---- begin encrypted part <--+ + // length of object data | + // object data +---- sensitive part + // SHA of (object data) | + // ---- end encrypted part <--+ + // + compute_sha1(tokdata, obj_data, obj_data_len, hash_sha); + + // encrypt the sensitive object data. need to be careful. + // if I use the normal high-level encryption routines I'll need to + // create a tepmorary key object containing the master key, perform the + // encryption, then destroy the key object. There is a race condition + // here if the application is multithreaded (if a thread-switch occurs, + // the other application thread could do a FindObject and be able to + // access the master key object. + // + // So I have to use the low-level encryption routines. + // + + if ((rc = get_encryption_info(&key_len, &block_size)) != CKR_OK) + goto error; + + // Duplicate key + key = malloc(key_len); + if (!key) + goto oom_error; + memcpy(key, tokdata->master_key, key_len); + + + clear_len = sizeof(CK_ULONG_32) + obj_data_len_32 + SHA1_HASH_SIZE; + cipher_len = padded_len = block_size * (clear_len / block_size + 1); + + clear = malloc(padded_len); + cipher = malloc(padded_len); + if (!clear || !cipher) + goto oom_error; + + // Build data that will be encrypted + ptr = clear; + memcpy(ptr, &obj_data_len_32, sizeof(CK_ULONG_32)); + ptr += sizeof(CK_ULONG_32); + memcpy(ptr, obj_data, obj_data_len_32); + ptr += obj_data_len_32; + memcpy(ptr, hash_sha, SHA1_HASH_SIZE); + + add_pkcs_padding(clear + clear_len, block_size, clear_len, padded_len); + + rc = encrypt_data_with_clear_key(tokdata, key, key_len, + token_specific.data_store. + obj_initial_vector, clear, padded_len, + cipher, &cipher_len); + if (rc != CKR_OK) { + goto error; + } + + sprintf(fname, "%s/%s/", tokdata->data_store, PK_LITE_OBJ_DIR); + strncat(fname, (char *) obj->name, 8); + fp = fopen(fname, "w"); + if (!fp) { + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto error; + } + + set_perm(fileno(fp)); + + total_len = sizeof(CK_ULONG_32) + sizeof(CK_BBOOL) + cipher_len; + + flag = TRUE; + + (void) fwrite(&total_len, sizeof(CK_ULONG_32), 1, fp); + (void) fwrite(&flag, sizeof(CK_BBOOL), 1, fp); + (void) fwrite(cipher, cipher_len, 1, fp); + + fclose(fp); + free(obj_data); + free(clear); + free(cipher); + free(key); + + return CKR_OK; + +oom_error: + rc = CKR_HOST_MEMORY; + +error: + if (fp) + fclose(fp); + if (obj_data) + free(obj_data); + if (clear) + free(clear); + if (cipher) + free(cipher); + if (key) + free(key); + + return rc; +} + +// +// Note: The token lock (XProcLock) must be held when calling this function. +// +CK_RV load_private_token_objects_old(STDLL_TokData_t *tokdata) +{ + FILE *fp1 = NULL, *fp2 = NULL; + CK_BYTE *buf = NULL; + char tmp[PATH_MAX]; + char iname[PATH_MAX]; + char fname[PATH_MAX]; + CK_BBOOL priv; + CK_ULONG_32 size; + CK_RV rc; + size_t read_size; + + sprintf(iname, "%s/%s/%s", tokdata->data_store, PK_LITE_OBJ_DIR, + PK_LITE_OBJ_IDX); + + fp1 = fopen(iname, "r"); + if (!fp1) + return CKR_OK; // no token objects + + while (fgets(tmp, 50, fp1)) { + tmp[strlen(tmp) - 1] = 0; + + sprintf(fname, "%s/%s/", tokdata->data_store, PK_LITE_OBJ_DIR); + strcat(fname, tmp); + + fp2 = fopen(fname, "r"); + if (!fp2) + continue; + + if (!fread(&size, sizeof(CK_ULONG_32), 1, fp2)) { + fclose(fp2); + OCK_SYSLOG(LOG_ERR, "Cannot read size\n"); + continue; + } + if (!fread(&priv, sizeof(CK_BBOOL), 1, fp2)) { + fclose(fp2); + OCK_SYSLOG(LOG_ERR, "Cannot read boolean\n"); + continue; + } + if (priv == FALSE) { + fclose(fp2); + continue; + } + //size--; + size = size - sizeof(CK_ULONG_32) - sizeof(CK_BBOOL); + buf = (CK_BYTE *) malloc(size); + if (!buf) { + fclose(fp2); + OCK_SYSLOG(LOG_ERR, + "Cannot malloc %u bytes to read in " + "token object %s (ignoring it)", size, fname); + continue; + } + + read_size = fread(buf, 1, size, fp2); + if (read_size != size) { + free(buf); + fclose(fp2); + OCK_SYSLOG(LOG_ERR, + "Cannot read token object %s " "(ignoring it)", fname); + continue; + } + + rc = restore_private_token_object_old(tokdata, buf, size, NULL); + if (rc != CKR_OK) + goto error; + + free(buf); + fclose(fp2); + } + + fclose(fp1); + + return CKR_OK; + +error: + if (buf) + free(buf); + if (fp1) + fclose(fp1); + if (fp2) + fclose(fp2); + + return rc; +} + +// +// +CK_RV load_masterkey_so_old(STDLL_TokData_t *tokdata) +{ + FILE *fp = NULL; + CK_BYTE hash_sha[SHA1_HASH_SIZE]; + CK_BYTE *cipher = NULL; + CK_BYTE *clear = NULL; + CK_BYTE *key = NULL; + CK_ULONG data_len; + CK_ULONG cipher_len, clear_len; + CK_RV rc; + char fname[PATH_MAX]; + CK_ULONG key_len = 0L; + CK_ULONG master_key_len = 0L; + CK_ULONG block_size = 0L; + + if ((rc = get_encryption_info_for_clear_key(&key_len, + &block_size)) != CKR_OK) + goto done; + + if ((rc = get_encryption_info(&master_key_len, NULL)) != CKR_OK) + goto done; + + memset(tokdata->master_key, 0x0, master_key_len); + + data_len = master_key_len + SHA1_HASH_SIZE; + clear_len = cipher_len = (data_len + block_size - 1) + & ~(block_size - 1); + + key = malloc(key_len); + cipher = malloc(cipher_len); + clear = malloc(clear_len); + if (key == NULL || cipher == NULL || clear == NULL) { + rc = ERR_HOST_MEMORY; + goto done; + } + // this file gets created on C_InitToken so we can assume that it always + // exists + // + sprintf(fname, "%s/MK_SO", tokdata->data_store); + fp = fopen(fname, "r"); + if (!fp) { + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + set_perm(fileno(fp)); + + rc = fread(cipher, cipher_len, 1, fp); + if (rc != 1) { + TRACE_ERROR("fread() failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + // decrypt the master key data using the MD5 of the SO key + // (we can't use the SHA of the SO key since the SHA of the key is + // stored in the token data file). + memcpy(key, tokdata->so_pin_md5, MD5_HASH_SIZE); + memcpy(key + MD5_HASH_SIZE, tokdata->so_pin_md5, key_len - MD5_HASH_SIZE); + + rc = decrypt_data_with_clear_key(tokdata, key, key_len, + token_specific.data_store. + pin_initial_vector, cipher, cipher_len, + clear, &clear_len); + if (rc != CKR_OK) { + TRACE_DEVEL("decrypt_data_with_clear_key failed.\n"); + goto done; + } + // + // technically should strip PKCS padding here but since I already know + // what the length should be, I don't bother. + // + + // compare the hashes + // + rc = compute_sha1(tokdata, clear, master_key_len, hash_sha); + if (rc != CKR_OK) { + goto done; + } + + if (memcmp(hash_sha, clear + master_key_len, SHA1_HASH_SIZE) != 0) { + TRACE_ERROR("masterkey hashes do not match\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + memcpy(tokdata->master_key, clear, master_key_len); + rc = CKR_OK; + +done: + if (fp) + fclose(fp); + if (clear) + free(clear); + if (cipher) + free(cipher); + if (key) + free(key); + + return rc; +} + +// +// +CK_RV load_masterkey_user_old(STDLL_TokData_t *tokdata) +{ + FILE *fp = NULL; + CK_BYTE hash_sha[SHA1_HASH_SIZE]; + CK_BYTE *cipher = NULL; + CK_BYTE *clear = NULL; + CK_BYTE *key = NULL; + CK_ULONG data_len; + CK_ULONG cipher_len, clear_len; + CK_RV rc; + char fname[PATH_MAX]; + CK_ULONG key_len = 0L; + CK_ULONG master_key_len = 0L; + CK_ULONG block_size = 0L; + + if ((rc = + get_encryption_info_for_clear_key(&key_len, &block_size)) != CKR_OK) + goto done; + + if ((rc = get_encryption_info(&master_key_len, NULL)) != CKR_OK) + goto done; + + memset(tokdata->master_key, 0x0, master_key_len); + + data_len = master_key_len + SHA1_HASH_SIZE; + clear_len = cipher_len = (data_len + block_size - 1) + & ~(block_size - 1); + + key = malloc(key_len); + cipher = malloc(cipher_len); + clear = malloc(clear_len); + if (key == NULL || cipher == NULL || clear == NULL) { + rc = ERR_HOST_MEMORY; + goto done; + } + // this file gets created on C_InitToken so we can assume that it always + // exists + // + sprintf(fname, "%s/MK_USER", tokdata->data_store); + fp = fopen(fname, "r"); + if (!fp) { + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + set_perm(fileno(fp)); + + rc = fread(cipher, cipher_len, 1, fp); + if (rc != 1) { + TRACE_ERROR("fread failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + // decrypt the master key data using the MD5 of the SO key + // (we can't use the SHA of the SO key since the SHA of the key is + // stored in the token data file). + memcpy(key, tokdata->user_pin_md5, MD5_HASH_SIZE); + memcpy(key + MD5_HASH_SIZE, tokdata->user_pin_md5, key_len - MD5_HASH_SIZE); + + rc = decrypt_data_with_clear_key(tokdata, key, key_len, + token_specific.data_store. + pin_initial_vector, cipher, cipher_len, + clear, &clear_len); + if (rc != CKR_OK) { + TRACE_DEVEL("decrypt_data_with_clear_key failed.\n"); + goto done; + } + // + // technically should strip PKCS padding here but since I already know + // what the length should be, I don't bother. + // + + // compare the hashes + // + rc = compute_sha1(tokdata, clear, master_key_len, hash_sha); + if (rc != CKR_OK) { + goto done; + } + + if (memcmp(hash_sha, clear + master_key_len, SHA1_HASH_SIZE) != 0) { + TRACE_ERROR("User's masterkey hashes do not match.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + memcpy(tokdata->master_key, clear, master_key_len); + rc = CKR_OK; + +done: + if (fp) + fclose(fp); + if (key) + free(key); + if (clear) + free(clear); + if (cipher) + free(cipher); + + return rc; +} + +// +// +CK_RV save_masterkey_so_old(STDLL_TokData_t *tokdata) +{ + FILE *fp = NULL; + CK_BYTE *clear = NULL; + CK_ULONG clear_len = 0L; + CK_BYTE *cipher = NULL; + CK_ULONG cipher_len = 0L; + CK_BYTE *key = NULL; + CK_ULONG key_len = 0L; + CK_ULONG master_key_len = 0L; + CK_ULONG block_size = 0L; + CK_ULONG data_len = 0L; + char fname[PATH_MAX]; + CK_RV rc; + + /* Skip it if master key is not needed. */ + if (!token_specific.data_store.use_master_key) + return CKR_OK; + + if ((rc = get_encryption_info_for_clear_key(&key_len, + &block_size)) != CKR_OK) + goto done; + + if ((rc = get_encryption_info(&master_key_len, NULL)) != CKR_OK) + goto done; + + data_len = master_key_len + SHA1_HASH_SIZE; + cipher_len = clear_len = block_size * (data_len / block_size + 1); + + key = malloc(key_len); + clear = malloc(clear_len); + cipher = malloc(cipher_len); + if (key == NULL || clear == NULL || cipher == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = ERR_HOST_MEMORY; + goto done; + } + // Copy data to buffer (key+hash) + memcpy(clear, tokdata->master_key, master_key_len); + if ((rc = compute_sha1(tokdata, tokdata->master_key, + master_key_len, clear + master_key_len)) != CKR_OK) + goto done; + add_pkcs_padding(clear + data_len, block_size, data_len, clear_len); + + // encrypt the key data + memcpy(key, tokdata->so_pin_md5, MD5_HASH_SIZE); + memcpy(key + MD5_HASH_SIZE, tokdata->so_pin_md5, key_len - MD5_HASH_SIZE); + + rc = encrypt_data_with_clear_key(tokdata, key, key_len, + token_specific.data_store. + pin_initial_vector, clear, clear_len, + cipher, &cipher_len); + if (rc != CKR_OK) { + goto done; + } + // write the file + // + // probably ought to ensure the permissions are correct + // + sprintf(fname, "%s/MK_SO", tokdata->data_store); + fp = fopen(fname, "w"); + if (!fp) { + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + set_perm(fileno(fp)); + + rc = fwrite(cipher, cipher_len, 1, fp); + if (rc != 1) { + TRACE_ERROR("fwrite failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + rc = CKR_OK; + +done: + if (fp) + fclose(fp); + if (key) + free(key); + if (clear) + free(clear); + if (cipher) + free(cipher); + + return rc; +} + +// +// +CK_RV save_masterkey_user_old(STDLL_TokData_t *tokdata) +{ + FILE *fp = NULL; + CK_BYTE *clear = NULL; + CK_ULONG clear_len = 0L; + CK_BYTE *cipher = NULL; + CK_ULONG cipher_len = 0L; + CK_BYTE *key = NULL; + CK_ULONG key_len = 0L; + CK_ULONG master_key_len = 0L; + CK_ULONG block_size = 0L; + CK_ULONG data_len = 0L; + char fname[PATH_MAX]; + CK_RV rc; + + if ((rc = get_encryption_info_for_clear_key(&key_len, + &block_size)) != CKR_OK) + goto done; + + if ((rc = get_encryption_info(&master_key_len, NULL)) != CKR_OK) + goto done; + + data_len = master_key_len + SHA1_HASH_SIZE; + cipher_len = clear_len = block_size * (data_len / block_size + 1); + + key = malloc(key_len); + clear = malloc(clear_len); + cipher = malloc(cipher_len); + if (key == NULL || clear == NULL || cipher == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = ERR_HOST_MEMORY; + goto done; + } + // Copy data to buffer (key+hash) + memcpy(clear, tokdata->master_key, master_key_len); + if ((rc = compute_sha1(tokdata, tokdata->master_key, + master_key_len, clear + master_key_len)) != CKR_OK) + goto done; + add_pkcs_padding(clear + data_len, block_size, data_len, clear_len); + + // encrypt the key data + memcpy(key, tokdata->user_pin_md5, MD5_HASH_SIZE); + memcpy(key + MD5_HASH_SIZE, tokdata->user_pin_md5, key_len - MD5_HASH_SIZE); + + rc = encrypt_data_with_clear_key(tokdata, key, key_len, + token_specific.data_store. + pin_initial_vector, clear, clear_len, + cipher, &cipher_len); + if (rc != CKR_OK) { + goto done; + } + // write the file + // + // probably ought to ensure the permissions are correct + // + sprintf(fname, "%s/MK_USER", tokdata->data_store); + fp = fopen(fname, "w"); + if (!fp) { + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + set_perm(fileno(fp)); + rc = fwrite(cipher, cipher_len, 1, fp); + if (rc != 1) { + TRACE_ERROR("fwrite failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + rc = CKR_OK; + +done: + if (fp) + fclose(fp); + if (key) + free(key); + if (clear) + free(clear); + if (cipher) + free(cipher); + + return rc; +} + +CK_RV generate_master_key_old(STDLL_TokData_t *tokdata, CK_BYTE *key) +{ + CK_RV rc = CKR_OK; + CK_ULONG key_len = 0L; + CK_ULONG master_key_len = 0L; + + /* Skip it if master key is not needed. */ + if (!token_specific.data_store.use_master_key) + return CKR_OK; + + if ((rc = get_encryption_info_for_clear_key(&key_len, NULL)) != CKR_OK || + (rc = get_encryption_info(&master_key_len, NULL)) != CKR_OK) + return ERR_FUNCTION_FAILED; + + /* For secure key tokens, object encrypt/decrypt uses + * software(openssl), not token. So generate masterkey via RNG. + */ + if (is_secure_key_token()) + return rng_generate(tokdata, key, key_len); + + /* For clear key tokens, let token generate masterkey + * since token will also encrypt/decrypt the objects. + */ + switch (token_specific.data_store.encryption_algorithm) { + case CKM_DES3_CBC: + return token_specific.t_des_key_gen(tokdata, key, + master_key_len, key_len); + case CKM_AES_CBC: + return token_specific.t_aes_key_gen(tokdata, key, + master_key_len, key_len); + } + + return ERR_MECHANISM_INVALID; +} + +CK_RV restore_private_token_object_old(STDLL_TokData_t *tokdata, CK_BYTE *data, + CK_ULONG len, OBJECT *pObj) +{ + CK_BYTE *clear = NULL; + CK_BYTE *obj_data = NULL; + CK_BYTE *ptr = NULL; + CK_BYTE *key = NULL; + CK_ULONG key_len; + CK_ULONG block_size; + CK_BYTE hash_sha[SHA1_HASH_SIZE]; + CK_ULONG clear_len, obj_data_len; + CK_RV rc; + + // format for the object data: + // (private flag has already been read at this point) + // ---- begin encrypted part + // length of object data + // object data + // SHA of object data + // ---- end encrypted part + // + + clear_len = len; + + clear = (CK_BYTE *) malloc(len); + if (!clear) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + + if ((rc = get_encryption_info(&key_len, &block_size)) != CKR_OK) + goto done; + + // decrypt the encrypted chunk + key = malloc(key_len); + if (!key) { + rc = ERR_HOST_MEMORY; + goto done; + } + memcpy(key, tokdata->master_key, key_len); + + rc = decrypt_data_with_clear_key(tokdata, key, key_len, + token_specific.data_store. + obj_initial_vector, data, len, clear, + &clear_len); + if (rc != CKR_OK) { + goto done; + } + + rc = strip_pkcs_padding(clear, len, &clear_len); + + // if the padding extraction didn't work it means the object was + // tampered with or the key was incorrect + // + if (rc != CKR_OK || (clear_len > len)) { + TRACE_DEVEL("strip_pkcs_padding failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + ptr = clear; + + obj_data_len = *(CK_ULONG_32 *) ptr; + + // prevent buffer overflow in sha_update + if (obj_data_len > clear_len) { + TRACE_ERROR("stripped length is greater than clear length\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + ptr += sizeof(CK_ULONG_32); + obj_data = ptr; + + // check the hash + // + rc = compute_sha1(tokdata, ptr, obj_data_len, hash_sha); + if (rc != CKR_OK) { + goto done; + } + ptr += obj_data_len; + + if (memcmp(ptr, hash_sha, SHA1_HASH_SIZE) != 0) { + TRACE_ERROR("stored hash does not match restored data hash.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + // okay. at this point, we're satisfied that nobody has tampered with + // the token object... + // + + rc = object_mgr_restore_obj(tokdata, obj_data, pObj); + if (rc != CKR_OK) { + goto done; + } + rc = CKR_OK; + +done: + if (clear) + free(clear); + if (key) + free(key); + + return rc; +} + +// +// +CK_RV reload_token_object_old(STDLL_TokData_t *tokdata, OBJECT *obj) +{ + FILE *fp = NULL; + CK_BYTE *buf = NULL; + char fname[PATH_MAX]; + CK_BBOOL priv; + CK_ULONG_32 size; + CK_ULONG size_64; + CK_RV rc; + size_t read_size; + + memset(fname, 0x0, sizeof(fname)); + + sprintf(fname, "%s/%s/", tokdata->data_store, PK_LITE_OBJ_DIR); + + strncat(fname, (char *) obj->name, 8); + + fp = fopen(fname, "r"); + if (!fp) { + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + set_perm(fileno(fp)); + + if (!fread(&size, sizeof(CK_ULONG_32), 1, fp)) { + OCK_SYSLOG(LOG_ERR, "Cannot read size\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (!fread(&priv, sizeof(CK_BBOOL), 1, fp)) { + OCK_SYSLOG(LOG_ERR, "Cannot read boolean\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + size = size - sizeof(CK_ULONG_32) - sizeof(CK_BBOOL); // SAB + + buf = (CK_BYTE *) malloc(size); + if (!buf) { + rc = CKR_HOST_MEMORY; + OCK_SYSLOG(LOG_ERR, + "Cannot malloc %u bytes to read in token object %s " + "(ignoring it)", size, fname); + goto done; + } + + read_size = fread(buf, 1, size, fp); + if (read_size != size) { + OCK_SYSLOG(LOG_ERR, + "Token object %s appears corrupted (ignoring it)", fname); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + size_64 = size; + + if (priv) + rc = restore_private_token_object_old(tokdata, buf, size_64, obj); + else + rc = object_mgr_restore_obj(tokdata, buf, obj); + +done: + if (fp) + fclose(fp); + if (buf) + free(buf); + + return rc; +} + +// this is the same as the old version. public token objects are stored in the +// clear +// Note: The token lock (XProcLock) must be held when calling this function. +// +CK_RV save_public_token_object_old(STDLL_TokData_t *tokdata, OBJECT * obj) +{ + FILE *fp = NULL; + CK_BYTE *clear = NULL; + char fname[PATH_MAX]; + CK_ULONG clear_len; + CK_BBOOL flag = FALSE; + CK_RV rc; + CK_ULONG_32 total_len; + rc = object_flatten(obj, &clear, &clear_len); + if (rc != CKR_OK) { + goto error; + } + + sprintf(fname, "%s/%s/", tokdata->data_store, PK_LITE_OBJ_DIR); + strncat(fname, (char *) obj->name, 8); + fp = fopen(fname, "w"); + if (!fp) { + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto error; + } + + set_perm(fileno(fp)); + + total_len = clear_len + sizeof(CK_ULONG_32) + sizeof(CK_BBOOL); + + (void) fwrite(&total_len, sizeof(CK_ULONG_32), 1, fp); + (void) fwrite(&flag, sizeof(CK_BBOOL), 1, fp); + (void) fwrite(clear, clear_len, 1, fp); + + fclose(fp); + free(clear); + + return CKR_OK; + +error: + if (fp) + fclose(fp); + if (clear) + free(clear); + + return rc; +} + +// +// Note: The token lock (XProcLock) must be held when calling this function. +// +CK_RV load_public_token_objects_old(STDLL_TokData_t *tokdata) +{ + FILE *fp1 = NULL, *fp2 = NULL; + CK_BYTE *buf = NULL; + char tmp[PATH_MAX]; + char iname[PATH_MAX]; + char fname[PATH_MAX]; + CK_BBOOL priv; + CK_ULONG_32 size; + size_t read_size; + + sprintf(iname, "%s/%s/%s", tokdata->data_store, PK_LITE_OBJ_DIR, + PK_LITE_OBJ_IDX); + + fp1 = fopen(iname, "r"); + if (!fp1) + return CKR_OK; // no token objects + + while (fgets(tmp, 50, fp1)) { + tmp[strlen(tmp) - 1] = 0; + + sprintf(fname, "%s/%s/", tokdata->data_store, PK_LITE_OBJ_DIR); + strcat(fname, tmp); + + fp2 = fopen(fname, "r"); + if (!fp2) + continue; + + if (!fread(&size, sizeof(CK_ULONG_32), 1, fp2)) { + fclose(fp2); + OCK_SYSLOG(LOG_ERR, "Cannot read size\n"); + continue; + } + if (!fread(&priv, sizeof(CK_BBOOL), 1, fp2)) { + fclose(fp2); + OCK_SYSLOG(LOG_ERR, "Cannot read boolean\n"); + continue; + } + if (priv == TRUE) { + fclose(fp2); + continue; + } + // size--; + size = size - sizeof(CK_ULONG_32) - sizeof(CK_BBOOL); + buf = (CK_BYTE *) malloc(size); + if (!buf) { + fclose(fp2); + OCK_SYSLOG(LOG_ERR, + "Cannot malloc %u bytes to read in " + "token object %s (ignoring it)", size, fname); + continue; + } + + read_size = fread(buf, 1, size, fp2); + if (read_size != size) { + fclose(fp2); + free(buf); + OCK_SYSLOG(LOG_ERR, + "Cannot read token object %s " "(ignoring it)", fname); + continue; + } + // ... grab object mutex here. + if (object_mgr_restore_obj_withSize(tokdata, + buf, NULL, size) != CKR_OK) { + OCK_SYSLOG(LOG_ERR, + "Cannot restore token object %s " + "(ignoring it)", fname); + } + free(buf); + fclose(fp2); + } + + fclose(fp1); + + return CKR_OK; +} + + +/****************************************************************************** + * tokversion >= 3.12 object store + */ + +static CK_RV aes_256_gcm_seal(unsigned char *out, + unsigned char tag[16], + const unsigned char *aad, + size_t aadlen, + const unsigned char *in, + size_t inlen, + const unsigned char key[32], + const unsigned char iv[12]) +{ + CK_RV rc; + int outlen; + + EVP_CIPHER_CTX *ctx = NULL; + + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = ERR_HOST_MEMORY; + goto done; + } + + if (EVP_CipherInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL, -1) != 1 + || EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL) != 1 + || EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) != 1 + || EVP_CipherUpdate(ctx, NULL, &outlen, aad, aadlen) != 1 + || EVP_CipherUpdate(ctx, out, &outlen, in, inlen) != 1 + || EVP_CipherFinal_ex(ctx, out, &outlen) != 1 + || EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag) != 1) { + TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR)); + rc = ERR_GENERAL_ERROR; + goto done; + } + + rc = CKR_OK; +done: + EVP_CIPHER_CTX_free(ctx); + return rc; +} + +static CK_RV aes_256_gcm_unseal(unsigned char *out, + const unsigned char *aad, + size_t aadlen, + const unsigned char *in, + size_t inlen, + const unsigned char tag[16], + const unsigned char key[32], + const unsigned char iv[12]) +{ + CK_RV rc; + int outlen; + + EVP_CIPHER_CTX *ctx = NULL; + + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = ERR_HOST_MEMORY; + goto done; + } + + if (EVP_CipherInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL, -1) != 1 + || EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, (unsigned char *)tag) != 1 + || EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL) != 1 + || EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 0) != 1 + || EVP_CipherUpdate(ctx, NULL, &outlen, aad, aadlen) != 1 + || EVP_CipherUpdate(ctx, out, &outlen, in, inlen) != 1 + || EVP_CipherFinal_ex(ctx, out, &outlen) != 1) { + TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR)); + rc = ERR_GENERAL_ERROR; + goto done; + } + + rc = CKR_OK; +done: + EVP_CIPHER_CTX_free(ctx); + return rc; +} + +static CK_RV aes_256_wrap(unsigned char out[40], + const unsigned char in[32], + const unsigned char kek[32]) +{ + CK_RV rc; + int outlen; + + EVP_CIPHER_CTX *ctx = NULL; + + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = ERR_HOST_MEMORY; + goto done; + } + + EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + + if (EVP_CipherInit_ex(ctx, EVP_aes_256_wrap(), NULL, kek, NULL, 1) != 1 + || EVP_CipherUpdate(ctx, out, &outlen, in, 32) != 1 + || EVP_CipherFinal_ex(ctx, out, &outlen) != 1) { + TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR)); + rc = ERR_GENERAL_ERROR; + goto done; + } + + rc = CKR_OK; +done: + EVP_CIPHER_CTX_free(ctx); + return rc; +} + +static CK_RV aes_256_unwrap(unsigned char key[32], + const unsigned char in[40], + const unsigned char kek[32]) +{ + CK_RV rc; + int outlen; + + EVP_CIPHER_CTX *ctx = NULL; + + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = ERR_HOST_MEMORY; + goto done; + } + + EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + + if (EVP_CipherInit_ex(ctx, EVP_aes_256_wrap(), NULL, kek, NULL, 0) != 1 + || EVP_CipherUpdate(ctx, key, &outlen, in, 40) != 1 + || EVP_CipherFinal_ex(ctx, key, &outlen) != 1) { + TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR)); + rc = ERR_GENERAL_ERROR; + goto done; + } + + rc = CKR_OK; +done: + EVP_CIPHER_CTX_free(ctx); + return rc; +} + +CK_RV generate_master_key(STDLL_TokData_t *tokdata, CK_BYTE *key) +{ + if (tokdata->version < TOK_NEW_DATA_STORE) + return generate_master_key_old(tokdata, key); + + /* generate a 256-bit AES key */ + return rng_generate(tokdata, key, 32); +} + +/** + * Wrap 256-bit AES master key by 256-bit AES SO wrap key + * using AES-KW (RFC 3394). The resulting 40-bytes cipher-text + * is stored in the MK_SO file in the token's data store. + */ +CK_RV save_masterkey_so(STDLL_TokData_t *tokdata) +{ + FILE *fp = NULL; + char fname[PATH_MAX]; + CK_RV rc; + unsigned char outbuf[40]; + + if (tokdata->version < TOK_NEW_DATA_STORE) + return save_masterkey_so_old(tokdata); + + /* Skip it if master key is not needed. */ + if (!token_specific.data_store.use_master_key) + return CKR_OK; + + /* wrap master key with so_wrap_key */ + rc = aes_256_wrap(outbuf, tokdata->master_key, tokdata->so_wrap_key); + if (rc != CKR_OK) + goto done; + + // write the file + // + // probably ought to ensure the permissions are correct + // + sprintf(fname, "%s/MK_SO", tokdata->data_store); + fp = fopen(fname, "w"); + if (!fp) { + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + set_perm(fileno(fp)); + + rc = fwrite(outbuf, sizeof(outbuf), 1, fp); + if (rc != 1) { + TRACE_ERROR("fwrite failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + rc = CKR_OK; +done: + if (fp) + fclose(fp); + return rc; +} + +CK_RV load_masterkey_so(STDLL_TokData_t *tokdata) +{ + FILE *fp = NULL; + CK_RV rc; + char fname[PATH_MAX]; + unsigned char inbuf[40]; + + if (tokdata->version < TOK_NEW_DATA_STORE) + return load_masterkey_so_old(tokdata); + + memset(tokdata->master_key, 0, sizeof(tokdata->master_key)); + + // this file gets created on C_InitToken so we can assume that it always + // exists + // + sprintf(fname, "%s/MK_SO", tokdata->data_store); + fp = fopen(fname, "r"); + if (!fp) { + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + set_perm(fileno(fp)); + + rc = fread(inbuf, sizeof(inbuf), 1, fp); + if (rc != 1) { + TRACE_ERROR("fread() failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* unwrap master key with so_wrap_key */ + rc = aes_256_unwrap(tokdata->master_key, inbuf, tokdata->so_wrap_key); + if (rc != CKR_OK) + goto done; + + rc = CKR_OK; +done: + if (fp) + fclose(fp); + return rc; +} + +/** + * Wrap 256-bit AES master key by 256-bit AES User wrap key + * using AES-KW (RFC 3394). The resulting 40-bytes cipher-text + * is stored in the MK_SO file in the token's data store. + */ +CK_RV save_masterkey_user(STDLL_TokData_t *tokdata) +{ + FILE *fp = NULL; + char fname[PATH_MAX]; + CK_RV rc; + unsigned char outbuf[40]; + + if (tokdata->version < TOK_NEW_DATA_STORE) + return save_masterkey_user_old(tokdata); + + /* wrap master key with so_wrap_key */ + rc = aes_256_wrap(outbuf, tokdata->master_key, tokdata->user_wrap_key); + if (rc != CKR_OK) + goto done; + + // write the file + // + // probably ought to ensure the permissions are correct + // + sprintf(fname, "%s/MK_USER", tokdata->data_store); + fp = fopen(fname, "w"); + if (!fp) { + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + set_perm(fileno(fp)); + rc = fwrite(outbuf, sizeof(outbuf), 1, fp); + if (rc != 1) { + TRACE_ERROR("fwrite failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + rc = CKR_OK; +done: + if (fp) + fclose(fp); + return rc; +} + +CK_RV load_masterkey_user(STDLL_TokData_t *tokdata) +{ + FILE *fp = NULL; + CK_RV rc; + char fname[PATH_MAX]; + EVP_CIPHER_CTX *ctx = NULL; + unsigned char inbuf[40]; + + if (tokdata->version < TOK_NEW_DATA_STORE) + return load_masterkey_user_old(tokdata); + + memset(tokdata->master_key, 0, sizeof(tokdata->master_key)); + + // this file gets created on C_InitToken so we can assume that it always + // exists + // + sprintf(fname, "%s/MK_USER", tokdata->data_store); + fp = fopen(fname, "r"); + if (!fp) { + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + set_perm(fileno(fp)); + + rc = fread(inbuf, sizeof(inbuf), 1, fp); + if (rc != 1) { + TRACE_ERROR("fread failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* unwrap master key with user_wrap_key */ + rc = aes_256_unwrap(tokdata->master_key, inbuf, tokdata->user_wrap_key); + if (rc != CKR_OK) + goto done; + + rc = CKR_OK; +done: + if (fp) + fclose(fp); + EVP_CIPHER_CTX_free(ctx); + return rc; +} + +CK_RV save_token_data(STDLL_TokData_t *tokdata, CK_SLOT_ID slot_id) +{ + FILE *fp = NULL; + TOKEN_DATA td; + CK_RV rc; + char fname[PATH_MAX]; + + if (tokdata->version < TOK_NEW_DATA_STORE) + return save_token_data_old(tokdata, slot_id); + + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get Process Lock.\n"); + goto out_nolock; + } + + sprintf(fname, "%s/%s", tokdata->data_store, PK_LITE_NV); + fp = fopen(fname, "w"); + if (!fp) { + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + set_perm(fileno(fp)); + + /* Write generic token data */ + memcpy(&td, tokdata->nv_token_data, sizeof(TOKEN_DATA)); + + td.token_info.flags = htobe32(td.token_info.flags); + td.token_info.ulMaxSessionCount = htobe32(td.token_info.ulMaxSessionCount); + td.token_info.ulSessionCount = htobe32(td.token_info.ulSessionCount); + td.token_info.ulMaxRwSessionCount + = htobe32(td.token_info.ulMaxRwSessionCount); + td.token_info.ulRwSessionCount = htobe32(td.token_info.ulRwSessionCount); + td.token_info.ulMaxPinLen = htobe32(td.token_info.ulMaxPinLen); + td.token_info.ulMinPinLen = htobe32(td.token_info.ulMinPinLen); + td.token_info.ulTotalPublicMemory + = htobe32(td.token_info.ulTotalPublicMemory); + td.token_info.ulFreePublicMemory + = htobe32(td.token_info.ulFreePublicMemory); + td.token_info.ulTotalPrivateMemory + = htobe32(td.token_info.ulTotalPrivateMemory); + td.token_info.ulFreePrivateMemory + = htobe32(td.token_info.ulFreePrivateMemory); + td.tweak_vector.allow_weak_des = htobe32(td.tweak_vector.allow_weak_des); + td.tweak_vector.check_des_parity + = htobe32(td.tweak_vector.check_des_parity); + td.tweak_vector.allow_key_mods = htobe32(td.tweak_vector.allow_key_mods); + td.tweak_vector.netscape_mods = htobe32(td.tweak_vector.netscape_mods); + td.dat.version = htobe32(td.dat.version); + td.dat.so_login_it = htobe64(td.dat.so_login_it); + td.dat.user_login_it = htobe64(td.dat.user_login_it); + td.dat.so_wrap_it = htobe64(td.dat.so_wrap_it); + td.dat.user_wrap_it = htobe64(td.dat.user_wrap_it); + + if (!fwrite(&td, sizeof(TOKEN_DATA), 1, fp)) { + TRACE_ERROR("fwrite(%s): %s\n", fname, + ferror(fp) ? strerror(errno) : "failed"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Write token-specific data */ + if (token_specific.t_save_token_data) { + rc = token_specific.t_save_token_data(tokdata, slot_id, fp); + if (rc) + goto done; + } + + rc = CKR_OK; + +done: + if (fp) + fclose(fp); + + if (rc == CKR_OK) { + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) + TRACE_ERROR("Failed to release Process Lock.\n"); + } else { + /* return error that occurred first */ + XProcUnLock(tokdata); + } + +out_nolock: + return rc; +} + +CK_RV load_token_data(STDLL_TokData_t *tokdata, CK_SLOT_ID slot_id) +{ + FILE *fp = NULL; + char fname[PATH_MAX]; + TOKEN_DATA td; + CK_RV rc; + + if (tokdata->version < TOK_NEW_DATA_STORE) + return load_token_data_old(tokdata, slot_id); + + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get Process Lock.\n"); + goto out_nolock; + } + + sprintf(fname, "%s/%s", tokdata->data_store, PK_LITE_NV); + fp = fopen(fname, "r"); + if (!fp) { + /* Better error checking added */ + if (errno == ENOENT) { + init_token_data(tokdata, slot_id); + + fp = fopen(fname, "r"); + if (!fp) { + // were really hosed here since the created + // did not occur + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto out_unlock; + } + } else { + /* Could not open file for some unknown reason */ + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto out_unlock; + } + } + set_perm(fileno(fp)); + + /* Load generic token data */ + if (!fread(&td, sizeof(TOKEN_DATA), 1, fp)) { + TRACE_ERROR("fread(%s): %s\n", fname, + ferror(fp) ? strerror(errno) : "failed"); + rc = CKR_FUNCTION_FAILED; + goto out_unlock; + } + /* data marshalling */ + td.token_info.flags = be32toh(td.token_info.flags); + td.token_info.ulMaxSessionCount = be32toh(td.token_info.ulMaxSessionCount); + td.token_info.ulSessionCount = be32toh(td.token_info.ulSessionCount); + td.token_info.ulMaxRwSessionCount + = be32toh(td.token_info.ulMaxRwSessionCount); + td.token_info.ulRwSessionCount = be32toh(td.token_info.ulRwSessionCount); + td.token_info.ulMaxPinLen = be32toh(td.token_info.ulMaxPinLen); + td.token_info.ulMinPinLen = be32toh(td.token_info.ulMinPinLen); + td.token_info.ulTotalPublicMemory + = be32toh(td.token_info.ulTotalPublicMemory); + td.token_info.ulFreePublicMemory + = be32toh(td.token_info.ulFreePublicMemory); + td.token_info.ulTotalPrivateMemory + = be32toh(td.token_info.ulTotalPrivateMemory); + td.token_info.ulFreePrivateMemory + = be32toh(td.token_info.ulFreePrivateMemory); + td.tweak_vector.allow_weak_des = be32toh(td.tweak_vector.allow_weak_des); + td.tweak_vector.check_des_parity + = be32toh(td.tweak_vector.check_des_parity); + td.tweak_vector.allow_key_mods = be32toh(td.tweak_vector.allow_key_mods); + td.tweak_vector.netscape_mods = be32toh(td.tweak_vector.netscape_mods); + td.dat.version = be32toh(td.dat.version); + td.dat.so_login_it = be64toh(td.dat.so_login_it); + td.dat.user_login_it = be64toh(td.dat.user_login_it); + td.dat.so_wrap_it = be64toh(td.dat.so_wrap_it); + td.dat.user_wrap_it = be64toh(td.dat.user_wrap_it); + + memcpy(tokdata->nv_token_data, &td, sizeof(TOKEN_DATA)); + + /* Load token-specific data */ + if (token_specific.t_load_token_data) { + rc = token_specific.t_load_token_data(tokdata, slot_id, fp); + if (rc) + goto out_unlock; + } + + rc = CKR_OK; + +out_unlock: + if (fp) + fclose(fp); + + if (rc == CKR_OK) { + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) + TRACE_ERROR("Failed to release Process Lock.\n"); + } else { + /* return error that occurred first */ + XProcUnLock(tokdata); + } + +out_nolock: + return rc; +} + +/** + * Big-endian increment. Return carry. + */ +static inline int inc32(unsigned char ctr[4]) +{ + unsigned int c = 1; + + c += (unsigned int)ctr[3]; + ctr[3] = (unsigned char)c; + c >>= 8; + c += (unsigned int)ctr[2]; + ctr[2] = (unsigned char)c; + c >>= 8; + c += (unsigned int)ctr[1]; + ctr[1] = (unsigned char)c; + c >>= 8; + c += (unsigned int)ctr[0]; + ctr[0] = (unsigned char)c; + c >>= 8; + + return c; +} + +/** + * private tok obj layout + * + * --- auth ------- <--+ + * u32 tokversion | 64-byte header + * u8 private_flag | + * u8 reserved[3] | + * u8 key_wrapped[40] | + * u8 iv[12] | + * u32 object_len | + * --- auth+enc --- <--+ + * u8 object[object_len] | body + * ---------------- <--+ + * u8 tag[16] | 16-byte footer + * ---------------- <--+ + */ +#define HEADER_LEN 64 +#define FOOTER_LEN 16 + +// +// Note: The token lock (XProcLock) must be held when calling this function. +// +CK_RV save_private_token_object(STDLL_TokData_t *tokdata, OBJECT *obj) +{ + FILE *fp = NULL; + CK_BYTE *obj_data = NULL; + char fname[PATH_MAX]; + CK_ULONG obj_data_len; + CK_RV rc; + CK_ULONG_32 obj_data_len_32; + CK_ULONG_32 total_len; + CK_BBOOL flag = CK_TRUE; + unsigned char obj_key[256 / 8], obj_iv[96 / 8], obj_key_wrapped[40]; + unsigned char *data = NULL; + uint32_t tmp; + int new = 0; + + if (tokdata->version < TOK_NEW_DATA_STORE) + return save_private_token_object_old(tokdata, obj); + + sprintf(fname, "%s/%s/", tokdata->data_store, PK_LITE_OBJ_DIR); + strncat(fname, (char *)obj->name, 8); + + rc = object_flatten(obj, &obj_data, &obj_data_len); + obj_data_len_32 = obj_data_len; + if (rc != CKR_OK) { + goto done; + } + + total_len = HEADER_LEN + obj_data_len_32 + FOOTER_LEN; + + data = malloc(total_len); + if (data == NULL) { + rc = CKR_HOST_MEMORY; + goto done; + } + + fp = fopen(fname, "r"); + if (fp == NULL) { + /* create new token object */ + new = 1; + } else { + /* update existing token object */ + if (fread(data, HEADER_LEN, 1, fp) != 1) { + TRACE_ERROR("fread(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + fclose(fp); + fp = NULL; + + /* iv */ + memcpy(obj_iv, data + 48, 12); + + /* increment iv counter field */ + if (inc32(obj_iv + 8)) { + /* counter overflow: generate new key */ + new = 1; + } else { + /* get wrapped key key */ + memcpy(obj_key_wrapped, data + 8, 40); + + /* get key */ + rc = aes_256_unwrap(obj_key, obj_key_wrapped, tokdata->master_key); + if (rc != CKR_OK) + goto done; + } + } + if (new) { + /* get key */ + rng_generate(tokdata, obj_key, 32); + + /* iv = [obj.-name|counter] */ + memcpy(obj_iv, obj->name, 8); + obj_iv[8] = 0; + obj_iv[9] = 0; + obj_iv[10] = 0; + obj_iv[11] = 1; + + /* get wrapped key */ + rc = aes_256_wrap(obj_key_wrapped, obj_key, tokdata->master_key); + if (rc != CKR_OK) + goto done; + } + + /* version */ + tmp = htobe32(tokdata->version); + memcpy(data, &tmp, 4); + /* flags */ + memcpy(data + 4, &flag, 1); + tmp = 0; + memcpy(data + 5, &tmp, 3); + /* wrapped key */ + memcpy(data + 8, obj_key_wrapped, 40); + /* iv */ + memcpy(data + 48, obj_iv, 12); + /* object len */ + tmp = htobe32(obj_data_len_32); + memcpy(data + 60, &tmp, 4); + + rc = aes_256_gcm_seal(/* ciphertext */ + data + HEADER_LEN, + /* tag */ + data + HEADER_LEN + + obj_data_len_32, + /* aad */ + data, HEADER_LEN, + /* plaintext */ + obj_data, obj_data_len_32, + /* key */ + obj_key, + /* iv */ + obj_iv); + if (rc != CKR_OK) + goto done; + + fp = fopen(fname, "w"); + if (!fp) { + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + set_perm(fileno(fp)); + + if (fwrite(data, total_len, 1, fp) != 1) { + TRACE_ERROR("fwrite(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + fclose(fp); + fp = NULL; + + rc = CKR_OK; +done: + if (fp) + fclose(fp); + if (obj_data) + free(obj_data); + if (data) + free(data); + return rc; +} + +// +// Note: The token lock (XProcLock) must be held when calling this function. +// +CK_RV load_private_token_objects(STDLL_TokData_t *tokdata) +{ + FILE *fp1 = NULL, *fp2 = NULL; + CK_BYTE *buf = NULL; + char tmp[PATH_MAX]; + char iname[PATH_MAX]; + char fname[PATH_MAX]; + CK_BBOOL priv; + CK_ULONG_32 size; + CK_RV rc; + unsigned char header[HEADER_LEN], footer[FOOTER_LEN]; + uint32_t len; + + if (tokdata->version < TOK_NEW_DATA_STORE) + return load_private_token_objects_old(tokdata); + + sprintf(iname, "%s/%s/%s", tokdata->data_store, PK_LITE_OBJ_DIR, + PK_LITE_OBJ_IDX); + + fp1 = fopen(iname, "r"); + if (!fp1) + return CKR_OK; // no token objects + + while (fgets(tmp, 50, fp1)) { + tmp[strlen(tmp) - 1] = 0; + + sprintf(fname, "%s/%s/", tokdata->data_store, PK_LITE_OBJ_DIR); + strcat(fname, tmp); + + fp2 = fopen(fname, "r"); + if (!fp2) + continue; + + if (fread(header, HEADER_LEN, 1, fp2) != 1) { + fclose(fp2); + continue; + } + + memcpy(&priv, header + 4, 1); + if (priv == FALSE) { + fclose(fp2); + continue; + } + + memcpy(&len, header + 60, 4); + size = be32toh(len); + + buf = (CK_BYTE *)malloc(size); + if (!buf) { + fclose(fp2); + OCK_SYSLOG(LOG_ERR, + "Cannot malloc %u bytes to read in " + "token object %s (ignoring it)", size, fname); + continue; + } + + if (fread(buf, size, 1, fp2) != 1) { + free(buf); + fclose(fp2); + OCK_SYSLOG(LOG_ERR, + "Cannot read token object %s " "(ignoring it)", fname); + continue; + } + if (fread(footer, FOOTER_LEN, 1, fp2) != 1) { + fclose(fp2); + OCK_SYSLOG(LOG_ERR, + "Cannot read token object %s " "(ignoring it)", fname); + continue; + } + + rc = restore_private_token_object(tokdata, header, + buf, size, + footer, NULL); + if (rc != CKR_OK) + goto error; + + free(buf); + fclose(fp2); + } + + fclose(fp1); + return CKR_OK; +error: + if (buf) + free(buf); + if (fp1) + fclose(fp1); + if (fp2) + fclose(fp2); + return rc; +} + +// +// +CK_RV restore_private_token_object(STDLL_TokData_t *tokdata, + CK_BYTE *header, + CK_BYTE *data, CK_ULONG len, + CK_BYTE *footer, + OBJECT *pObj) +{ + unsigned char obj_iv[12], obj_key[32], obj_key_wrapped[40]; + CK_BYTE *buff = NULL; + CK_RV rc; + + if (tokdata->version < TOK_NEW_DATA_STORE) + return restore_private_token_object_old(tokdata, data, len, pObj); + + /* wrapped key */ + memcpy(obj_key_wrapped, header + 8, 40); + /* iv */ + memcpy(obj_iv, header + 48, 12); + + rc = aes_256_unwrap(obj_key, obj_key_wrapped, tokdata->master_key); + if (rc != CKR_OK) { + rc = CKR_FUNCTION_FAILED; + goto done; + } + + buff = (CK_BYTE *)malloc(len); + if (buff == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + + rc = aes_256_gcm_unseal(buff, /* plain-text */ + header, HEADER_LEN, /* aad */ + data, len, /* cipher-text*/ + footer, /* tag */ + obj_key, obj_iv); + if (rc != CKR_OK) { + rc = CKR_FUNCTION_FAILED; + goto done; + } + + rc = object_mgr_restore_obj(tokdata, buff, pObj); + if (rc != CKR_OK) { + goto done; + } + + rc = CKR_OK; +done: + if (buff) + free(buff); + return rc; +} + +CK_RV reload_token_object(STDLL_TokData_t *tokdata, OBJECT *obj) +{ + unsigned char header[HEADER_LEN], footer[FOOTER_LEN]; + FILE *fp = NULL; + CK_BYTE *buf = NULL; + char fname[PATH_MAX]; + CK_BBOOL priv; + CK_ULONG_32 size; + CK_ULONG size_64; + CK_RV rc; + uint32_t len; + + if (tokdata->version < TOK_NEW_DATA_STORE) + return reload_token_object_old(tokdata, obj); + + memset(fname, 0x0, sizeof(fname)); + sprintf(fname, "%s/%s/", tokdata->data_store, PK_LITE_OBJ_DIR); + strncat(fname, (char *) obj->name, 8); + + fp = fopen(fname, "r"); + if (!fp) { + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + set_perm(fileno(fp)); + + if (fread(header, HEADER_LEN, 1, fp) != 1) { + OCK_SYSLOG(LOG_ERR, "Cannot read header\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + memcpy(&priv, header + 4, 1); + memcpy(&len, header + 60, 4); + size = be32toh(len); + + buf = (CK_BYTE *) malloc(size); + if (buf == NULL) { + rc = CKR_HOST_MEMORY; + OCK_SYSLOG(LOG_ERR, + "Cannot malloc %u bytes to read in token object %s " + "(ignoring it)", size, fname); + goto done; + } + + if (fread(buf, size, 1, fp) != 1) { + OCK_SYSLOG(LOG_ERR, + "Token object %s appears corrupted (ignoring it)", fname); + rc = CKR_FUNCTION_FAILED; + goto done; + } + if (fread(footer, FOOTER_LEN, 1, fp) != 1) { + OCK_SYSLOG(LOG_ERR, + "Token object %s appears corrupted (ignoring it)", fname); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + size_64 = size; + + if (priv) { + rc = restore_private_token_object(tokdata, header, buf, size_64, + footer, obj); + } else { + rc = object_mgr_restore_obj(tokdata, buf, obj); + } +done: + if (fp) + fclose(fp); + if (buf) + free(buf); + return rc; +} + +/** + * public tok obj layout + * + * ---------------- <--+ + * u32 tokversion | 16-byte header + * u8 private_flag | + * u8 reserved[7] | + * u32 object_len | + * ---------------- <--+ + * u8 object[object_len] | body + * ---------------- <--+ + */ +#define PUB_HEADER_LEN 16 + +// +// Note: The token lock (XProcLock) must be held when calling this function. +// +CK_RV save_public_token_object(STDLL_TokData_t *tokdata, OBJECT *obj) +{ + FILE *fp = NULL; + CK_BYTE *clear = NULL; + char fname[PATH_MAX]; + CK_ULONG clear_len; + CK_BBOOL flag = FALSE; + CK_RV rc; + CK_ULONG_32 len; + unsigned char reserved[7] = {0}; + + if (tokdata->version < TOK_NEW_DATA_STORE) + return save_public_token_object_old(tokdata, obj); + + rc = object_flatten(obj, &clear, &clear_len); + if (rc != CKR_OK) { + goto done; + } + len = (CK_ULONG_32)clear_len; + + sprintf(fname, "%s/%s/", tokdata->data_store, PK_LITE_OBJ_DIR); + strncat(fname, (char *) obj->name, 8); + + fp = fopen(fname, "w"); + if (!fp) { + TRACE_ERROR("fopen(%s): %s\n", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + set_perm(fileno(fp)); + if (fwrite(&tokdata->version, 4, 1, fp) != 1 + || fwrite(&flag, 1, 1, fp) != 1 + || fwrite(reserved, 7, 1, fp) != 1 + || fwrite(&len, 4, 1, fp) != 1 + || fwrite(clear, len, 1, fp) != 1) { + rc = CKR_FUNCTION_FAILED; + goto done; + } + + fclose(fp); + fp = NULL; + + rc = CKR_OK; +done: + if (fp) + fclose(fp); + if (clear) + free(clear); + return rc; +} + +// +// Note: The token lock (XProcLock) must be held when calling this function. +// +CK_RV load_public_token_objects(STDLL_TokData_t *tokdata) +{ + FILE *fp1 = NULL, *fp2 = NULL; + CK_BYTE *buf = NULL; + char tmp[PATH_MAX]; + char iname[PATH_MAX]; + char fname[PATH_MAX]; + CK_BBOOL priv; + CK_ULONG_32 size; + unsigned char header[PUB_HEADER_LEN]; + + if (tokdata->version < TOK_NEW_DATA_STORE) + return load_public_token_objects_old(tokdata); + + sprintf(iname, "%s/%s/%s", tokdata->data_store, PK_LITE_OBJ_DIR, + PK_LITE_OBJ_IDX); + + fp1 = fopen(iname, "r"); + if (!fp1) + return CKR_OK; // no token objects + + while (fgets(tmp, 50, fp1)) { + tmp[strlen(tmp) - 1] = 0; + + sprintf(fname, "%s/%s/", tokdata->data_store, PK_LITE_OBJ_DIR); + strcat(fname, tmp); + + fp2 = fopen(fname, "r"); + if (!fp2) + continue; + + if (fread(header, PUB_HEADER_LEN, 1, fp2) != 1) { + fclose(fp2); + OCK_SYSLOG(LOG_ERR, "Cannot read header\n"); + continue; + } + + memcpy(&priv, header + 4, 1); + memcpy(&size, header + 12, 4); + size = be32toh(size); + + if (priv == TRUE) { + fclose(fp2); + continue; + } + + buf = (CK_BYTE *) malloc(size); + if (!buf) { + fclose(fp2); + OCK_SYSLOG(LOG_ERR, + "Cannot malloc %u bytes to read in " + "token object %s (ignoring it)", size, fname); + continue; + } + + if (fread(buf, size, 1, fp2) != 1) { + fclose(fp2); + free(buf); + OCK_SYSLOG(LOG_ERR, + "Cannot read token object %s " "(ignoring it)", fname); + continue; + } + // ... grab object mutex here. + if (object_mgr_restore_obj_withSize(tokdata, + buf, NULL, size) != CKR_OK) { + OCK_SYSLOG(LOG_ERR, + "Cannot restore token object %s " + "(ignoring it)", fname); + } + free(buf); + fclose(fp2); + } + + fclose(fp1); + return CKR_OK; +} diff --git a/usr/lib/common/lock_btree.c b/usr/lib/common/lock_btree.c new file mode 100644 index 0000000..8e086bf --- /dev/null +++ b/usr/lib/common/lock_btree.c @@ -0,0 +1,508 @@ +/* + * 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 --git a/usr/lib/common/lock_sess_mgr.c b/usr/lib/common/lock_sess_mgr.c new file mode 100644 index 0000000..604a13a --- /dev/null +++ b/usr/lib/common/lock_sess_mgr.c @@ -0,0 +1,1023 @@ +/* + * 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; +} + +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) + free(sess->encr_ctx.context); + + if (sess->encr_ctx.mech.pParameter) + free(sess->encr_ctx.mech.pParameter); + + if (sess->decr_ctx.context) + free(sess->decr_ctx.context); + + if (sess->decr_ctx.mech.pParameter) + free(sess->decr_ctx.mech.pParameter); + + if (sess->digest_ctx.context) + free(sess->digest_ctx.context); + + if (sess->digest_ctx.mech.pParameter) + free(sess->digest_ctx.mech.pParameter); + + if (sess->sign_ctx.context) + free(sess->sign_ctx.context); + + if (sess->sign_ctx.mech.pParameter) + free(sess->sign_ctx.mech.pParameter); + + if (sess->verify_ctx.context) + 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) + free(sess->encr_ctx.context); + + if (sess->encr_ctx.mech.pParameter) + free(sess->encr_ctx.mech.pParameter); + + if (sess->decr_ctx.context) + free(sess->decr_ctx.context); + + if (sess->decr_ctx.mech.pParameter) + free(sess->decr_ctx.mech.pParameter); + + if (sess->digest_ctx.context) + free(sess->digest_ctx.context); + + if (sess->digest_ctx.mech.pParameter) + free(sess->digest_ctx.mech.pParameter); + + if (sess->sign_ctx.context) + free(sess->sign_ctx.context); + + if (sess->sign_ctx.mech.pParameter) + free(sess->sign_ctx.mech.pParameter); + + if (sess->verify_ctx.context) + 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(SESSION *sess, + CK_BBOOL length_only, + CK_BYTE *data, CK_ULONG *data_len) +{ + OP_STATE_DATA *op_data = NULL; + CK_ULONG op_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) { + active_ops++; + if (op_data != NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); + return CKR_STATE_UNSAVEABLE; + } + op_data_len = sizeof(OP_STATE_DATA) + + sizeof(ENCR_DECR_CONTEXT) + + sess->encr_ctx.context_len + sess->encr_ctx.mech.ulParameterLen; + + if (length_only == FALSE) { + op_data = (OP_STATE_DATA *) data; + + 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); + } + } + } + + if (sess->decr_ctx.active == TRUE) { + active_ops++; + if (op_data != NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); + return CKR_STATE_UNSAVEABLE; + } + op_data_len = sizeof(OP_STATE_DATA) + + sizeof(ENCR_DECR_CONTEXT) + + sess->decr_ctx.context_len + sess->decr_ctx.mech.ulParameterLen; + + if (length_only == FALSE) { + op_data = (OP_STATE_DATA *) data; + + 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); + } + } + } + + if (sess->digest_ctx.active == TRUE) { + active_ops++; + if (op_data != NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); + return CKR_STATE_UNSAVEABLE; + } + op_data_len = sizeof(OP_STATE_DATA) + + sizeof(DIGEST_CONTEXT) + + sess->digest_ctx.context_len + sess->digest_ctx.mech.ulParameterLen; + + if (length_only == FALSE) { + op_data = (OP_STATE_DATA *) data; + + 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); + } + } + } + + if (sess->sign_ctx.active == TRUE) { + active_ops++; + if (op_data != NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); + return CKR_STATE_UNSAVEABLE; + } + op_data_len = sizeof(OP_STATE_DATA) + + sizeof(SIGN_VERIFY_CONTEXT) + + sess->sign_ctx.context_len + sess->sign_ctx.mech.ulParameterLen; + + if (length_only == FALSE) { + op_data = (OP_STATE_DATA *) data; + + 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); + } + } + } + + if (sess->verify_ctx.active == TRUE) { + active_ops++; + if (op_data != NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); + return CKR_STATE_UNSAVEABLE; + } + op_data_len = sizeof(OP_STATE_DATA) + + sizeof(SIGN_VERIFY_CONTEXT) + + sess->verify_ctx.context_len + sess->verify_ctx.mech.ulParameterLen; + + if (length_only == FALSE) { + op_data = (OP_STATE_DATA *) data; + + 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->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); + } + } + } + + if (!active_ops) { + TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); + return CKR_OPERATION_NOT_INITIALIZED; + } + + *data_len = op_data_len; + return CKR_OK; +} + + +// +// +CK_RV session_mgr_set_op_state(SESSION *sess, + CK_OBJECT_HANDLE encr_key, + CK_OBJECT_HANDLE auth_key, + CK_BYTE *data, CK_ULONG 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; + + UNUSED(data_len); + + if (!sess || !data) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + op_data = (OP_STATE_DATA *) data; + + // make sure the session states are compatible + // + if (sess->session_info.state != op_data->session_state) { + TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); + return CKR_SAVED_STATE_INVALID; + } + // validate the new state information. don't touch the session + // until the new state is valid. + // + switch (op_data->active_operation) { + case STATE_ENCR: + case STATE_DECR: + { + ENCR_DECR_CONTEXT *ctx = + (ENCR_DECR_CONTEXT *) (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 (auth_key != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_NOT_NEEDED)); + return CKR_KEY_NOT_NEEDED; + } + if (encr_key == 0) { + 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 *) (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 == 0) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_NEEDED)); + return CKR_KEY_NEEDED; + } + if (encr_key != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_NOT_NEEDED)); + return CKR_KEY_NOT_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 *) (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; + } + if (auth_key != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_NOT_NEEDED)); + return CKR_KEY_NOT_NEEDED; + } + if (encr_key != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_NOT_NEEDED)); + return CKR_KEY_NOT_NEEDED; + } + 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; + } + + + // state information looks okay. cleanup the current session state, first + // + if (sess->encr_ctx.active) + encr_mgr_cleanup(&sess->encr_ctx); + + if (sess->decr_ctx.active) + decr_mgr_cleanup(&sess->decr_ctx); + + if (sess->digest_ctx.active) + digest_mgr_cleanup(&sess->digest_ctx); + + if (sess->sign_ctx.active) + sign_mgr_cleanup(&sess->sign_ctx); + + if (sess->verify_ctx.active) + verify_mgr_cleanup(&sess->verify_ctx); + + + // 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; + } + + 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 --git a/usr/lib/common/mech_aes.c b/usr/lib/common/mech_aes.c new file mode 100644 index 0000000..7448587 --- /dev/null +++ b/usr/lib/common/mech_aes.c @@ -0,0 +1,3742 @@ +/* + * 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: mech_aes.c +// +// Mechanisms for AES +// + +#include // for memcmp() et al +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "trace.h" + +#include + +// +// +CK_RV aes_ecb_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (in_data_len % AES_BLOCK_SIZE != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < in_data_len) { + *out_data_len = in_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + rc = ckm_aes_ecb_encrypt(tokdata, in_data, in_data_len, + out_data, out_data_len, key); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + + +// +// +CK_RV aes_ecb_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // CKM_DES3_ECB requires the input data to be an integral + // multiple of the block size + // + if (in_data_len % AES_BLOCK_SIZE != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + return CKR_ENCRYPTED_DATA_LEN_RANGE; + } + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < in_data_len) { + *out_data_len = in_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + rc = ckm_aes_ecb_decrypt(tokdata, in_data, in_data_len, + out_data, out_data_len, key); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + + +// +// +CK_RV aes_cbc_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // CKM_DES3_CBC requires the input data to be an integral + // multiple of the block size + // + if (in_data_len % AES_BLOCK_SIZE != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < in_data_len) { + *out_data_len = in_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + rc = ckm_aes_cbc_encrypt(tokdata, in_data, in_data_len, out_data, + out_data_len, ctx->mech.pParameter, key); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + +// +// +CK_RV aes_cbc_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // CKM_DES3_CBC requires the input data to be an integral + // multiple of the block size + // + if (in_data_len % AES_BLOCK_SIZE != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + return CKR_ENCRYPTED_DATA_LEN_RANGE; + } + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < in_data_len) { + *out_data_len = in_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + rc = ckm_aes_cbc_decrypt(tokdata, in_data, in_data_len, out_data, + out_data_len, ctx->mech.pParameter, key); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + + +// +// +CK_RV aes_cbc_pad_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_BYTE *clear = NULL; + CK_ULONG padded_len; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // AES-CBC-PAD has no input length requirements + // + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + // compute the output length, accounting for padding + // + padded_len = AES_BLOCK_SIZE * (in_data_len / AES_BLOCK_SIZE + 1); + + if (length_only == TRUE) { + *out_data_len = padded_len; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < padded_len) { + *out_data_len = padded_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + clear = (CK_BYTE *) malloc(padded_len); + if (!clear) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memcpy(clear, in_data, in_data_len); + + 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, + ctx->mech.pParameter, key); + + free(clear); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + + +// +// +CK_RV aes_cbc_pad_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_BYTE *clear = NULL; + CK_ULONG padded_len; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // + // no need to validate the input length since we'll pad as necessary + // + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + // we're decrypting so even with CBC-PAD, we should have an integral + // number of block to decrypt + // + if (in_data_len % AES_BLOCK_SIZE != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + rc = CKR_ENCRYPTED_DATA_LEN_RANGE; + goto done; + } + // the amount of cleartext after stripping the padding will actually be less + // than the input bytes... + // + padded_len = in_data_len; + + if (length_only == TRUE) { + *out_data_len = padded_len; + rc = CKR_OK; + goto done; + } + + clear = (CK_BYTE *) malloc(padded_len); + if (!clear) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + rc = ckm_aes_cbc_decrypt(tokdata, in_data, in_data_len, clear, &padded_len, + ctx->mech.pParameter, key); + + if (rc == CKR_OK) { + strip_pkcs_padding(clear, padded_len, out_data_len); + memcpy(out_data, clear, *out_data_len); + } + + free(clear); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + +// +// +CK_RV aes_ctr_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_RV rc; + CK_AES_CTR_PARAMS *aesctr = NULL; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (in_data_len % AES_BLOCK_SIZE != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < in_data_len) { + *out_data_len = in_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + aesctr = (CK_AES_CTR_PARAMS *) ctx->mech.pParameter; + + rc = ckm_aes_ctr_encrypt(tokdata, in_data, in_data_len, out_data, + out_data_len, (CK_BYTE *) aesctr->cb, + (CK_ULONG) aesctr->ulCounterBits, key); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + +// +// +CK_RV aes_ctr_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_RV rc; + CK_AES_CTR_PARAMS *aesctr = NULL; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (in_data_len % AES_BLOCK_SIZE != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + return CKR_ENCRYPTED_DATA_LEN_RANGE; + } + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < in_data_len) { + *out_data_len = in_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + aesctr = (CK_AES_CTR_PARAMS *) ctx->mech.pParameter; + + rc = ckm_aes_ctr_decrypt(tokdata, in_data, in_data_len, out_data, + out_data_len, (CK_BYTE *) aesctr->cb, + (CK_ULONG) aesctr->ulCounterBits, key); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + +// +// +CK_RV aes_ecb_encrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + AES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *clear = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad arguments\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (AES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < AES_BLOCK_SIZE) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + // + remain = (total % AES_BLOCK_SIZE); + out_len = (total - remain); // should always be at least 1 block + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + clear = (CK_BYTE *) malloc(out_len); + if (!clear) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_put(tokdata, key, TRUE); + key = NULL; + return CKR_HOST_MEMORY; + } + // copy any data left over from the previous encryption operation first + // + 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, + out_data_len, key); + if (rc == CKR_OK) { + *out_data_len = out_len; + + // update the context buffer. we already used the buffer's current + // contents so we completely overwrite it + // + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + + context->len = remain; + } + + free(clear); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } +} + + +// +// +CK_RV aes_ecb_decrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + AES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (AES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < AES_BLOCK_SIZE) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + // + remain = (total % AES_BLOCK_SIZE); + out_len = total - remain; + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_put(tokdata, key, TRUE); + key = NULL; + return CKR_HOST_MEMORY; + } + // copy any data left over from the previous decryption operation first + // + 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, + out_data_len, key); + if (rc == CKR_OK) { + *out_data_len = out_len; + + // copy the remaining 'new' input data to the context buffer + // + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } + + free(cipher); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } +} + + +// +// +CK_RV aes_cbc_encrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + AES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *clear = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (AES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < AES_BLOCK_SIZE) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + // + remain = (total % AES_BLOCK_SIZE); + out_len = total - remain; + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + // these buffers need to be longword aligned + // + clear = (CK_BYTE *) malloc(out_len); + if (!clear) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_put(tokdata, key, TRUE); + key = NULL; + return CKR_HOST_MEMORY; + } + // copy any data left over from the previous encryption operation first + // + 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, + out_data_len, ctx->mech.pParameter, key); + + if (rc == CKR_OK) { + *out_data_len = out_len; + + // the new init_v is the last encrypted data block + // + memcpy(ctx->mech.pParameter, + out_data + (*out_data_len - AES_BLOCK_SIZE), AES_BLOCK_SIZE); + + // copy the remaining 'new' input data to the context buffer + // + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } + + free(clear); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } +} + + +// +// +CK_RV aes_cbc_decrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + AES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (AES_CONTEXT *) ctx->context; + + total = context->len + in_data_len; + + if (total < AES_BLOCK_SIZE) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + // + remain = total % AES_BLOCK_SIZE; + out_len = total - remain; + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + // these buffers need to be longword aligned + // + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_put(tokdata, key, TRUE); + key = NULL; + return CKR_HOST_MEMORY; + } + // copy any data left over from the previous decryption operation first + // + 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, + out_data_len, ctx->mech.pParameter, key); + + if (rc == CKR_OK) { + *out_data_len = out_len; + + // the new init_v is the last input data block + // + memcpy(ctx->mech.pParameter, cipher + (out_len - AES_BLOCK_SIZE), + AES_BLOCK_SIZE); + + // copy the remaining 'new' input data to the context buffer + // + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + + context->len = remain; + } + + free(cipher); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } +} + + +// +// +CK_RV aes_cbc_pad_encrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + AES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *clear = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (AES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + // note, this is subtly different from the other encrypt update routines + // + if (total <= AES_BLOCK_SIZE) { + if (length_only == FALSE) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + remain = (total % AES_BLOCK_SIZE); + out_len = total - remain; // out_len is a multiple of DES_BLOCK_SIZE + + if (remain == 0) { + remain = AES_BLOCK_SIZE; + out_len -= AES_BLOCK_SIZE; + } + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + // at this point, we should have: + // 1) remain != 0 + // 2) out_len != 0 + // + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + // these buffers need to be longword aligned + // + clear = (CK_BYTE *) malloc(out_len); + if (!clear) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_put(tokdata, key, TRUE); + key = NULL; + return CKR_HOST_MEMORY; + } + // copy any data left over from the previous encryption operation first + // + memcpy(clear, context->data, context->len); + memcpy(clear + context->len, in_data, out_len - context->len); + + // + // we don't do padding during the update + // + rc = ckm_aes_cbc_encrypt(tokdata, clear, out_len, out_data, + out_data_len, ctx->mech.pParameter, key); + + if (rc == CKR_OK) { + // the new init_v is the last encrypted data block + // + memcpy(ctx->mech.pParameter, + out_data + (*out_data_len - AES_BLOCK_SIZE), AES_BLOCK_SIZE); + + // copy the remaining 'new' input data to the temporary space + // + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } + + free(clear); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } +} + + +// +// +CK_RV aes_cbc_pad_decrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + AES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (AES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + // note, this is subtly different from the other decrypt update routines + // + if (total <= AES_BLOCK_SIZE) { + if (length_only == FALSE) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + 1 byte + // + remain = total % AES_BLOCK_SIZE; + out_len = total - remain; + + if (remain == 0) { + remain = AES_BLOCK_SIZE; + out_len -= AES_BLOCK_SIZE; + } + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + // at this point, we should have: + // 1) remain != 0 + // 2) out_len != 0 + // + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + // these buffers need to be longword aligned + // + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_put(tokdata, key, TRUE); + key = NULL; + return CKR_HOST_MEMORY; + } + // copy any data left over from the previous decryption operation first + // + 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, + out_data_len, ctx->mech.pParameter, key); + + if (rc == CKR_OK) { + // the new init_v is the last input data block + // + memcpy(ctx->mech.pParameter, cipher + (out_len - AES_BLOCK_SIZE), + AES_BLOCK_SIZE); + + // copy the remaining 'new' input data to the temporary space + // + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } + + free(cipher); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } +} + +// +// +CK_RV aes_ctr_encrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + AES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *clear = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + CK_AES_CTR_PARAMS *aesctr = NULL; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (AES_CONTEXT *) ctx->context; + total = (context->len + in_data_len); + if (total < AES_BLOCK_SIZE) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + *out_data_len = 0; + return CKR_OK; + } else { + // we atleast have 1 block + remain = (total % AES_BLOCK_SIZE); + out_len = total - remain; + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + //these buffers need to be longword aligned + clear = (CK_BYTE *) malloc(out_len); + if (!clear) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_put(tokdata, key, TRUE); + key = NULL; + return CKR_HOST_MEMORY; + } + //copy all the leftover data from the previous encryption operation + //first + memcpy(clear, context->data, context->len); + memcpy(clear + context->len, in_data, out_len - context->len); + aesctr = (CK_AES_CTR_PARAMS *) ctx->mech.pParameter; + rc = ckm_aes_ctr_encrypt(tokdata, clear, out_len, out_data, + out_data_len, (CK_BYTE *) aesctr->cb, + (CK_ULONG) aesctr->ulCounterBits, key); + if (rc == CKR_OK) { + *out_data_len = out_len; + // copy the remaining 'new' input data to the context buffer + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } + + free(clear); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } +} + +// +// +CK_RV aes_ctr_decrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + AES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *clear = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + CK_AES_CTR_PARAMS *aesctr = NULL; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (AES_CONTEXT *) ctx->context; + total = (context->len + in_data_len); + if (total < AES_BLOCK_SIZE) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + *out_data_len = 0; + return CKR_OK; + } else { + // we atleast have 1 block + remain = (total % AES_BLOCK_SIZE); + out_len = total - remain; + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + //these buffers need to be longword aligned + clear = (CK_BYTE *) malloc(out_len); + if (!clear) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_put(tokdata, key, TRUE); + key = NULL; + return CKR_HOST_MEMORY; + } + //copy all the leftover data from the previous encryption operation + //first + memcpy(clear, context->data, context->len); + memcpy(clear + context->len, in_data, out_len - context->len); + aesctr = (CK_AES_CTR_PARAMS *) ctx->mech.pParameter; + rc = ckm_aes_ctr_decrypt(tokdata, clear, out_len, out_data, + out_data_len, (CK_BYTE *) aesctr->cb, + (CK_ULONG) aesctr->ulCounterBits, key); + if (rc == CKR_OK) { + *out_data_len = out_len; + // copy the remaining 'new' input data to the context buffer + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } + + free(clear); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } +} + +// +// +CK_RV aes_ecb_encrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + AES_CONTEXT *context = NULL; + + UNUSED(tokdata); + UNUSED(out_data); + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // satisfy the compiler + // + if (length_only) + context = NULL; + + context = (AES_CONTEXT *) ctx->context; + + // DES3-ECB does no padding so there had better not be + // any data in the context buffer. if there is it means + // that the overall data length was not a multiple of the blocksize + // + if (context->len != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + + *out_data_len = 0; + + return CKR_OK; +} + + +// +// +CK_RV aes_ecb_decrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + AES_CONTEXT *context = NULL; + + UNUSED(tokdata); + UNUSED(out_data); + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // satisfy the compiler + // + if (length_only) + context = NULL; + + context = (AES_CONTEXT *) ctx->context; + + // DES3-ECB does no padding so there had better not be + // any data in the context buffer. if there is it means + // that the overall data length was not a multiple of the blocksize + // + if (context->len != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + return CKR_ENCRYPTED_DATA_LEN_RANGE; + } + + *out_data_len = 0; + + return CKR_OK; +} + + +// +// +CK_RV aes_cbc_encrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + AES_CONTEXT *context = NULL; + + UNUSED(tokdata); + UNUSED(out_data); + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // satisfy the compiler + // + if (length_only) + context = NULL; + + context = (AES_CONTEXT *) ctx->context; + + // DES3-CBC does no padding so there had better not be + // any data in the context buffer. if there is it means + // that the overall data length was not a multiple of the blocksize + // + if (context->len != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + + *out_data_len = 0; + + return CKR_OK; +} + + +// +// +CK_RV aes_cbc_decrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + AES_CONTEXT *context = NULL; + + UNUSED(tokdata); + UNUSED(out_data); + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // satisfy the compiler + // + if (length_only) + context = NULL; + + context = (AES_CONTEXT *) ctx->context; + + if (context->len != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + return CKR_ENCRYPTED_DATA_LEN_RANGE; + } + + *out_data_len = 0; + + return CKR_OK; +} + + +// +// +CK_RV aes_cbc_pad_encrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + AES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE clear[2 * AES_BLOCK_SIZE]; + CK_ULONG out_len; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + context = (AES_CONTEXT *) ctx->context; + + // there will never be more than one block in the context buffer + // so the amount of output is as follows: + // if less than 1 block stored, we generate one block of output + // if a full block is stored, we generate two blocks of output (one pad + // block) + // + if (context->len == AES_BLOCK_SIZE) + out_len = 2 * AES_BLOCK_SIZE; + else + out_len = AES_BLOCK_SIZE; + + if (length_only == TRUE) { + *out_data_len = out_len; + rc = CKR_OK; + } else { + memcpy(clear, context->data, context->len); + + add_pkcs_padding(clear + context->len, + AES_BLOCK_SIZE, context->len, out_len); + + rc = ckm_aes_cbc_encrypt(tokdata, clear, out_len, out_data, + out_data_len, ctx->mech.pParameter, key); + } + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + + +// +// +CK_RV aes_cbc_pad_decrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + AES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE clear[AES_BLOCK_SIZE]; + CK_ULONG out_len; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + context = (AES_CONTEXT *) ctx->context; + + // there had better be a full block in the context buffer + // + if (context->len != AES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + rc = CKR_ENCRYPTED_DATA_LEN_RANGE; + goto done; + } + // we don't know a priori how much data we'll be returning. we won't + // know until after we decrypt it and strip the padding. it's possible + // that we'll return nothing (the final block might be a padding block). + // + out_len = AES_BLOCK_SIZE; // upper bound on what we'll return + + if (length_only == TRUE) { + *out_data_len = out_len; + rc = CKR_OK; + } else { + rc = ckm_aes_cbc_decrypt(tokdata, context->data, AES_BLOCK_SIZE, clear, + &out_len, ctx->mech.pParameter, key); + + if (rc == CKR_OK) { + strip_pkcs_padding(clear, out_len, &out_len); + + if (out_len != 0) + memcpy(out_data, clear, out_len); + + *out_data_len = out_len; + } + } + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + +// +// +CK_RV aes_ctr_encrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + AES_CONTEXT *context = NULL; + CK_AES_CTR_PARAMS *aesctr = NULL; + + UNUSED(tokdata); + UNUSED(out_data); + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // satisfy the compiler + // + if (length_only) + context = NULL; + + context = (AES_CONTEXT *) ctx->context; + + // DES3-CBC does no padding so there had better not be + // any data in the context buffer. if there is it means + // that the overall data length was not a multiple of the blocksize + // + if (context->len != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + aesctr = (CK_AES_CTR_PARAMS *) ctx->mech.pParameter; + //to check that the counter buffer doesnot overflow + if (((CK_ULONG) aesctr->ulCounterBits) > + ((CK_ULONG) aesctr->ulCounterBits + 1)) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + + *out_data_len = 0; + + return CKR_OK; +} + +// +// +CK_RV aes_ctr_decrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + AES_CONTEXT *context = NULL; + CK_AES_CTR_PARAMS *aesctr = NULL; + + UNUSED(tokdata); + UNUSED(out_data); + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // satisfy the compiler + // + if (length_only) + context = NULL; + + context = (AES_CONTEXT *) ctx->context; + + // DES3-CBC does no padding so there had better not be + // any data in the context buffer. if there is it means + // that the overall data length was not a multiple of the blocksize + // + if (context->len != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + return CKR_ENCRYPTED_DATA_LEN_RANGE; + } + aesctr = (CK_AES_CTR_PARAMS *) ctx->mech.pParameter; + //to check that the counter buffer doesnot overflow + if (((CK_ULONG) aesctr->ulCounterBits) > + ((CK_ULONG) aesctr->ulCounterBits + 1)) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + + *out_data_len = 0; + + return CKR_OK; +} + +CK_RV aes_ofb_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + + if (!sess || !ctx || !in_data || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + return CKR_OK; + } + + if (*out_data_len < in_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_aes_ofb(tokdata, in_data, in_data_len, out_data, + key_obj, ctx->mech.pParameter, 1); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific aes ofb encrypt failed.\n"); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV aes_ofb_encrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + AES_CONTEXT *context = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + OBJECT *key_obj = NULL; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (AES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < AES_BLOCK_SIZE) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + remain = (total % AES_BLOCK_SIZE); + out_len = total - remain; + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + if (*out_data_len < out_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + // copy any data left over from the previous encryption operation first + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = token_specific.t_aes_ofb(tokdata, cipher, out_len, out_data, + key_obj, ctx->mech.pParameter, 1); + + if (rc == CKR_OK) { + *out_data_len = out_len; + + // copy the remaining 'new' input data to the context buffer + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } else { + TRACE_DEVEL("Token specific aes ofb encrypt failed.\n"); + } + + free(cipher); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; + } +} + +CK_RV aes_ofb_encrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + AES_CONTEXT *context = NULL; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (AES_CONTEXT *) ctx->context; + + // there will never be more than one block in the context buffer + // so the amount of output is as follows: + // if less than 1 block stored, we generate same length of output data + // if no data stored, no data can be returned (length zero) + + if (length_only == TRUE) { + *out_data_len = context->len; + return CKR_OK; + } else { + if (context->len == 0) { + *out_data_len = 0; + return CKR_OK; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_aes_ofb(tokdata, context->data, context->len, + out_data, key_obj, ctx->mech.pParameter, + 1); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific aes ofb encrypt failed.\n"); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + *out_data_len = context->len; + + return rc; + } +} + +CK_RV aes_ofb_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + + if (!sess || !ctx || !in_data || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + return CKR_OK; + } + + if (*out_data_len < in_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_aes_ofb(tokdata, in_data, in_data_len, out_data, + key_obj, ctx->mech.pParameter, 0); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific aes ofb decrypt failed.\n"); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV aes_ofb_decrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + AES_CONTEXT *context = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + OBJECT *key_obj = NULL; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (AES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < AES_BLOCK_SIZE) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + remain = (total % AES_BLOCK_SIZE); + out_len = total - remain; + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + if (*out_data_len < out_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + // copy any data left over from the previous decryption operation first + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = token_specific.t_aes_ofb(tokdata, cipher, out_len, out_data, + key_obj, ctx->mech.pParameter, 0); + + if (rc == CKR_OK) { + *out_data_len = out_len; + + // copy the remaining 'new' input data to the context buffer + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } else { + TRACE_DEVEL("Token specific aes ofb decrypt failed.\n"); + } + + free(cipher); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; + } +} + +CK_RV aes_ofb_decrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + AES_CONTEXT *context = NULL; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // satisfy the compiler + //if (length_only) + // context = NULL; + + context = (AES_CONTEXT *) ctx->context; + + // there will never be more than one block in the context buffer + // so the amount of output is as follows: + // if less than 1 block stored, we generate same length of output data + // if no data stored, no data can be returned (length zero) + + if (length_only == TRUE) { + *out_data_len = context->len; + return CKR_OK; + } else { + if (context->len == 0) { + *out_data_len = 0; + return CKR_OK; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_aes_ofb(tokdata, context->data, context->len, + out_data, key_obj, ctx->mech.pParameter, + 0); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific aes ofb decrypt failed.\n"); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + *out_data_len = context->len; + + return rc; + } +} + +CK_RV aes_cfb_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_ULONG cfb_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + + if (!sess || !ctx || !in_data || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + return CKR_OK; + } + + if (*out_data_len < in_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_aes_cfb(tokdata, in_data, in_data_len, out_data, + key_obj, ctx->mech.pParameter, cfb_len, 1); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific aes cfb encrypt failed.\n"); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV aes_cfb_encrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_ULONG cfb_len) +{ + AES_CONTEXT *context = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + OBJECT *key_obj = NULL; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (AES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < cfb_len) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + remain = (total % cfb_len); + out_len = total - remain; + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + if (*out_data_len < out_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + // copy any data left over from the previous encryption operation first + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = token_specific.t_aes_cfb(tokdata, cipher, out_len, out_data, + key_obj, ctx->mech.pParameter, cfb_len, + 1); + + if (rc == CKR_OK) { + *out_data_len = out_len; + + // copy the remaining 'new' input data to the context buffer + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } else { + TRACE_DEVEL("Token specific aes cfb encrypt failed.\n"); + } + + free(cipher); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; + } +} + +CK_RV aes_cfb_encrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_ULONG cfb_len) +{ + OBJECT *key_obj = NULL; + AES_CONTEXT *context = NULL; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (AES_CONTEXT *) ctx->context; + + // there will never be more than one block in the context buffer + // so the amount of output is as follows: + // if less than 1 block stored, we generate same length of output data + // if no data stored, no data can be returned (length zero) + + if (context->len == 0) { + *out_data_len = 0; + return CKR_OK; + } + + if (length_only == TRUE) { + *out_data_len = context->len; + return CKR_OK; + } else { + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_aes_cfb(tokdata, context->data, context->len, + out_data, key_obj, ctx->mech.pParameter, + cfb_len, 1); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific aes cfb encrypt failed.\n"); + + *out_data_len = context->len; + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; + } +} + +CK_RV aes_cfb_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_ULONG cfb_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + + if (!sess || !ctx || !in_data || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + return CKR_OK; + } + + if (*out_data_len < in_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_aes_cfb(tokdata, in_data, in_data_len, out_data, + key_obj, ctx->mech.pParameter, cfb_len, 0); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific aes cfb decrypt failed.\n"); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV aes_cfb_decrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_ULONG cfb_len) +{ + AES_CONTEXT *context = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + OBJECT *key_obj = NULL; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (AES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < cfb_len) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + remain = (total % cfb_len); + out_len = total - remain; + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + if (*out_data_len < out_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + // copy any data left over from the previous decryption operation first + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = token_specific.t_aes_cfb(tokdata, cipher, out_len, out_data, + key_obj, ctx->mech.pParameter, cfb_len, + 0); + + if (rc == CKR_OK) { + *out_data_len = out_len; + + // copy the remaining 'new' input data to the context buffer + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } else { + TRACE_DEVEL("Token specific aes cfb decrypt failed.\n"); + } + + free(cipher); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; + } +} + +CK_RV aes_cfb_decrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_ULONG cfb_len) +{ + OBJECT *key_obj = NULL; + AES_CONTEXT *context = NULL; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (AES_CONTEXT *) ctx->context; + + // there will never be more than one block in the context buffer + // so the amount of output is as follows: + // if less than 1 block stored, we generate same length of output data + // if no data stored, no data can be returned (length zero) + + if (context->len == 0) { + *out_data_len = 0; + return CKR_OK; + } + + if (length_only == TRUE) { + *out_data_len = context->len; + return CKR_OK; + } else { + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_aes_cfb(tokdata, context->data, context->len, + out_data, key_obj, ctx->mech.pParameter, + cfb_len, 0); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific aes cfb decrypt failed.\n"); + + *out_data_len = context->len; + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; + } +} + + +CK_RV aes_mac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + CK_ULONG mac_len; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (ctx->mech.pParameter) + mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; + else + mac_len = AES_BLOCK_SIZE / 2; + + if (length_only == TRUE) { + *out_data_len = mac_len; + return CKR_OK; + } + + if ((in_data_len % AES_BLOCK_SIZE) != 0) { + rc = aes_mac_sign_update(tokdata, sess, ctx, in_data, in_data_len); + if (rc != CKR_OK) + return rc; + + rc = aes_mac_sign_final(tokdata, sess, length_only, ctx, out_data, + out_data_len); + + return rc; + } else { + + if (*out_data_len < mac_len) { + *out_data_len = mac_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_aes_mac(tokdata, in_data, in_data_len, + key_obj, + ((AES_DATA_CONTEXT *) ctx->context)->iv); + if (rc != CKR_OK) + TRACE_DEVEL("Token specific aes mac failed.\n"); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + memcpy(out_data, ((AES_DATA_CONTEXT *) ctx->context)->iv, mac_len); + *out_data_len = mac_len; + + return rc; + } +} + +CK_RV aes_mac_sign_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + AES_DATA_CONTEXT *context = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + + if (!sess || !ctx) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (AES_DATA_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < AES_BLOCK_SIZE) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + return CKR_OK; + } else { + // we have at least 1 block + remain = (total % AES_BLOCK_SIZE); + out_len = total - remain; + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + // copy any data left over from the previous signUpdate operation first + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = token_specific.t_aes_mac(tokdata, cipher, out_len, key_obj, + context->iv); + + if (rc == CKR_OK) { + // copy the remaining 'new' input data to the context buffer + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } else { + TRACE_DEVEL("Token specific aes mac failed.\n"); + } + + free(cipher); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; + } +} + +CK_RV aes_mac_sign_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_ULONG rc = CKR_OK; + CK_ULONG mac_len; + AES_DATA_CONTEXT *context = NULL; + OBJECT *key_obj = NULL; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (AES_DATA_CONTEXT *) ctx->context; + + if (ctx->mech.pParameter) + mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; + else + mac_len = AES_BLOCK_SIZE / 2; + + // there will never be more than one block in the context buffer + // so the amount of output is as follows: + // if less than 1 block stored, we generate one block of output (with + // padding) + // if no data stored, we are done (take the cipher from previous round) + + if (length_only == TRUE) { + *out_data_len = mac_len; + return CKR_OK; + } + + if (context->len > 0) { + + if (*out_data_len < mac_len) { + *out_data_len = mac_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + /* padding with '00' in case case we didn't reach block size */ + memset(context->data + context->len, 0x0, + AES_BLOCK_SIZE - context->len); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_aes_mac(tokdata, context->data, AES_BLOCK_SIZE, + key_obj, context->iv); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + if (rc != CKR_OK) { + TRACE_DEVEL("Token Specific aes mac failed.\n"); + return rc; + } + } + memcpy(out_data, context->iv, mac_len); + *out_data_len = mac_len; + + return rc; +} + +CK_RV aes_mac_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG out_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + CK_ULONG mac_len; + + if (!sess || !ctx || !in_data || !out_data) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if ((in_data_len % AES_BLOCK_SIZE) != 0) { + rc = aes_mac_verify_update(tokdata, sess, ctx, in_data, in_data_len); + if (rc != CKR_OK) + return rc; + + rc = aes_mac_verify_final(tokdata, sess, ctx, out_data, out_data_len); + return rc; + } else { + + if (ctx->mech.pParameter) + mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; + else + mac_len = AES_BLOCK_SIZE / 2; + + if (out_data_len != mac_len) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + return CKR_SIGNATURE_LEN_RANGE; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_aes_mac(tokdata, in_data, in_data_len, + key_obj, + ((AES_DATA_CONTEXT *) ctx->context)->iv); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + if (rc != CKR_OK) { + TRACE_DEVEL("Token specific aes mac failed.\n"); + return rc; + } + + if (CRYPTO_memcmp(out_data, ((AES_DATA_CONTEXT *) ctx->context)->iv, + out_data_len) == 0) + return CKR_OK; + + return CKR_SIGNATURE_INVALID; + } +} + + +CK_RV aes_mac_verify_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + AES_DATA_CONTEXT *context = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + + if (!sess || !ctx) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (AES_DATA_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < AES_BLOCK_SIZE) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + return CKR_OK; + } else { + // we have at least 1 block + remain = (total % AES_BLOCK_SIZE); + out_len = total - remain; + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + // copy any data left over from the previous signUpdate operation first + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = token_specific.t_aes_mac(tokdata, cipher, out_len, key_obj, + context->iv); + if (rc == CKR_OK) { + // copy the remaining 'new' input data to the context buffer + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } else { + TRACE_DEVEL("Token specific aes mac failed.\n"); + } + + free(cipher); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; + } +} + +CK_RV aes_mac_verify_final(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG signature_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + CK_ULONG mac_len; + AES_DATA_CONTEXT *context = NULL; + + if (!sess || !ctx || !signature) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (AES_DATA_CONTEXT *) ctx->context; + + if (ctx->mech.pParameter) + mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; + else + mac_len = AES_BLOCK_SIZE / 2; + + // there will never be more than one block in the context buffer + // so the amount of output is as follows: + // if less than 1 block stored, we generate one block of output (with + // padding) + // if no data stored, we are done (take the cipher from previous round) + + if (context->len > 0) { + + if (signature_len != mac_len) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + return CKR_SIGNATURE_LEN_RANGE; + } + + /* padding with '00' in case case we didn't reach block size */ + memset(context->data + context->len, 0x0, + AES_BLOCK_SIZE - context->len); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + rc = token_specific.t_aes_mac(tokdata, context->data, AES_BLOCK_SIZE, + key_obj, context->iv); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + if (rc != CKR_OK) { + TRACE_DEVEL("Token specific aes mac failed.\n"); + return rc; + } + } + + if (CRYPTO_memcmp(signature, context->iv, signature_len) == 0) + return CKR_OK; + + return CKR_SIGNATURE_INVALID; +} + +CK_RV aes_cmac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + CK_ULONG mac_len; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (ctx->mech.pParameter) + mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; + else + mac_len = AES_BLOCK_SIZE; + + if (length_only == TRUE) { + *out_data_len = mac_len; + return CKR_OK; + } + + if (*out_data_len < mac_len) { + *out_data_len = mac_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_aes_cmac(tokdata, in_data, in_data_len, + key_obj, + ((AES_CMAC_CONTEXT *)ctx->context)->iv, + CK_TRUE, CK_TRUE, + &((AES_CMAC_CONTEXT *)ctx->context)->ctx); + if (rc != CKR_OK) { + TRACE_DEVEL("Token specific aes cmac failed.\n"); + goto done; + } + + memcpy(out_data, ((AES_CMAC_CONTEXT *) ctx->context)->iv, mac_len); + *out_data_len = mac_len; + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV aes_cmac_sign_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + AES_CMAC_CONTEXT *context = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + + if (!sess || !ctx) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (AES_CMAC_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total <= AES_BLOCK_SIZE) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + return CKR_OK; + } else { + // we have at least 1 block + remain = (total % AES_BLOCK_SIZE); + if (remain == 0) + remain = AES_BLOCK_SIZE; /* Keep last block in context */ + out_len = total - remain; + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + // copy any data left over from the previous signUpdate operation first + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = token_specific.t_aes_cmac(tokdata, cipher, out_len, key_obj, + context->iv, + !context->initialized, CK_FALSE, + &context->ctx); + + if (rc == CKR_OK) { + // copy the remaining 'new' input data to the context buffer + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + + context->initialized = CK_TRUE; + } else { + TRACE_DEVEL("Token specific aes cmac failed.\n"); + } + + free(cipher); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; + } +} + +CK_RV aes_cmac_sign_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_ULONG rc = CKR_OK; + CK_ULONG mac_len; + AES_CMAC_CONTEXT *context = NULL; + OBJECT *key_obj = NULL; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (AES_CMAC_CONTEXT *) ctx->context; + + if (ctx->mech.pParameter) + mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; + else + mac_len = AES_BLOCK_SIZE; + + if (length_only == TRUE) { + *out_data_len = mac_len; + return CKR_OK; + } + + if (*out_data_len < mac_len) { + *out_data_len = mac_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_aes_cmac(tokdata, context->data, context->len, + key_obj, context->iv, + !context->initialized, CK_TRUE, + &context->ctx); + if (rc != CKR_OK) { + TRACE_DEVEL("Token Specific aes cmac failed.\n"); + goto done; + } + + memcpy(out_data, context->iv, mac_len); + *out_data_len = mac_len; + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV aes_cmac_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG out_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + CK_ULONG mac_len; + + if (!sess || !ctx || !in_data || !out_data) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (ctx->mech.pParameter) + mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; + else + mac_len = AES_BLOCK_SIZE; + + if (out_data_len != mac_len) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + return CKR_SIGNATURE_LEN_RANGE; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_aes_cmac(tokdata, in_data, in_data_len, + key_obj, + ((AES_CMAC_CONTEXT *) ctx->context)->iv, + CK_TRUE, CK_TRUE, + &((AES_CMAC_CONTEXT *)ctx->context)->ctx); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + if (rc != CKR_OK) { + TRACE_DEVEL("Token specific aes cmac failed.\n"); + return rc; + } + + if (CRYPTO_memcmp(out_data, ((AES_CMAC_CONTEXT *) ctx->context)->iv, + out_data_len) == 0) { + return CKR_OK; + } + + return CKR_SIGNATURE_INVALID; +} + + +CK_RV aes_cmac_verify_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + AES_CMAC_CONTEXT *context = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + + if (!sess || !ctx) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (AES_CMAC_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total <= AES_BLOCK_SIZE) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + return CKR_OK; + } else { + // we have at least 1 block + remain = (total % AES_BLOCK_SIZE); + if (remain == 0) + remain = AES_BLOCK_SIZE; /* Keep last block in context */ + out_len = total - remain; + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + // copy any data left over from the previous signUpdate operation first + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = token_specific.t_aes_cmac(tokdata, cipher, out_len, key_obj, + context->iv, + !context->initialized, CK_FALSE, + &context->ctx); + if (rc == CKR_OK) { + // copy the remaining 'new' input data to the context buffer + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + + context->initialized = CK_TRUE; + } else { + TRACE_DEVEL("Token specific aes cmac failed.\n"); + } + + free(cipher); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; + } +} + +CK_RV aes_cmac_verify_final(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG signature_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + CK_ULONG mac_len; + AES_CMAC_CONTEXT *context = NULL; + + if (!sess || !ctx || !signature) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (AES_CMAC_CONTEXT *) ctx->context; + + if (ctx->mech.pParameter) + mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; + else + mac_len = AES_BLOCK_SIZE; + + if (signature_len != mac_len) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + return CKR_SIGNATURE_LEN_RANGE; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_aes_cmac(tokdata, context->data, context->len, + key_obj, context->iv, + !context->initialized, CK_TRUE, + &context->ctx); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + if (rc != CKR_OK) { + TRACE_DEVEL("Token specific aes mac failed.\n"); + return rc; + } + + if (CRYPTO_memcmp(signature, context->iv, signature_len) == 0) + return CKR_OK; + + return CKR_SIGNATURE_INVALID; +} + + +CK_RV aes_gcm_init(STDLL_TokData_t *tokdata, SESSION *sess, + ENCR_DECR_CONTEXT *ctx, CK_MECHANISM *mech, + CK_OBJECT_HANDLE key, CK_BYTE direction) +{ + if (token_specific.t_aes_gcm_init == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + return token_specific.t_aes_gcm_init(tokdata, sess, ctx, mech, key, + direction); +} + +CK_RV aes_gcm_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len) +{ + CK_RV rc; + CK_GCM_PARAMS *aesgcm = NULL; + CK_ULONG tag_data_len; + + if (!sess || !ctx || !in_data || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + aesgcm = (CK_GCM_PARAMS *) ctx->mech.pParameter; + tag_data_len = (aesgcm->ulTagBits + 7) / 8; /* round to full byte */ + + + if (length_only == TRUE) { + *out_data_len = in_data_len + tag_data_len; + return CKR_OK; + } + + if (*out_data_len < in_data_len + tag_data_len) { + *out_data_len = in_data_len + tag_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + if (token_specific.t_aes_gcm == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + rc = token_specific.t_aes_gcm(tokdata, sess, ctx, in_data, + in_data_len, out_data, out_data_len, 1); + if (rc != CKR_OK) + TRACE_ERROR("Token specific aes gcm encrypt failed: %02lx\n", rc); + + return rc; + +} + +CK_RV aes_gcm_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len) +{ + AES_GCM_CONTEXT *context = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (AES_GCM_CONTEXT *) ctx->context; + total = (context->len + in_data_len); + + if (length_only) { + if (total < AES_BLOCK_SIZE) { + *out_data_len = 0; + return CKR_OK; + } else { + remain = (total % AES_BLOCK_SIZE); + out_len = total - remain; + *out_data_len = out_len; + TRACE_DEVEL("Length Only requested (%02ld bytes).\n", + *out_data_len); + return CKR_OK; + } + } + + if (token_specific.t_aes_gcm_update == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + rc = token_specific.t_aes_gcm_update(tokdata, sess, ctx, in_data, + in_data_len, out_data, + out_data_len, 1); + if (rc != CKR_OK) + TRACE_ERROR("Token specific AES GCM EncryptUpdate failed: %02lx\n", rc); + + return rc; +} + +CK_RV aes_gcm_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_GCM_PARAMS *aesgcm = NULL; + AES_GCM_CONTEXT *context = NULL; + CK_ULONG tag_data_len; + CK_RV rc = CKR_OK; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (AES_GCM_CONTEXT *) ctx->context; + + aesgcm = (CK_GCM_PARAMS *) ctx->mech.pParameter; + tag_data_len = (aesgcm->ulTagBits + 7) / 8; /* round to full byte */ + + if (length_only) { + if (context->len == 0) { + *out_data_len = tag_data_len; + } else { + *out_data_len = context->len + tag_data_len; + } + return CKR_OK; + } + + if (*out_data_len < context->len + tag_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + if (token_specific.t_aes_gcm_final == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + rc = token_specific.t_aes_gcm_final(tokdata, sess, ctx, out_data, + out_data_len, 1); + if (rc != CKR_OK) + TRACE_ERROR("Token specific AES GCM EncryptFinal failed: " + "%02lx\n", rc); + + return rc; +} + +CK_RV aes_gcm_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len) +{ + CK_GCM_PARAMS *aesgcm = NULL; + CK_ULONG tag_data_len; + CK_RV rc; + + if (!sess || !ctx || !in_data || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + aesgcm = (CK_GCM_PARAMS *) ctx->mech.pParameter; + tag_data_len = (aesgcm->ulTagBits + 7) / 8; /* round to full byte */ + + if (length_only == TRUE) { + *out_data_len = in_data_len - tag_data_len; + return CKR_OK; + } + + if (*out_data_len < in_data_len - tag_data_len) { + *out_data_len = in_data_len - tag_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + if (token_specific.t_aes_gcm == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + rc = token_specific.t_aes_gcm(tokdata, sess, ctx, in_data, in_data_len, + out_data, out_data_len, 0); + if (rc != CKR_OK) + TRACE_ERROR("Token specific aes gcm decrypt failed.\n"); + + return rc; +} + +CK_RV aes_gcm_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len) +{ + AES_GCM_CONTEXT *context = NULL; + CK_GCM_PARAMS *aesgcm = NULL; + CK_ULONG total, remain, out_len; + CK_ULONG tag_data_len; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + /* Be aware that this part of incoming data could be the last chunk, + * that means it's tag data, not encrypted plaintext. + * Hence we'll keep at least tag data size in the context buffer */ + + context = (AES_GCM_CONTEXT *) ctx->context; + total = (context->len + in_data_len); + + aesgcm = (CK_GCM_PARAMS *) ctx->mech.pParameter; + tag_data_len = (aesgcm->ulTagBits + 7) / 8; /* round to full byte */ + + if (length_only) { + if (total < AES_BLOCK_SIZE + tag_data_len) { + *out_data_len = 0; + return CKR_OK; + } else { + remain = ((total - tag_data_len) % AES_BLOCK_SIZE) + + tag_data_len; + out_len = total - remain; + *out_data_len = out_len; + TRACE_DEVEL("Length Only requested (%02ld bytes).\n", + *out_data_len); + return CKR_OK; + } + } + + if (token_specific.t_aes_gcm_update == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + rc = token_specific.t_aes_gcm_update(tokdata, sess, ctx, in_data, + in_data_len, out_data, + out_data_len, 0); + if (rc != CKR_OK) + TRACE_ERROR("Token specific AES GCM DecryptUpdate failed: %02lx\n", rc); + + return rc; +} + +CK_RV aes_gcm_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, + CK_ULONG *out_data_len) +{ + AES_GCM_CONTEXT *context = NULL; + CK_RV rc = CKR_OK; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (AES_GCM_CONTEXT *) ctx->context; + + if (length_only) { + if (context->len == 0) { + *out_data_len = 0; + } else { + *out_data_len = context->len; + } + return CKR_OK; + } + + if (token_specific.t_aes_gcm_final == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + rc = token_specific.t_aes_gcm_final(tokdata, sess, ctx, out_data, + out_data_len, 0); + if (rc != CKR_OK) + TRACE_ERROR("Token specific AES GCM DecryptFinal failed: %02lx\n", rc); + + return rc; +} + +// +// mechanisms +// + + +// +// +CK_RV ckm_aes_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl) +{ + CK_ATTRIBUTE *opaque_attr = NULL; + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *key_type_attr = NULL; + CK_ATTRIBUTE *class_attr = NULL; + CK_ATTRIBUTE *local_attr = NULL; + CK_ATTRIBUTE *val_len_attr = NULL; + CK_BYTE *aes_key = NULL; + CK_BYTE dummy_key[AES_KEY_SIZE_256] = { 0, }; + CK_ULONG rc; + CK_ULONG key_size; + CK_ULONG token_keysize; + CK_BBOOL found = FALSE; + + + found = template_attribute_find(tmpl, CKA_VALUE_LEN, &val_len_attr); + if (found == FALSE) + return CKR_TEMPLATE_INCONSISTENT; + + key_size = *(CK_ULONG *) val_len_attr->pValue; + if (key_size != AES_KEY_SIZE_128 && + key_size != AES_KEY_SIZE_192 && key_size != AES_KEY_SIZE_256) { + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + if (token_specific.t_aes_key_gen == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + if (is_secure_key_token()) + token_keysize = token_specific.token_keysize; + else + token_keysize = key_size; + + if ((aes_key = (CK_BYTE *) calloc(1, token_keysize)) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + rc = token_specific.t_aes_key_gen(tokdata, aes_key, token_keysize, + key_size); + + if (rc != CKR_OK) + goto err; + + /* For secure-key keys put in CKA_IBM_OPAQUE + * and put dummy_key in CKA_VALUE. + */ + if (is_secure_key_token()) { + opaque_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + token_keysize); + if (!opaque_attr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto err; + } + opaque_attr->type = CKA_IBM_OPAQUE; + opaque_attr->ulValueLen = token_keysize; + opaque_attr->pValue = (CK_BYTE *) opaque_attr + sizeof(CK_ATTRIBUTE); + memcpy(opaque_attr->pValue, aes_key, token_keysize); + template_update_attribute(tmpl, opaque_attr); + } + + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + key_size); + key_type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + class_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_OBJECT_CLASS)); + local_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + + if (!value_attr || !key_type_attr || !class_attr || !local_attr) { + if (value_attr) + free(value_attr); + if (key_type_attr) + free(key_type_attr); + if (class_attr) + free(class_attr); + if (local_attr) + free(local_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto err; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = key_size; + value_attr->pValue = (CK_BYTE *) value_attr + sizeof(CK_ATTRIBUTE); + if (is_secure_key_token()) + memcpy(value_attr->pValue, dummy_key, key_size); + else + memcpy(value_attr->pValue, aes_key, key_size); + free(aes_key); + + key_type_attr->type = CKA_KEY_TYPE; + key_type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + key_type_attr->pValue = (CK_BYTE *) key_type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) key_type_attr->pValue = CKK_AES; + + class_attr->type = CKA_CLASS; + class_attr->ulValueLen = sizeof(CK_OBJECT_CLASS); + class_attr->pValue = (CK_BYTE *) class_attr + sizeof(CK_ATTRIBUTE); + *(CK_OBJECT_CLASS *) class_attr->pValue = CKO_SECRET_KEY; + + local_attr->type = CKA_LOCAL; + local_attr->ulValueLen = sizeof(CK_BBOOL); + local_attr->pValue = (CK_BYTE *) local_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) local_attr->pValue = TRUE; + + template_update_attribute(tmpl, value_attr); + template_update_attribute(tmpl, key_type_attr); + template_update_attribute(tmpl, class_attr); + template_update_attribute(tmpl, local_attr); + + return CKR_OK; + +err: + if (aes_key) + free(aes_key); + + return rc; +} + + +// +// +CK_RV ckm_aes_ecb_encrypt(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, OBJECT *key) +{ + CK_ULONG rc; + + if (!in_data || !out_data || !key) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (*out_data_len < in_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + if (token_specific.t_aes_ecb == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + rc = token_specific.t_aes_ecb(tokdata, in_data, in_data_len, + out_data, out_data_len, key, 1); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific aes ecb encrypt failed.\n"); + + return rc; +} + +// +// +CK_RV ckm_aes_ecb_decrypt(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, OBJECT *key) +{ + CK_ULONG rc; + + + if (!in_data || !out_data || !key) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (*out_data_len < in_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + if (token_specific.t_aes_ecb == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + rc = token_specific.t_aes_ecb(tokdata, in_data, in_data_len, + out_data, out_data_len, key, 0); + + if (rc != CKR_OK) + TRACE_DEVEL("token specific aes ecb decrypt failed.\n"); + + return rc; +} + + +// +// +CK_RV ckm_aes_cbc_encrypt(STDLL_TokData_t *tokdata, + 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_ULONG rc; + + if (!in_data || !out_data || !init_v || !key) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (*out_data_len < in_data_len) { + *out_data_len = in_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + if (token_specific.t_aes_cbc == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + rc = token_specific.t_aes_cbc(tokdata, in_data, in_data_len, + out_data, out_data_len, key, init_v, 1); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific aes cbc encrypt failed.\n"); + + return rc; +} + + +// +// +CK_RV ckm_aes_cbc_decrypt(STDLL_TokData_t *tokdata, + 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_ULONG rc; + + if (!in_data || !out_data || !init_v || !key) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (*out_data_len < in_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + if (token_specific.t_aes_cbc == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + rc = token_specific.t_aes_cbc(tokdata, in_data, in_data_len, + out_data, out_data_len, key, init_v, 0); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific aes cbc decrypt failed.\n"); + + return rc; +} + +// +// +CK_RV ckm_aes_ctr_encrypt(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, + CK_BYTE *counterblock, + CK_ULONG counter_width, OBJECT *key) +{ + CK_ULONG rc; + if (!in_data || !out_data || !counterblock || !key) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (*out_data_len < in_data_len) { + *out_data_len = in_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + if (counter_width % 8 != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + + if (token_specific.t_aes_ctr == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + rc = token_specific.t_aes_ctr(tokdata, in_data, in_data_len, + out_data, out_data_len, key, + counterblock, counter_width, 1); + if (rc != CKR_OK) + TRACE_DEVEL("Token specific aes ctr encrypt failed.\n"); + + return rc; +} + +// +// +CK_RV ckm_aes_ctr_decrypt(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, + CK_BYTE *counterblock, + CK_ULONG counter_width, OBJECT *key) +{ + CK_ULONG rc; + if (!in_data || !out_data || !counterblock || !key) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (*out_data_len < in_data_len) { + *out_data_len = in_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + if (counter_width % 8 != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + + if (token_specific.t_aes_ctr == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + rc = token_specific.t_aes_ctr(tokdata, in_data, in_data_len, + out_data, out_data_len, key, + counterblock, counter_width, 0); + if (rc != CKR_OK) + TRACE_ERROR("Token specific aes ctr decrypt failed.\n"); + + return rc; +} + +// +// +CK_RV ckm_aes_wrap_format(STDLL_TokData_t *tokdata, + CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len) +{ + CK_BYTE *ptr = NULL; + CK_ULONG len1, len2; + + UNUSED(tokdata); + + len1 = *data_len; + if (*data == NULL) + len1 = 0; + + // if the input key data isn't a multiple of the blocksize, + // we pad with NULLs to the next blocksize multiple. + // + if (len1 % AES_BLOCK_SIZE != 0) { + len2 = AES_BLOCK_SIZE * ((len1 / AES_BLOCK_SIZE) + 1); + + if (length_only == FALSE) { + /* + * Don't use realloc here, since the buffer contains a key and the + * old buffer needs to be cleansed before it is freed. + */ + ptr = (CK_BYTE *)malloc(len2); + if (!ptr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + memset(ptr + len1, 0x0, (len2 - len1)); + if (*data != NULL) { + memcpy(ptr, *data, len1); + OPENSSL_cleanse(*data, len1); + free(*data); + } + + *data = ptr; + *data_len = len2; + } + } + + return CKR_OK; +} diff --git a/usr/lib/common/mech_des.c b/usr/lib/common/mech_des.c new file mode 100644 index 0000000..6e5bef9 --- /dev/null +++ b/usr/lib/common/mech_des.c @@ -0,0 +1,1595 @@ +/* + * 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: mech_des.c +// +// Mechanisms for DES +// + +#include // for memcmp() et al +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "trace.h" + +#include + +// +// +CK_RV pk_des_ecb_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // CKM_DES_ECB requires the input data to be an integral + // multiple of the block size + // + if (in_data_len % DES_BLOCK_SIZE != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < in_data_len) { + *out_data_len = in_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + rc = ckm_des_ecb_encrypt(tokdata, in_data, in_data_len, + out_data, out_data_len, key); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + + +// +// +CK_RV des_ecb_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // CKM_DES_ECB requires the input data to be an integral + // multiple of the block size + // + if (in_data_len % DES_BLOCK_SIZE != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + return CKR_ENCRYPTED_DATA_LEN_RANGE; + } + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < in_data_len) { + *out_data_len = in_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + rc = ckm_des_ecb_decrypt(tokdata, in_data, in_data_len, + out_data, out_data_len, key); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + + +// +// +CK_RV pk_des_cbc_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // CKM_DES_CBC requires the input data to be an integral + // multiple of the block size + // + if (in_data_len % DES_BLOCK_SIZE != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < in_data_len) { + *out_data_len = in_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + rc = ckm_des_cbc_encrypt(tokdata, in_data, in_data_len, out_data, + out_data_len, ctx->mech.pParameter, key); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + + +// +// +CK_RV des_cbc_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // CKM_DES_CBC requires the input data to be an integral + // multiple of the block size + // + if (in_data_len % DES_BLOCK_SIZE != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + return CKR_ENCRYPTED_DATA_LEN_RANGE; + } + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < in_data_len) { + *out_data_len = in_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + rc = ckm_des_cbc_decrypt(tokdata, in_data, in_data_len, out_data, + out_data_len, ctx->mech.pParameter, key); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + + +// +// +CK_RV des_cbc_pad_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_BYTE *clear = NULL; + CK_ULONG padded_len; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // DES-CBC-PAD has no input length requirements + // + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + // compute the output length, accounting for padding + // + padded_len = DES_BLOCK_SIZE * (in_data_len / DES_BLOCK_SIZE + 1); + + if (length_only == TRUE) { + *out_data_len = padded_len; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < padded_len) { + *out_data_len = padded_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + clear = (CK_BYTE *) malloc(padded_len); + if (!clear) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memcpy(clear, in_data, in_data_len); + + add_pkcs_padding(clear + in_data_len, + DES_BLOCK_SIZE, in_data_len, padded_len); + + rc = ckm_des_cbc_encrypt(tokdata, clear, padded_len, out_data, out_data_len, + ctx->mech.pParameter, key); + free(clear); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + + +// +// +CK_RV des_cbc_pad_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_BYTE *clear = NULL; + CK_ULONG padded_len; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // + // no need to validate the input length since we'll pad as necessary + // + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + // we're decrypting so even with CBC-PAD, we should have an integral + // number of block to decrypt + // + if (in_data_len % DES_BLOCK_SIZE != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + rc = CKR_ENCRYPTED_DATA_LEN_RANGE; + goto done; + } + // the amount of cleartext after stripping the padding will actually be less + // than the input bytes... + // + padded_len = in_data_len; + + if (length_only == TRUE) { + *out_data_len = padded_len; + rc = CKR_OK; + goto done; + } + + clear = (CK_BYTE *) malloc(padded_len); + if (!clear) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + rc = ckm_des_cbc_decrypt(tokdata, in_data, in_data_len, clear, &padded_len, + ctx->mech.pParameter, key); + + if (rc == CKR_OK) { + strip_pkcs_padding(clear, padded_len, out_data_len); + memcpy(out_data, clear, *out_data_len); + } + + free(clear); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + + +// +// +CK_RV des_ecb_encrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *clear = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (DES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < DES_BLOCK_SIZE) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + // + remain = (total % DES_BLOCK_SIZE); + out_len = (total - remain); // should always be at least 1 block + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + clear = (CK_BYTE *) malloc(out_len); + if (!clear) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_put(tokdata, key, TRUE); + key = NULL; + return CKR_HOST_MEMORY; + } + // copy any data left over from the previous encryption operation first + // + memcpy(clear, context->data, context->len); + memcpy(clear + context->len, in_data, out_len - context->len); + + rc = ckm_des_ecb_encrypt(tokdata, clear, out_len, out_data, + out_data_len, key); + if (rc == CKR_OK) { + *out_data_len = out_len; + + // update the context buffer. we already used the buffer's current + // contents so we completely overwrite it + // + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } + + free(clear); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } +} + + +// +// +CK_RV des_ecb_decrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (DES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < DES_BLOCK_SIZE) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + // + remain = (total % DES_BLOCK_SIZE); + out_len = total - remain; + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_put(tokdata, key, TRUE); + key = NULL; + return CKR_HOST_MEMORY; + } + // copy any data left over from the previous decryption operation first + // + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = ckm_des_ecb_decrypt(tokdata, cipher, out_len, out_data, + out_data_len, key); + if (rc == CKR_OK) { + *out_data_len = out_len; + + // copy the remaining 'new' input data to the context buffer + // + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } + + free(cipher); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } +} + + +// +// +CK_RV des_cbc_encrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *clear = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (DES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < DES_BLOCK_SIZE) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + // + remain = (total % DES_BLOCK_SIZE); + out_len = total - remain; + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + // these buffers need to be longword aligned + // + clear = (CK_BYTE *) malloc(out_len); + if (!clear) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_put(tokdata, key, TRUE); + key = NULL; + return CKR_HOST_MEMORY; + } + // copy any data left over from the previous encryption operation first + // + memcpy(clear, context->data, context->len); + memcpy(clear + context->len, in_data, out_len - context->len); + + rc = ckm_des_cbc_encrypt(tokdata, clear, out_len, out_data, + out_data_len, ctx->mech.pParameter, key); + if (rc == CKR_OK) { + *out_data_len = out_len; + + // the new init_v is the last encrypted data block + // + memcpy(ctx->mech.pParameter, + out_data + (*out_data_len - DES_BLOCK_SIZE), DES_BLOCK_SIZE); + + // copy the remaining 'new' input data to the context buffer + // + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } + + free(clear); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } +} + + +// +// +CK_RV des_cbc_decrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (DES_CONTEXT *) ctx->context; + + total = context->len + in_data_len; + + if (total < DES_BLOCK_SIZE) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + // + remain = total % DES_BLOCK_SIZE; + out_len = total - remain; + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + // these buffers need to be longword aligned + // + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_put(tokdata, key, TRUE); + key = NULL; + return CKR_HOST_MEMORY; + } + // copy any data left over from the previous decryption operation first + // + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = ckm_des_cbc_decrypt(tokdata, cipher, out_len, out_data, + out_data_len, ctx->mech.pParameter, key); + if (rc == CKR_OK) { + *out_data_len = out_len; + + // the new init_v is the last decrypted data block + // + memcpy(ctx->mech.pParameter, cipher + (out_len - DES_BLOCK_SIZE), + DES_BLOCK_SIZE); + + // copy the remaining 'new' input data to the context buffer + // + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } + + free(cipher); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } +} + + +// +// +CK_RV des_cbc_pad_encrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *clear = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (DES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + // note, this is subtly different from the other encrypt update routines + // + if (total <= DES_BLOCK_SIZE) { + if (length_only == FALSE) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + 1 byte + // + remain = total % DES_BLOCK_SIZE; + out_len = total - remain; + + if (remain == 0) { + remain = DES_BLOCK_SIZE; + out_len -= DES_BLOCK_SIZE; + } + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + // at this point, we should have: + // 1) remain != 0 + // 2) out_len != 0 + // + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + // these buffers need to be longword aligned + // + clear = (CK_BYTE *) malloc(out_len); + if (!clear) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_put(tokdata, key, TRUE); + key = NULL; + return CKR_HOST_MEMORY; + } + // copy any data left over from the previous encryption operation first + // + memcpy(clear, context->data, context->len); + memcpy(clear + context->len, in_data, out_len - context->len); + + // + // we don't do padding during the update + // + rc = ckm_des_cbc_encrypt(tokdata, clear, out_len, out_data, + out_data_len, ctx->mech.pParameter, key); + + if (rc == CKR_OK) { + // the new init_v is the last encrypted data block + // + memcpy(ctx->mech.pParameter, + out_data + (*out_data_len - DES_BLOCK_SIZE), DES_BLOCK_SIZE); + + // copy the remaining 'new' input data to the temporary space + // + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } + + free(clear); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } +} + + +// +// +CK_RV des_cbc_pad_decrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (DES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + // note, this is subtly different from the other decrypt update routines + // + if (total <= DES_BLOCK_SIZE) { + if (length_only == FALSE) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + 1 byte + // + remain = total % DES_BLOCK_SIZE; + out_len = total - remain; + + if (remain == 0) { + remain = DES_BLOCK_SIZE; + out_len -= DES_BLOCK_SIZE; + } + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + // at this point, we should have: + // 1) remain != 0 + // 2) out_len != 0 + // + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + // these buffers need to be longword aligned + // + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_put(tokdata, key, TRUE); + key = NULL; + return CKR_HOST_MEMORY; + } + // copy any data left over from the previous decryption operation first + // + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = ckm_des_cbc_decrypt(tokdata, cipher, out_len, out_data, + out_data_len, ctx->mech.pParameter, key); + + if (rc == CKR_OK) { + // the new init_v is the last decrypted data block + // + memcpy(ctx->mech.pParameter, cipher + (out_len - DES_BLOCK_SIZE), + DES_BLOCK_SIZE); + + // copy the remaining 'new' input data to the temporary space + // + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } + free(cipher); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } +} + + +// +// +CK_RV des_ecb_encrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + + UNUSED(tokdata); + UNUSED(out_data); + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // satisfy the compiler + // + if (length_only) + context = NULL; + + context = (DES_CONTEXT *) ctx->context; + + // DES-ECB does no padding so there had better not be + // any data in the context buffer. if there is it means + // that the overall data length was not a multiple of the blocksize + // + if (context->len != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + + *out_data_len = 0; + + return CKR_OK; +} + + +// +// +CK_RV des_ecb_decrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + + UNUSED(tokdata); + UNUSED(out_data); + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // satisfy the compiler + // + if (length_only) + context = NULL; + + context = (DES_CONTEXT *) ctx->context; + + // DES-ECB does no padding so there had better not be + // any data in the context buffer. if there is it means + // that the overall data length was not a multiple of the blocksize + // + if (context->len != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + return CKR_ENCRYPTED_DATA_LEN_RANGE; + } + + *out_data_len = 0; + + return CKR_OK; +} + + +// +// +CK_RV des_cbc_encrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + + UNUSED(tokdata); + UNUSED(out_data); + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // satisfy the compiler + // + if (length_only) + context = NULL; + + context = (DES_CONTEXT *) ctx->context; + + // DES-CBC does no padding so there had better not be + // any data in the context buffer. if there is it means + // that the overall data length was not a multiple of the blocksize + // + if (context->len != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + + *out_data_len = 0; + + return CKR_OK; +} + + +// +// +CK_RV des_cbc_decrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + + UNUSED(tokdata); + UNUSED(out_data); + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // satisfy the compiler + // + if (length_only) + context = NULL; + + context = (DES_CONTEXT *) ctx->context; + + // DES-CBC does no padding so there had better not be + // any data in the context buffer. if there is it means + // that the overall data length was not a multiple of the blocksize + // + if (context->len != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + return CKR_ENCRYPTED_DATA_LEN_RANGE; + } + + *out_data_len = 0; + + return CKR_OK; +} + + +// +// +CK_RV des_cbc_pad_encrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE clear[2 * DES_BLOCK_SIZE]; + CK_ULONG out_len; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + context = (DES_CONTEXT *) ctx->context; + + // there will never be more than one block in the context buffer + // so the amount of output is as follows: + // if less than 1 block stored, we generate one block of output + // if a full block is stored, we generate two blocks of output (one pad + // block) + // + if (context->len == DES_BLOCK_SIZE) + out_len = 2 * DES_BLOCK_SIZE; + else + out_len = DES_BLOCK_SIZE; + + if (length_only == TRUE) { + *out_data_len = out_len; + rc = CKR_OK; + } else { + memcpy(clear, context->data, context->len); + + add_pkcs_padding(clear + context->len, + DES_BLOCK_SIZE, context->len, out_len); + + rc = ckm_des_cbc_encrypt(tokdata, clear, out_len, out_data, + out_data_len, ctx->mech.pParameter, key); + } + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + + +// +// +CK_RV des_cbc_pad_decrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE clear[DES_BLOCK_SIZE]; + CK_BYTE cipher[DES_BLOCK_SIZE]; + CK_ULONG out_len; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + context = (DES_CONTEXT *) ctx->context; + + // there had better be a full block in the context buffer + // + if (context->len != DES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + rc = CKR_ENCRYPTED_DATA_LEN_RANGE; + goto done; + } + // we don't know a priori how much data we'll be returning. we won't + // know until after we decrypt it and strip the padding. it's possible + // that we'll return nothing (the final block might be a padding block). + // + out_len = DES_BLOCK_SIZE; // upper bound on what we'll return + + if (length_only == TRUE) { + *out_data_len = out_len; + rc = CKR_OK; + } else { + memcpy(cipher, context->data, DES_BLOCK_SIZE); + + rc = ckm_des_cbc_decrypt(tokdata, cipher, DES_BLOCK_SIZE, clear, + &out_len, ctx->mech.pParameter, key); + if (rc == CKR_OK) { + strip_pkcs_padding(clear, DES_BLOCK_SIZE, &out_len); + + if (out_len != 0) + memcpy(out_data, clear, out_len); + + *out_data_len = out_len; + } + + } + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + + +// +// mechanisms +// + + +// +// +CK_RV ckm_des_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl) +{ + + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *opaque_attr = NULL; + CK_ATTRIBUTE *key_type_attr = NULL; + CK_ATTRIBUTE *class_attr = NULL; + CK_ATTRIBUTE *local_attr = NULL; + CK_BYTE *des_key = NULL; + CK_BYTE dummy_key[DES_KEY_SIZE] = { 0, }; + CK_ULONG rc; + CK_ULONG keysize; + + if (token_specific.t_des_key_gen == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + if (is_secure_key_token()) + keysize = token_specific.token_keysize; + else + keysize = DES_KEY_SIZE; + + if ((des_key = (CK_BYTE *) calloc(1, keysize)) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + rc = token_specific.t_des_key_gen(tokdata, des_key, keysize, DES_KEY_SIZE); + if (rc != CKR_OK) + goto err; + + /* For secure-key keys put in CKA_IBM_OPAQUE + * and put dummy_key in CKA_VALUE. + */ + if (is_secure_key_token()) { + opaque_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + keysize); + if (!opaque_attr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto err; + } + opaque_attr->type = CKA_IBM_OPAQUE; + opaque_attr->ulValueLen = keysize; + opaque_attr->pValue = (CK_BYTE *) opaque_attr + sizeof(CK_ATTRIBUTE); + memcpy(opaque_attr->pValue, des_key, keysize); + template_update_attribute(tmpl, opaque_attr); + } + + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + DES_KEY_SIZE); + key_type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + class_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_OBJECT_CLASS)); + local_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + + if (!value_attr || !key_type_attr || !class_attr || !local_attr) { + if (value_attr) + free(value_attr); + if (key_type_attr) + free(key_type_attr); + if (class_attr) + free(class_attr); + if (local_attr) + free(local_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto err; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = DES_KEY_SIZE; + value_attr->pValue = (CK_BYTE *) value_attr + sizeof(CK_ATTRIBUTE); + if (is_secure_key_token()) + memcpy(value_attr->pValue, dummy_key, DES_KEY_SIZE); + else + memcpy(value_attr->pValue, des_key, DES_KEY_SIZE); + free(des_key); + + key_type_attr->type = CKA_KEY_TYPE; + key_type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + key_type_attr->pValue = (CK_BYTE *) key_type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) key_type_attr->pValue = CKK_DES; + + class_attr->type = CKA_CLASS; + class_attr->ulValueLen = sizeof(CK_OBJECT_CLASS); + class_attr->pValue = (CK_BYTE *) class_attr + sizeof(CK_ATTRIBUTE); + *(CK_OBJECT_CLASS *) class_attr->pValue = CKO_SECRET_KEY; + + local_attr->type = CKA_LOCAL; + local_attr->ulValueLen = sizeof(CK_BBOOL); + local_attr->pValue = (CK_BYTE *) local_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) local_attr->pValue = TRUE; + + template_update_attribute(tmpl, value_attr); + template_update_attribute(tmpl, key_type_attr); + template_update_attribute(tmpl, class_attr); + template_update_attribute(tmpl, local_attr); + + return CKR_OK; + +err: + if (des_key) + free(des_key); + + return rc; +} + +#if !(NOCDMF) + +// +// +CK_RV ckm_cdmf_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *key_type_attr = NULL; + CK_ATTRIBUTE *class_attr = NULL; + CK_ATTRIBUTE *local_attr = NULL; + CK_BYTE cdmf_key[DES_KEY_SIZE]; + CK_ULONG repl_len, expected_repl_len; + CK_ULONG rc; + + repl_len = expected_repl_len = DES_KEY_SIZE; + + rc = communicate(PK_CDMF_KEYGEN, + NULL, 0, cdmf_key, &repl_len, NULL, 0, NULL, 0); + + if (rc == CKR_OK) { + if (repl_len != expected_repl_len) + return CKR_GENERAL_ERROR; + } + + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + DES_KEY_SIZE); + key_type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + class_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_OBJECT_CLASS)); + local_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + + if (!value_attr || !key_type_attr || !class_attr || !local_attr) { + if (value_attr) + free(value_attr); + if (key_type_attr) + free(key_type_attr); + if (class_attr) + free(class_attr); + if (local_attr) + free(local_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = DES_KEY_SIZE; + value_attr->pValue = (CK_BYTE *) value_attr + sizeof(CK_ATTRIBUTE); + memcpy(value_attr->pValue, cdmf_key, DES_KEY_SIZE); + + key_type_attr->type = CKA_KEY_TYPE; + key_type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + key_type_attr->pValue = (CK_BYTE *) key_type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) key_type_attr->pValue = CKK_CDMF; + + class_attr->type = CKA_CLASS; + class_attr->ulValueLen = sizeof(CK_OBJECT_CLASS); + class_attr->pValue = (CK_BYTE *) class_attr + sizeof(CK_ATTRIBUTE); + *(CK_OBJECT_CLASS *) class_attr->pValue = CKO_SECRET_KEY; + + local_attr->type = CKA_LOCAL; + local_attr->ulValueLen = sizeof(CK_BBOOL); + local_attr->pValue = (CK_BYTE *) local_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) local_attr->pValue = TRUE; + + template_update_attribute(tmpl, value_attr); + template_update_attribute(tmpl, key_type_attr); + template_update_attribute(tmpl, class_attr); + template_update_attribute(tmpl, local_attr); + + return CKR_OK; +} + +#endif + +// +// +CK_RV ckm_des_ecb_encrypt(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, OBJECT *key) +{ + CK_ULONG rc; + + + if (!in_data || !out_data || !key) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (*out_data_len < in_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + if (token_specific.t_des_ecb == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + rc = token_specific.t_des_ecb(tokdata, in_data, in_data_len, + out_data, out_data_len, key, 1); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific des_ecb encrypt failed.\n"); + + return rc; +} + + +// +// +CK_RV ckm_des_ecb_decrypt(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, OBJECT *key) +{ + CK_ULONG rc; + + + + if (!in_data || !out_data || !key) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (*out_data_len < in_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + if (token_specific.t_des_ecb == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + rc = token_specific.t_des_ecb(tokdata, in_data, in_data_len, out_data, + out_data_len, key, 0); + if (rc != CKR_OK) + TRACE_ERROR("Token specific des ecb decrypt failed.\n"); + + return rc; +} + + +// +// +CK_RV ckm_des_cbc_encrypt(STDLL_TokData_t *tokdata, + 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_ULONG rc; + + + if (!in_data || !out_data || !init_v || !key) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (*out_data_len < in_data_len) { + *out_data_len = in_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + if (token_specific.t_des_cbc == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + rc = token_specific.t_des_cbc(tokdata, in_data, in_data_len, out_data, + out_data_len, key, init_v, 1); + + if (rc != CKR_OK) + TRACE_ERROR("Token specific dec cbc encrypt failed.\n"); + + return rc; +} + + +// +// +CK_RV ckm_des_cbc_decrypt(STDLL_TokData_t *tokdata, + 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_ULONG rc; + + + if (!in_data || !out_data || !init_v || !key) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (*out_data_len < in_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + if (token_specific.t_des_cbc == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + rc = token_specific.t_des_cbc(tokdata, in_data, in_data_len, out_data, + out_data_len, key, init_v, 0); + + if (rc != CKR_OK) + TRACE_ERROR("Token specific des cbc decrypt failed.\n"); + + return rc; +} + + +// we're preparing to wrap a key using DES. need to make sure the +// data length is a integral multiple of the DES block size. +// +// PKCS #11 specifies that the padding shall be in the form of NULL +// bytes appended to the data +// +// this routine works with either DES and 3DES as the wrapping mechanism +// +CK_RV ckm_des_wrap_format(STDLL_TokData_t *tokdata, + CK_BBOOL length_only, + CK_BYTE **data, CK_ULONG *data_len) +{ + CK_BYTE *ptr = NULL; + CK_ULONG len1, len2; + + UNUSED(tokdata); + + len1 = *data_len; + if (*data == NULL) + len1 = 0; + + // if the input key data isn't a multiple of the blocksize, + // we pad with NULLs to the next blocksize multiple. + // + if (len1 % DES_BLOCK_SIZE != 0) { + len2 = DES_BLOCK_SIZE * ((len1 / DES_BLOCK_SIZE) + 1); + + if (length_only == FALSE) { + /* + * Don't use realloc here, since the buffer contains a key and the + * old buffer needs to be cleansed before it is freed. + */ + ptr = (CK_BYTE *)malloc(len2); + if (!ptr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + memset(ptr + len1, 0x0, (len2 - len1)); + if (*data != NULL) { + memcpy(ptr, *data, len1); + OPENSSL_cleanse(*data, len1); + free(*data); + } + + *data = ptr; + *data_len = len2; + } + } + + return CKR_OK; +} diff --git a/usr/lib/common/mech_des3.c b/usr/lib/common/mech_des3.c new file mode 100644 index 0000000..8a588f7 --- /dev/null +++ b/usr/lib/common/mech_des3.c @@ -0,0 +1,2948 @@ +/* + * 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: mech_des3.c +// +// Mechanisms for DES3 +// + +#include // for memcmp() et al +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "trace.h" + +#include + +// +// +CK_RV des3_ecb_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // CKM_DES3_ECB requires the input data to be an integral + // multiple of the block size + // + if (in_data_len % DES_BLOCK_SIZE != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < in_data_len) { + *out_data_len = in_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + rc = ckm_des3_ecb_encrypt(tokdata, in_data, in_data_len, + out_data, out_data_len, key); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + + +// +// +CK_RV des3_ecb_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // CKM_DES3_ECB requires the input data to be an integral + // multiple of the block size + // + if (in_data_len % DES_BLOCK_SIZE != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + return CKR_ENCRYPTED_DATA_LEN_RANGE; + } + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < in_data_len) { + *out_data_len = in_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + rc = ckm_des3_ecb_decrypt(tokdata, in_data, in_data_len, + out_data, out_data_len, key); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + + +// +// +CK_RV des3_cbc_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // CKM_DES3_CBC requires the input data to be an integral + // multiple of the block size + // + if (in_data_len % DES_BLOCK_SIZE != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < in_data_len) { + *out_data_len = in_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + rc = ckm_des3_cbc_encrypt(tokdata, in_data, in_data_len, out_data, + out_data_len, ctx->mech.pParameter, key); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + +// +// +CK_RV des3_cbc_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // CKM_DES3_CBC requires the input data to be an integral + // multiple of the block size + // + if (in_data_len % DES_BLOCK_SIZE != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + return CKR_ENCRYPTED_DATA_LEN_RANGE; + } + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < in_data_len) { + *out_data_len = in_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + rc = ckm_des3_cbc_decrypt(tokdata, in_data, in_data_len, out_data, + out_data_len, ctx->mech.pParameter, key); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + + +// +// +CK_RV des3_cbc_pad_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_BYTE *clear = NULL; + CK_ULONG padded_len; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // DES3-CBC-PAD has no input length requirements + // + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + // compute the output length, accounting for padding + // + padded_len = DES_BLOCK_SIZE * (in_data_len / DES_BLOCK_SIZE + 1); + + if (length_only == TRUE) { + *out_data_len = padded_len; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < padded_len) { + *out_data_len = padded_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + clear = (CK_BYTE *) malloc(padded_len); + if (!clear) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memcpy(clear, in_data, in_data_len); + + add_pkcs_padding(clear + in_data_len, + DES_BLOCK_SIZE, in_data_len, padded_len); + + rc = ckm_des3_cbc_encrypt(tokdata, clear, padded_len, out_data, + out_data_len, ctx->mech.pParameter, key); + + free(clear); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + + +// +// +CK_RV des3_cbc_pad_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key = NULL; + CK_BYTE *clear = NULL; + CK_ULONG padded_len; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // + // no need to validate the input length since we'll pad as necessary + // + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + // we're decrypting so even with CBC-PAD, we should have an integral + // number of block to decrypt + // + if (in_data_len % DES_BLOCK_SIZE != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + rc = CKR_ENCRYPTED_DATA_LEN_RANGE; + goto done; + } + // the amount of cleartext after stripping the padding will actually be less + // than the input bytes... + // + padded_len = in_data_len; + + if (length_only == TRUE) { + *out_data_len = padded_len; + rc = CKR_OK; + goto done; + } + + clear = (CK_BYTE *) malloc(padded_len); + if (!clear) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + rc = ckm_des3_cbc_decrypt(tokdata, in_data, in_data_len, clear, &padded_len, + ctx->mech.pParameter, key); + + if (rc == CKR_OK) { + strip_pkcs_padding(clear, padded_len, out_data_len); + memcpy(out_data, clear, *out_data_len); + } + + free(clear); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + + +// +// +CK_RV des3_ecb_encrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *clear = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (DES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < DES_BLOCK_SIZE) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + // + remain = (total % DES_BLOCK_SIZE); + out_len = (total - remain); // should always be at least 1 block + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + clear = (CK_BYTE *) malloc(out_len); + if (!clear) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_put(tokdata, key, TRUE); + key = NULL; + return CKR_HOST_MEMORY; + } + // copy any data left over from the previous encryption operation first + // + memcpy(clear, context->data, context->len); + memcpy(clear + context->len, in_data, out_len - context->len); + + rc = ckm_des3_ecb_encrypt(tokdata, clear, out_len, + out_data, out_data_len, key); + if (rc == CKR_OK) { + *out_data_len = out_len; + + // update the context buffer. we already used the buffer's current + // contents so we completely overwrite it + // + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + + context->len = remain; + } + + free(clear); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } +} + + +// +// +CK_RV des3_ecb_decrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (DES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < DES_BLOCK_SIZE) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + // + remain = (total % DES_BLOCK_SIZE); + out_len = total - remain; + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + // copy any data left over from the previous decryption operation first + // + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = ckm_des3_ecb_decrypt(tokdata, cipher, out_len, out_data, + out_data_len, key); + if (rc == CKR_OK) { + *out_data_len = out_len; + + // copy the remaining 'new' input data to the context buffer + // + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } + + free(cipher); + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } + +} + + +// +// +CK_RV des3_cbc_encrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *clear = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (DES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < DES_BLOCK_SIZE) { + if (length_only == FALSE) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + // + remain = (total % DES_BLOCK_SIZE); + out_len = total - remain; + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + // these buffers need to be longword aligned + // + clear = (CK_BYTE *) malloc(out_len); + if (!clear) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_put(tokdata, key, TRUE); + key = NULL; + return CKR_HOST_MEMORY; + } + // copy any data left over from the previous encryption operation first + // + memcpy(clear, context->data, context->len); + memcpy(clear + context->len, in_data, out_len - context->len); + + rc = ckm_des3_cbc_encrypt(tokdata, clear, out_len, out_data, + out_data_len, ctx->mech.pParameter, key); + + if (rc == CKR_OK) { + *out_data_len = out_len; + + // the new init_v is the last encrypted data block + // + memcpy(ctx->mech.pParameter, + out_data + (*out_data_len - DES_BLOCK_SIZE), DES_BLOCK_SIZE); + + // copy the remaining 'new' input data to the context buffer + // + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } + + free(clear); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } +} + + +// +// +CK_RV des3_cbc_decrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (DES_CONTEXT *) ctx->context; + + total = context->len + in_data_len; + + if (total < DES_BLOCK_SIZE) { + if (length_only == FALSE) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + // + remain = total % DES_BLOCK_SIZE; + out_len = total - remain; + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + // these buffers need to be longword aligned + // + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_put(tokdata, key, TRUE); + key = NULL; + return CKR_HOST_MEMORY; + } + // copy any data left over from the previous decryption operation first + // + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = ckm_des3_cbc_decrypt(tokdata, cipher, out_len, out_data, + out_data_len, ctx->mech.pParameter, key); + + if (rc == CKR_OK) { + *out_data_len = out_len; + + // the new init_v is the last input data block + // + memcpy(ctx->mech.pParameter, cipher + (out_len - DES_BLOCK_SIZE), + DES_BLOCK_SIZE); + + // copy the remaining 'new' input data to the context buffer + // + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + + context->len = remain; + } + + free(cipher); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } + +} + + +// +// +CK_RV des3_cbc_pad_encrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *clear = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (DES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + // note, this is subtly different from the other encrypt update routines + // + if (total <= DES_BLOCK_SIZE) { + if (length_only == FALSE) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + remain = (total % DES_BLOCK_SIZE); + out_len = total - remain; // out_len is a multiple of DES_BLOCK_SIZE + + if (remain == 0) { + remain = DES_BLOCK_SIZE; + out_len -= DES_BLOCK_SIZE; + } + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + // at this point, we should have: + // 1) remain != 0 + // 2) out_len != 0 + // + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + // these buffers need to be longword aligned + // + clear = (CK_BYTE *) malloc(out_len); + if (!clear) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_put(tokdata, key, TRUE); + key = NULL; + return CKR_HOST_MEMORY; + } + // copy any data left over from the previous encryption operation first + // + memcpy(clear, context->data, context->len); + memcpy(clear + context->len, in_data, out_len - context->len); + + // + // we don't do padding during the update + // + rc = ckm_des3_cbc_encrypt(tokdata, clear, out_len, out_data, + out_data_len, ctx->mech.pParameter, key); + + if (rc == CKR_OK) { + // the new init_v is the last encrypted data block + // + memcpy(ctx->mech.pParameter, + out_data + (*out_data_len - DES_BLOCK_SIZE), DES_BLOCK_SIZE); + + // copy the remaining 'new' input data to the temporary space + // + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } + + free(clear); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } +} + + +// +// +CK_RV des3_cbc_pad_decrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (DES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + // note, this is subtly different from the other decrypt update routines + // + if (total <= DES_BLOCK_SIZE) { + if (length_only == FALSE) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + 1 byte + // + remain = total % DES_BLOCK_SIZE; + out_len = total - remain; + + if (remain == 0) { + remain = DES_BLOCK_SIZE; + out_len -= DES_BLOCK_SIZE; + } + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + // at this point, we should have: + // 1) remain != 0 + // 2) out_len != 0 + // + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + // these buffers need to be longword aligned + // + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + object_put(tokdata, key, TRUE); + key = NULL; + return CKR_HOST_MEMORY; + } + // copy any data left over from the previous decryption operation first + // + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = ckm_des3_cbc_decrypt(tokdata, cipher, out_len, out_data, + out_data_len, ctx->mech.pParameter, key); + + if (rc == CKR_OK) { + // the new init_v is the last input data block + // + memcpy(ctx->mech.pParameter, cipher + (out_len - DES_BLOCK_SIZE), + DES_BLOCK_SIZE); + + // copy the remaining 'new' input data to the temporary space + // + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } + + free(cipher); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; + } +} + + +// +// +CK_RV des3_ecb_encrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + + UNUSED(tokdata); + UNUSED(out_data); + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // satisfy the compiler + // + if (length_only) + context = NULL; + + context = (DES_CONTEXT *) ctx->context; + + // DES3-ECB does no padding so there had better not be + // any data in the context buffer. if there is it means + // that the overall data length was not a multiple of the blocksize + // + if (context->len != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + + *out_data_len = 0; + + return CKR_OK; +} + +// +// +CK_RV des3_ecb_decrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + + UNUSED(tokdata); + UNUSED(out_data); + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // satisfy the compiler + // + if (length_only) + context = NULL; + + context = (DES_CONTEXT *) ctx->context; + + // DES3-ECB does no padding so there had better not be + // any data in the context buffer. if there is it means + // that the overall data length was not a multiple of the blocksize + // + if (context->len != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + return CKR_ENCRYPTED_DATA_LEN_RANGE; + } + + *out_data_len = 0; + + return CKR_OK; +} + + +// +// +CK_RV des3_cbc_encrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + + UNUSED(tokdata); + UNUSED(out_data); + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // satisfy the compiler + // + if (length_only) + context = NULL; + + context = (DES_CONTEXT *) ctx->context; + + // DES3-CBC does no padding so there had better not be + // any data in the context buffer. if there is it means + // that the overall data length was not a multiple of the blocksize + // + if (context->len != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + + *out_data_len = 0; + + return CKR_OK; +} + + +// +// +CK_RV des3_cbc_decrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + + UNUSED(tokdata); + UNUSED(out_data); + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // satisfy the compiler + // + if (length_only) + context = NULL; + + context = (DES_CONTEXT *) ctx->context; + + // DES3-CBC does no padding so there had better not be + // any data in the context buffer. if there is it means + // that the overall data length was not a multiple of the blocksize + // + if (context->len != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + return CKR_ENCRYPTED_DATA_LEN_RANGE; + } + + *out_data_len = 0; + + return CKR_OK; +} + + +// +// +CK_RV des3_cbc_pad_encrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE clear[2 * DES_BLOCK_SIZE]; + CK_ULONG out_len; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + context = (DES_CONTEXT *) ctx->context; + + // there will never be more than one block in the context buffer + // so the amount of output is as follows: + // if less than 1 block stored, we generate one block of output + // if a full block is stored, we generate two blocks of output (one pad + // block) + // + if (context->len == DES_BLOCK_SIZE) + out_len = 2 * DES_BLOCK_SIZE; + else + out_len = DES_BLOCK_SIZE; + + if (length_only == TRUE) { + *out_data_len = out_len; + rc = CKR_OK; + } else { + memcpy(clear, context->data, context->len); + + add_pkcs_padding(clear + context->len, + DES_BLOCK_SIZE, context->len, out_len); + + rc = ckm_des3_cbc_encrypt(tokdata, clear, out_len, out_data, + out_data_len, ctx->mech.pParameter, key); + } + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + + +// +// +CK_RV des3_cbc_pad_decrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + OBJECT *key = NULL; + CK_BYTE clear[DES_BLOCK_SIZE]; + CK_ULONG out_len; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + context = (DES_CONTEXT *) ctx->context; + + // there had better be a full block in the context buffer + // + if (context->len != DES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + rc = CKR_ENCRYPTED_DATA_LEN_RANGE; + goto done; + } + // we don't know a priori how much data we'll be returning. we won't + // know until after we decrypt it and strip the padding. it's possible + // that we'll return nothing (the final block might be a padding block). + // + out_len = DES_BLOCK_SIZE; // upper bound on what we'll return + + if (length_only == TRUE) { + *out_data_len = out_len; + rc = CKR_OK; + } else { + rc = ckm_des3_cbc_decrypt(tokdata, context->data, DES_BLOCK_SIZE, clear, + &out_len, ctx->mech.pParameter, key); + + if (rc == CKR_OK) { + strip_pkcs_padding(clear, out_len, &out_len); + + if (out_len != 0) + memcpy(out_data, clear, out_len); + + *out_data_len = out_len; + } + } + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + +CK_RV des3_ofb_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + + if (!sess || !ctx || !in_data || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + return CKR_OK; + } + + if (*out_data_len < in_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_tdes_ofb(tokdata, in_data, out_data, in_data_len, + key_obj, ctx->mech.pParameter, 1); + if (rc != CKR_OK) + TRACE_DEVEL("Token specific des3 ofb encrypt failed.\n"); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV des3_ofb_encrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_DATA_CONTEXT *context = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + OBJECT *key_obj = NULL; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (DES_DATA_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < DES_BLOCK_SIZE) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + remain = (total % DES_BLOCK_SIZE); + out_len = total - remain; + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + if (*out_data_len < out_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + // copy any data left over from the previous encryption operation first + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = token_specific.t_tdes_ofb(tokdata, cipher, out_data, out_len, + key_obj, ctx->mech.pParameter, 1); + + if (rc == CKR_OK) { + *out_data_len = out_len; + + // copy the remaining 'new' input data to the context buffer + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } else { + TRACE_DEVEL("Token specific des3 ofb encrypt failed.\n"); + } + + free(cipher); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; + } +} + +CK_RV des3_ofb_encrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + DES_CONTEXT *context = NULL; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (DES_CONTEXT *) ctx->context; + + // there will never be more than one block in the context buffer + // so the amount of output is as follows: + // if less than 1 block stored, we generate same length of output data + // if no data stored, no data can be returned (length zero) + + if (length_only == TRUE) { + *out_data_len = context->len; + return CKR_OK; + } else { + if (context->len == 0) { + *out_data_len = 0; + return CKR_OK; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_tdes_ofb(tokdata, context->data, out_data, + context->len, key_obj, + ctx->mech.pParameter, 1); + if (rc != CKR_OK) + TRACE_DEVEL("Token specific des3 ofb encrypt failed.\n"); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + *out_data_len = context->len; + return rc; + } +} + +CK_RV des3_ofb_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + + if (!sess || !ctx || !in_data || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + return CKR_OK; + } + + if (*out_data_len < in_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_tdes_ofb(tokdata, in_data, out_data, in_data_len, + key_obj, ctx->mech.pParameter, 0); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific des3 ofb decrypt failed.\n"); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV des3_ofb_decrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + DES_CONTEXT *context = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + OBJECT *key_obj = NULL; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (DES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < DES_BLOCK_SIZE) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + remain = (total % DES_BLOCK_SIZE); + out_len = total - remain; + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + if (*out_data_len < out_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + // copy any data left over from the previous decryption operation first + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = token_specific.t_tdes_ofb(tokdata, cipher, out_data, out_len, + key_obj, ctx->mech.pParameter, 0); + + if (rc == CKR_OK) { + *out_data_len = out_len; + + // copy the remaining 'new' input data to the context buffer + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } else { + TRACE_DEVEL("Token specific des3 ofb decrypt failed.\n"); + } + + free(cipher); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; + } +} + +CK_RV des3_ofb_decrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + DES_CONTEXT *context = NULL; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (DES_CONTEXT *) ctx->context; + + // there will never be more than one block in the context buffer + // so the amount of output is as follows: + // if less than 1 block stored, we generate same length of output data + // if no data stored, no data can be returned (length zero) + + if (length_only == TRUE) { + *out_data_len = context->len; + return CKR_OK; + } else { + if (context->len == 0) { + *out_data_len = 0; + return CKR_OK; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_tdes_ofb(tokdata, context->data, out_data, + context->len, key_obj, + ctx->mech.pParameter, 0); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific des3 ofb decrypt failed.\n"); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + *out_data_len = context->len; + + return rc; + } +} + +CK_RV des3_cfb_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_ULONG cfb_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + + if (!sess || !ctx || !in_data || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + return CKR_OK; + } + + if (*out_data_len < in_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_tdes_cfb(tokdata, in_data, out_data, in_data_len, + key_obj, ctx->mech.pParameter, cfb_len, 1); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific des3 cfb encrypt failed.\n"); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV des3_cfb_encrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_ULONG cfb_len) +{ + DES_CONTEXT *context = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + OBJECT *key_obj = NULL; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (DES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < cfb_len) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + remain = (total % cfb_len); + out_len = total - remain; + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + if (*out_data_len < out_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + // copy any data left over from the previous encryption operation first + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = token_specific.t_tdes_cfb(tokdata, cipher, out_data, out_len, + key_obj, ctx->mech.pParameter, cfb_len, + 1); + + if (rc == CKR_OK) { + *out_data_len = out_len; + + // copy the remaining 'new' input data to the context buffer + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } else { + TRACE_DEVEL("Token specific des3 cfb encrypt failed.\n"); + } + + free(cipher); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; + } +} + +CK_RV des3_cfb_encrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_ULONG cfb_len) +{ + OBJECT *key_obj = NULL; + DES_CONTEXT *context = NULL; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (DES_CONTEXT *) ctx->context; + + // there will never be more than one block in the context buffer + // so the amount of output is as follows: + // if less than 1 block stored, we generate same length of output data + // if no data stored, no data can be returned (length zero) + + if (context->len == 0) { + *out_data_len = 0; + return CKR_OK; + } + + if (length_only == TRUE) { + *out_data_len = context->len; + return CKR_OK; + } else { + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_tdes_cfb(tokdata, context->data, out_data, + context->len, key_obj, + ctx->mech.pParameter, cfb_len, 1); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific des3 cfb encrypt failed.\n"); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + *out_data_len = context->len; + + return rc; + } +} + +CK_RV des3_cfb_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_ULONG cfb_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + + if (!sess || !ctx || !in_data || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (length_only == TRUE) { + *out_data_len = in_data_len; + return CKR_OK; + } + + if (*out_data_len < in_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_tdes_cfb(tokdata, in_data, out_data, in_data_len, + key_obj, ctx->mech.pParameter, cfb_len, 0); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific des3 cfd decrypt failed.\n"); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV des3_cfb_decrypt_update(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_ULONG cfb_len) +{ + DES_CONTEXT *context = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + CK_RV rc; + OBJECT *key_obj = NULL; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (DES_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < cfb_len) { + if (length_only == FALSE && in_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + } + + *out_data_len = 0; + return CKR_OK; + } else { + // we have at least 1 block + remain = (total % cfb_len); + out_len = total - remain; + + if (length_only == TRUE) { + *out_data_len = out_len; + return CKR_OK; + } + + if (*out_data_len < out_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + // copy any data left over from the previous decryption operation first + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = token_specific.t_tdes_cfb(tokdata, cipher, out_data, out_len, + key_obj, ctx->mech.pParameter, cfb_len, + 0); + + if (rc == CKR_OK) { + *out_data_len = out_len; + + // copy the remaining 'new' input data to the context buffer + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } else { + TRACE_DEVEL("Token specific des3 cfb decrypt failed.\n"); + } + + free(cipher); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; + } +} + +CK_RV des3_cfb_decrypt_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_ULONG cfb_len) +{ + OBJECT *key_obj = NULL; + DES_CONTEXT *context = NULL; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (DES_CONTEXT *) ctx->context; + + // there will never be more than one block in the context buffer + // so the amount of output is as follows: + // if less than 1 block stored, we generate same length of output data + // if no data stored, no data can be returned (length zero) + + if (context->len == 0) { + *out_data_len = 0; + return CKR_OK; + } + + if (length_only == TRUE) { + *out_data_len = context->len; + return CKR_OK; + } else { + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_tdes_cfb(tokdata, context->data, out_data, + context->len, key_obj, + ctx->mech.pParameter, cfb_len, 0); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific des3 cfb decrypt failed.\n"); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + *out_data_len = context->len; + + return rc; + } +} + +CK_RV des3_mac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + CK_ULONG mac_len; + + if (!sess || !ctx || !in_data || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (ctx->mech.pParameter) + mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; + else + mac_len = DES_BLOCK_SIZE / 2; + + if (length_only == TRUE) { + *out_data_len = mac_len; + return CKR_OK; + } + + if ((in_data_len % DES_BLOCK_SIZE) != 0) { + rc = des3_mac_sign_update(tokdata, sess, ctx, in_data, in_data_len); + if (rc != CKR_OK) + return rc; + + rc = des3_mac_sign_final(tokdata, sess, length_only, ctx, out_data, + out_data_len); + return rc; + } else { + + if (*out_data_len < mac_len) { + *out_data_len = mac_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + rc = token_specific.t_tdes_mac(tokdata, in_data, in_data_len, key_obj, + ((DES_DATA_CONTEXT *) ctx->context)->iv); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific des3 mac failed.\n"); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + memcpy(out_data, ((DES_DATA_CONTEXT *) ctx->context)->iv, mac_len); + + *out_data_len = mac_len; + + return rc; + } +} + +CK_RV des3_mac_sign_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + DES_DATA_CONTEXT *context = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + + if (!sess || !ctx) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (DES_DATA_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < DES_BLOCK_SIZE) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + return CKR_OK; + } else { + // we have at least 1 block + remain = (total % DES_BLOCK_SIZE); + out_len = total - remain; + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + // copy any data left over from the previous signUpdate operation first + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = token_specific.t_tdes_mac(tokdata, cipher, out_len, key_obj, + context->iv); + + if (rc == CKR_OK) { + // copy the remaining 'new' input data to the context buffer + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } else { + TRACE_DEVEL("Token specific des3 mac failed.\n"); + } + + free(cipher); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; + } +} + +CK_RV des3_mac_sign_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_ULONG rc = CKR_OK; + OBJECT *key_obj = NULL; + CK_ULONG mac_len; + DES_DATA_CONTEXT *context = NULL; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (DES_DATA_CONTEXT *) ctx->context; + + if (ctx->mech.pParameter) + mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; + else + mac_len = DES_BLOCK_SIZE / 2; + + // there will never be more than one block in the context buffer + // so the amount of output is as follows: + // if less than 1 block stored, we generate one block of output (with + // padding) + // if no data stored, we are done (take the cipher from previous round) + + if (length_only == TRUE) { + *out_data_len = mac_len; + return CKR_OK; + } + + if (context->len > 0) { + + if (*out_data_len < mac_len) { + *out_data_len = mac_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + /* padding with '00' in case case we didn't reach block size */ + memset(context->data + context->len, 0x0, + DES_BLOCK_SIZE - context->len); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + rc = token_specific.t_tdes_mac(tokdata, context->data, DES_BLOCK_SIZE, + key_obj, context->iv); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + if (rc != CKR_OK) { + TRACE_DEVEL("Token specific des3 mac failed.\n"); + return rc; + } + } + memcpy(out_data, context->iv, mac_len); + + *out_data_len = mac_len; + + return rc; +} + +CK_RV des3_mac_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG out_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + CK_ULONG mac_len; + + if (!sess || !ctx || !in_data || !out_data) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if ((in_data_len % DES_BLOCK_SIZE) != 0) { + rc = des3_mac_verify_update(tokdata, sess, ctx, in_data, in_data_len); + if (rc != CKR_OK) + return rc; + + rc = des3_mac_verify_final(tokdata, sess, ctx, out_data, out_data_len); + return rc; + } else { + + if (ctx->mech.pParameter) + mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; + else + mac_len = DES_BLOCK_SIZE / 2; + + if (out_data_len != mac_len) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + return CKR_SIGNATURE_LEN_RANGE; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_tdes_mac(tokdata, in_data, in_data_len, key_obj, + ((DES_DATA_CONTEXT *) ctx->context)->iv); + if (rc != CKR_OK) + TRACE_DEVEL("Token specific des3 mac failed.\n"); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + if (CRYPTO_memcmp(out_data, ((DES_DATA_CONTEXT *) ctx->context)->iv, + out_data_len) == 0) + return CKR_OK; + + return CKR_SIGNATURE_INVALID; + } +} + +CK_RV des3_mac_verify_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + DES_DATA_CONTEXT *context = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + + if (!sess || !ctx) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (DES_DATA_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total < DES_BLOCK_SIZE) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + return CKR_OK; + } else { + // we have at least 1 block + remain = (total % DES_BLOCK_SIZE); + out_len = total - remain; + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + // copy any data left over from the previous signUpdate operation first + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = token_specific.t_tdes_mac(tokdata, cipher, out_len, key_obj, + context->iv); + if (rc == CKR_OK) { + // copy the remaining 'new' input data to the context buffer + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + } else { + TRACE_DEVEL("Token specific des3 mac failed.\n"); + } + + free(cipher); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; + } +} + +CK_RV des3_mac_verify_final(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG signature_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + CK_ULONG mac_len; + DES_DATA_CONTEXT *context = NULL; + + if (!sess || !ctx || !signature) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (DES_DATA_CONTEXT *) ctx->context; + + if (ctx->mech.pParameter) + mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; + else + mac_len = DES_BLOCK_SIZE / 2; + + // there will never be more than one block in the context buffer + // so the amount of output is as follows: + // if less than 1 block stored, we generate one block of output (with + // padding) + // if no data stored, we are done (take the cipher from previous round) + + if (context->len > 0) { + + if (signature_len != mac_len) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + return CKR_SIGNATURE_LEN_RANGE; + } + + /* padding with '00' in case case we didn't reach block size */ + memset(context->data + context->len, 0x0, + DES_BLOCK_SIZE - context->len); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_tdes_mac(tokdata, context->data, DES_BLOCK_SIZE, + key_obj, context->iv); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + if (rc != CKR_OK) { + TRACE_DEVEL("Token specific des3 mac failed.\n"); + return rc; + } + } + + if (CRYPTO_memcmp(signature, context->iv, signature_len) == 0) + return CKR_OK; + + return CKR_SIGNATURE_INVALID; +} + +CK_RV des3_cmac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + CK_ULONG mac_len; + + if (!sess || !ctx || !in_data || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (ctx->mech.pParameter) + mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; + else + mac_len = DES_BLOCK_SIZE; + + if (length_only == TRUE) { + *out_data_len = mac_len; + return CKR_OK; + } + + if (*out_data_len < mac_len) { + *out_data_len = mac_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + rc = token_specific.t_tdes_cmac(tokdata, in_data, in_data_len, key_obj, + ((DES_CMAC_CONTEXT *)ctx->context)->iv, + CK_TRUE, CK_TRUE, + &((DES_CMAC_CONTEXT *)ctx->context)->ctx); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific des3 cmac failed.\n"); + + memcpy(out_data, ((DES_CMAC_CONTEXT *) ctx->context)->iv, mac_len); + + *out_data_len = mac_len; + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV des3_cmac_sign_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + DES_CMAC_CONTEXT *context = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + + if (!sess || !ctx) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (DES_CMAC_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total <= DES_BLOCK_SIZE) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + return CKR_OK; + } else { + // we have at least 1 block + remain = (total % DES_BLOCK_SIZE); + if (remain == 0) + remain = DES_BLOCK_SIZE; /* Keep last block in context */ + out_len = total - remain; + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + // copy any data left over from the previous signUpdate operation first + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = token_specific.t_tdes_cmac(tokdata, cipher, out_len, key_obj, + context->iv, + !context->initialized, CK_FALSE, + &context->ctx); + + if (rc == CKR_OK) { + // copy the remaining 'new' input data to the context buffer + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + + context->initialized = CK_TRUE; + } else { + TRACE_DEVEL("Token specific des3 cmac failed.\n"); + } + + free(cipher); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; + } +} + +CK_RV des3_cmac_sign_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_ULONG rc = CKR_OK; + OBJECT *key_obj = NULL; + CK_ULONG mac_len; + DES_CMAC_CONTEXT *context = NULL; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (DES_CMAC_CONTEXT *) ctx->context; + + if (ctx->mech.pParameter) + mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; + else + mac_len = DES_BLOCK_SIZE; + + if (length_only == TRUE) { + *out_data_len = mac_len; + return CKR_OK; + } + + if (*out_data_len < mac_len) { + *out_data_len = mac_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + rc = token_specific.t_tdes_cmac(tokdata, context->data, context->len, + key_obj, context->iv, + !context->initialized, CK_TRUE, + &context->ctx); + if (rc != CKR_OK) { + TRACE_DEVEL("Token specific des3 cmac failed.\n"); + goto done; + } + + memcpy(out_data, context->iv, mac_len); + + *out_data_len = mac_len; + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV des3_cmac_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG out_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + CK_ULONG mac_len; + + if (!sess || !ctx || !in_data || !out_data) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (ctx->mech.pParameter) + mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; + else + mac_len = DES_BLOCK_SIZE; + + if (out_data_len != mac_len) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + return CKR_SIGNATURE_LEN_RANGE; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_tdes_cmac(tokdata, in_data, in_data_len, key_obj, + ((DES_CMAC_CONTEXT *)ctx->context)->iv, + CK_TRUE, CK_TRUE, + &((DES_CMAC_CONTEXT *)ctx->context)->ctx); + if (rc != CKR_OK) + TRACE_DEVEL("Token specific des3 cmac failed.\n"); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + if (CRYPTO_memcmp(out_data, ((DES_CMAC_CONTEXT *) ctx->context)->iv, + out_data_len) == 0) { + return CKR_OK; + } + return CKR_SIGNATURE_INVALID; +} + +CK_RV des3_cmac_verify_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + DES_CMAC_CONTEXT *context = NULL; + CK_BYTE *cipher = NULL; + CK_ULONG total, remain, out_len; + + if (!sess || !ctx) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (DES_CMAC_CONTEXT *) ctx->context; + + total = (context->len + in_data_len); + + if (total <= DES_BLOCK_SIZE) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + return CKR_OK; + } else { + // we have at least 1 block + remain = (total % DES_BLOCK_SIZE); + if (remain == 0) + remain = DES_BLOCK_SIZE; /* Keep last block in context */ + out_len = total - remain; + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + cipher = (CK_BYTE *) malloc(out_len); + if (!cipher) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + // copy any data left over from the previous signUpdate operation first + memcpy(cipher, context->data, context->len); + memcpy(cipher + context->len, in_data, out_len - context->len); + + rc = token_specific.t_tdes_cmac(tokdata, cipher, out_len, key_obj, + context->iv, + !context->initialized, CK_FALSE, + &context->ctx); + if (rc == CKR_OK) { + // copy the remaining 'new' input data to the context buffer + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + + context->initialized = CK_TRUE; + } else { + TRACE_DEVEL("Token specific des3 cmac failed.\n"); + } + + free(cipher); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; + } +} + +CK_RV des3_cmac_verify_final(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG signature_len) +{ + CK_ULONG rc; + OBJECT *key_obj = NULL; + CK_ULONG mac_len; + DES_CMAC_CONTEXT *context = NULL; + + if (!sess || !ctx || !signature) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + context = (DES_CMAC_CONTEXT *) ctx->context; + + if (ctx->mech.pParameter) + mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; + else + mac_len = DES_BLOCK_SIZE; + + if (signature_len != mac_len) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + return CKR_SIGNATURE_LEN_RANGE; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + rc = token_specific.t_tdes_cmac(tokdata, context->data, context->len, + key_obj, context->iv, + !context->initialized, CK_TRUE, + &context->ctx); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + if (rc != CKR_OK) { + TRACE_DEVEL("Token specific des3 cmac failed.\n"); + return rc; + } + + if (CRYPTO_memcmp(signature, context->iv, signature_len) == 0) + return CKR_OK; + + return CKR_SIGNATURE_INVALID; +} + +// +// mechanisms +// + + +// +// +CK_RV ckm_des3_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl) +{ + + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *opaque_attr = NULL; + CK_ATTRIBUTE *key_type_attr = NULL; + CK_ATTRIBUTE *class_attr = NULL; + CK_ATTRIBUTE *local_attr = NULL; + CK_BYTE *des_key = NULL; + CK_BYTE dummy_key[3 * DES_KEY_SIZE] = { 0, }; + CK_ULONG rc; + CK_ULONG keysize; + + if (token_specific.t_des_key_gen == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + if (is_secure_key_token()) + keysize = token_specific.token_keysize; + else + keysize = (3 * DES_KEY_SIZE); + + if ((des_key = (CK_BYTE *) calloc(1, keysize)) == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + rc = token_specific.t_des_key_gen(tokdata, des_key, keysize, + 3 * DES_KEY_SIZE); + if (rc != CKR_OK) + goto err; + + /* For secure-key keys put in CKA_IBM_OPAQUE + * and put dummy_key in CKA_VALUE. + */ + if (is_secure_key_token()) { + opaque_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + keysize); + if (!opaque_attr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto err; + } + opaque_attr->type = CKA_IBM_OPAQUE; + opaque_attr->ulValueLen = keysize; + opaque_attr->pValue = (CK_BYTE *) opaque_attr + sizeof(CK_ATTRIBUTE); + memcpy(opaque_attr->pValue, des_key, keysize); + template_update_attribute(tmpl, opaque_attr); + } + + value_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + 3 * DES_KEY_SIZE); + key_type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + class_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_OBJECT_CLASS)); + local_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + + if (!value_attr || !key_type_attr || !class_attr || !local_attr) { + if (value_attr) + free(value_attr); + if (key_type_attr) + free(key_type_attr); + if (class_attr) + free(class_attr); + if (local_attr) + free(local_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto err; + } + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 3 * DES_KEY_SIZE; + value_attr->pValue = (CK_BYTE *) value_attr + sizeof(CK_ATTRIBUTE); + if (is_secure_key_token()) + memcpy(value_attr->pValue, dummy_key, 3 * DES_KEY_SIZE); + else + memcpy(value_attr->pValue, des_key, 3 * DES_KEY_SIZE); + free(des_key); + + key_type_attr->type = CKA_KEY_TYPE; + key_type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + key_type_attr->pValue = (CK_BYTE *) key_type_attr + sizeof(CK_ATTRIBUTE); + *(CK_KEY_TYPE *) key_type_attr->pValue = CKK_DES3; + + class_attr->type = CKA_CLASS; + class_attr->ulValueLen = sizeof(CK_OBJECT_CLASS); + class_attr->pValue = (CK_BYTE *) class_attr + sizeof(CK_ATTRIBUTE); + *(CK_OBJECT_CLASS *) class_attr->pValue = CKO_SECRET_KEY; + + local_attr->type = CKA_LOCAL; + local_attr->ulValueLen = sizeof(CK_BBOOL); + local_attr->pValue = (CK_BYTE *) local_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) local_attr->pValue = TRUE; + + template_update_attribute(tmpl, value_attr); + template_update_attribute(tmpl, key_type_attr); + template_update_attribute(tmpl, class_attr); + template_update_attribute(tmpl, local_attr); + + return CKR_OK; + +err: + if (des_key) + free(des_key); + + return rc; +} + + +// +// +CK_RV ckm_des3_ecb_encrypt(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, OBJECT *key) +{ + CK_ULONG rc; + + + if (!in_data || !out_data || !key) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (*out_data_len < in_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + if (token_specific.t_tdes_ecb == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + rc = token_specific.t_tdes_ecb(tokdata, in_data, in_data_len, + out_data, out_data_len, key, 1); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific des3 ecb encrypt failed.\n"); + + return rc; +} + + +// +// +CK_RV ckm_des3_ecb_decrypt(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, OBJECT *key) +{ + CK_ULONG rc; + + + if (!in_data || !out_data || !key) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (*out_data_len < in_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + if (token_specific.t_tdes_ecb == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + rc = token_specific.t_tdes_ecb(tokdata, in_data, in_data_len, + out_data, out_data_len, key, 0); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific des3 ecb decrypt failed.\n"); + + return rc; +} + + +// +// +CK_RV ckm_des3_cbc_encrypt(STDLL_TokData_t *tokdata, + 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_ULONG rc; + + + if (!in_data || !out_data || !init_v || !key) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (*out_data_len < in_data_len) { + *out_data_len = in_data_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + if (token_specific.t_tdes_cbc == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + rc = token_specific.t_tdes_cbc(tokdata, in_data, in_data_len, + out_data, out_data_len, key, init_v, 1); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific des3 cbc encrypt failed.\n"); + + return rc; +} + + +// +// +CK_RV ckm_des3_cbc_decrypt(STDLL_TokData_t *tokdata, + 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_ULONG rc; + + + if (!in_data || !out_data || !init_v || !key) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (*out_data_len < in_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + if (token_specific.t_tdes_cbc == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + rc = token_specific.t_tdes_cbc(tokdata, in_data, in_data_len, + out_data, out_data_len, key, init_v, 0); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific des3 cbc decrypt failed.\n"); + + return rc; +} diff --git a/usr/lib/common/mech_dh.c b/usr/lib/common/mech_dh.c new file mode 100644 index 0000000..6733075 --- /dev/null +++ b/usr/lib/common/mech_dh.c @@ -0,0 +1,218 @@ +/* + * 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 + */ + +/************************************************************************ +* * +* Copyright: Corrent Corporation (c) 2000-2003 * +* * +* Filename: mech_dh.c * +* Created By: Kapil Sood * +* Created On: Jan 18, 2003 * +* Description: This is the file implementing Diffie-Hellman * +* key pair generation and shared key derivation * +* operations. * +* * +************************************************************************/ + +// File: mech_dh.c +// +// Mechanisms for DH +// +// Routines contained within: + +#include +#include // for memcmp() et al +#include +#include +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "trace.h" + +#ifndef NODH + +// +// +CK_RV dh_pkcs_derive(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_MECHANISM *mech, + CK_OBJECT_HANDLE base_key, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, CK_OBJECT_HANDLE *handle) +{ + CK_RV rc; + CK_ULONG i, keyclass = 0, keytype = 0; + CK_ATTRIBUTE *new_attr; + OBJECT *temp_obj = NULL; + + CK_BYTE secret_key_value[256]; + CK_ULONG secret_key_value_len = 256; + + // Prelim checking of sess, mech, pTemplate, and ulCount was + // done in the calling function (key_mgr_derive_key). + + // Perform DH checking of parameters + // Check the existance of the public-value in mechanism + if ((!mech->pParameter) || + ((mech->ulParameterLen != 64) && + (mech->ulParameterLen != 96) && + (mech->ulParameterLen != 128) && + (mech->ulParameterLen != 192) && (mech->ulParameterLen != 256))) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return (CKR_MECHANISM_PARAM_INVALID); + } + // Check valid object handle pointer of derived key + if (handle == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + return CKR_KEY_HANDLE_INVALID; + } + // Extract the object class and keytype from the supplied template. + for (i = 0; i < ulCount; i++) { + if (pTemplate[i].type == CKA_CLASS) { + keyclass = *(CK_OBJECT_CLASS *) pTemplate[i].pValue; + if (keyclass != CKO_SECRET_KEY) { + TRACE_ERROR("This operation requires a secret key.\n"); + return CKR_KEY_FUNCTION_NOT_PERMITTED; + } + } + + if (pTemplate[i].type == CKA_KEY_TYPE) + keytype = *(CK_ULONG *) pTemplate[i].pValue; + } + + // Extract public-key from mechanism parameters. base-key contains the + // private key, prime, and base. The return value will be in the handle. + + rc = ckm_dh_pkcs_derive(tokdata, mech->pParameter, mech->ulParameterLen, + base_key, secret_key_value, &secret_key_value_len); + if (rc != CKR_OK) + return rc; + + // Build the attribute from the vales that were returned back + rc = build_attribute(CKA_VALUE, secret_key_value, secret_key_value_len, + &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to build the new attribute.\n"); + return rc; + } + // Create the object that will be passed back as a handle. This will + // contain the new (computed) value of the attribute. + + rc = object_mgr_create_skel(tokdata, sess, + pTemplate, ulCount, + MODE_KEYGEN, keyclass, keytype, &temp_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("Object Mgr create skeleton failed.\n"); + free(new_attr); + return rc; + } + // Update the template in the object with the new attribute + template_update_attribute(temp_obj->template, new_attr); + + // at this point, the derived key is fully constructed...assign an + // object handle and store the key + // + rc = object_mgr_create_final(tokdata, sess, temp_obj, handle); + if (rc != CKR_OK) { + TRACE_DEVEL("Object Mgr create final failed.\n"); + object_free(temp_obj); + temp_obj = NULL; + return rc; + } + + return rc; +} + +// +// mechanisms +// + +// +// +CK_RV ckm_dh_pkcs_derive(STDLL_TokData_t *tokdata, + CK_VOID_PTR other_pubkey, + CK_ULONG other_pubkey_len, + CK_OBJECT_HANDLE base_key, + CK_BYTE *secret_value, CK_ULONG *secret_value_len) +{ + CK_RV rc; + CK_BYTE p[256]; + CK_ULONG p_len; + CK_BYTE x[256]; + CK_ULONG x_len; + CK_ATTRIBUTE *temp_attr; + OBJECT *base_key_obj = NULL; + CK_BYTE *p_other_pubkey; + + rc = object_mgr_find_in_map1(tokdata, base_key, &base_key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + // Extract secret (x) from base_key + rc = template_attribute_find(base_key_obj->template, CKA_VALUE, &temp_attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + memset(x, 0, sizeof(x)); + x_len = temp_attr->ulValueLen; + memcpy(x, (CK_BYTE *) temp_attr->pValue, x_len); + } + + // Extract prime (p) from base_key + rc = template_attribute_find(base_key_obj->template, CKA_PRIME, &temp_attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_PRIME in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + memset(p, 0, sizeof(p)); + p_len = temp_attr->ulValueLen; + memcpy(p, (CK_BYTE *) temp_attr->pValue, p_len); + } + + p_other_pubkey = (CK_BYTE *) other_pubkey; + + // Perform: z = other_pubkey^x mod p + rc = token_specific.t_dh_pkcs_derive(tokdata, secret_value, + secret_value_len, p_other_pubkey, + other_pubkey_len, x, x_len, p, p_len); + if (rc != CKR_OK) + TRACE_DEVEL("Token specific dh pkcs derive failed.\n"); + +done: + object_put(tokdata, base_key_obj, TRUE); + base_key_obj = NULL; + + return rc; +} + +// +// +CK_RV ckm_dh_pkcs_key_pair_gen(STDLL_TokData_t *tokdata, + TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) +{ + CK_RV rc; + + rc = token_specific.t_dh_pkcs_key_pair_gen(tokdata, publ_tmpl, priv_tmpl); + if (rc != CKR_OK) + TRACE_DEVEL("Token specific dh pkcs key pair gen failed.\n"); + + return rc; +} + +#endif diff --git a/usr/lib/common/mech_dsa.c b/usr/lib/common/mech_dsa.c new file mode 100644 index 0000000..41bd4ab --- /dev/null +++ b/usr/lib/common/mech_dsa.c @@ -0,0 +1,266 @@ +/* + * 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: mech_dsa.c +// +// Mechanisms for DSA +// +// Routines contained within: + +#include +#include // for memcmp() et al +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "trace.h" + + +#ifndef NODSA + +// +// +CK_RV dsa_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE sig[DSA_SIGNATURE_SIZE]; + CK_OBJECT_CLASS class; + CK_BBOOL flag; + CK_RV rc; + + UNUSED(sess); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + // must be a PRIVATE key operation + // + flag = template_attribute_find(key_obj->template, CKA_CLASS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + class = *(CK_OBJECT_CLASS *) attr->pValue; + } + + // if it's not a private DSA key then we have an internal failure...means + // that somehow a public key got assigned a CKA_SIGN attribute + // + if (class != CKO_PRIVATE_KEY) { + TRACE_ERROR("This operation requires a private key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + // check input data length restrictions. Generic DSA works on the SHA-1 + // hash of the data so the input to the DSA operation must be 20 bytes + // + if (in_data_len != 20) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + rc = CKR_DATA_LEN_RANGE; + goto done; + } + if (length_only == TRUE) { + *out_data_len = DSA_SIGNATURE_SIZE; + rc = CKR_OK; + goto done; + } + + rc = ckm_dsa_sign(tokdata, in_data, sig, key_obj); + if (rc == CKR_OK) { + memcpy(out_data, sig, DSA_SIGNATURE_SIZE); + *out_data_len = DSA_SIGNATURE_SIZE; + } + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +// +// +CK_RV dsa_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG sig_len) +{ + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_OBJECT_CLASS class; + CK_BBOOL flag; + CK_RV rc; + + UNUSED(sess); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + // must be a PUBLIC key operation + // + flag = template_attribute_find(key_obj->template, CKA_CLASS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + class = *(CK_OBJECT_CLASS *) attr->pValue; + } + + if (class != CKO_PUBLIC_KEY) { + TRACE_ERROR("This operation requires a public key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + // check input data length restrictions + // + if (sig_len != DSA_SIGNATURE_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + rc = CKR_SIGNATURE_LEN_RANGE; + goto done; + } + if (in_data_len != 20) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + rc = CKR_DATA_LEN_RANGE; + goto done; + } + + rc = ckm_dsa_verify(tokdata, signature, in_data, key_obj); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +// +// mechanisms +// + + +// +// +CK_RV ckm_dsa_key_pair_gen(STDLL_TokData_t *tokdata, + TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) +{ + CK_RV rc; + + + if (token_specific.t_dsa_generate_keypair == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + rc = token_specific.t_dsa_generate_keypair(tokdata, publ_tmpl, priv_tmpl); + if (rc != CKR_OK) + TRACE_DEVEL("Token specific dsa keypair generation failed.\n"); + + return rc; +} + + +// +// +CK_RV ckm_dsa_sign(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, CK_BYTE *signature, OBJECT *priv_key) +{ + CK_ATTRIBUTE *attr = NULL; + CK_OBJECT_CLASS keyclass; + CK_RV rc; + + rc = template_attribute_find(priv_key->template, CKA_CLASS, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS in the template\n"); + return CKR_FUNCTION_FAILED; + } else { + keyclass = *(CK_OBJECT_CLASS *) attr->pValue; + } + + // this had better be a private key + // + if (keyclass != CKO_PRIVATE_KEY) { + TRACE_ERROR("This operation requires a private key.\n"); + return CKR_KEY_FUNCTION_NOT_PERMITTED; + } + + if (token_specific.t_dsa_sign == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + rc = token_specific.t_dsa_sign(tokdata, in_data, signature, priv_key); + if (rc != CKR_OK) + TRACE_DEVEL("Token specific dsa sign failed.\n"); + + return rc; +} + + +// +// +CK_RV ckm_dsa_verify(STDLL_TokData_t *tokdata, + CK_BYTE *signature, CK_BYTE *data, OBJECT *publ_key) +{ + CK_ATTRIBUTE *attr = NULL; + CK_OBJECT_CLASS keyclass; + CK_RV rc; + + rc = template_attribute_find(publ_key->template, CKA_CLASS, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS in the template\n"); + return CKR_FUNCTION_FAILED; + } else { + keyclass = *(CK_OBJECT_CLASS *) attr->pValue; + } + + // this had better be a private key + // + if (keyclass != CKO_PUBLIC_KEY) { + TRACE_ERROR("This operation requires a public key.\n"); + return CKR_KEY_FUNCTION_NOT_PERMITTED; + } + + if (token_specific.t_dsa_verify == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + rc = token_specific.t_dsa_verify(tokdata, signature, data, publ_key); + if (rc != CKR_OK) + TRACE_DEVEL("Token specific dsa verify failed.\n"); + + return rc; +} + +#endif diff --git a/usr/lib/common/mech_ec.c b/usr/lib/common/mech_ec.c new file mode 100644 index 0000000..29705a2 --- /dev/null +++ b/usr/lib/common/mech_ec.c @@ -0,0 +1,1375 @@ +/* + * 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: mech_ec.c + * + * Mechanisms for Elliptic Curve (EC) + */ + +#include +#include +#include +#include +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "trace.h" +#include "tok_specific.h" +#include "ec_defs.h" + +#include "openssl/obj_mac.h" +#include + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +/* + * Older OpenSLL versions do not have BN_bn2binpad, so implement it here + */ +static int BN_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen) +{ + int len, pad; + unsigned char *buf; + + len = BN_num_bytes(a); + buf = (unsigned char *)malloc(len); + if (buf == NULL) + return -1; + BN_bn2bin(a, buf); + + if (len >= tolen) { + memcpy(to, buf, tolen); + } else { + pad = tolen - len; + memset(to, 0, pad); + memcpy(to + pad, buf, len); + } + + free(buf); + return tolen; +} +#endif + +#ifndef NID_brainpoolP160r1 +/* + * Older OpenSLL versions may not have the brainpool NIDs defined, define them + * here + */ +#define NID_brainpoolP160r1 921 +#define NID_brainpoolP160t1 922 +#define NID_brainpoolP192r1 923 +#define NID_brainpoolP192t1 924 +#define NID_brainpoolP224r1 925 +#define NID_brainpoolP224t1 926 +#define NID_brainpoolP256r1 927 +#define NID_brainpoolP256t1 928 +#define NID_brainpoolP320r1 929 +#define NID_brainpoolP320t1 930 +#define NID_brainpoolP384r1 931 +#define NID_brainpoolP384t1 932 +#define NID_brainpoolP512r1 933 +#define NID_brainpoolP512t1 934 + +#endif + +#ifndef NID_X25519 +#define NID_X25519 1034 +#define NID_X448 1035 +#endif +#ifndef NID_ED25519 +#define NID_ED25519 1087 +#define NID_ED448 1088 +#endif + +const CK_BYTE brainpoolP160r1[] = OCK_BRAINPOOL_P160R1; +const CK_BYTE brainpoolP160t1[] = OCK_BRAINPOOL_P160T1; +const CK_BYTE brainpoolP192r1[] = OCK_BRAINPOOL_P192R1; +const CK_BYTE brainpoolP192t1[] = OCK_BRAINPOOL_P192T1; +const CK_BYTE brainpoolP224r1[] = OCK_BRAINPOOL_P224R1; +const CK_BYTE brainpoolP224t1[] = OCK_BRAINPOOL_P224T1; +const CK_BYTE brainpoolP256r1[] = OCK_BRAINPOOL_P256R1; +const CK_BYTE brainpoolP256t1[] = OCK_BRAINPOOL_P256T1; +const CK_BYTE brainpoolP320r1[] = OCK_BRAINPOOL_P320R1; +const CK_BYTE brainpoolP320t1[] = OCK_BRAINPOOL_P320T1; +const CK_BYTE brainpoolP384r1[] = OCK_BRAINPOOL_P384R1; +const CK_BYTE brainpoolP384t1[] = OCK_BRAINPOOL_P384T1; +const CK_BYTE brainpoolP512r1[] = OCK_BRAINPOOL_P512R1; +const CK_BYTE brainpoolP512t1[] = OCK_BRAINPOOL_P512T1; +const CK_BYTE prime192v1[] = OCK_PRIME192V1; +const CK_BYTE secp224r1[] = OCK_SECP224R1; +const CK_BYTE prime256v1[] = OCK_PRIME256V1; +const CK_BYTE secp384r1[] = OCK_SECP384R1; +const CK_BYTE secp521r1[] = OCK_SECP521R1; +const CK_BYTE secp256k1[] = OCK_SECP256K1; +const CK_BYTE curve25519[] = OCK_CURVE25519; +const CK_BYTE curve448[] = OCK_CURVE448; +const CK_BYTE ed25519[] = OCK_ED25519; +const CK_BYTE ed448[] = OCK_ED448; + +const struct _ec der_ec_supported[NUMEC] = { + {BRAINPOOL_CURVE, CURVE160, NID_brainpoolP160r1, + sizeof(brainpoolP160r1), &brainpoolP160r1}, + {BRAINPOOL_CURVE, CURVE160, NID_brainpoolP160t1, + sizeof(brainpoolP160t1), &brainpoolP160t1}, + {BRAINPOOL_CURVE, CURVE192, NID_brainpoolP192r1, + sizeof(brainpoolP192r1), &brainpoolP192r1}, + {BRAINPOOL_CURVE, CURVE192, NID_brainpoolP192t1, + sizeof(brainpoolP192t1), &brainpoolP192t1}, + {BRAINPOOL_CURVE, CURVE224, NID_brainpoolP224r1, + sizeof(brainpoolP224r1), &brainpoolP224r1}, + {BRAINPOOL_CURVE, CURVE224, NID_brainpoolP224t1, + sizeof(brainpoolP224t1), &brainpoolP224t1}, + {BRAINPOOL_CURVE, CURVE256, NID_brainpoolP256r1, + sizeof(brainpoolP256r1), &brainpoolP256r1}, + {BRAINPOOL_CURVE, CURVE256, NID_brainpoolP256t1, + sizeof(brainpoolP256t1), &brainpoolP256t1}, + {BRAINPOOL_CURVE, CURVE320, NID_brainpoolP320r1, + sizeof(brainpoolP320r1), &brainpoolP320r1}, + {BRAINPOOL_CURVE, CURVE320, NID_brainpoolP320t1, + sizeof(brainpoolP320t1), &brainpoolP320t1}, + {BRAINPOOL_CURVE, CURVE384, NID_brainpoolP384r1, + sizeof(brainpoolP384r1), &brainpoolP384r1}, + {BRAINPOOL_CURVE, CURVE384, NID_brainpoolP384t1, + sizeof(brainpoolP384t1), &brainpoolP384t1}, + {BRAINPOOL_CURVE, CURVE512, NID_brainpoolP512r1, + sizeof(brainpoolP512r1), &brainpoolP512r1}, + {BRAINPOOL_CURVE, CURVE512, NID_brainpoolP512t1, + sizeof(brainpoolP512t1), &brainpoolP512t1}, + {PRIME_CURVE, CURVE192, NID_X9_62_prime192v1, + sizeof(prime192v1), &prime192v1}, + {PRIME_CURVE, CURVE224, NID_secp224r1, sizeof(secp224r1), &secp224r1}, + {PRIME_CURVE, CURVE256, NID_X9_62_prime256v1, + sizeof(prime256v1), &prime256v1}, + {PRIME_CURVE, CURVE384, NID_secp384r1, sizeof(secp384r1), &secp384r1}, + {PRIME_CURVE, CURVE521, NID_secp521r1, sizeof(secp521r1), &secp521r1}, + {PRIME_CURVE, CURVE256, NID_secp256k1, sizeof(secp256k1), &secp256k1}, + {MONTGOMERY_CURVE, CURVE256, NID_X25519, sizeof(curve25519), &curve25519}, + {MONTGOMERY_CURVE, CURVE456, NID_X448, sizeof(curve448), &curve448}, + {EDWARDS_CURVE, CURVE256, NID_ED25519, sizeof(ed25519), &ed25519}, + {EDWARDS_CURVE, CURVE456, NID_ED448, sizeof(ed448), &ed448}, +}; + + +CK_RV get_ecsiglen(OBJECT *key_obj, CK_ULONG *size) +{ + CK_BBOOL flag; + CK_ATTRIBUTE *attr = NULL; + int i; + + flag = template_attribute_find(key_obj->template, CKA_ECDSA_PARAMS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_ECDSA_PARAMS for the key.\n"); + return CKR_FUNCTION_FAILED; + } + + /* loop thru supported curves to find the size. + * both pkcs#11v2.20 and CCA expect the signature length to be + * twice the length of p. + * (See EC Signatures in pkcs#11v2.20 and docs for CSNDDSG.) + */ + for (i = 0; i < NUMEC; i++) { + if (!memcmp(attr->pValue, der_ec_supported[i].data, + MIN(attr->ulValueLen, der_ec_supported[i].data_size))) { + *size = der_ec_supported[i].len_bits; + /* round up if necessary */ + if ((*size % 8) == 0) + *size = (*size / 8) * 2; + else + *size = ((*size / 8) + 1) * 2; + + TRACE_DEVEL("getlen, curve = %d, size = %lu\n", + der_ec_supported[i].len_bits, *size); + return CKR_OK; + } + } + + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + + return CKR_MECHANISM_PARAM_INVALID; +} + +CK_RV ckm_ec_key_pair_gen(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, + TEMPLATE *priv_tmpl) +{ + CK_RV rc; + + if (token_specific.t_ec_generate_keypair == NULL) { + TRACE_ERROR("ec_generate_keypair not supported by this token\n"); + return CKR_FUNCTION_NOT_SUPPORTED; + } + + rc = token_specific.t_ec_generate_keypair(tokdata, publ_tmpl, priv_tmpl); + if (rc != CKR_OK) + TRACE_ERROR("Key Generation failed\n"); + + return rc; +} + +CK_RV ckm_ec_sign(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_ATTRIBUTE *attr = NULL; + CK_OBJECT_CLASS keyclass; + CK_RV rc; + + if (token_specific.t_ec_sign == NULL) { + TRACE_ERROR("ec_sign not supported by this token\n"); + return CKR_FUNCTION_NOT_SUPPORTED; + } + + rc = template_attribute_find(key_obj->template, CKA_CLASS, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS in the template\n"); + return CKR_FUNCTION_FAILED; + } + + keyclass = *(CK_OBJECT_CLASS *) attr->pValue; + + // this had better be a private key + // + if (keyclass != CKO_PRIVATE_KEY) { + TRACE_ERROR("This operation requires a private key.\n"); + return CKR_KEY_FUNCTION_NOT_PERMITTED; + } + + rc = token_specific.t_ec_sign(tokdata, sess, in_data, in_data_len, out_data, + out_data_len, key_obj); + if (rc != CKR_OK) + TRACE_DEVEL("EC Sign failed.\n"); + + return rc; +} + +CK_RV ec_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + CK_ULONG plen; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + rc = get_ecsiglen(key_obj, &plen); + if (rc != CKR_OK) { + TRACE_DEVEL("get_ecsiglen failed.\n"); + goto done; + } + + if (length_only == TRUE) { + *out_data_len = plen; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < plen) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + rc = ckm_ec_sign(tokdata, sess, in_data, in_data_len, out_data, + out_data_len, key_obj); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV ckm_ec_verify(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_ATTRIBUTE *attr = NULL; + CK_OBJECT_CLASS keyclass; + CK_RV rc; + + if (token_specific.t_ec_verify == NULL) { + TRACE_ERROR("ec_verify not supported by this token\n"); + return CKR_FUNCTION_NOT_SUPPORTED; + } + + rc = template_attribute_find(key_obj->template, CKA_CLASS, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS in the template\n"); + return CKR_FUNCTION_FAILED; + } + + keyclass = *(CK_OBJECT_CLASS *) attr->pValue; + + // this had better be a public key + // + if (keyclass != CKO_PUBLIC_KEY) { + TRACE_ERROR("This operation requires a public key.\n"); + return CKR_KEY_FUNCTION_NOT_PERMITTED; + } + + rc = token_specific.t_ec_verify(tokdata, sess, in_data, in_data_len, + out_data, out_data_len, key_obj); + if (rc != CKR_OK) + TRACE_ERROR("Token specific ec verify failed.\n"); + + return rc; +} + +CK_RV ec_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG sig_len) +{ + OBJECT *key_obj = NULL; + CK_ULONG plen; + CK_RV rc; + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + rc = get_ecsiglen(key_obj, &plen); + if (rc != CKR_OK) { + TRACE_DEVEL("get_ecsiglen failed.\n"); + goto done; + } + // check input data length restrictions + // + if (sig_len > plen) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + rc = CKR_SIGNATURE_LEN_RANGE; + goto done; + } + rc = ckm_ec_verify(tokdata, sess, in_data, in_data_len, signature, + sig_len, key_obj); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV ec_hash_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG *sig_len) +{ + CK_BYTE hash[MAX_SHA_HASH_SIZE]; + DIGEST_CONTEXT digest_ctx; + SIGN_VERIFY_CONTEXT sign_ctx; + CK_MECHANISM digest_mech; + CK_MECHANISM sign_mech; + CK_ULONG hash_len; + CK_RV rc; + + if (!sess || !ctx || !in_data) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + memset(&digest_ctx, 0x0, sizeof(digest_ctx)); + memset(&sign_ctx, 0x0, sizeof(sign_ctx)); + + switch (ctx->mech.mechanism) { + case CKM_ECDSA_SHA1: + digest_mech.mechanism = CKM_SHA_1; + break; + case CKM_ECDSA_SHA224: + digest_mech.mechanism = CKM_SHA224; + break; + case CKM_ECDSA_SHA256: + digest_mech.mechanism = CKM_SHA256; + break; + case CKM_ECDSA_SHA384: + digest_mech.mechanism = CKM_SHA384; + break; + case CKM_ECDSA_SHA512: + digest_mech.mechanism = CKM_SHA512; + break; + default: + return CKR_MECHANISM_INVALID; + } + + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = get_sha_size(digest_mech.mechanism, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Get SHA Size failed.\n"); + return rc; + } + + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + return rc; + } + + rc = digest_mgr_digest(tokdata, sess, length_only, &digest_ctx, in_data, + in_data_len, hash, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Digest failed.\n"); + return rc; + } + + sign_mech.mechanism = CKM_ECDSA; + sign_mech.ulParameterLen = 0; + sign_mech.pParameter = NULL; + + rc = sign_mgr_init(tokdata, sess, &sign_ctx, &sign_mech, FALSE, ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Init failed.\n"); + goto error; + } + + rc = sign_mgr_sign(tokdata, sess, length_only, &sign_ctx, hash, hash_len, + signature, sig_len); + if (rc != CKR_OK) + TRACE_DEVEL("Sign Mgr Sign failed.\n"); + +error: + sign_mgr_cleanup(&sign_ctx); + + return rc; +} + +CK_RV ec_hash_sign_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + RSA_DIGEST_CONTEXT *context = NULL; + CK_MECHANISM digest_mech; + CK_RV rc; + + if (!sess || !ctx) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (RSA_DIGEST_CONTEXT *) ctx->context; + + if (context->flag == FALSE) { + switch (ctx->mech.mechanism) { + case CKM_ECDSA_SHA1: + digest_mech.mechanism = CKM_SHA_1; + break; + case CKM_ECDSA_SHA224: + digest_mech.mechanism = CKM_SHA224; + break; + case CKM_ECDSA_SHA256: + digest_mech.mechanism = CKM_SHA256; + break; + case CKM_ECDSA_SHA384: + digest_mech.mechanism = CKM_SHA384; + break; + case CKM_ECDSA_SHA512: + digest_mech.mechanism = CKM_SHA512; + break; + default: + return CKR_MECHANISM_INVALID; + } + + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = digest_mgr_init(tokdata, sess, &context->hash_context, + &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + return rc; + } + context->flag = TRUE; + } + + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, + in_data, in_data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + return rc; + } + + return CKR_OK; +} + +CK_RV ec_hash_sign_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG *sig_len) +{ + CK_BYTE hash[MAX_SHA_HASH_SIZE]; + RSA_DIGEST_CONTEXT *context = NULL; + CK_ULONG hash_len; + CK_MECHANISM sign_mech; + SIGN_VERIFY_CONTEXT sign_ctx; + CK_RV rc; + + if (!sess || !ctx || !sig_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + memset(&sign_ctx, 0x0, sizeof(sign_ctx)); + + context = (RSA_DIGEST_CONTEXT *) ctx->context; + + rc = get_sha_size(context->hash_context.mech.mechanism, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Get SHA Size failed.\n"); + return rc; + } + + rc = digest_mgr_digest_final(tokdata, sess, length_only, + &context->hash_context, hash, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + return rc; + } + + sign_mech.mechanism = CKM_ECDSA; + sign_mech.ulParameterLen = 0; + sign_mech.pParameter = NULL; + + rc = sign_mgr_init(tokdata, sess, &sign_ctx, &sign_mech, FALSE, ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Init failed.\n"); + goto done; + } + //rc = sign_mgr_sign( sess, length_only, &sign_ctx, ber_data, ber_data_len, + //signature, sig_len ); + rc = sign_mgr_sign(tokdata, sess, length_only, &sign_ctx, hash, hash_len, + signature, sig_len); + if (rc != CKR_OK) + TRACE_DEVEL("Sign Mgr Sign failed.\n"); + + if (length_only == TRUE || rc == CKR_BUFFER_TOO_SMALL) { + sign_mgr_cleanup(&sign_ctx); + return rc; + } + +done: + sign_mgr_cleanup(&sign_ctx); + + return rc; +} + +CK_RV ec_hash_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) +{ + CK_BYTE hash[MAX_SHA_HASH_SIZE]; + DIGEST_CONTEXT digest_ctx; + SIGN_VERIFY_CONTEXT verify_ctx; + CK_MECHANISM digest_mech; + CK_MECHANISM verify_mech; + CK_ULONG hash_len; + CK_RV rc; + + if (!sess || !ctx || !in_data) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + memset(&digest_ctx, 0x0, sizeof(digest_ctx)); + memset(&verify_ctx, 0x0, sizeof(verify_ctx)); + + switch (ctx->mech.mechanism) { + case CKM_ECDSA_SHA1: + digest_mech.mechanism = CKM_SHA_1; + break; + case CKM_ECDSA_SHA224: + digest_mech.mechanism = CKM_SHA224; + break; + case CKM_ECDSA_SHA256: + digest_mech.mechanism = CKM_SHA256; + break; + case CKM_ECDSA_SHA384: + digest_mech.mechanism = CKM_SHA384; + break; + case CKM_ECDSA_SHA512: + digest_mech.mechanism = CKM_SHA512; + break; + default: + return CKR_MECHANISM_INVALID; + } + + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = get_sha_size(digest_mech.mechanism, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Get SHA Size failed.\n"); + return rc; + } + + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + return rc; + } + + rc = digest_mgr_digest(tokdata, sess, FALSE, &digest_ctx, in_data, + in_data_len, hash, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Digest failed.\n"); + return rc; + } + // Verify the Signed BER-encoded Data block + // + verify_mech.mechanism = CKM_ECDSA; + verify_mech.ulParameterLen = 0; + verify_mech.pParameter = NULL; + + rc = verify_mgr_init(tokdata, sess, &verify_ctx, &verify_mech, FALSE, + ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Verify Mgr Init failed.\n"); + goto done; + } + //rc = verify_mgr_verify( sess, &verify_ctx, ber_data, ber_data_len, + //signature, sig_len ); + rc = verify_mgr_verify(tokdata, sess, &verify_ctx, hash, hash_len, + signature, sig_len); + if (rc != CKR_OK) + TRACE_DEVEL("Verify Mgr Verify failed.\n"); +done: + sign_mgr_cleanup(&verify_ctx); + + return rc; +} + + +CK_RV ec_hash_verify_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + RSA_DIGEST_CONTEXT *context = NULL; + CK_MECHANISM digest_mech; + CK_RV rc; + + if (!sess || !ctx) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (RSA_DIGEST_CONTEXT *) ctx->context; + + if (context->flag == FALSE) { + switch (ctx->mech.mechanism) { + case CKM_ECDSA_SHA1: + digest_mech.mechanism = CKM_SHA_1; + break; + case CKM_ECDSA_SHA224: + digest_mech.mechanism = CKM_SHA224; + break; + case CKM_ECDSA_SHA256: + digest_mech.mechanism = CKM_SHA256; + break; + case CKM_ECDSA_SHA384: + digest_mech.mechanism = CKM_SHA384; + break; + case CKM_ECDSA_SHA512: + digest_mech.mechanism = CKM_SHA512; + break; + default: + return CKR_MECHANISM_INVALID; + } + + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = digest_mgr_init(tokdata, sess, &context->hash_context, + &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + return rc; + } + context->flag = TRUE; + } + + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, + in_data, in_data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + return rc; + } + + return CKR_OK; +} + +CK_RV ec_hash_verify_final(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG sig_len) +{ + CK_BYTE hash[MAX_SHA_HASH_SIZE]; + RSA_DIGEST_CONTEXT *context = NULL; + CK_ULONG hash_len; + CK_MECHANISM verify_mech; + SIGN_VERIFY_CONTEXT verify_ctx; + CK_RV rc; + + if (!sess || !ctx || !signature) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + memset(&verify_ctx, 0x0, sizeof(verify_ctx)); + + context = (RSA_DIGEST_CONTEXT *) ctx->context; + + rc = get_sha_size(context->hash_context.mech.mechanism, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Get SHA Size failed.\n"); + return rc; + } + + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &context->hash_context, + hash, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + return rc; + } + verify_mech.mechanism = CKM_ECDSA; + verify_mech.ulParameterLen = 0; + verify_mech.pParameter = NULL; + + rc = verify_mgr_init(tokdata, sess, &verify_ctx, &verify_mech, FALSE, + ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Verify Mgr Init failed.\n"); + goto done; + } + + rc = verify_mgr_verify(tokdata, sess, &verify_ctx, hash, hash_len, + signature, sig_len); + if (rc != CKR_OK) + TRACE_DEVEL("Verify Mgr Verify failed.\n"); +done: + verify_mgr_cleanup(&verify_ctx); + + return rc; +} + +CK_RV ckm_kdf(STDLL_TokData_t *tokdata, SESSION *sess, CK_ULONG kdf, + CK_BYTE *data, CK_ULONG data_len, CK_BYTE *hash, CK_ULONG *h_len) +{ + CK_RV rc; + DIGEST_CONTEXT ctx; + CK_MECHANISM digest_mech; + + memset(&ctx, 0, sizeof(DIGEST_CONTEXT)); + memset(&digest_mech, 0, sizeof(CK_MECHANISM)); + + switch (kdf) { + case CKD_SHA1_KDF: + digest_mech.mechanism = CKM_SHA_1; + *h_len = SHA1_HASH_SIZE; + break; + case CKD_SHA224_KDF: + digest_mech.mechanism = CKM_SHA224; + *h_len = SHA224_HASH_SIZE; + break; + case CKD_SHA256_KDF: + digest_mech.mechanism = CKM_SHA256; + *h_len = SHA256_HASH_SIZE; + break; + case CKD_SHA384_KDF: + digest_mech.mechanism = CKM_SHA384; + *h_len = SHA384_HASH_SIZE; + break; + case CKD_SHA512_KDF: + digest_mech.mechanism = CKM_SHA512; + *h_len = SHA512_HASH_SIZE; + break; + case CKD_NULL: + memcpy(hash, data, data_len - 4); + *h_len = data_len - 4; // data length minus counter length + return CKR_OK; + default: + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + return CKR_FUNCTION_NOT_SUPPORTED; + } + + rc = digest_mgr_init(tokdata, sess, &ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return rc; + } + + rc = digest_mgr_digest(tokdata, sess, FALSE, &ctx, data, data_len, hash, + h_len); + if (rc != CKR_OK) { + TRACE_ERROR("digest_mgr_digest failed with rc = %s\n", ock_err(rc)); + return rc; + } + + return CKR_OK; +} + +CK_RV ckm_kdf_X9_63(STDLL_TokData_t *tokdata, SESSION *sess, CK_ULONG kdf, + CK_ULONG kdf_digest_len, const CK_BYTE *z, CK_ULONG z_len, + const CK_BYTE *shared_data, CK_ULONG shared_data_len, + CK_BYTE *key, CK_ULONG key_len) +{ + CK_ULONG counter_length = 4; + CK_BYTE *ctx = NULL; + CK_ULONG ctx_len; + CK_BYTE hash[MAX_SUPPORTED_HASH_LENGTH]; + CK_ULONG h_len; + CK_RV rc; + unsigned int i, counter; + + /* Check max keylen according to ANSI X9.63 */ + /* digest_len * 2^32 */ + CK_ULONG max_keybytes = kdf_digest_len * 0x100000000ul; + if (key_len >= max_keybytes) { + TRACE_ERROR("Desired key length %lu greater than max supported key " + "length %lu.\n", key_len, max_keybytes); + return CKR_KEY_SIZE_RANGE; + } + + /* If no KDF to be used, just return the shared_data. + * Cannot concatenate hashes. */ + if (kdf == CKD_NULL) { + memcpy(key, z, z_len); + return CKR_OK; + } + + /* Allocate memory for hash context */ + ctx_len = z_len + counter_length + shared_data_len; + ctx = malloc(ctx_len); + if (!ctx) + return CKR_HOST_MEMORY; + memcpy(ctx, z, z_len); + if (shared_data_len > 0) + memcpy(ctx + z_len + counter_length, shared_data, shared_data_len); + + /* Provide key bytes according to ANSI X9.63 */ + counter = 1; + for (i = 0; i < key_len / kdf_digest_len; i++) { + memcpy(ctx + z_len, &counter, sizeof(int)); + rc = ckm_kdf(tokdata, sess, kdf, ctx, ctx_len, hash, &h_len); + if (rc != 0) { + free(ctx); + return rc; + } + memcpy(key + i * kdf_digest_len, hash, kdf_digest_len); + counter++; + } + + free(ctx); + return CKR_OK; +} + +CK_RV ckm_ecdh_pkcs_derive(STDLL_TokData_t *tokdata, CK_VOID_PTR other_pubkey, + CK_ULONG other_pubkey_len, CK_OBJECT_HANDLE base_key, + CK_BYTE *secret_value, CK_ULONG *secret_value_len) +{ + CK_RV rc; + CK_ATTRIBUTE *attr; + OBJECT *base_key_obj = NULL; + CK_BYTE *oid_p; + CK_ULONG oid_len; + + if (token_specific.t_ecdh_pkcs_derive == NULL) { + TRACE_ERROR("ecdh pkcs derive is not supported by this token.\n"); + return CKR_FUNCTION_NOT_SUPPORTED; + } + + /* Find base_key struct */ + rc = object_mgr_find_in_map1(tokdata, base_key, &base_key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + /* Get curve oid from CKA_ECDSA_PARAMS */ + if (!template_attribute_find + (base_key_obj->template, CKA_ECDSA_PARAMS, &attr)) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + rc = CKR_TEMPLATE_INCOMPLETE; + goto done; + } + oid_p = attr->pValue; + oid_len = attr->ulValueLen; + + /* Extract EC private key (D) from base_key */ + if (!template_attribute_find(base_key_obj->template, CKA_VALUE, &attr)) { + TRACE_ERROR("Could not find CKA_VALUE in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Call token specific ECDH key derivation function */ + rc = token_specific.t_ecdh_pkcs_derive(tokdata, + (CK_BYTE *) (attr->pValue), + attr->ulValueLen, + (CK_BYTE *) other_pubkey, + other_pubkey_len, secret_value, + secret_value_len, oid_p, oid_len); + if (rc != CKR_OK) { + TRACE_ERROR("Token specific ecdh pkcs derive failed with rc=%ld.\n", + rc); + } + +done: + object_put(tokdata, base_key_obj, TRUE); + base_key_obj = NULL; + + return rc; +} + +static CK_RV digest_from_kdf(CK_EC_KDF_TYPE kdf, CK_MECHANISM_TYPE *mech) +{ + switch (kdf) { + case CKD_SHA1_KDF: + *mech = CKM_SHA_1; + break; + case CKD_SHA224_KDF: + *mech = CKM_SHA224; + break; + case CKD_SHA256_KDF: + *mech = CKM_SHA256; + break; + case CKD_SHA384_KDF: + *mech = CKM_SHA384; + break; + case CKD_SHA512_KDF: + *mech = CKM_SHA512; + break; + default: + TRACE_ERROR("Error unsupported KDF %ld.\n", kdf); + return CKR_FUNCTION_FAILED; + } + + return CKR_OK; +} + +CK_RV pkcs_get_keytype(CK_ATTRIBUTE *attrs, CK_ULONG attrs_len, + CK_MECHANISM_PTR mech, CK_ULONG *type, CK_ULONG *class) +{ + CK_ULONG i; + + *type = 0; + *class = 0; + + for (i = 0; i < attrs_len; i++) { + if (attrs[i].type == CKA_CLASS) { + *class = *(CK_ULONG *) attrs[i].pValue; + } + } + + for (i = 0; i < attrs_len; i++) { + if (attrs[i].type == CKA_KEY_TYPE) { + *type = *(CK_ULONG *) attrs[i].pValue; + 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_DES3_KEY_GEN: + *type = CKK_DES3; + break; + case CKM_CDMF_KEY_GEN: + *type = CKK_CDMF; + break; + case CKM_AES_KEY_GEN: + *type = CKK_AES; + 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; + default: + return CKR_MECHANISM_INVALID; + } + + return CKR_OK; +} + +/** + * From PKCS#11 v2.40: PKCS #3 Diffie-Hellman key derivation + * + * [...] It computes a Diffie-Hellman secret value from the public value and + * private key according to PKCS #3, and truncates the result according to the + * CKA_KEY_TYPE attribute of the template and, if it has one and the key type + * supports it, the CKA_VALUE_LEN attribute of the template. + * + * For some key types, the derived key length is known, for others it + * must be specified in the template through CKA_VALUE_LEN. + * + */ +static CK_ULONG keylen_from_keytype(CK_ULONG keytype) +{ + switch (keytype) { + case CKK_DES: + return 8; + case CKK_DES2: + return 16; + case CKK_DES3: + return 24; + /* for all other keytypes CKA_VALUE_LEN must be specified */ + default: + return 0; + } +} + +CK_RV ecdh_pkcs_derive(STDLL_TokData_t *tokdata, SESSION *sess, + CK_MECHANISM *mech, CK_OBJECT_HANDLE base_key, + CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, + CK_OBJECT_HANDLE *derived_key_obj) +{ + CK_RV rc; + CK_ULONG class = 0, keytype = 0, key_len = 0; + CK_ATTRIBUTE *new_attr; + OBJECT *temp_obj = NULL; + CK_ECDH1_DERIVE_PARAMS *pParms; + CK_BYTE z_value[MAX_ECDH_SHARED_SECRET_SIZE]; + CK_ULONG z_len = 0, kdf_digest_len; + CK_MECHANISM_TYPE digest_mech; + CK_BYTE *derived_key = NULL; + CK_ULONG derived_key_len, i; + + /* Check parm length */ + if (mech->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + + /* Check buffers */ + pParms = mech->pParameter; + if (pParms == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + + if (pParms->pPublicData == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + + /* Get the keytype to use when deriving the key object */ + rc = pkcs_get_keytype(pTemplate, ulCount, mech, &keytype, &class); + if (rc != CKR_OK) { + TRACE_ERROR("get_keytype failed with rc=0x%lx\n", rc); + return rc; + } + + /* Determine derived key length */ + for (i = 0; i < ulCount; i++) { + if (pTemplate[i].type == CKA_VALUE_LEN) { + key_len = *(CK_ULONG *) pTemplate[i].pValue; + } + } + + if (key_len == 0) { + key_len = keylen_from_keytype(keytype); + if (key_len == 0) { + TRACE_ERROR("Derived key length not specified in template.\n"); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + } + + /* Optional shared data can only be provided together with a KDF */ + if (pParms->kdf == CKD_NULL + && (pParms->pSharedData != NULL || pParms->ulSharedDataLen != 0)) { + TRACE_ERROR("No KDF specified, but shared data ptr is not NULL.\n"); + return CKR_ARGUMENTS_BAD; + } + + /* Derive the shared secret */ + rc = ckm_ecdh_pkcs_derive(tokdata, pParms->pPublicData, + pParms->ulPublicDataLen, base_key, z_value, + &z_len); + if (rc != CKR_OK) { + TRACE_ERROR("Error deriving the shared secret.\n"); + return rc; + } + + /* If no KDF used, max possible key length is the shared_secret length */ + if (pParms->kdf == CKD_NULL && key_len > z_len) { + TRACE_ERROR("Can only provide %ld key bytes without a KDF, " + "but %ld bytes requested.\n", + (pParms->ulPublicDataLen / 2), key_len); + return CKR_ARGUMENTS_BAD; + } + + /* Determine digest length */ + if (pParms->kdf != CKD_NULL) { + rc = digest_from_kdf(pParms->kdf, &digest_mech); + if (rc != CKR_OK) { + TRACE_ERROR("Cannot determine mech from kdf.\n"); + return CKR_ARGUMENTS_BAD; + } + rc = get_sha_size(digest_mech, &kdf_digest_len); + if (rc != CKR_OK) { + TRACE_ERROR("Cannot determine SHA digest size.\n"); + return CKR_ARGUMENTS_BAD; + } + } else { + kdf_digest_len = z_len; + } + + /* Allocate memory for derived key */ + derived_key_len = ((key_len / kdf_digest_len) + 1) * kdf_digest_len; + derived_key = malloc(derived_key_len); + if (!derived_key) { + TRACE_ERROR("Cannot allocate %lu bytes for derived key.\n", + derived_key_len); + return CKR_HOST_MEMORY; + } + + /* Apply KDF function to shared secret */ + rc = ckm_kdf_X9_63(tokdata, sess, pParms->kdf, kdf_digest_len, + z_value, z_len, pParms->pSharedData, + pParms->ulSharedDataLen, derived_key, derived_key_len); + if (rc != CKR_OK) + goto end; + + /* Return the hashed and truncated derived bytes as CKA_VALUE attribute */ + rc = build_attribute(CKA_VALUE, derived_key, key_len, &new_attr); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to build the attribute from CKA_VALUE, rc=%s.\n", + ock_err(rc)); + goto end; + } + + /* Create the object that will be passed back as a handle. This will contain + * the new (computed) value of the attribute. */ + rc = object_mgr_create_skel(tokdata, sess, pTemplate, ulCount, MODE_KEYGEN, + class, keytype, &temp_obj); + if (rc != CKR_OK) { + TRACE_ERROR("Object Mgr create skeleton failed, rc=%s.\n", ock_err(rc)); + free(new_attr); + goto end; + } + + /* Update the template in the object with the new attribute */ + template_update_attribute(temp_obj->template, new_attr); + + /* At this point, the derived key is fully constructed...assign an object + * handle and store the key */ + rc = object_mgr_create_final(tokdata, sess, temp_obj, derived_key_obj); + if (rc != CKR_OK) { + TRACE_ERROR("Object Mgr create final failed, rc=%s.\n", ock_err(rc)); + object_free(temp_obj); + temp_obj = NULL; + goto end; + } + + rc = CKR_OK; + +end: + free(derived_key); + + return rc; +} + +static int ec_nid_from_oid(CK_BYTE *oid, CK_ULONG oid_length) +{ + int i; + + for (i = 0; i < NUMEC; i++) { + if (der_ec_supported[i].data_size == oid_length && + memcmp(der_ec_supported[i].data, oid, oid_length) == 0) + return der_ec_supported[i].nid; + } + + return -1; +} + +static int ec_curve_type_from_oid(CK_BYTE *oid, CK_ULONG oid_length) +{ + int i; + + for (i = 0; i < NUMEC; i++) { + if (der_ec_supported[i].data_size == oid_length && + memcmp(der_ec_supported[i].data, oid, oid_length) == 0) + return der_ec_supported[i].curve_type; + } + + return -1; +} + +/* + * Uncompress a compressed EC public key. EC public keys can be un-compressed, + * compressed, or hybrid. The fist byte of an EC public key determines if it + * is compressed or not: + * POINT_CONVERSION_COMPRESSED = 0x02 + * POINT_CONVERSION_UNCOMPRESSED = 0x04 + * POINT_CONVERSION_HYBRID = 0x06 + * Bit 0x01 determines if it is odd or even + * The out_pubkey buffer size must be at least 1+2*privkey_len. + */ +CK_RV ec_uncompress_public_key(CK_BYTE *curve, CK_ULONG curve_len, + CK_BYTE *pubkey, CK_ULONG pubkey_len, + CK_ULONG privkey_len, + CK_BYTE *out_pubkey, CK_ULONG *out_len) +{ + EC_GROUP *group = NULL; + EC_POINT *point = NULL; + CK_ULONG pad_len = 0; + BIGNUM *bn_x = NULL; + BIGNUM *bn_y = NULL; + BN_CTX *ctx = NULL; + CK_RV rc; + int y_bit = 0; + CK_BYTE *x; + int nid, type; + + if (*out_len < 1 + 2 * privkey_len) + return CKR_BUFFER_TOO_SMALL; + + type = ec_curve_type_from_oid(curve, curve_len); + if (type == -1) + return CKR_CURVE_NOT_SUPPORTED; + + if (type == MONTGOMERY_CURVE || type == EDWARDS_CURVE) { + /* + * Public keys of Montgomery and Edwards curves are always compressed + * and are not uncompressed. + */ + memcpy(out_pubkey, pubkey, pubkey_len); + *out_len = pubkey_len; + return CKR_OK; + } + + *out_len = 1 + 2 * privkey_len; + + if (pubkey_len == 1 + privkey_len && + (pubkey[0] == POINT_CONVERSION_COMPRESSED || + pubkey[0] == POINT_CONVERSION_COMPRESSED + 1)) { + /* Compressed form */ + x = pubkey + 1; + y_bit = pubkey[0] & 0x01; + } else if (pubkey_len == 1 + 2 * privkey_len && + pubkey[0] == POINT_CONVERSION_UNCOMPRESSED) { + /* Uncompressed form */ + memcpy(out_pubkey, pubkey, pubkey_len); + return CKR_OK; + } else if (pubkey_len == 1 + 2 * privkey_len && + (pubkey[0] == POINT_CONVERSION_HYBRID || + pubkey[0] == POINT_CONVERSION_HYBRID + 1)) { + /* Hybrid form */ + out_pubkey[0] = POINT_CONVERSION_UNCOMPRESSED; + memcpy(out_pubkey + 1, pubkey + 1, pubkey_len - 1); + return CKR_OK; + } else if (pubkey_len <= 2 * privkey_len) { + /* Without format byte (and leading zeros), treat as uncompressed */ + pad_len = 2 * privkey_len - pubkey_len; + out_pubkey[0] = POINT_CONVERSION_UNCOMPRESSED; + memset(out_pubkey + 1, 0, pad_len); + memcpy(out_pubkey + 1 + pad_len, pubkey, pubkey_len); + return CKR_OK; + } else { + return CKR_KEY_SIZE_RANGE; + } + + nid = ec_nid_from_oid(curve, curve_len); + if (nid == -1) + return CKR_CURVE_NOT_SUPPORTED; + + group = EC_GROUP_new_by_curve_name(nid); + if (group == NULL) { + TRACE_ERROR("Curve %d is not supported by openssl. Cannot decompress " + "public key\n", nid); + return CKR_CURVE_NOT_SUPPORTED; + } + + point = EC_POINT_new(group); + if (point == NULL) { + rc = CKR_FUNCTION_FAILED; + goto end; + } + + bn_x = BN_bin2bn(x, privkey_len, NULL); + bn_y = BN_new(); + ctx = BN_CTX_new(); + + if (!EC_POINT_set_compressed_coordinates_GFp(group, + point, bn_x, y_bit, ctx)) { + rc = CKR_FUNCTION_FAILED; + goto end; + } + + if (!EC_POINT_is_on_curve(group, point, ctx)) { + rc = CKR_FUNCTION_FAILED; + goto end; + } + + if (!EC_POINT_get_affine_coordinates_GFp(group, point, bn_x, bn_y, ctx)) { + rc = CKR_FUNCTION_FAILED; + goto end; + } + + out_pubkey[0] = POINT_CONVERSION_UNCOMPRESSED; + memcpy(out_pubkey + 1, x, privkey_len); + BN_bn2binpad(bn_y, out_pubkey + 1 + privkey_len, privkey_len); + rc = CKR_OK; + +end: + if (ctx) + BN_CTX_free(ctx); + if (point) + EC_POINT_free(point); + if (group) + EC_GROUP_free(group); + if (bn_x) + BN_free(bn_x); + if (bn_y) + BN_free(bn_y); + + return rc; +} diff --git a/usr/lib/common/mech_list.c b/usr/lib/common/mech_list.c new file mode 100644 index 0000000..6b6c397 --- /dev/null +++ b/usr/lib/common/mech_list.c @@ -0,0 +1,94 @@ +/* + * 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 + */ + +#include +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "trace.h" + + +CK_RV ock_generic_get_mechanism_list(STDLL_TokData_t * tokdata, + CK_MECHANISM_TYPE_PTR pMechanismList, + CK_ULONG_PTR pulCount) +{ + int rc = CKR_OK; + unsigned int i; + if (pMechanismList == NULL) { + (*pulCount) = tokdata->mech_list_len; + goto out; + } + if ((*pulCount) < tokdata->mech_list_len) { + (*pulCount) = tokdata->mech_list_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto out; + } + for (i = 0; i < tokdata->mech_list_len; i++) + pMechanismList[i] = tokdata->mech_list[i].mech_type; + (*pulCount) = tokdata->mech_list_len; + +out: + return rc; +} + +CK_RV ock_generic_get_mechanism_info(STDLL_TokData_t * tokdata, + CK_MECHANISM_TYPE type, + CK_MECHANISM_INFO_PTR pInfo) +{ + int rc = CKR_OK; + unsigned int i; + for (i = 0; i < tokdata->mech_list_len; i++) { + if (tokdata->mech_list[i].mech_type == type) { + memcpy(pInfo, &tokdata->mech_list[i].mech_info, + sizeof(CK_MECHANISM_INFO)); + goto out; + } + } + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + +out: + return rc; +} + +/* + * For Netscape we want to not support the SSL3 mechs since the native + * ones perform much better. Force those slots to be RSA... it's ugly + * but it works. + */ +static void netscape_hack(CK_MECHANISM_TYPE_PTR mech_arr_ptr, CK_ULONG count) +{ + char *envrn; + CK_ULONG i; + if ((envrn = getenv("NS_SERVER_HOME")) != NULL) { + for (i = 0; i < count; i++) { + switch (mech_arr_ptr[i]) { + case CKM_SSL3_PRE_MASTER_KEY_GEN: + case CKM_SSL3_MASTER_KEY_DERIVE: + case CKM_SSL3_KEY_AND_MAC_DERIVE: + case CKM_SSL3_MD5_MAC: + case CKM_SSL3_SHA1_MAC: + mech_arr_ptr[i] = CKM_RSA_PKCS; + break; + } + } + } +} + +void mechanism_list_transformations(CK_MECHANISM_TYPE_PTR mech_arr_ptr, + CK_ULONG_PTR count_ptr) +{ + netscape_hack(mech_arr_ptr, (*count_ptr)); +} diff --git a/usr/lib/common/mech_md2.c b/usr/lib/common/mech_md2.c new file mode 100644 index 0000000..880d52d --- /dev/null +++ b/usr/lib/common/mech_md2.c @@ -0,0 +1,507 @@ +/* + * 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 + */ + +#include +#include // for memcmp() et al +#include + + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "trace.h" + +#include + +// Permutation of 0..255 constructed from the digits of pi. It gives a +// "random" nonlinear byte substitution operation. +// +static const CK_BYTE S[256] = { + 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, + 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, + 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, + 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, + 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, + 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, + 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, + 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, + 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, + 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, + 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, + 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, + 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, + 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, + 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, + 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, + 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, + 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 +}; + +static const CK_BYTE *padding[] = { + (CK_BYTE *) "", + (CK_BYTE *) "\x01", + (CK_BYTE *) "\x02\x02", + (CK_BYTE *) "\x03\x03\x03", + (CK_BYTE *) "\x04\x04\x04\x04", + (CK_BYTE *) "\x05\x05\x05\x05\x05", + (CK_BYTE *) "\x06\x06\x06\x06\x06\x06", + (CK_BYTE *) "\x07\x07\x07\x07\x07\x07\x07", + (CK_BYTE *) "\x08\x08\x08\x08\x08\x08\x08\x08", + (CK_BYTE *) "\x09\x09\x09\x09\x09\x09\x09\x09\x09", + (CK_BYTE *) "\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a", + (CK_BYTE *) "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + (CK_BYTE *) "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c", + (CK_BYTE *) "\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d", + (CK_BYTE *) "\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e", + (CK_BYTE *) "\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f", + (CK_BYTE *) + "\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10" +}; + + + +// +// +CK_RV md2_hash(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + DIGEST_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (length_only == TRUE) { + *out_data_len = MD2_HASH_SIZE; + return CKR_OK; + } + + if (*out_data_len < MD2_HASH_SIZE) { + *out_data_len = MD2_HASH_SIZE; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = md2_hash_update(tokdata, sess, ctx, in_data, in_data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("md2_hash_update failed.\n"); + return CKR_FUNCTION_FAILED; + } + + return md2_hash_final(tokdata, sess, FALSE, ctx, out_data, out_data_len); +} + + +// +// +CK_RV md2_hash_update(STDLL_TokData_t *tokdata, + SESSION *sess, + DIGEST_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + if (!sess || !ctx || !in_data) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + return ckm_md2_update(tokdata, (MD2_CONTEXT *) ctx->context, in_data, + in_data_len); +} + + +// +// +CK_RV md2_hash_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BYTE length_only, + DIGEST_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (length_only == TRUE) { + *out_data_len = MD2_HASH_SIZE; + return CKR_OK; + } + + if (*out_data_len < MD2_HASH_SIZE) { + *out_data_len = MD2_HASH_SIZE; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + rc = ckm_md2_final(tokdata, (MD2_CONTEXT *) ctx->context, + out_data, MD2_HASH_SIZE); + + if (rc == CKR_OK) { + *out_data_len = MD2_HASH_SIZE; + return rc; + } + + return rc; +} + + +// this routine gets called for two mechanisms actually: +// CKM_MD2_HMAC +// CKM_MD2_HMAC_GENERAL +// +CK_RV md2_hmac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE hash[MD2_HASH_SIZE]; + DIGEST_CONTEXT digest_ctx; + CK_MECHANISM digest_mech; + CK_BYTE k_ipad[MD2_BLOCK_SIZE]; + CK_BYTE k_opad[MD2_BLOCK_SIZE]; + CK_ULONG key_bytes, hash_len, hmac_len; + CK_ULONG i; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (ctx->mech.mechanism == CKM_MD2_HMAC_GENERAL) { + hmac_len = *(CK_ULONG *) ctx->mech.pParameter; + + if (hmac_len == 0) { + *out_data_len = 0; + return CKR_OK; + } + } else { + hmac_len = MD2_HASH_SIZE; + } + + + if (length_only == TRUE) { + *out_data_len = hmac_len; + return CKR_OK; + } + + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + rc = template_attribute_find(key_obj->template, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + key_bytes = attr->ulValueLen; + + + // build (K XOR ipad), (K XOR opad) + // + if (key_bytes > MD2_BLOCK_SIZE) { + digest_mech.mechanism = CKM_MD2; + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + hash_len = sizeof(hash); + rc = digest_mgr_digest(tokdata, sess, FALSE, &digest_ctx, + attr->pValue, attr->ulValueLen, hash, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Digest failed.\n"); + goto done; + } + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + for (i = 0; i < hash_len; i++) { + k_ipad[i] = hash[i] ^ 0x36; + k_opad[i] = hash[i] ^ 0x5C; + } + + memset(&k_ipad[i], 0x36, MD2_BLOCK_SIZE - i); + memset(&k_opad[i], 0x5C, MD2_BLOCK_SIZE - i); + } else { + CK_BYTE *key = (CK_BYTE *) attr + sizeof(CK_ATTRIBUTE); + + for (i = 0; i < key_bytes; i++) { + k_ipad[i] = key[i] ^ 0x36; + k_opad[i] = key[i] ^ 0x5C; + } + + memset(&k_ipad[i], 0x36, MD2_BLOCK_SIZE - key_bytes); + memset(&k_opad[i], 0x5C, MD2_BLOCK_SIZE - key_bytes); + } + + digest_mech.mechanism = CKM_MD2; + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + + // inner hash + // + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, k_ipad, + MD2_BLOCK_SIZE); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, in_data, + in_data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &digest_ctx, hash, + &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + goto done; + } + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + + // outer hash + // + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, k_opad, + MD2_BLOCK_SIZE); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, hash, hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &digest_ctx, hash, + &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + goto done; + } + memcpy(out_data, hash, hmac_len); + *out_data_len = hmac_len; + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +// +// +CK_RV md2_hmac_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) +{ + CK_BYTE hmac[MD2_HASH_SIZE]; + SIGN_VERIFY_CONTEXT hmac_ctx; + CK_ULONG hmac_len, len; + CK_RV rc; + + if (!sess || !ctx || !in_data || !signature) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (ctx->mech.mechanism == CKM_MD2_HMAC_GENERAL) + hmac_len = *(CK_ULONG *) ctx->mech.pParameter; + else + hmac_len = MD2_HASH_SIZE; + + memset(&hmac_ctx, 0, sizeof(SIGN_VERIFY_CONTEXT)); + + rc = sign_mgr_init(tokdata, sess, &hmac_ctx, &ctx->mech, FALSE, ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Init failed.\n"); + return rc; + } + len = sizeof(hmac); + rc = sign_mgr_sign(tokdata, sess, FALSE, &hmac_ctx, + in_data, in_data_len, hmac, &len); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Sign failed.\n"); + return rc; + } + if ((len != hmac_len) || (len != sig_len)) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + return CKR_SIGNATURE_LEN_RANGE; + } + if (CRYPTO_memcmp(hmac, signature, hmac_len) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + return CKR_SIGNATURE_INVALID; + } + + return CKR_OK; +} + + +// +// CKM routines +// + + +// MD2 block update operation. Continues an MD2 message-digest +// operation, processing another message block, and updating the +// context. +// +CK_RV ckm_md2_update(STDLL_TokData_t *tokdata, + MD2_CONTEXT *context, CK_BYTE *input, CK_ULONG inputLen) +{ + CK_ULONG i, index, partLen; + + // Update number of bytes mod 16 + // + index = context->count; + context->count = (index + inputLen) & 0xf; + + partLen = 16 - index; + + // Process any complete 16-byte blocks + // + if (inputLen >= partLen) { + memcpy((CK_BYTE *) & context->buffer[index], (CK_BYTE *) input, + partLen); + ckm_md2_transform(tokdata, context->state, context->checksum, + context->buffer); + + for (i = partLen; i + 15 < inputLen; i += 16) + ckm_md2_transform(tokdata, context->state, context->checksum, + &input[i]); + + index = 0; + } else { + i = 0; + } + + // Buffer remaining input + // + memcpy((CK_BYTE *) & context->buffer[index], (CK_BYTE *) & input[i], + inputLen - i); + + return CKR_OK; +} + + +// MD2 finalization. Ends an MD2 message-digest operation, writing the +// message digest and zeroizing the context. +// +CK_RV ckm_md2_final(STDLL_TokData_t *tokdata, + MD2_CONTEXT *context, + CK_BYTE *out_data, CK_ULONG out_data_len) +{ + CK_ULONG index, padLen; + + if (!context || !out_data || (out_data_len < MD2_HASH_SIZE)) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + // Pad input to 16-byte multiple (1 - 16 pad bytes) + // + index = context->count; + padLen = 16 - index; + ckm_md2_update(tokdata, context, (CK_BYTE *)padding[padLen], padLen); + + // Add checksum + // + ckm_md2_update(tokdata, context, context->checksum, 16); + + // Store state in digest + // + memcpy((CK_BYTE *) out_data, (CK_BYTE *) context->state, 16); + + return CKR_OK; +} + + +// MD2 basic transformation. Transforms state and updates checksum +// based on block. +// +void ckm_md2_transform(STDLL_TokData_t *tokdata, + CK_BYTE *state, CK_BYTE *checksum, CK_BYTE *block) +{ + CK_ULONG i, j, t; + CK_BYTE x[48]; + + UNUSED(tokdata); + + // Form encryption block from state, block, state ^ block. + // + memcpy((CK_BYTE *) x, (CK_BYTE *) state, 16); + memcpy((CK_BYTE *) x + 16, (CK_BYTE *) block, 16); + + for (i = 0; i < 16; i++) + x[i + 32] = state[i] ^ block[i]; + + // Encrypt block (18 rounds). + // + t = 0; + for (i = 0; i < 18; i++) { + for (j = 0; j < 48; j++) + t = x[j] ^= S[t]; + t = (t + i) & 0xff; + } + + // Save new state + // + memcpy((CK_BYTE *) state, (CK_BYTE *) x, 16); + + // Update checksum. + // + t = checksum[15]; + for (i = 0; i < 16; i++) + t = checksum[i] ^= S[block[i] ^ t]; + +} diff --git a/usr/lib/common/mech_md5.c b/usr/lib/common/mech_md5.c new file mode 100644 index 0000000..b7aae49 --- /dev/null +++ b/usr/lib/common/mech_md5.c @@ -0,0 +1,418 @@ +/* + * 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 + */ + +#include +#include // for memcmp() et al +#include +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "trace.h" + +#include +#include + +// +// Software MD5 implementation (OpenSSL based) +// + +void sw_md5_init(DIGEST_CONTEXT *ctx) +{ + ctx->context_len = sizeof(MD5_CTX); + ctx->context = (CK_BYTE *) malloc(sizeof(MD5_CTX)); + if (ctx->context == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + // TODO: propagate error up? + return; + } + + MD5_Init((MD5_CTX *)ctx->context); +} + +CK_RV sw_md5_hash(DIGEST_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len) +{ + if (!ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (*out_data_len < MD5_HASH_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + if (ctx->context == NULL) + return CKR_OPERATION_NOT_INITIALIZED; + + MD5_Update((MD5_CTX *)ctx->context, in_data, in_data_len); + MD5_Final(out_data, (MD5_CTX *)ctx->context); + *out_data_len = MD5_HASH_SIZE; + + free(ctx->context); + ctx->context = NULL; + + return CKR_OK; +} + +CK_RV sw_MD5_Update(DIGEST_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len) +{ + if (ctx->context == NULL) + return CKR_OPERATION_NOT_INITIALIZED; + + MD5_Update((MD5_CTX *)ctx->context, in_data, in_data_len); + return CKR_OK; +} + +CK_RV sw_MD5_Final(DIGEST_CONTEXT *ctx, CK_BYTE *out_data, + CK_ULONG *out_data_len) +{ + if (ctx->context == NULL) + return CKR_OPERATION_NOT_INITIALIZED; + + MD5_Final(out_data, (MD5_CTX *)ctx->context); + *out_data_len = MD5_HASH_SIZE; + + free(ctx->context); + ctx->context = NULL; + + return CKR_OK; +} + +CK_RV md5_init(STDLL_TokData_t *tokdata, SESSION *sess, DIGEST_CONTEXT *ctx, + CK_MECHANISM *mech) +{ + UNUSED(tokdata); + UNUSED(sess); + + if (mech->mechanism == CKM_MD5) { + sw_md5_init(ctx); + return CKR_OK; + } else { + return CKR_MECHANISM_INVALID; + } +} + +CK_RV md5_hash(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, + DIGEST_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + UNUSED(tokdata); + UNUSED(sess); + + if (!ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (length_only == TRUE) { + *out_data_len = MD5_HASH_SIZE; + return CKR_OK; + } + + if (*out_data_len < MD5_HASH_SIZE) { + *out_data_len = MD5_HASH_SIZE; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + if (ctx->context == NULL) + return CKR_HOST_MEMORY; + + if (ctx->mech.mechanism == CKM_MD5) + return sw_md5_hash(ctx, in_data, in_data_len, out_data, + out_data_len); + else + return CKR_MECHANISM_INVALID; +} + +// +// +CK_RV md5_hash_update(STDLL_TokData_t *tokdata, SESSION *sess, + DIGEST_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len) +{ + UNUSED(tokdata); + UNUSED(sess); + + /* if no data to hash, just return */ + if (!in_data_len) + return CKR_OK; + + if (ctx->mech.mechanism == CKM_MD5) + return sw_MD5_Update(ctx, in_data, in_data_len); + else + return CKR_MECHANISM_INVALID; +} + +CK_RV md5_hash_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BYTE length_only, DIGEST_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + UNUSED(tokdata); + UNUSED(sess); + + if (!out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (length_only == TRUE) { + *out_data_len = MD5_HASH_SIZE; + return CKR_OK; + } + + if (*out_data_len < MD5_HASH_SIZE) { + *out_data_len = MD5_HASH_SIZE; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + if (ctx->mech.mechanism == CKM_MD5) + return sw_MD5_Final(ctx, out_data, out_data_len); + else + return CKR_MECHANISM_INVALID; +} + +// this routine gets called for two mechanisms actually: +// CKM_MD5_HMAC +// CKM_MD5_HMAC_GENERAL +// +CK_RV md5_hmac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE hash[MD5_HASH_SIZE]; + DIGEST_CONTEXT digest_ctx; + CK_MECHANISM digest_mech; + CK_BYTE k_ipad[MD5_BLOCK_SIZE]; + CK_BYTE k_opad[MD5_BLOCK_SIZE]; + CK_ULONG key_bytes, hash_len, hmac_len; + CK_ULONG i; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (ctx->mech.mechanism == CKM_MD5_HMAC_GENERAL) { + hmac_len = *(CK_ULONG *) ctx->mech.pParameter; + + if (hmac_len == 0) { + *out_data_len = 0; + return CKR_OK; + } + } else { + hmac_len = MD5_HASH_SIZE; + } + + if (length_only == TRUE) { + *out_data_len = hmac_len; + return CKR_OK; + } + + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + rc = template_attribute_find(key_obj->template, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + key_bytes = attr->ulValueLen; + + + // build (K XOR ipad), (K XOR opad) + // + if (key_bytes > MD5_BLOCK_SIZE) { + digest_mech.mechanism = CKM_MD5; + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + + hash_len = sizeof(hash); + rc = digest_mgr_digest(tokdata, sess, FALSE, &digest_ctx, + attr->pValue, attr->ulValueLen, hash, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Digest failed.\n"); + goto done; + } + + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + for (i = 0; i < hash_len; i++) { + k_ipad[i] = hash[i] ^ 0x36; + k_opad[i] = hash[i] ^ 0x5C; + } + + memset(&k_ipad[i], 0x36, MD5_BLOCK_SIZE - i); + memset(&k_opad[i], 0x5C, MD5_BLOCK_SIZE - i); + } else { + CK_BYTE *key = attr->pValue; + + for (i = 0; i < key_bytes; i++) { + k_ipad[i] = key[i] ^ 0x36; + k_opad[i] = key[i] ^ 0x5C; + } + + memset(&k_ipad[i], 0x36, MD5_BLOCK_SIZE - key_bytes); + memset(&k_opad[i], 0x5C, MD5_BLOCK_SIZE - key_bytes); + } + + digest_mech.mechanism = CKM_MD5; + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + // inner hash + // + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, k_ipad, + MD5_BLOCK_SIZE); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, in_data, + in_data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &digest_ctx, hash, + &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + goto done; + } + + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + // outer hash + // + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, k_opad, + MD5_BLOCK_SIZE); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, hash, hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &digest_ctx, hash, + &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + goto done; + } + + memcpy(out_data, hash, hmac_len); + *out_data_len = hmac_len; + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV md5_hmac_verify(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) +{ + CK_BYTE hmac[MD5_HASH_SIZE]; + SIGN_VERIFY_CONTEXT hmac_ctx; + CK_ULONG hmac_len, len; + CK_RV rc; + + if (!sess || !ctx || !in_data || !signature) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (ctx->mech.mechanism == CKM_MD5_HMAC_GENERAL) + hmac_len = *(CK_ULONG *) ctx->mech.pParameter; + else + hmac_len = MD5_HASH_SIZE; + + memset(&hmac_ctx, 0, sizeof(SIGN_VERIFY_CONTEXT)); + + rc = sign_mgr_init(tokdata, sess, &hmac_ctx, &ctx->mech, FALSE, ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Init failed.\n"); + goto done; + } + len = sizeof(hmac); + rc = sign_mgr_sign(tokdata, sess, FALSE, &hmac_ctx, in_data, in_data_len, + hmac, &len); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Sign failed.\n"); + goto done; + } + if ((len != hmac_len) || (len != sig_len)) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + rc = CKR_SIGNATURE_LEN_RANGE; + goto done; + } + + if (CRYPTO_memcmp(hmac, signature, hmac_len) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + rc = CKR_SIGNATURE_INVALID; + } + +done: + sign_mgr_cleanup(&hmac_ctx); + return rc; +} diff --git a/usr/lib/common/mech_rng.c b/usr/lib/common/mech_rng.c new file mode 100644 index 0000000..7140270 --- /dev/null +++ b/usr/lib/common/mech_rng.c @@ -0,0 +1,73 @@ +/* + * 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: mech_rng.c +// +// Mechanisms for Random Numbers +// +// PKCS #11 doesn't consider random number generator to be a "mechanism" +// + +#include // for memcmp() et al +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" + +#include "tok_spec_struct.h" +#include "tok_specific.h" +#include "trace.h" + +// +// +CK_RV local_rng(CK_BYTE *output, CK_ULONG bytes) +{ + int ranfd; + int rlen; + unsigned int totallen = 0; + + ranfd = open("/dev/prandom", O_RDONLY); + if (ranfd < 0) + ranfd = open("/dev/urandom", O_RDONLY); + if (ranfd >= 0) { + do { + rlen = read(ranfd, output + totallen, bytes - totallen); + totallen += rlen; + } while (totallen < bytes); + close(ranfd); + return CKR_OK; + } + + return CKR_FUNCTION_FAILED; +} + +// +// +CK_RV rng_generate(STDLL_TokData_t *tokdata, CK_BYTE *output, CK_ULONG bytes) +{ + CK_RV rc; + + /* Do token specific rng if it exists. */ + if (token_specific.t_rng != NULL) + rc = token_specific.t_rng(tokdata, output, bytes); + else + rc = local_rng(output, bytes); + + if (rc != CKR_OK) + TRACE_DEVEL("Token specific rng failed.\n"); + + return rc; +} diff --git a/usr/lib/common/mech_rsa.c b/usr/lib/common/mech_rsa.c new file mode 100644 index 0000000..f5c2d06 --- /dev/null +++ b/usr/lib/common/mech_rsa.c @@ -0,0 +1,2859 @@ +/* + * 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: mech_rsa.c +// +// Mechanisms for RSA +// +// Routines contained within: + +#include +#include + +#include // for memcmp() et al +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "trace.h" + +#include + +CK_RV rsa_get_key_info(OBJECT *key_obj, CK_ULONG *mod_bytes, + CK_OBJECT_CLASS *keyclass) +{ + CK_RV rc; + CK_ATTRIBUTE *attr; + + rc = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS in the template\n"); + return CKR_FUNCTION_FAILED; + } + + *mod_bytes = attr->ulValueLen; + + rc = template_attribute_find(key_obj->template, CKA_CLASS, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS in the template\n"); + return CKR_FUNCTION_FAILED; + } + + *keyclass = *(CK_OBJECT_CLASS *) attr->pValue; + + return CKR_OK; +} + + +/* + * Format an encryption block according to PKCS #1: RSA Encryption, Version + * 1.5. + */ + +CK_RV rsa_format_block(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG out_data_len, CK_ULONG type) +{ + CK_ULONG padding_len, i; + CK_RV rc = CKR_OK; + + if (!in_data || !out_data || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (out_data_len < (in_data_len + 11)) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + /* + * The padding string PS shall consist of k-3-||D|| octets. + */ + padding_len = out_data_len - 3 - in_data_len; + + /* + * For block types 01 and 02, 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) && ((padding_len) < 8)) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + + /* + * The leading 00 octet. + */ + out_data[0] = (CK_BYTE) 0; + + /* + * The block type. + */ + out_data[1] = (CK_BYTE) type; + + 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: + if (in_data[0] == (CK_BYTE) 0) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_INVALID)); + return CKR_DATA_INVALID; + } + + for (i = 2; i < (padding_len + 2); i++) + out_data[i] = (CK_BYTE) 0; + + break; + /* + * For block type 01, they shall have value FF. + * EB = 00 || 01 || FF * i || 00 || D + */ + case 1: + for (i = 2; i < (padding_len + 2); i++) + out_data[i] = (CK_BYTE) 0xff; + + break; + /* + * For block type 02, they shall be pseudorandomly generated and + * nonzero. + * EB = 00 || 02 || ?? * i || 00 || D + * Where ?? is nonzero. + */ + case 2: + rc = rng_generate(tokdata, &out_data[2], padding_len); + if (rc != CKR_OK) { + TRACE_DEVEL("rng_generate failed.\n"); + return rc; + } + for (i = 2; i < (padding_len + 2); i++) { + while (out_data[i] == (CK_BYTE) 0) { + rc = rng_generate(tokdata, &out_data[i], 1); + if (rc != CKR_OK) { + TRACE_DEVEL("rng_generate failed.\n"); + return rc; + } + } + } + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_DATA_INVALID)); + return CKR_DATA_INVALID; + } + + out_data[i] = (CK_BYTE) 0; + i++; + + if (in_data_len) + memcpy(&out_data[i], in_data, in_data_len); + + return rc; +} + + +/* + * Parse an encryption block according to PKCS #1: RSA Encryption, Version + * 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) +{ + CK_ULONG i; + CK_RV rc = CKR_OK; + + if (!in_data || !out_data || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (in_data_len <= 11) { + TRACE_DEVEL("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + /* + * Check for the leading 00 octet. + */ + if (in_data[0] != (CK_BYTE) 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID)); + return CKR_ENCRYPTED_DATA_INVALID; + } + + /* + * Check the block type. + */ + if (in_data[1] != (CK_BYTE) type) { + 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. + * + * 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 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 + * 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) + break; + } + 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++; + break; + } + + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID)); + return CKR_ENCRYPTED_DATA_INVALID; + } + } + 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++) { + if (in_data[i] == (CK_BYTE) 0) { + i++; + break; + } + } + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID)); + return CKR_ENCRYPTED_DATA_INVALID; + } + + /* + * For block types 01 and 02, 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)) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID)); + return CKR_ENCRYPTED_DATA_INVALID; + } + + if (in_data_len <= i) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID)); + return CKR_ENCRYPTED_DATA_INVALID; + } + + if (*out_data_len < (in_data_len - i)) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + memcpy(out_data, &in_data[i], in_data_len - i); + *out_data_len = in_data_len - i; + + return rc; +} + +/* helper function for rsa-oaep */ +CK_RV get_mgf_mech(CK_RSA_PKCS_MGF_TYPE mgf, CK_MECHANISM_TYPE *mech) +{ + switch (mgf) { + case CKG_MGF1_SHA1: + *mech = CKM_SHA_1; + break; + case CKG_MGF1_SHA224: + *mech = CKM_SHA224; + break; + case CKG_MGF1_SHA256: + *mech = CKM_SHA256; + break; + case CKG_MGF1_SHA384: + *mech = CKM_SHA384; + break; + case CKG_MGF1_SHA512: + *mech = CKM_SHA512; + break; + default: + return CKR_MECHANISM_INVALID; + } + + return CKR_OK; +} + +// +// +CK_RV rsa_pkcs_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + CK_ULONG modulus_bytes; + CK_OBJECT_CLASS keyclass; + CK_RV rc; + + UNUSED(sess); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass); + if (rc != CKR_OK) { + TRACE_DEVEL("rsa_get_key_info failed.\n"); + goto done; + } + // check input data length restrictions + // + if (in_data_len > (modulus_bytes - 11)) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + rc = CKR_DATA_LEN_RANGE; + goto done; + } + + if (length_only == TRUE) { + *out_data_len = modulus_bytes; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < modulus_bytes) { + *out_data_len = modulus_bytes; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + // this had better be a public key + if (keyclass != CKO_PUBLIC_KEY) { + TRACE_ERROR("This operation requires a public key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + + if (token_specific.t_rsa_encrypt == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + rc = token_specific.t_rsa_encrypt(tokdata, in_data, in_data_len, out_data, + out_data_len, key_obj); + + if (rc != CKR_OK) + TRACE_DEVEL("Token Specific rsa encrypt failed.\n"); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + return rc; +} + + +// +// +CK_RV rsa_pkcs_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + CK_ULONG modulus_bytes; + CK_OBJECT_CLASS keyclass; + CK_RV rc; + + UNUSED(sess); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass); + if (rc != CKR_OK) { + TRACE_DEVEL("rsa_get_key_info failed.\n"); + goto done; + } + // check input data length restrictions + // + if (in_data_len != modulus_bytes) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + rc = CKR_ENCRYPTED_DATA_LEN_RANGE; + goto done; + } + if (length_only == TRUE) { + // this is not exact but it's the upper bound; otherwise we'll need + // to do the RSA operation just to get the required length + // + *out_data_len = modulus_bytes - 11; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < (modulus_bytes - 11)) { + *out_data_len = modulus_bytes - 11; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + // this had better be a private key + if (keyclass != CKO_PRIVATE_KEY) { + TRACE_ERROR("This operation requires a private key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + + /* check for token specific call first */ + if (token_specific.t_rsa_decrypt == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + 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"); + } + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +CK_RV rsa_oaep_crypt(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_BBOOL encrypt) +{ + OBJECT *key_obj = NULL; + CK_ULONG hlen, modulus_bytes; + CK_OBJECT_CLASS keyclass; + CK_BYTE hash[MAX_SHA_HASH_SIZE]; + CK_RV rc; + CK_RSA_PKCS_OAEP_PARAMS_PTR oaepParms = NULL; + + UNUSED(sess); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass); + if (rc != CKR_OK) { + TRACE_DEVEL("rsa_get_key_info failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (length_only == TRUE) { + *out_data_len = modulus_bytes; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < modulus_bytes) { + *out_data_len = modulus_bytes; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + /* + * To help mitigate timing and fault attacks when decrypting, + * check oaep parameters that are passed in right now and compute + * the hash of the Label. + * + * PKCS#11v2.20, section 12.1.7, Step a: if "source" is empty, + * then pSourceData and ulSourceDatalen must be NULL, and zero + * respectively. + */ + oaepParms = (CK_RSA_PKCS_OAEP_PARAMS_PTR) ctx->mech.pParameter; + if (!(oaepParms->source) && (oaepParms->pSourceData || + oaepParms->ulSourceDataLen)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + /* verify hashAlg now as well as get hash size. */ + hlen = 0; + rc = get_sha_size(oaepParms->hashAlg, &hlen); + if (rc != CKR_OK) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + /* modulus size should be >= 2*hashsize+2 */ + if (modulus_bytes < (2 * hlen + 2)) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_SIZE_RANGE)); + rc = CKR_KEY_SIZE_RANGE; + goto done; + } + + /* hash the label now */ + if (!(oaepParms->pSourceData) || !(oaepParms->ulSourceDataLen)) + rc = compute_sha(tokdata, (CK_BYTE *)"", 0, hash, oaepParms->hashAlg); + else + rc = compute_sha(tokdata, oaepParms->pSourceData, + oaepParms->ulSourceDataLen, hash, oaepParms->hashAlg); + if (rc != CKR_OK) + goto done; + + if (encrypt) { + if (in_data_len > (modulus_bytes - 2 * hlen - 2)) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + rc = CKR_DATA_LEN_RANGE; + goto done; + } + // this had better be a public key + if (keyclass != CKO_PUBLIC_KEY) { + TRACE_ERROR("This operation requires a public key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + + if (token_specific.t_rsa_oaep_encrypt == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + rc = token_specific.t_rsa_oaep_encrypt(tokdata, ctx, in_data, + in_data_len, out_data, + out_data_len, hash, hlen); + } else { + // decrypt + if (in_data_len != modulus_bytes) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + rc = CKR_ENCRYPTED_DATA_LEN_RANGE; + goto done; + } + // this had better be a private key + if (keyclass != CKO_PRIVATE_KEY) { + TRACE_ERROR("This operation requires a private key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + + if (token_specific.t_rsa_oaep_decrypt == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + rc = token_specific.t_rsa_oaep_decrypt(tokdata, ctx, in_data, + in_data_len, out_data, + out_data_len, hash, hlen); + } + + if (rc != CKR_OK) + TRACE_DEVEL("Token Specific rsa oaep decrypt failed.\n"); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV rsa_pkcs_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + CK_ULONG modulus_bytes; + CK_OBJECT_CLASS keyclass; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass); + if (rc != CKR_OK) { + TRACE_DEVEL("rsa_get_key_info failed.\n"); + goto done; + } + // check input data length restrictions + // + if (in_data_len > (modulus_bytes - 11)) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + rc = CKR_DATA_LEN_RANGE; + goto done; + } + if (length_only == TRUE) { + *out_data_len = modulus_bytes; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < modulus_bytes) { + *out_data_len = modulus_bytes; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + // this had better be a private key + // + if (keyclass != CKO_PRIVATE_KEY) { + TRACE_ERROR("This operation requires a private key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + + /* check for token specific call first */ + if (token_specific.t_rsa_sign == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + rc = token_specific.t_rsa_sign(tokdata, sess, in_data, in_data_len, + out_data, out_data_len, key_obj); + + if (rc != CKR_OK) + TRACE_DEVEL("Token Specific rsa sign failed.\n"); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +// +// +CK_RV rsa_pkcs_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) +{ + OBJECT *key_obj = NULL; + CK_ULONG modulus_bytes; + CK_OBJECT_CLASS keyclass; + CK_RV rc; + + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass); + if (rc != CKR_OK) { + TRACE_DEVEL("rsa_get_key_info failed.\n"); + goto done; + } + // check input data length restrictions + // + if (sig_len != modulus_bytes) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + rc = CKR_SIGNATURE_LEN_RANGE; + goto done; + } + // verifying is a public key operation + // + if (keyclass != CKO_PUBLIC_KEY) { + TRACE_ERROR("This operation requires a public key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + + /* check for token specific call first */ + if (token_specific.t_rsa_verify == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + rc = token_specific.t_rsa_verify(tokdata, sess, in_data, in_data_len, + signature, sig_len, key_obj); + if (rc != CKR_OK) + TRACE_DEVEL("Token Specific rsa verify failed.\n"); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +// +// +CK_RV rsa_pkcs_verify_recover(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, + CK_ULONG sig_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + CK_OBJECT_CLASS keyclass; + CK_ULONG modulus_bytes; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass); + if (rc != CKR_OK) { + TRACE_DEVEL("rsa_get_key_info failed.\n"); + goto done; + } + // check input data length restrictions + // + if (sig_len != modulus_bytes) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + rc = CKR_SIGNATURE_LEN_RANGE; + goto done; + } + if (length_only == TRUE) { + *out_data_len = modulus_bytes - 11; + rc = CKR_OK; + goto done; + } + + /* this had better be a public key */ + if (keyclass != CKO_PUBLIC_KEY) { + TRACE_ERROR("This operation requires a public key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + + /* check for token specific call first */ + if (token_specific.t_rsa_verify_recover == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + rc = token_specific.t_rsa_verify_recover(tokdata, signature, sig_len, + out_data, out_data_len, key_obj); + if (rc != CKR_OK) + TRACE_DEVEL("Token Specific rsa verify failed.\n"); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +// +// +CK_RV rsa_x509_encrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + CK_OBJECT_CLASS keyclass; + CK_ULONG modulus_bytes; + CK_RV rc; + + UNUSED(sess); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass); + if (rc != CKR_OK) { + TRACE_DEVEL("rsa_get_key_info failed.\n"); + goto done; + } + // CKM_RSA_X_509 requires input data length to be no bigger than the modulus + // + if (in_data_len > modulus_bytes) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + if (length_only == TRUE) { + *out_data_len = modulus_bytes; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < modulus_bytes) { + *out_data_len = modulus_bytes; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + /* this had better be a public key */ + if (keyclass != CKO_PUBLIC_KEY) { + TRACE_ERROR("This operation requires a public key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + + /* check for token specific call first */ + if (token_specific.t_rsa_x509_encrypt == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + rc = token_specific.t_rsa_x509_encrypt(tokdata, in_data, in_data_len, + out_data, out_data_len, key_obj); + if (rc != CKR_OK) + TRACE_DEVEL("Token Specific rsa x509 encrypt failed.\n"); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +// +// +CK_RV rsa_x509_decrypt(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + CK_ULONG modulus_bytes; + CK_OBJECT_CLASS keyclass; + CK_RV rc; + + UNUSED(sess); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass); + if (rc != CKR_OK) { + TRACE_DEVEL("rsa_get_key_info failed.\n"); + goto done; + } + // check input data length restrictions + // + if (in_data_len != modulus_bytes) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + rc = CKR_ENCRYPTED_DATA_LEN_RANGE; + goto done; + } + if (length_only == TRUE) { + *out_data_len = modulus_bytes; + rc = CKR_OK; + goto done; + } + // Although X.509 prepads with zeros, we don't strip it after + // decryption (PKCS #11 specifies that X.509 decryption is supposed + // to produce K bytes of cleartext where K is the modulus length) + // + if (*out_data_len < modulus_bytes) { + *out_data_len = modulus_bytes; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + /* this had better be a private key */ + if (keyclass != CKO_PRIVATE_KEY) { + TRACE_ERROR("This operation requires a private key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + + /* check for token specific call first */ + if (token_specific.t_rsa_x509_encrypt == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + rc = token_specific.t_rsa_x509_decrypt(tokdata, in_data, in_data_len, + out_data, out_data_len, key_obj); + if (rc != CKR_OK) + TRACE_ERROR("Token Specific rsa x509 decrypt failed.\n"); + // ckm_rsa_operation is used for all RSA operations so we need to adjust + // the return code accordingly + // + 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; + } + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +// +// +CK_RV rsa_x509_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + CK_ULONG modulus_bytes; + CK_OBJECT_CLASS keyclass; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass); + if (rc != CKR_OK) { + TRACE_DEVEL("rsa_get_key_info failed.\n"); + goto done; + } + // check input data length restrictions + // + if (in_data_len > modulus_bytes) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + rc = CKR_DATA_LEN_RANGE; + goto done; + } + if (length_only == TRUE) { + *out_data_len = modulus_bytes; + rc = CKR_OK; + goto done; + } + + if (*out_data_len < modulus_bytes) { + *out_data_len = modulus_bytes; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + /* this had better be a private key */ + if (keyclass != CKO_PRIVATE_KEY) { + TRACE_ERROR("This operation requires a private key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + + /* check for token specific call first */ + if (token_specific.t_rsa_x509_sign == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + rc = token_specific.t_rsa_x509_sign(tokdata, in_data, in_data_len, out_data, + out_data_len, key_obj); + if (rc != CKR_OK) + TRACE_DEVEL("Token Specific rsa x509 sign failed.\n"); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +// +// +CK_RV rsa_x509_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) +{ + OBJECT *key_obj = NULL; + CK_OBJECT_CLASS keyclass; + CK_ULONG modulus_bytes; + CK_RV rc; + + UNUSED(sess); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass); + if (rc != CKR_OK) { + TRACE_DEVEL("rsa_get_key_info failed.\n"); + goto done; + } + // check input data length restrictions + // + if (sig_len != modulus_bytes) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + rc = CKR_SIGNATURE_LEN_RANGE; + goto done; + } + + /* this had better be a public key */ + if (keyclass != CKO_PUBLIC_KEY) { + TRACE_ERROR("This operation requires a public key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + + /* check for token specific call first */ + if (token_specific.t_rsa_x509_verify == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + // verify is a public key operation --> encrypt + // + rc = token_specific.t_rsa_x509_verify(tokdata, in_data, in_data_len, + signature, sig_len, key_obj); + if (rc != CKR_OK) + TRACE_ERROR("Token Specific rsa x509 verify failed.\n"); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +// +// +CK_RV rsa_x509_verify_recover(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, + CK_ULONG sig_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + CK_ULONG modulus_bytes; + CK_OBJECT_CLASS keyclass; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass); + if (rc != CKR_OK) { + TRACE_DEVEL("rsa_get_key_info failed.\n"); + goto done; + } + // check input data length restrictions + // + if (sig_len != modulus_bytes) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + return CKR_SIGNATURE_LEN_RANGE; + } + if (length_only == TRUE) { + *out_data_len = modulus_bytes; + rc = CKR_OK; + goto done; + } + // we perform no stripping of prepended zero bytes here + // + if (*out_data_len < modulus_bytes) { + *out_data_len = modulus_bytes; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + /* this had better be a public key */ + if (keyclass != CKO_PUBLIC_KEY) { + TRACE_ERROR("This operation requires a public key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + + /* check for token specific call first */ + if (token_specific.t_rsa_x509_verify_recover == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + // verify is a public key operation --> encrypt + // + rc = token_specific.t_rsa_x509_verify_recover(tokdata, signature, sig_len, + out_data, out_data_len, + key_obj); + if (rc != CKR_OK) + TRACE_ERROR("Token Specific rsa x509 verify recover.\n"); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV rsa_pss_sign(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len) +{ + CK_RV rc; + OBJECT *key_obj = NULL; + CK_ULONG modulus_bytes, hlen; + CK_OBJECT_CLASS keyclass; + CK_RSA_PKCS_PSS_PARAMS_PTR pssParms = NULL; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + /* get modulus and key class */ + rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass); + if (rc != CKR_OK) { + TRACE_DEVEL("rsa_get_key_info failed.\n"); + goto done; + } + + if (length_only == TRUE) { + *out_data_len = modulus_bytes; + rc = CKR_OK; + goto done; + } + + /* verify hashAlg now as well as get hash size. */ + pssParms = (CK_RSA_PKCS_PSS_PARAMS_PTR) ctx->mech.pParameter; + hlen = 0; + rc = get_sha_size(pssParms->hashAlg, &hlen); + if (rc != CKR_OK) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + /* pkcs#11v2.2, 12.1.10 states that this mechanism does not + * compute a hash value on the message to be signed. + * It assumes the input data is the hashed message. + */ + if (in_data_len != hlen) { + TRACE_ERROR("%s\n", ock_err(CKR_DATA_LEN_RANGE)); + rc = CKR_DATA_LEN_RANGE; + goto done; + } + + if (*out_data_len < modulus_bytes) { + *out_data_len = modulus_bytes; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + goto done; + } + + /* this had better be a private key */ + if (keyclass != CKO_PRIVATE_KEY) { + TRACE_ERROR("This operation requires a private key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + + if (token_specific.t_rsa_pss_sign == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + rc = token_specific.t_rsa_pss_sign(tokdata, sess, ctx, in_data, in_data_len, + out_data, out_data_len); + if (rc != CKR_OK) + TRACE_DEVEL("Token Specific rsa pss sign failed.\n"); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV rsa_pss_verify(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *signature, + CK_ULONG sig_len) +{ + CK_RV rc; + OBJECT *key_obj = NULL; + CK_ULONG modulus_bytes; + CK_OBJECT_CLASS keyclass; + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + /* get modulus and key class */ + rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass); + if (rc != CKR_OK) { + TRACE_DEVEL("rsa_get_key_info failed.\n"); + goto done; + } + + /* check input data length restrictions */ + if (sig_len != modulus_bytes) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + rc = CKR_SIGNATURE_LEN_RANGE; + goto done; + } + + /* this had better be a public key */ + if (keyclass != CKO_PUBLIC_KEY) { + TRACE_ERROR("This operation requires a public key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + + if (token_specific.t_rsa_pss_verify == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + rc = token_specific.t_rsa_pss_verify(tokdata, sess, ctx, in_data, + in_data_len, signature, sig_len); + if (rc != CKR_OK) + TRACE_ERROR("Token Specific rsa pss verify.\n"); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV rsa_hash_pss_sign(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *sig, CK_ULONG *sig_len) +{ + CK_ULONG hlen; + CK_BYTE hash[MAX_SHA_HASH_SIZE]; + DIGEST_CONTEXT digest_ctx; + SIGN_VERIFY_CONTEXT sign_ctx; + CK_MECHANISM digest_mech, sign_mech; + CK_RV rc; + + if (!sess || !ctx || !in_data) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + memset(&digest_ctx, 0x0, sizeof(digest_ctx)); + memset(&sign_ctx, 0x0, sizeof(sign_ctx)); + + switch (ctx->mech.mechanism) { + case CKM_SHA1_RSA_PKCS_PSS: + digest_mech.mechanism = CKM_SHA_1; + break; + case CKM_SHA224_RSA_PKCS_PSS: + digest_mech.mechanism = CKM_SHA224; + break; + case CKM_SHA256_RSA_PKCS_PSS: + digest_mech.mechanism = CKM_SHA256; + break; + case CKM_SHA384_RSA_PKCS_PSS: + digest_mech.mechanism = CKM_SHA384; + break; + case CKM_SHA512_RSA_PKCS_PSS: + digest_mech.mechanism = CKM_SHA512; + break; + default: + return CKR_MECHANISM_INVALID; + } + + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = get_sha_size(digest_mech.mechanism, &hlen); + if (rc != CKR_OK) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + return rc; + } + + rc = digest_mgr_digest(tokdata, sess, length_only, &digest_ctx, + in_data, in_data_len, hash, &hlen); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Digest failed.\n"); + return rc; + } + + /* sign the hash */ + sign_mech.mechanism = CKM_RSA_PKCS_PSS; + sign_mech.ulParameterLen = ctx->mech.ulParameterLen; + sign_mech.pParameter = ctx->mech.pParameter; + + rc = sign_mgr_init(tokdata, sess, &sign_ctx, &sign_mech, FALSE, ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Init failed.\n"); + goto done; + } + + rc = sign_mgr_sign(tokdata, sess, length_only, &sign_ctx, hash, hlen, + sig, sig_len); + if (rc != CKR_OK) + TRACE_DEVEL("Sign Mgr Sign failed.\n"); + +done: + sign_mgr_cleanup(&sign_ctx); + + return rc; +} + +CK_RV rsa_hash_pss_update(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + DIGEST_CONTEXT *digest_ctx = NULL; + CK_MECHANISM digest_mech; + CK_RV rc; + + if (!sess || !ctx) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + /* see if digest has already been through init */ + digest_ctx = (DIGEST_CONTEXT *) ctx->context; + if (digest_ctx->active == FALSE) { + switch (ctx->mech.mechanism) { + case CKM_SHA1_RSA_PKCS_PSS: + digest_mech.mechanism = CKM_SHA_1; + break; + case CKM_SHA224_RSA_PKCS_PSS: + digest_mech.mechanism = CKM_SHA224; + break; + case CKM_SHA256_RSA_PKCS_PSS: + digest_mech.mechanism = CKM_SHA256; + break; + case CKM_SHA384_RSA_PKCS_PSS: + digest_mech.mechanism = CKM_SHA384; + break; + case CKM_SHA512_RSA_PKCS_PSS: + digest_mech.mechanism = CKM_SHA512; + break; + default: + return CKR_MECHANISM_INVALID; + } + + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = digest_mgr_init(tokdata, sess, digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + return rc; + } + } + + rc = digest_mgr_digest_update(tokdata, sess, digest_ctx, in_data, + in_data_len); + if (rc != CKR_OK) + TRACE_DEVEL("Digest Mgr Update failed.\n"); + + return rc; +} + +CK_RV rsa_hash_pss_sign_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BBOOL length_only, SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG *sig_len) +{ + CK_ULONG hlen; + CK_BYTE hash[MAX_SHA_HASH_SIZE]; + DIGEST_CONTEXT *digest_ctx; + SIGN_VERIFY_CONTEXT sign_ctx; + CK_MECHANISM sign_mech; + CK_RV rc; + + if (!sess || !ctx || !sig_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + memset(&sign_ctx, 0x0, sizeof(sign_ctx)); + + digest_ctx = (DIGEST_CONTEXT *) ctx->context; + + rc = get_sha_size(digest_ctx->mech.mechanism, &hlen); + if (rc != CKR_OK) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + + rc = digest_mgr_digest_final(tokdata, sess, length_only, digest_ctx, + hash, &hlen); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + return rc; + } + + /* sign the hash */ + sign_mech.mechanism = CKM_RSA_PKCS_PSS; + sign_mech.ulParameterLen = ctx->mech.ulParameterLen; + sign_mech.pParameter = ctx->mech.pParameter; + + rc = sign_mgr_init(tokdata, sess, &sign_ctx, &sign_mech, FALSE, ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Init failed.\n"); + goto done; + } + + rc = sign_mgr_sign(tokdata, sess, length_only, &sign_ctx, hash, hlen, + signature, sig_len); + if (rc != CKR_OK) + TRACE_DEVEL("Sign Mgr Sign failed.\n"); + +done: + sign_mgr_cleanup(&sign_ctx); + + return rc; +} + +CK_RV rsa_hash_pss_verify(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) +{ + CK_ULONG hlen; + CK_BYTE hash[MAX_SHA_HASH_SIZE]; + DIGEST_CONTEXT digest_ctx; + SIGN_VERIFY_CONTEXT verify_ctx; + CK_MECHANISM digest_mech, verify_mech; + CK_RV rc; + + if (!sess || !ctx || !in_data) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + memset(&digest_ctx, 0x0, sizeof(digest_ctx)); + memset(&verify_ctx, 0x0, sizeof(verify_ctx)); + + switch (ctx->mech.mechanism) { + case CKM_SHA1_RSA_PKCS_PSS: + digest_mech.mechanism = CKM_SHA_1; + break; + case CKM_SHA224_RSA_PKCS_PSS: + digest_mech.mechanism = CKM_SHA224; + break; + case CKM_SHA256_RSA_PKCS_PSS: + digest_mech.mechanism = CKM_SHA256; + break; + case CKM_SHA384_RSA_PKCS_PSS: + digest_mech.mechanism = CKM_SHA384; + break; + case CKM_SHA512_RSA_PKCS_PSS: + digest_mech.mechanism = CKM_SHA512; + break; + default: + return CKR_MECHANISM_INVALID; + } + + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = get_sha_size(digest_mech.mechanism, &hlen); + if (rc != CKR_OK) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + return rc; + } + + rc = digest_mgr_digest(tokdata, sess, FALSE, &digest_ctx, in_data, + in_data_len, hash, &hlen); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Digest failed.\n"); + return rc; + } + + /* sign the hash */ + verify_mech.mechanism = CKM_RSA_PKCS_PSS; + verify_mech.ulParameterLen = ctx->mech.ulParameterLen; + verify_mech.pParameter = ctx->mech.pParameter; + + rc = verify_mgr_init(tokdata, sess, &verify_ctx, &verify_mech, FALSE, + ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Verify Mgr Init failed.\n"); + goto done; + } + + rc = verify_mgr_verify(tokdata, sess, &verify_ctx, hash, hlen, + signature, sig_len); + if (rc != CKR_OK) + TRACE_DEVEL("Verify Mgr Verify failed.\n"); + +done: + verify_mgr_cleanup(&verify_ctx); + + return rc; +} + +CK_RV rsa_hash_pss_verify_final(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG sig_len) +{ + CK_ULONG hlen; + CK_BYTE hash[MAX_SHA_HASH_SIZE]; + DIGEST_CONTEXT *digest_ctx; + SIGN_VERIFY_CONTEXT verify_ctx; + CK_MECHANISM verify_mech; + CK_RV rc; + + if (!sess || !ctx || !signature) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + memset(&verify_ctx, 0x0, sizeof(verify_ctx)); + + digest_ctx = (DIGEST_CONTEXT *) ctx->context; + + rc = get_sha_size(digest_ctx->mech.mechanism, &hlen); + if (rc != CKR_OK) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + + rc = digest_mgr_digest_final(tokdata, sess, FALSE, digest_ctx, hash, &hlen); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + return rc; + } + + /* sign the hash */ + verify_mech.mechanism = CKM_RSA_PKCS_PSS; + verify_mech.ulParameterLen = ctx->mech.ulParameterLen; + verify_mech.pParameter = ctx->mech.pParameter; + + rc = verify_mgr_init(tokdata, sess, &verify_ctx, &verify_mech, FALSE, + ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Verify Mgr Init failed.\n"); + goto done; + } + + rc = verify_mgr_verify(tokdata, sess, &verify_ctx, hash, hlen, + signature, sig_len); + if (rc != CKR_OK) + TRACE_DEVEL("Verify Mgr Verify failed.\n"); + +done: + verify_mgr_cleanup(&verify_ctx); + + return rc; +} + +// +// +CK_RV rsa_hash_pkcs_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG *sig_len) +{ + CK_BYTE *ber_data = NULL; + CK_BYTE *octet_str = NULL; + const CK_BYTE *oid = NULL; + CK_BYTE *tmp = NULL; + + CK_ULONG buf1[16]; // 64 bytes is more than enough + + // must be large enough for the largest hash + CK_BYTE hash[MAX_SHA_HASH_SIZE]; + DIGEST_CONTEXT digest_ctx; + SIGN_VERIFY_CONTEXT sign_ctx; + CK_MECHANISM digest_mech; + CK_MECHANISM sign_mech; + CK_ULONG ber_data_len, hash_len, octet_str_len, oid_len; + CK_RV rc; + + if (!sess || !ctx || !in_data) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + memset(&digest_ctx, 0x0, sizeof(digest_ctx)); + memset(&sign_ctx, 0x0, sizeof(sign_ctx)); + + if (ctx->mech.mechanism == CKM_MD2_RSA_PKCS) { + digest_mech.mechanism = CKM_MD2; + oid = ber_AlgMd2; + oid_len = ber_AlgMd2Len; + + } else if (ctx->mech.mechanism == CKM_MD5_RSA_PKCS) { + digest_mech.mechanism = CKM_MD5; + oid = ber_AlgMd5; + oid_len = ber_AlgMd5Len; + } else if (ctx->mech.mechanism == CKM_SHA224_RSA_PKCS) { + digest_mech.mechanism = CKM_SHA224; + oid = ber_AlgSha224; + oid_len = ber_AlgSha224Len; + } else if (ctx->mech.mechanism == CKM_SHA256_RSA_PKCS) { + digest_mech.mechanism = CKM_SHA256; + oid = ber_AlgSha256; + oid_len = ber_AlgSha256Len; + } else if (ctx->mech.mechanism == CKM_SHA384_RSA_PKCS) { + digest_mech.mechanism = CKM_SHA384; + oid = ber_AlgSha384; + oid_len = ber_AlgSha384Len; + } else if (ctx->mech.mechanism == CKM_SHA512_RSA_PKCS) { + digest_mech.mechanism = CKM_SHA512; + oid = ber_AlgSha512; + oid_len = ber_AlgSha512Len; + } else { + digest_mech.mechanism = CKM_SHA_1; + oid = ber_AlgSha1; + oid_len = ber_AlgSha1Len; + } + + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + return rc; + } + hash_len = sizeof(hash); + rc = digest_mgr_digest(tokdata, sess, length_only, &digest_ctx, in_data, + in_data_len, hash, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Digest failed.\n"); + return rc; + } + // build the BER-encodings + + rc = ber_encode_OCTET_STRING(FALSE, &octet_str, &octet_str_len, hash, + hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_OCTET_STRING failed.\n"); + goto error; + } + tmp = (CK_BYTE *) buf1; + memcpy(tmp, oid, oid_len); + memcpy(tmp + oid_len, octet_str, octet_str_len); + + rc = ber_encode_SEQUENCE(FALSE, &ber_data, &ber_data_len, tmp, + (oid_len + octet_str_len)); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_SEQUENCE failed.\n"); + goto error; + } + // sign the BER-encoded data block + + + sign_mech.mechanism = CKM_RSA_PKCS; + sign_mech.ulParameterLen = 0; + sign_mech.pParameter = NULL; + + rc = sign_mgr_init(tokdata, sess, &sign_ctx, &sign_mech, FALSE, ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Init failed.\n"); + goto error; + } + rc = sign_mgr_sign(tokdata, sess, length_only, &sign_ctx, ber_data, + ber_data_len, signature, sig_len); + if (rc != CKR_OK) + TRACE_DEVEL("Sign Mgr Sign failed.\n"); + +error: + if (octet_str) + free(octet_str); + if (ber_data) + free(ber_data); + sign_mgr_cleanup(&sign_ctx); + + return rc; +} + + +// +// +CK_RV rsa_hash_pkcs_sign_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + RSA_DIGEST_CONTEXT *context = NULL; + CK_MECHANISM digest_mech; + CK_RV rc; + + if (!sess || !ctx) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (RSA_DIGEST_CONTEXT *) ctx->context; + + if (context->flag == FALSE) { + if (ctx->mech.mechanism == CKM_MD2_RSA_PKCS) + digest_mech.mechanism = CKM_MD2; + else if (ctx->mech.mechanism == CKM_MD5_RSA_PKCS) + digest_mech.mechanism = CKM_MD5; + else if (ctx->mech.mechanism == CKM_SHA224_RSA_PKCS) + digest_mech.mechanism = CKM_SHA224; + else if (ctx->mech.mechanism == CKM_SHA256_RSA_PKCS) + digest_mech.mechanism = CKM_SHA256; + else if (ctx->mech.mechanism == CKM_SHA384_RSA_PKCS) + digest_mech.mechanism = CKM_SHA384; + else if (ctx->mech.mechanism == CKM_SHA512_RSA_PKCS) + digest_mech.mechanism = CKM_SHA512; + else + digest_mech.mechanism = CKM_SHA_1; + + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = digest_mgr_init(tokdata, sess, &context->hash_context, + &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + return rc; + } + context->flag = TRUE; + } + + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, + in_data, in_data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Digest failed.\n"); + return rc; + } + + return CKR_OK; +} + + +// +// +CK_RV rsa_hash_pkcs_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) +{ + CK_BYTE *ber_data = NULL; + CK_BYTE *octet_str = NULL; + const CK_BYTE *oid = NULL; + CK_BYTE *tmp = NULL; + + CK_ULONG buf1[16]; // 64 bytes is more than enough + CK_BYTE hash[MAX_SHA_HASH_SIZE]; + DIGEST_CONTEXT digest_ctx; + SIGN_VERIFY_CONTEXT verify_ctx; + CK_MECHANISM digest_mech; + CK_MECHANISM verify_mech; + CK_ULONG ber_data_len, hash_len, octet_str_len, oid_len; + CK_RV rc; + + if (!sess || !ctx || !in_data) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + memset(&digest_ctx, 0x0, sizeof(digest_ctx)); + memset(&verify_ctx, 0x0, sizeof(verify_ctx)); + + if (ctx->mech.mechanism == CKM_MD2_RSA_PKCS) { + digest_mech.mechanism = CKM_MD2; + oid = ber_AlgMd2; + oid_len = ber_AlgMd2Len; + } else if (ctx->mech.mechanism == CKM_MD5_RSA_PKCS) { + digest_mech.mechanism = CKM_MD5; + oid = ber_AlgMd5; + oid_len = ber_AlgMd5Len; + } else if (ctx->mech.mechanism == CKM_SHA224_RSA_PKCS) { + digest_mech.mechanism = CKM_SHA224; + oid = ber_AlgSha224; + oid_len = ber_AlgSha224Len; + } else if (ctx->mech.mechanism == CKM_SHA256_RSA_PKCS) { + digest_mech.mechanism = CKM_SHA256; + oid = ber_AlgSha256; + oid_len = ber_AlgSha256Len; + } else if (ctx->mech.mechanism == CKM_SHA384_RSA_PKCS) { + digest_mech.mechanism = CKM_SHA384; + oid = ber_AlgSha384; + oid_len = ber_AlgSha384Len; + } else if (ctx->mech.mechanism == CKM_SHA512_RSA_PKCS) { + digest_mech.mechanism = CKM_SHA512; + oid = ber_AlgSha512; + oid_len = ber_AlgSha512Len; + } else { + digest_mech.mechanism = CKM_SHA_1; + oid = ber_AlgSha1; + oid_len = ber_AlgSha1Len; + } + + + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + return rc; + } + hash_len = sizeof(hash); + rc = digest_mgr_digest(tokdata, sess, FALSE, &digest_ctx, in_data, + in_data_len, hash, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Digest failed.\n"); + return rc; + } + // Build the BER encoding + // + rc = ber_encode_OCTET_STRING(FALSE, &octet_str, &octet_str_len, hash, + hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_OCTET_STRING failed.\n"); + goto done; + } + tmp = (CK_BYTE *) buf1; + memcpy(tmp, oid, oid_len); + memcpy(tmp + oid_len, octet_str, octet_str_len); + + rc = ber_encode_SEQUENCE(FALSE, &ber_data, &ber_data_len, tmp, + (oid_len + octet_str_len)); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_SEQUENCE failed.\n"); + goto done; + } + // Verify the Signed BER-encoded Data block + // + verify_mech.mechanism = CKM_RSA_PKCS; + verify_mech.ulParameterLen = 0; + verify_mech.pParameter = NULL; + + rc = verify_mgr_init(tokdata, sess, &verify_ctx, &verify_mech, FALSE, + ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Verify Mgr Init failed.\n"); + goto done; + } + rc = verify_mgr_verify(tokdata, sess, &verify_ctx, ber_data, ber_data_len, + signature, sig_len); + if (rc != CKR_OK) + TRACE_DEVEL("Verify Mgr Verify failed.\n"); +done: + if (octet_str) + free(octet_str); + if (ber_data) + free(ber_data); + sign_mgr_cleanup(&verify_ctx); + + return rc; +} + +// +// +CK_RV rsa_hash_pkcs_verify_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + RSA_DIGEST_CONTEXT *context = NULL; + CK_MECHANISM digest_mech; + CK_RV rc; + + if (!sess || !ctx) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (RSA_DIGEST_CONTEXT *) ctx->context; + + if (context->flag == FALSE) { + if (ctx->mech.mechanism == CKM_MD2_RSA_PKCS) + digest_mech.mechanism = CKM_MD2; + else if (ctx->mech.mechanism == CKM_MD5_RSA_PKCS) + digest_mech.mechanism = CKM_MD5; + else if (ctx->mech.mechanism == CKM_SHA224_RSA_PKCS) + digest_mech.mechanism = CKM_SHA224; + else if (ctx->mech.mechanism == CKM_SHA256_RSA_PKCS) + digest_mech.mechanism = CKM_SHA256; + else if (ctx->mech.mechanism == CKM_SHA384_RSA_PKCS) + digest_mech.mechanism = CKM_SHA384; + else if (ctx->mech.mechanism == CKM_SHA512_RSA_PKCS) + digest_mech.mechanism = CKM_SHA512; + else + digest_mech.mechanism = CKM_SHA_1; + + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = digest_mgr_init(tokdata, sess, &context->hash_context, + &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + return rc; + } + context->flag = TRUE; + } + + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, + in_data, in_data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + return rc; + } + + return CKR_OK; +} + + +// +// +CK_RV rsa_hash_pkcs_sign_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG *sig_len) +{ + CK_BYTE *ber_data = NULL; + CK_BYTE *octet_str = NULL; + const CK_BYTE *oid = NULL; + CK_BYTE *tmp = NULL; + + CK_ULONG buf1[16]; // 64 bytes is more than enough + + CK_BYTE hash[MAX_SHA_HASH_SIZE]; + RSA_DIGEST_CONTEXT *context = NULL; + CK_ULONG ber_data_len, hash_len, octet_str_len, oid_len; + CK_MECHANISM sign_mech; + SIGN_VERIFY_CONTEXT sign_ctx; + CK_RV rc; + + if (!sess || !ctx || !sig_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (ctx->mech.mechanism == CKM_MD2_RSA_PKCS) { + oid = ber_AlgMd2; + oid_len = ber_AlgMd2Len; + } else if (ctx->mech.mechanism == CKM_MD5_RSA_PKCS) { + oid = ber_AlgMd5; + oid_len = ber_AlgMd5Len; + } else if (ctx->mech.mechanism == CKM_SHA224_RSA_PKCS) { + oid = ber_AlgSha224; + oid_len = ber_AlgSha224Len; + } else if (ctx->mech.mechanism == CKM_SHA256_RSA_PKCS) { + oid = ber_AlgSha256; + oid_len = ber_AlgSha256Len; + } else if (ctx->mech.mechanism == CKM_SHA384_RSA_PKCS) { + oid = ber_AlgSha384; + oid_len = ber_AlgSha384Len; + } else if (ctx->mech.mechanism == CKM_SHA512_RSA_PKCS) { + oid = ber_AlgSha512; + oid_len = ber_AlgSha512Len; + } else { + oid = ber_AlgSha1; + oid_len = ber_AlgSha1Len; + } + + memset(&sign_ctx, 0x0, sizeof(sign_ctx)); + + context = (RSA_DIGEST_CONTEXT *) ctx->context; + + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, length_only, + &context->hash_context, hash, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + return rc; + } + // Build the BER Encoded Data block + // + rc = ber_encode_OCTET_STRING(FALSE, &octet_str, &octet_str_len, hash, + hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_OCTET_STRING failed.\n"); + return rc; + } + tmp = (CK_BYTE *) buf1; + memcpy(tmp, oid, oid_len); + memcpy(tmp + oid_len, octet_str, octet_str_len); + + rc = ber_encode_SEQUENCE(FALSE, &ber_data, &ber_data_len, tmp, + (oid_len + octet_str_len)); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_SEQUENCE failed.\n"); + goto done; + } + // sign the BER-encoded data block + // + + sign_mech.mechanism = CKM_RSA_PKCS; + sign_mech.ulParameterLen = 0; + sign_mech.pParameter = NULL; + + rc = sign_mgr_init(tokdata, sess, &sign_ctx, &sign_mech, FALSE, ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Init failed.\n"); + goto done; + } + rc = sign_mgr_sign(tokdata, sess, length_only, &sign_ctx, ber_data, + ber_data_len, signature, sig_len); + if (rc != CKR_OK) + TRACE_DEVEL("Sign Mgr Sign failed.\n"); + + /** Not sure why this check is here */ + if (length_only == TRUE || rc == CKR_BUFFER_TOO_SMALL) + goto done; + +done: + if (octet_str) + free(octet_str); + if (ber_data) + free(ber_data); + sign_mgr_cleanup(&sign_ctx); + + return rc; +} + + +// +// +CK_RV rsa_hash_pkcs_verify_final(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG sig_len) +{ + CK_BYTE *ber_data = NULL; + CK_BYTE *octet_str = NULL; + const CK_BYTE *oid = NULL; + CK_BYTE *tmp = NULL; + + CK_ULONG buf1[16]; // 64 bytes is more than enough + CK_BYTE hash[MAX_SHA_HASH_SIZE]; + RSA_DIGEST_CONTEXT *context = NULL; + CK_ULONG ber_data_len, hash_len, octet_str_len, oid_len; + CK_MECHANISM verify_mech; + SIGN_VERIFY_CONTEXT verify_ctx; + CK_RV rc; + + if (!sess || !ctx || !signature) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (ctx->mech.mechanism == CKM_MD2_RSA_PKCS) { + oid = ber_AlgMd2; + oid_len = ber_AlgMd2Len; + } else if (ctx->mech.mechanism == CKM_MD5_RSA_PKCS) { + oid = ber_AlgMd5; + oid_len = ber_AlgMd5Len; + } else if (ctx->mech.mechanism == CKM_SHA224_RSA_PKCS) { + oid = ber_AlgSha224; + oid_len = ber_AlgSha224Len; + } else if (ctx->mech.mechanism == CKM_SHA256_RSA_PKCS) { + oid = ber_AlgSha256; + oid_len = ber_AlgSha256Len; + } else if (ctx->mech.mechanism == CKM_SHA384_RSA_PKCS) { + oid = ber_AlgSha384; + oid_len = ber_AlgSha384Len; + } else if (ctx->mech.mechanism == CKM_SHA512_RSA_PKCS) { + oid = ber_AlgSha512; + oid_len = ber_AlgSha512Len; + } else { + oid = ber_AlgSha1; + oid_len = ber_AlgSha1Len; + } + + memset(&verify_ctx, 0x0, sizeof(verify_ctx)); + + context = (RSA_DIGEST_CONTEXT *) ctx->context; + + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &context->hash_context, + hash, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + return rc; + } + // Build the BER encoding + // + rc = ber_encode_OCTET_STRING(FALSE, &octet_str, &octet_str_len, hash, + hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_OCTET_STRING failed.\n"); + goto done; + } + tmp = (CK_BYTE *) buf1; + memcpy(tmp, oid, oid_len); + memcpy(tmp + oid_len, octet_str, octet_str_len); + + rc = ber_encode_SEQUENCE(FALSE, &ber_data, &ber_data_len, tmp, + (oid_len + octet_str_len)); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_SEQUENCE failed.\n"); + goto done; + } + // verify the signed BER-encoded data block + // + + verify_mech.mechanism = CKM_RSA_PKCS; + verify_mech.ulParameterLen = 0; + verify_mech.pParameter = NULL; + + rc = verify_mgr_init(tokdata, sess, &verify_ctx, &verify_mech, FALSE, + ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Verify Mgr Init failed.\n"); + goto done; + } + rc = verify_mgr_verify(tokdata, sess, &verify_ctx, ber_data, ber_data_len, + signature, sig_len); + if (rc != CKR_OK) + TRACE_DEVEL("Verify Mgr Verify failed.\n"); +done: + if (octet_str) + free(octet_str); + if (ber_data) + free(ber_data); + verify_mgr_cleanup(&verify_ctx); + + return rc; +} + + +// +// mechanisms +// + + + +// +// +CK_RV ckm_rsa_key_pair_gen(STDLL_TokData_t *tokdata, + TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) +{ + CK_RV rc; + + /* check for token specific call first */ + if (token_specific.t_rsa_generate_keypair == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + rc = token_specific.t_rsa_generate_keypair(tokdata, publ_tmpl, priv_tmpl); + if (rc != CKR_OK) + TRACE_DEVEL("Token specific rsa generate keypair failed.\n"); + + return rc; +} + +CK_RV mgf1(STDLL_TokData_t *tokdata, CK_BYTE *seed, CK_ULONG seedlen, + CK_BYTE *mask, CK_ULONG maskLen, CK_RSA_PKCS_MGF_TYPE mgf) +{ + + int i; + char *seed_buffer; + unsigned char counter[4]; + CK_BYTE hash[MAX_SHA_HASH_SIZE]; + CK_RV rc = CKR_OK; + CK_MECHANISM_TYPE mech; + CK_ULONG hlen, T_len = 0; + + if (!mask || !seed) + return CKR_FUNCTION_FAILED; + + rc = get_mgf_mech(mgf, &mech); + if (rc != CKR_OK) + return CKR_FUNCTION_FAILED; + + rc = get_sha_size(mech, &hlen); + if (rc != CKR_OK) + return CKR_FUNCTION_FAILED; + + /* do some preparations */ + seed_buffer = malloc(seedlen + 4); + if (seed_buffer == NULL) + return CKR_HOST_MEMORY; + + T_len = maskLen; + for (i = 0; T_len > 0; i++) { + /* convert i to an octet string of length 4 octets. */ + counter[0] = (unsigned char) ((i >> 24) & 0xff); + counter[1] = (unsigned char) ((i >> 16) & 0xff); + counter[2] = (unsigned char) ((i >> 8) & 0xff); + counter[3] = (unsigned char) (i & 0xff); + + /* concatenate seed and octet string */ + memset(seed_buffer, 0, seedlen + 4); + memcpy(seed_buffer, seed, seedlen); + memcpy(seed_buffer + seedlen, counter, 4); + + /* compute hash of concatenated seed and octet string */ + rc = compute_sha(tokdata, (CK_BYTE *)seed_buffer, seedlen + 4, hash, + mech); + if (rc != CKR_OK) + goto done; + + if (T_len >= hlen) { + memcpy(mask + (i * hlen), hash, hlen); + T_len -= hlen; + } else { + /* in the case masklen is not a multiple of the + * of the hash length, only copy over remainder + */ + memcpy(mask + (i * hlen), hash, T_len); + T_len = 0; + } + } + +done: + if (seed_buffer) + free(seed_buffer); + + return rc; +} + +// RSA mechanism - EME-OAEP encoding +// +CK_RV encode_eme_oaep(STDLL_TokData_t *tokdata, CK_BYTE *mData, CK_ULONG mLen, + CK_BYTE *emData, CK_ULONG modLength, + CK_RSA_PKCS_MGF_TYPE mgf, CK_BYTE *hash, CK_ULONG hlen) +{ + int ps_len; + CK_ULONG dbMask_len, i; + CK_BYTE *maskedSeed, *maskedDB, *dbMask; + CK_BYTE seed[MAX_SHA_HASH_SIZE]; + CK_RV rc = CKR_OK; + + if (!mData || !emData) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + /* pkcs1v2.2 Step i: + * The encoded messages is a concatenated single octet, 0x00 with + * maskedSeed and maskedDB to create encoded message EM. + * So lets mark of the places in our output buffer. + */ + memset(emData, 0, modLength); + maskedSeed = emData + 1; + maskedDB = emData + hlen + 1; + + /* pkcs1v2.2, Step b: + * Generate an octet string PS and concatenate to DB. + */ + ps_len = modLength - mLen - (2 * hlen) - 2; + memcpy(maskedDB, hash, hlen); + memset(maskedDB + hlen, 0, ps_len); + + /* pkcs1v2.2, Step c: + * We have already concatenated hash and PS to maskedDB. + * Now just concatenate 0x01 and message. + */ + maskedDB[hlen + ps_len] = 0x01; + memcpy(maskedDB + (hlen + ps_len + 1), mData, mLen); + + /* pkcs1v2.2, Step d: + * Generate a random seed. + */ + rc = rng_generate(tokdata, seed, hlen); + if (rc != CKR_OK) + return rc; + + /* pkcs1v2.2, Step e: + * Compute dbmask using MGF1. + */ + dbMask_len = modLength - hlen - 1; + dbMask = malloc(sizeof(CK_BYTE) * dbMask_len); + if (dbMask == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + rc = mgf1(tokdata, seed, hlen, dbMask, dbMask_len, mgf); + if (rc != CKR_OK) + goto done; + + /* pkcs1v2.2, Step f: + * Compute maskedDB. + */ + for (i = 0; i < dbMask_len; i++) + maskedDB[i] ^= dbMask[i]; + + /* pkcs1v2.2, Step g: + * Compute seedMask using MGF1. + */ + memset(maskedSeed, 0, hlen); + rc = mgf1(tokdata, maskedDB, dbMask_len, maskedSeed, hlen, mgf); + if (rc != CKR_OK) + goto done; + + /* pkcs1v2.2, Step h: + * Compute maskedSeed. + */ + for (i = 0; i < hlen; i++) + maskedSeed[i] ^= seed[i]; +done: + if (dbMask) + free(dbMask); + + return rc; +} + +CK_RV decode_eme_oaep(STDLL_TokData_t *tokdata, CK_BYTE *emData, + CK_ULONG emLen, CK_BYTE *out_data, + 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; + + UNUSED(emLen); + + if (!emData || !out_data) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + /* 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)) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + + /* 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. + */ + maskedSeed = emData + 1; + maskedDB = emData + hlen + 1; + + /* pkcs1v2.2, section 7.1.2, Step 3c: + * Compute seedMask using MGF1. + */ + if (mgf1(tokdata, maskedDB, dbMask_len, seedMask, hlen, mgf)) + error++; + + /* pkcs1v2.2, section 7.1.2, Step 3d: + * Compute seed using MGF1. + */ + for (i = 0; i < hlen; i++) + seedMask[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++; + + /* pkcs1v2.2, section 7.1.2, Step 3f: + * Compute db using MGF1. + */ + for (i = 0; i < dbMask_len; i++) + dbMask[i] ^= maskedDB[i]; + + /* 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 ((dbMask[ps_len] == 0x00) && (ps_len < dbMask_len)) + ps_len++; + + if ((ps_len >= dbMask_len) || + (ps_len < dbMask_len && dbMask[ps_len] != 0x01) || + emData[0]) + error++; + + 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); + } + +done: + if (seedMask) + free(seedMask); + if (dbMask) + free(dbMask); + + return rc; +} + +CK_RV emsa_pss_encode(STDLL_TokData_t *tokdata, + CK_RSA_PKCS_PSS_PARAMS *pssParms, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *em, CK_ULONG *modbytes) +{ + CK_BYTE *salt, *DB, *H, *buf = NULL; + CK_ULONG emBits, emLen, buflen, hlen, PSlen, i; + CK_RV rc = CKR_OK; + + /* + * Note: pkcs#11v2.20, Section 12.1.10: + * in_data is the hashed message, mHash. + * + * Note: em is provided by the caller. It should be big enough to + * hold k bytes of data, where k is the length in octets of the + * modulus n. + */ + + /* pkcs1v2.2 8.1.1 describes emBits as length in bits of the + * modulus - 1. It also says, the octet length of EM will be + * one less than k if modBits - 1 is divisible by 8 and equal + * to k otherwise. k is the length in octets of the modulus n. + */ + emBits = (*modbytes * 8) - 1; + if ((emBits % 8) == 0) + emLen = *modbytes - 1; + else + emLen = *modbytes; + + /* get hash size based on hashAlg */ + if (get_sha_size(pssParms->hashAlg, &hlen)) + return CKR_MECHANISM_INVALID; + + /* allocate a helper buffer to be used for M' and dbmask */ + buflen = emLen - hlen - 1; + if (buflen < (8 + hlen + pssParms->sLen)) + buflen = 8 + hlen + pssParms->sLen; + buf = (CK_BYTE *) malloc(buflen); + if (buf == NULL) + return CKR_HOST_MEMORY; + + memset(em, 0, emLen); + memset(buf, 0, buflen); + + /* set some pointers for EM */ + DB = em; + H = em + (emLen - hlen - 1); + + /* pkcs1v2.2, Step 3: Check length */ + if (emLen < hlen + pssParms->sLen + 2) { + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* pkcs1v2.2, Step 4: Generate salt */ + salt = buf + (8 + in_data_len); + if (pssParms->sLen > 0) { + rc = rng_generate(tokdata, salt, pssParms->sLen); + if (rc != CKR_OK) + goto done; + } + + /* pkcs1v2.2, Step 5: set M' */ + memcpy(buf + 8, in_data, in_data_len); + + /* pkcs1v2.2, Step 6: Compute Hash(M') */ + rc = compute_sha(tokdata, buf, 8 + hlen + pssParms->sLen, H, + pssParms->hashAlg); + if (rc != CKR_OK) + goto done; + + /* pkcs1v2.2, Step 7 & 8: Generate DB */ + PSlen = emLen - pssParms->sLen - hlen - 2; + DB[PSlen] = 0x01; + memcpy(DB + (PSlen + 1), salt, pssParms->sLen); + + /* pkcs1v2.2, Step 9: Generate dbMask + * Note: reuse "buf" for dbMask. + */ + memset(buf, 0, buflen); + rc = mgf1(tokdata, H, hlen, buf, emLen - hlen - 1, pssParms->mgf); + if (rc != CKR_OK) + goto done; + + /* pkcs1v2.2, Step 10: Compute maskedDB */ + for (i = 0; i < (emLen - hlen - 1); i++) + em[i] ^= buf[i]; + + /* pkcs1v2.2, Step 11: Set leftmost bits to zero. */ + em[0] &= 0xFF >> (8 * emLen - emBits); + + /* pkcs1v2.2, Step 12: EM = maskedDB || H || 0xbc */ + em[emLen - 1] = 0xbc; + *modbytes = emLen; + +done: + if (buf) + free(buf); + + return rc; +} + +CK_RV emsa_pss_verify(STDLL_TokData_t *tokdata, + CK_RSA_PKCS_PSS_PARAMS *pssParms, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *sig, CK_ULONG modbytes) +{ + CK_ULONG buflen, hlen, emBits, emLen, plen, i; + CK_BYTE *salt, *H, *M, *buf = NULL; + CK_BYTE hash[MAX_SHA_HASH_SIZE]; + CK_RV rc = CKR_OK; + + /* pkcs1v2.2 8.1.1 describes emBits as length in bits of the + * modulus - 1. It also says, the octet length of EM will be + * one less than k if modBits - 1 is divisible by 8 and equal + * to k otherwise. k is the length in octets of the modulus n. + */ + emBits = (modbytes * 8) - 1; + if ((emBits % 8) == 0) + emLen = modbytes - 1; + else + emLen = modbytes; + + /* get hash size based on hashAlg */ + if (get_sha_size(pssParms->hashAlg, &hlen)) + return CKR_MECHANISM_INVALID; + + /* set up a big enough helper buffer to be used for M' and DB. */ + buflen = (emLen - hlen - 1) + (8 + hlen + pssParms->sLen); + buf = (CK_BYTE *) malloc(buflen); + if (buf == NULL) + return CKR_HOST_MEMORY; + memset(buf, 0, buflen); + + /* pkcs1v2.2, Step 4: Check rightmost octet. */ + if (sig[emLen - 1] != 0xbc) { + rc = CKR_SIGNATURE_INVALID; + goto done; + } + + /* pkcs1v2.2, Step 5: Extract maskedDB and H */ + H = sig + (emLen - hlen - 1); + + /* pkcs1v2.2, Step 6: Check leftmost bits */ + if (sig[0] & ~(0xFF >> (8 * emLen - emBits))) { + rc = CKR_SIGNATURE_INVALID; + goto done; + } + + /* pkcs1v2.2, Step 7: Compute mgf. */ + rc = mgf1(tokdata, H, hlen, buf, emLen - hlen - 1, pssParms->mgf); + if (rc != CKR_OK) + goto done; + + /* pkcs1v2.2, Step 8: DB = maskedDB ^ dbMask. */ + for (i = 0; i < emLen - hlen - 1; i++) + buf[i] ^= sig[i]; + + /* pkcs1v2.2, Step 9: Set leftmost bits in DB to zero. */ + buf[0] &= 0xFF >> (8 * emLen - emBits); + + /* pkcs1v2.2, Step 10: check DB. */ + i = 0; + plen = emLen - hlen - pssParms->sLen - 2; + while ((buf[i] == 0) && (i < plen)) + i++; + + if ((i != plen) || (buf[i++] != 0x01)) { + rc = CKR_SIGNATURE_INVALID; + goto done; + } + + /* pkcs1v2.2, Step 11: Get the salt from DB. */ + salt = buf + i; + + /* pkcs1v2.2, Step 12: Set M'. Note: Use end of buf. */ + M = buf + (i + pssParms->sLen); + memset(M, 0, 8); + memcpy(M + 8, in_data, in_data_len); // in_data is mHash. + memcpy(M + (8 + in_data_len), salt, pssParms->sLen); + + /* pkcs1v2.2, Step 13: Compute Hash(M'). */ + rc = compute_sha(tokdata, M, 8 + hlen + pssParms->sLen, hash, + pssParms->hashAlg); + if (rc != CKR_OK) + goto done; + + /* pkcs1v2.2, Step 14: H == H'. */ + if (CRYPTO_memcmp(hash, H, hlen)) + rc = CKR_SIGNATURE_INVALID; + else + rc = CKR_OK; +done: + if (buf) + free(buf); + + return rc; +} + +CK_RV check_pss_params(CK_MECHANISM *mech, CK_ULONG modlen) +{ + CK_RSA_PKCS_PSS_PARAMS *pssParams; + CK_MECHANISM_TYPE mgf_mech; + CK_ULONG hlen; + CK_RV rc; + + pssParams = (CK_RSA_PKCS_PSS_PARAMS *) mech->pParameter; + + if (mech->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + + /* + * If the signature mechanism includes hashing, make sure + * pssParams->hashAlg matches. + * + * Note: pkcs#1v2.2, Section 8.1, It is recommended that the + * hash algorithm used to hash the message be the same as the + * one used in mgf. + */ + rc = get_mgf_mech(pssParams->mgf, &mgf_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("MGF mechanism is invalid.\n"); + return rc; + } + + switch (mech->mechanism) { + case CKM_SHA1_RSA_PKCS_PSS: + if ((pssParams->hashAlg != CKM_SHA_1) && + (pssParams->hashAlg != mgf_mech)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + break; + case CKM_SHA224_RSA_PKCS_PSS: + if ((pssParams->hashAlg != CKM_SHA224) && + (pssParams->hashAlg != mgf_mech)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + break; + case CKM_SHA256_RSA_PKCS_PSS: + if ((pssParams->hashAlg != CKM_SHA256) && + (pssParams->hashAlg != mgf_mech)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + break; + case CKM_SHA384_RSA_PKCS_PSS: + if ((pssParams->hashAlg != CKM_SHA384) && + (pssParams->hashAlg != mgf_mech)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + break; + case CKM_SHA512_RSA_PKCS_PSS: + if ((pssParams->hashAlg != CKM_SHA512) && + (pssParams->hashAlg != mgf_mech)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + break; + case CKM_RSA_PKCS_PSS: + if (pssParams->hashAlg != mgf_mech) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + /* check the salt length, pkcs11v2.2 Section 12.1.14 */ + rc = get_sha_size(pssParams->hashAlg, &hlen); + if (rc != CKR_OK) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + + if (!(pssParams->sLen <= modlen - 2 - hlen)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + + return CKR_OK; +} diff --git a/usr/lib/common/mech_sha.c b/usr/lib/common/mech_sha.c new file mode 100644 index 0000000..8a60bb1 --- /dev/null +++ b/usr/lib/common/mech_sha.c @@ -0,0 +1,1648 @@ +/* + * 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: mech_sha.c +// +// Mechanisms for SHA-1 related routines +// +// The following applies to the software SHA implementation: +// Written 2 September 1992, Peter C. Gutmann. +// This implementation placed in the public domain. +// +// Modified 1 June 1993, Colin Plumb. +// Modified for the new SHS based on Peter Gutmann's work, +// 18 July 1994, Colin Plumb. +// Gutmann's work. +// Renamed to SHA and comments updated a bit 1 November 1995, Colin Plumb. +// These modifications placed in the public domain. +// +// Comments to pgut1@cs.aukuni.ac.nz +// + +#include +#include // for memcmp() et al +#include +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "trace.h" + +#include +#include + +// +// Software SHA-1 implementation (OpenSSL based) +// + +void sw_sha1_init(DIGEST_CONTEXT *ctx) +{ + ctx->context_len = sizeof(SHA_CTX); + ctx->context = (CK_BYTE *) malloc(sizeof(SHA_CTX)); + if (ctx->context == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + // TODO: propagate error up? + return; + } + + SHA1_Init((SHA_CTX *)ctx->context); +} + +CK_RV sw_sha1_hash(DIGEST_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len) +{ + + if (!ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (*out_data_len < SHA1_HASH_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + if (ctx->context == NULL) + return CKR_OPERATION_NOT_INITIALIZED; + + SHA1_Update((SHA_CTX *)ctx->context, in_data, in_data_len); + SHA1_Final(out_data, (SHA_CTX *)ctx->context); + *out_data_len = SHA1_HASH_SIZE; + + free(ctx->context); + ctx->context = NULL; + + return CKR_OK; +} + +CK_RV sw_sha1_update(DIGEST_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len) +{ + if (ctx->context == NULL) + return CKR_OPERATION_NOT_INITIALIZED; + + SHA1_Update((SHA_CTX *)ctx->context, in_data, in_data_len); + return CKR_OK; +} + +CK_RV sw_sha1_final(DIGEST_CONTEXT *ctx, CK_BYTE *out_data, + CK_ULONG *out_data_len) +{ + if (ctx->context == NULL) + return CKR_OPERATION_NOT_INITIALIZED; + + SHA1_Final(out_data, (SHA_CTX *)ctx->context); + *out_data_len = SHA1_HASH_SIZE; + + free(ctx->context); + ctx->context = NULL; + + return CKR_OK; +} + +CK_RV sha_init(STDLL_TokData_t *tokdata, SESSION *sess, DIGEST_CONTEXT *ctx, + CK_MECHANISM *mech) +{ + UNUSED(sess); + + if (token_specific.t_sha_init != NULL) { + return token_specific.t_sha_init(tokdata, ctx, mech); + } else { + /* For current tokens, continue legacy of using software + * implemented SHA-1 if the token does not have its own + * SHA-1 implementation. + * Future tokens' crypto should be its own so that + * opencryptoki is not responsible for crypto. If token + * does not have SHA-1, then should be mechanism not + * supported. JML + */ + if (mech->mechanism == CKM_SHA_1) { + sw_sha1_init(ctx); + return CKR_OK; + } else { + return CKR_MECHANISM_INVALID; + } + } +} + +CK_RV sha_hash(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, + DIGEST_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_ULONG hsize; + + UNUSED(sess); + + if (!ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + switch (ctx->mech.mechanism) { + case CKM_SHA_1: + hsize = SHA1_HASH_SIZE; + break; + case CKM_SHA224: + case CKM_SHA512_224: + hsize = SHA224_HASH_SIZE; + break; + case CKM_SHA256: + case CKM_SHA512_256: + hsize = SHA256_HASH_SIZE; + break; + case CKM_SHA384: + hsize = SHA384_HASH_SIZE; + break; + case CKM_SHA512: + hsize = SHA512_HASH_SIZE; + break; + case CKM_IBM_SHA3_224: + hsize = SHA3_224_HASH_SIZE; + break; + case CKM_IBM_SHA3_256: + hsize = SHA3_256_HASH_SIZE; + break; + case CKM_IBM_SHA3_384: + hsize = SHA3_384_HASH_SIZE; + break; + case CKM_IBM_SHA3_512: + hsize = SHA3_512_HASH_SIZE; + break; + default: + return CKR_MECHANISM_INVALID; + } + + if (length_only == TRUE) { + *out_data_len = hsize; + return CKR_OK; + } + + if (*out_data_len < hsize) { + *out_data_len = hsize; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + if (ctx->context == NULL) + return CKR_HOST_MEMORY; + + if (token_specific.t_sha != NULL) { + return token_specific.t_sha(tokdata, ctx, in_data, in_data_len, + out_data, out_data_len); + } else { + if (ctx->mech.mechanism == CKM_SHA_1) + return sw_sha1_hash(ctx, in_data, in_data_len, out_data, + out_data_len); + else + return CKR_MECHANISM_INVALID; + } +} + +// +// +CK_RV sha_hash_update(STDLL_TokData_t *tokdata, SESSION *sess, + DIGEST_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len) +{ + UNUSED(sess); + + /* if no data to hash, just return */ + if (!in_data_len) + return CKR_OK; + + if (token_specific.t_sha_update != NULL) { + return token_specific.t_sha_update(tokdata, ctx, in_data, in_data_len); + } else { + if (ctx->mech.mechanism == CKM_SHA_1) + return sw_sha1_update(ctx, in_data, in_data_len); + else + return CKR_MECHANISM_INVALID; + } +} + +CK_RV sha_hash_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BYTE length_only, DIGEST_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + CK_ULONG hsize; + + UNUSED(sess); + + if (!out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + switch (ctx->mech.mechanism) { + case CKM_SHA_1: + hsize = SHA1_HASH_SIZE; + break; + case CKM_SHA224: + case CKM_SHA512_224: + hsize = SHA224_HASH_SIZE; + break; + case CKM_SHA256: + case CKM_SHA512_256: + hsize = SHA256_HASH_SIZE; + break; + case CKM_SHA384: + hsize = SHA384_HASH_SIZE; + break; + case CKM_SHA512: + hsize = SHA512_HASH_SIZE; + break; + case CKM_IBM_SHA3_224: + hsize = SHA3_224_HASH_SIZE; + break; + case CKM_IBM_SHA3_256: + hsize = SHA3_256_HASH_SIZE; + break; + case CKM_IBM_SHA3_384: + hsize = SHA3_384_HASH_SIZE; + break; + case CKM_IBM_SHA3_512: + hsize = SHA3_512_HASH_SIZE; + break; + default: + return CKR_MECHANISM_INVALID; + } + + if (length_only == TRUE) { + *out_data_len = hsize; + return CKR_OK; + } + + if (*out_data_len < hsize) { + *out_data_len = hsize; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + if (token_specific.t_sha_final != NULL) { + return token_specific.t_sha_final(tokdata, ctx, out_data, out_data_len); + } else { + if (ctx->mech.mechanism == CKM_SHA_1) + return sw_sha1_final(ctx, out_data, out_data_len); + else + return CKR_MECHANISM_INVALID; + } +} + +// this routine gets called for two mechanisms actually: +// CKM_SHA_1_HMAC +// CKM_SHA_1_HMAC_GENERAL +// +CK_RV sha1_hmac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE hash[SHA1_HASH_SIZE]; + DIGEST_CONTEXT digest_ctx; + CK_MECHANISM digest_mech; + CK_BYTE k_ipad[SHA1_BLOCK_SIZE]; + CK_BYTE k_opad[SHA1_BLOCK_SIZE]; + CK_ULONG key_bytes, hash_len, hmac_len; + CK_ULONG i; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (ctx->mech.mechanism == CKM_SHA_1_HMAC_GENERAL) { + hmac_len = *(CK_ULONG *) ctx->mech.pParameter; + + if (hmac_len == 0) { + *out_data_len = 0; + return CKR_OK; + } + } else { + hmac_len = SHA1_HASH_SIZE; + } + + if (length_only == TRUE) { + *out_data_len = hmac_len; + return CKR_OK; + } + + if (token_specific.t_hmac_sign != NULL) + return token_specific.t_hmac_sign(tokdata, sess, in_data, + in_data_len, out_data, out_data_len); + + /* Do manual hmac if token doesn't have an hmac crypto call. + * Secure tokens should not do manual hmac. + */ + + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + rc = template_attribute_find(key_obj->template, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + key_bytes = attr->ulValueLen; + + + // build (K XOR ipad), (K XOR opad) + // + if (key_bytes > SHA1_BLOCK_SIZE) { + digest_mech.mechanism = CKM_SHA_1; + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + + hash_len = sizeof(hash); + rc = digest_mgr_digest(tokdata, sess, FALSE, &digest_ctx, + attr->pValue, attr->ulValueLen, hash, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Digest failed.\n"); + goto done; + } + + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + for (i = 0; i < hash_len; i++) { + k_ipad[i] = hash[i] ^ 0x36; + k_opad[i] = hash[i] ^ 0x5C; + } + + memset(&k_ipad[i], 0x36, SHA1_BLOCK_SIZE - i); + memset(&k_opad[i], 0x5C, SHA1_BLOCK_SIZE - i); + } else { + CK_BYTE *key = attr->pValue; + + for (i = 0; i < key_bytes; i++) { + k_ipad[i] = key[i] ^ 0x36; + k_opad[i] = key[i] ^ 0x5C; + } + + memset(&k_ipad[i], 0x36, SHA1_BLOCK_SIZE - key_bytes); + memset(&k_opad[i], 0x5C, SHA1_BLOCK_SIZE - key_bytes); + } + + digest_mech.mechanism = CKM_SHA_1; + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + // inner hash + // + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, k_ipad, + SHA1_BLOCK_SIZE); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, in_data, + in_data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &digest_ctx, hash, + &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + goto done; + } + + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + // outer hash + // + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, k_opad, + SHA1_BLOCK_SIZE); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, hash, hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &digest_ctx, hash, + &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + goto done; + } + + memcpy(out_data, hash, hmac_len); + *out_data_len = hmac_len; + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +/** This routine gets called for two mechanisms actually: + * CKM_SHA224_HMAC + * CKM_SHA224_HMAC_GENERAL + */ +CK_RV sha224_hmac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE hash[SHA224_HASH_SIZE]; + DIGEST_CONTEXT digest_ctx; + CK_MECHANISM digest_mech; + CK_BYTE k_ipad[SHA224_BLOCK_SIZE]; + CK_BYTE k_opad[SHA224_BLOCK_SIZE]; + CK_ULONG key_bytes, hash_len, hmac_len; + CK_ULONG i; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (ctx->mech.mechanism == CKM_SHA224_HMAC_GENERAL) { + hmac_len = *(CK_ULONG *) ctx->mech.pParameter; + + if (hmac_len == 0) { + *out_data_len = 0; + return CKR_OK; + } + } else { + hmac_len = SHA224_HASH_SIZE; + } + + if (length_only == TRUE) { + *out_data_len = hmac_len; + return CKR_OK; + } + + if (token_specific.t_hmac_sign != NULL) + return token_specific.t_hmac_sign(tokdata, sess, in_data, + in_data_len, out_data, out_data_len); + + /* Do manual hmac if token doesn't have an hmac crypto call. + * Secure tokens should not do manual hmac. + */ + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + rc = template_attribute_find(key_obj->template, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + key_bytes = attr->ulValueLen; + + // build (K XOR ipad), (K XOR opad) + // + if (key_bytes > SHA224_BLOCK_SIZE) { + digest_mech.mechanism = CKM_SHA224; + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + + hash_len = sizeof(hash); + rc = digest_mgr_digest(tokdata, sess, FALSE, &digest_ctx, + attr->pValue, attr->ulValueLen, hash, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Digest failed.\n"); + goto done; + } + + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + for (i = 0; i < hash_len; i++) { + k_ipad[i] = hash[i] ^ 0x36; + k_opad[i] = hash[i] ^ 0x5C; + } + + memset(&k_ipad[i], 0x36, SHA224_BLOCK_SIZE - i); + memset(&k_opad[i], 0x5C, SHA224_BLOCK_SIZE - i); + } else { + CK_BYTE *key = attr->pValue; + + for (i = 0; i < key_bytes; i++) { + k_ipad[i] = key[i] ^ 0x36; + k_opad[i] = key[i] ^ 0x5C; + } + + memset(&k_ipad[i], 0x36, SHA224_BLOCK_SIZE - key_bytes); + memset(&k_opad[i], 0x5C, SHA224_BLOCK_SIZE - key_bytes); + } + + digest_mech.mechanism = CKM_SHA224; + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + // inner hash + // + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, k_ipad, + SHA224_BLOCK_SIZE); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, in_data, + in_data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &digest_ctx, hash, + &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + goto done; + } + + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + // outer hash + // + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, k_opad, + SHA224_BLOCK_SIZE); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, hash, hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &digest_ctx, hash, + &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + goto done; + } + + memcpy(out_data, hash, hmac_len); + *out_data_len = hmac_len; + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +/** This routine gets called for two mechanisms actually: + * CKM_SHA256_HMAC + * CKM_SHA256_HMAC_GENERAL + */ +CK_RV sha256_hmac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE hash[SHA256_HASH_SIZE]; + DIGEST_CONTEXT digest_ctx; + CK_MECHANISM digest_mech; + CK_BYTE k_ipad[SHA256_BLOCK_SIZE]; + CK_BYTE k_opad[SHA256_BLOCK_SIZE]; + CK_ULONG key_bytes, hash_len, hmac_len; + CK_ULONG i; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (ctx->mech.mechanism == CKM_SHA256_HMAC_GENERAL) { + hmac_len = *(CK_ULONG *) ctx->mech.pParameter; + + if (hmac_len == 0) { + *out_data_len = 0; + return CKR_OK; + } + } else { + hmac_len = SHA256_HASH_SIZE; + } + + if (length_only == TRUE) { + *out_data_len = hmac_len; + return CKR_OK; + } + + if (token_specific.t_hmac_sign != NULL) + return token_specific.t_hmac_sign(tokdata, sess, in_data, + in_data_len, out_data, out_data_len); + + /* Do manual hmac if token doesn't have an hmac crypto call. + * Secure tokens should not do manual hmac. + */ + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + rc = template_attribute_find(key_obj->template, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + key_bytes = attr->ulValueLen; + + // build (K XOR ipad), (K XOR opad) + // + if (key_bytes > SHA256_BLOCK_SIZE) { + digest_mech.mechanism = CKM_SHA256; + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + + hash_len = sizeof(hash); + rc = digest_mgr_digest(tokdata, sess, FALSE, &digest_ctx, + attr->pValue, attr->ulValueLen, hash, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Digest failed.\n"); + goto done; + } + + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + for (i = 0; i < hash_len; i++) { + k_ipad[i] = hash[i] ^ 0x36; + k_opad[i] = hash[i] ^ 0x5C; + } + + memset(&k_ipad[i], 0x36, SHA256_BLOCK_SIZE - i); + memset(&k_opad[i], 0x5C, SHA256_BLOCK_SIZE - i); + } else { + CK_BYTE *key = attr->pValue; + + for (i = 0; i < key_bytes; i++) { + k_ipad[i] = key[i] ^ 0x36; + k_opad[i] = key[i] ^ 0x5C; + } + + memset(&k_ipad[i], 0x36, SHA256_BLOCK_SIZE - key_bytes); + memset(&k_opad[i], 0x5C, SHA256_BLOCK_SIZE - key_bytes); + } + + digest_mech.mechanism = CKM_SHA256; + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + // inner hash + // + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, k_ipad, + SHA256_BLOCK_SIZE); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, in_data, + in_data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &digest_ctx, hash, + &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + goto done; + } + + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + // outer hash + // + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, k_opad, + SHA256_BLOCK_SIZE); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, hash, hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &digest_ctx, hash, + &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + goto done; + } + + memcpy(out_data, hash, hmac_len); + *out_data_len = hmac_len; + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +/** This routine gets called for two mechanisms actually: + * CKM_SHA384_HMAC + * CKM_SHA384_HMAC_GENERAL + */ +CK_RV sha384_hmac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE hash[SHA384_HASH_SIZE]; + DIGEST_CONTEXT digest_ctx; + CK_MECHANISM digest_mech; + CK_BYTE k_ipad[SHA384_BLOCK_SIZE]; + CK_BYTE k_opad[SHA384_BLOCK_SIZE]; + CK_ULONG key_bytes, hash_len, hmac_len; + CK_ULONG i; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (ctx->mech.mechanism == CKM_SHA384_HMAC_GENERAL) { + hmac_len = *(CK_ULONG *) ctx->mech.pParameter; + + if (hmac_len == 0) { + *out_data_len = 0; + return CKR_OK; + } + } else { + hmac_len = SHA384_HASH_SIZE; + } + + if (length_only == TRUE) { + *out_data_len = hmac_len; + return CKR_OK; + } + + if (token_specific.t_hmac_sign != NULL) + return token_specific.t_hmac_sign(tokdata, sess, in_data, + in_data_len, out_data, out_data_len); + + /* Do manual hmac if token doesn't have an hmac crypto call. + * Secure tokens should not do manual hmac. + */ + + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + rc = template_attribute_find(key_obj->template, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + key_bytes = attr->ulValueLen; + + // build (K XOR ipad), (K XOR opad) + // + if (key_bytes > SHA384_BLOCK_SIZE) { + digest_mech.mechanism = CKM_SHA384; + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + + hash_len = sizeof(hash); + rc = digest_mgr_digest(tokdata, sess, FALSE, &digest_ctx, + attr->pValue, attr->ulValueLen, hash, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Digest failed.\n"); + goto done; + } + + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + for (i = 0; i < hash_len; i++) { + k_ipad[i] = hash[i] ^ 0x36; + k_opad[i] = hash[i] ^ 0x5C; + } + + memset(&k_ipad[i], 0x36, SHA384_BLOCK_SIZE - i); + memset(&k_opad[i], 0x5C, SHA384_BLOCK_SIZE - i); + } else { + CK_BYTE *key = attr->pValue; + + for (i = 0; i < key_bytes; i++) { + k_ipad[i] = key[i] ^ 0x36; + k_opad[i] = key[i] ^ 0x5C; + } + + memset(&k_ipad[i], 0x36, SHA384_BLOCK_SIZE - key_bytes); + memset(&k_opad[i], 0x5C, SHA384_BLOCK_SIZE - key_bytes); + } + + digest_mech.mechanism = CKM_SHA384; + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + // inner hash + // + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, k_ipad, + SHA384_BLOCK_SIZE); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, in_data, + in_data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &digest_ctx, hash, + &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + goto done; + } + + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + // outer hash + // + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, k_opad, + SHA384_BLOCK_SIZE); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, hash, hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &digest_ctx, hash, + &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + goto done; + } + + memcpy(out_data, hash, hmac_len); + *out_data_len = hmac_len; + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +/** This routine gets called for 6 mechanisms actually: + * CKM_SHA512_HMAC + * CKM_SHA512_HMAC_GENERAL + * CKM_SHA512_224_HMAC + * CKM_SHA512_224_HMAC_GENERAL + * CKM_SHA512_256_HMAC + * CKM_SHA512_256_HMAC_GENERAL + */ +CK_RV sha512_hmac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE hash[SHA512_HASH_SIZE]; + DIGEST_CONTEXT digest_ctx; + CK_MECHANISM digest_mech; + CK_BYTE k_ipad[SHA512_BLOCK_SIZE]; + CK_BYTE k_opad[SHA512_BLOCK_SIZE]; + CK_ULONG key_bytes, hash_len, hmac_len; + CK_ULONG i; + CK_RV rc; + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (ctx->mech.mechanism == CKM_SHA512_HMAC_GENERAL || + ctx->mech.mechanism == CKM_SHA512_224_HMAC_GENERAL || + ctx->mech.mechanism == CKM_SHA512_256_HMAC_GENERAL) { + hmac_len = *(CK_ULONG *) ctx->mech.pParameter; + + if (hmac_len == 0) { + *out_data_len = 0; + return CKR_OK; + } + } else if (ctx->mech.mechanism == CKM_SHA512_224_HMAC) { + hmac_len = SHA224_HASH_SIZE; + } else if (ctx->mech.mechanism == CKM_SHA512_224_HMAC) { + hmac_len = SHA256_HASH_SIZE; + } else { + hmac_len = SHA512_HASH_SIZE; + } + + if (length_only == TRUE) { + *out_data_len = hmac_len; + return CKR_OK; + } + + if (token_specific.t_hmac_sign != NULL) + return token_specific.t_hmac_sign(tokdata, sess, in_data, + in_data_len, out_data, out_data_len); + + /* Do manual hmac if token doesn't have an hmac crypto call. + * Secure tokens should not do manual hmac. + */ + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + rc = template_attribute_find(key_obj->template, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + key_bytes = attr->ulValueLen; + + // build (K XOR ipad), (K XOR opad) + // + if (key_bytes > SHA512_BLOCK_SIZE) { + digest_mech.mechanism = CKM_SHA512; + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + + hash_len = sizeof(hash); + rc = digest_mgr_digest(tokdata, sess, FALSE, &digest_ctx, + attr->pValue, attr->ulValueLen, hash, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Digest failed.\n"); + goto done; + } + + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + for (i = 0; i < hash_len; i++) { + k_ipad[i] = hash[i] ^ 0x36; + k_opad[i] = hash[i] ^ 0x5C; + } + + memset(&k_ipad[i], 0x36, SHA512_BLOCK_SIZE - i); + memset(&k_opad[i], 0x5C, SHA512_BLOCK_SIZE - i); + } else { + CK_BYTE *key = attr->pValue; + + for (i = 0; i < key_bytes; i++) { + k_ipad[i] = key[i] ^ 0x36; + k_opad[i] = key[i] ^ 0x5C; + } + + memset(&k_ipad[i], 0x36, SHA512_BLOCK_SIZE - key_bytes); + memset(&k_opad[i], 0x5C, SHA512_BLOCK_SIZE - key_bytes); + } + + digest_mech.mechanism = CKM_SHA512; + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + // inner hash + // + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, k_ipad, + SHA512_BLOCK_SIZE); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, in_data, + in_data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &digest_ctx, hash, + &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + return rc; + } + + /* Do manual hmac if token doesn't have an hmac crypto call. + * Secure tokens should not do manual hmac. + */ + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + // outer hash + // + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Init failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, k_opad, + SHA512_BLOCK_SIZE); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, hash, hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Update failed.\n"); + goto done; + } + + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &digest_ctx, hash, + &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Mgr Final failed.\n"); + goto done; + } + + memcpy(out_data, hash, hmac_len); + *out_data_len = hmac_len; + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV sha1_hmac_verify(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) +{ + CK_BYTE hmac[SHA1_HASH_SIZE]; + SIGN_VERIFY_CONTEXT hmac_ctx; + CK_ULONG hmac_len, len; + CK_RV rc; + + if (!sess || !ctx || !in_data || !signature) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (token_specific.t_hmac_verify != NULL) + return token_specific.t_hmac_verify(tokdata, sess, in_data, + in_data_len, signature, sig_len); + + /* Do manual hmac verify if token doesn't have an hmac crypto call. + * Secure tokens should not do manual hmac. + */ + if (ctx->mech.mechanism == CKM_SHA_1_HMAC_GENERAL) + hmac_len = *(CK_ULONG *) ctx->mech.pParameter; + else + hmac_len = SHA1_HASH_SIZE; + + memset(&hmac_ctx, 0, sizeof(SIGN_VERIFY_CONTEXT)); + + rc = sign_mgr_init(tokdata, sess, &hmac_ctx, &ctx->mech, FALSE, ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Init failed.\n"); + goto done; + } + len = sizeof(hmac); + rc = sign_mgr_sign(tokdata, sess, FALSE, &hmac_ctx, in_data, in_data_len, + hmac, &len); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Sign failed.\n"); + goto done; + } + if ((len != hmac_len) || (len != sig_len)) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + rc = CKR_SIGNATURE_LEN_RANGE; + goto done; + } + + if (CRYPTO_memcmp(hmac, signature, hmac_len) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + rc = CKR_SIGNATURE_INVALID; + } + +done: + sign_mgr_cleanup(&hmac_ctx); + return rc; +} + +CK_RV sha224_hmac_verify(STDLL_TokData_t *tokdata, + SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) +{ + CK_BYTE hmac[SHA224_HASH_SIZE]; + SIGN_VERIFY_CONTEXT hmac_ctx; + CK_ULONG hmac_len, len; + CK_RV rc; + + if (!sess || !ctx || !in_data || !signature) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (token_specific.t_hmac_verify != NULL) + return token_specific.t_hmac_verify(tokdata, sess, in_data, + in_data_len, signature, sig_len); + + /* Do manual hmac verify if token doesn't have an hmac crypto call. + * Secure tokens should not do manual hmac. + */ + if (ctx->mech.mechanism == CKM_SHA224_HMAC_GENERAL) + hmac_len = *(CK_ULONG *) ctx->mech.pParameter; + else + hmac_len = SHA224_HASH_SIZE; + + memset(&hmac_ctx, 0, sizeof(SIGN_VERIFY_CONTEXT)); + + rc = sign_mgr_init(tokdata, sess, &hmac_ctx, &ctx->mech, FALSE, ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Init failed.\n"); + goto done; + } + + len = sizeof(hmac); + rc = sign_mgr_sign(tokdata, sess, FALSE, &hmac_ctx, in_data, in_data_len, + hmac, &len); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Sign failed.\n"); + goto done; + } + + if ((len != hmac_len) || (len != sig_len)) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + rc = CKR_SIGNATURE_LEN_RANGE; + goto done; + } + + if (CRYPTO_memcmp(hmac, signature, hmac_len) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + rc = CKR_SIGNATURE_INVALID; + } + +done: + sign_mgr_cleanup(&hmac_ctx); + return rc; +} + +CK_RV sha256_hmac_verify(STDLL_TokData_t *tokdata, + SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) +{ + CK_BYTE hmac[SHA256_HASH_SIZE]; + SIGN_VERIFY_CONTEXT hmac_ctx; + CK_ULONG hmac_len, len; + CK_RV rc; + + if (!sess || !ctx || !in_data || !signature) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (token_specific.t_hmac_verify != NULL) + return token_specific.t_hmac_verify(tokdata, sess, in_data, + in_data_len, signature, sig_len); + + /* Do manual hmac verify if token doesn't have an hmac crypto call. + * Secure tokens should not do manual hmac. + */ + if (ctx->mech.mechanism == CKM_SHA256_HMAC_GENERAL) + hmac_len = *(CK_ULONG *) ctx->mech.pParameter; + else + hmac_len = SHA256_HASH_SIZE; + + memset(&hmac_ctx, 0, sizeof(SIGN_VERIFY_CONTEXT)); + + rc = sign_mgr_init(tokdata, sess, &hmac_ctx, &ctx->mech, FALSE, ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Init failed.\n"); + goto done; + } + + len = sizeof(hmac); + rc = sign_mgr_sign(tokdata, sess, FALSE, &hmac_ctx, in_data, in_data_len, + hmac, &len); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Sign failed.\n"); + goto done; + } + + if ((len != hmac_len) || (len != sig_len)) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + rc = CKR_SIGNATURE_LEN_RANGE; + goto done; + } + + if (CRYPTO_memcmp(hmac, signature, hmac_len) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + rc = CKR_SIGNATURE_INVALID; + } + +done: + sign_mgr_cleanup(&hmac_ctx); + + return rc; +} + +CK_RV sha384_hmac_verify(STDLL_TokData_t *tokdata, + SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) +{ + CK_BYTE hmac[SHA384_HASH_SIZE]; + SIGN_VERIFY_CONTEXT hmac_ctx; + CK_ULONG hmac_len, len; + CK_RV rc; + + if (!sess || !ctx || !in_data || !signature) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (token_specific.t_hmac_verify != NULL) + return token_specific.t_hmac_verify(tokdata, sess, in_data, + in_data_len, signature, sig_len); + + /* Do manual hmac verify if token doesn't have an hmac crypto call. + * Secure tokens should not do manual hmac. + */ + if (ctx->mech.mechanism == CKM_SHA384_HMAC_GENERAL) + hmac_len = *(CK_ULONG *) ctx->mech.pParameter; + else + hmac_len = SHA384_HASH_SIZE; + + memset(&hmac_ctx, 0, sizeof(SIGN_VERIFY_CONTEXT)); + + rc = sign_mgr_init(tokdata, sess, &hmac_ctx, &ctx->mech, FALSE, ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Init failed.\n"); + goto done; + } + len = sizeof(hmac); + rc = sign_mgr_sign(tokdata, sess, FALSE, &hmac_ctx, in_data, in_data_len, + hmac, &len); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Sign failed.\n"); + goto done; + } + if ((len != hmac_len) || (len != sig_len)) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + rc = CKR_SIGNATURE_LEN_RANGE; + goto done; + } + + if (CRYPTO_memcmp(hmac, signature, hmac_len) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + rc = CKR_SIGNATURE_INVALID; + } +done: + sign_mgr_cleanup(&hmac_ctx); + + return rc; +} + +CK_RV sha512_hmac_verify(STDLL_TokData_t *tokdata, + SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) +{ + CK_BYTE hmac[SHA512_HASH_SIZE]; + SIGN_VERIFY_CONTEXT hmac_ctx; + CK_ULONG hmac_len, len; + CK_RV rc; + + if (!sess || !ctx || !in_data || !signature) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + if (token_specific.t_hmac_verify != NULL) + return token_specific.t_hmac_verify(tokdata, sess, in_data, + in_data_len, signature, sig_len); + + /* Do manual hmac verify if token doesn't have an hmac crypto call. + * Secure tokens should not do manual hmac. + */ + if (ctx->mech.mechanism == CKM_SHA512_HMAC_GENERAL) + hmac_len = *(CK_ULONG *) ctx->mech.pParameter; + else if (ctx->mech.mechanism == CKM_SHA512_224_HMAC) + hmac_len = SHA224_HASH_SIZE; + else if (ctx->mech.mechanism == CKM_SHA512_256_HMAC) + hmac_len = SHA256_HASH_SIZE; + else + hmac_len = SHA512_HASH_SIZE; + + memset(&hmac_ctx, 0, sizeof(SIGN_VERIFY_CONTEXT)); + + rc = sign_mgr_init(tokdata, sess, &hmac_ctx, &ctx->mech, FALSE, ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Init failed.\n"); + goto done; + } + len = sizeof(hmac); + rc = sign_mgr_sign(tokdata, sess, FALSE, &hmac_ctx, in_data, in_data_len, + hmac, &len); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Mgr Sign failed.\n"); + goto done; + } + if ((len != hmac_len) || (len != sig_len)) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + rc = CKR_SIGNATURE_LEN_RANGE; + goto done; + } + + if (CRYPTO_memcmp(hmac, signature, hmac_len) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + rc = CKR_SIGNATURE_INVALID; + } +done: + sign_mgr_cleanup(&hmac_ctx); + + return rc; +} + +CK_RV hmac_sign_init(STDLL_TokData_t *tokdata, SESSION *sess, + CK_MECHANISM *mech, CK_OBJECT_HANDLE hkey) +{ + if (token_specific.t_hmac_sign_init != NULL) + return token_specific.t_hmac_sign_init(tokdata, sess, mech, hkey); + + /* Return ok with the intention that the local hmac + * implementation will get used instead. + * For those tokens not supporting HMAC at all, + * will need to return CKR_MECHANISM_INVALID. + */ + return CKR_OK; +} + +CK_RV hmac_sign_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + SIGN_VERIFY_CONTEXT *ctx = &sess->sign_ctx; + + if (!sess || !ctx) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (token_specific.t_hmac_sign_update != NULL) + return token_specific.t_hmac_sign_update(tokdata, sess, + in_data, in_data_len); + + TRACE_ERROR("hmac-update is not supported\n"); + + return CKR_MECHANISM_INVALID; +} + +CK_RV hmac_sign_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BYTE *signature, CK_ULONG *sig_len) +{ + SIGN_VERIFY_CONTEXT *ctx = &sess->sign_ctx; + + if (!sess || !ctx) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (token_specific.t_hmac_sign_final != NULL) + return token_specific.t_hmac_sign_final(tokdata, sess, + signature, sig_len); + + TRACE_ERROR("hmac-final is not supported\n"); + + return CKR_MECHANISM_INVALID; +} + +CK_RV hmac_verify_init(STDLL_TokData_t *tokdata, SESSION *sess, + CK_MECHANISM *mech, CK_OBJECT_HANDLE hkey) +{ + if (token_specific.t_hmac_verify_init != NULL) + return token_specific.t_hmac_verify_init(tokdata, sess, mech, hkey); + + /* Return ok with the intention that the local hmac + * implementation will get used instead. + * For those tokens not supporting HMAC at all, + * will need to return CKR_MECHANISM_INVALID. + */ + return CKR_OK; +} + +CK_RV hmac_verify_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + SIGN_VERIFY_CONTEXT *ctx = &sess->sign_ctx; + + if (!sess || !ctx) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (token_specific.t_hmac_verify_update != NULL) + return token_specific.t_hmac_verify_update(tokdata, sess, + in_data, in_data_len); + + TRACE_ERROR("hmac-update is not supported\n"); + + return CKR_MECHANISM_INVALID; +} + +CK_RV hmac_verify_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BYTE *signature, CK_ULONG sig_len) +{ + SIGN_VERIFY_CONTEXT *ctx = &sess->sign_ctx; + + if (!sess || !ctx) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (token_specific.t_hmac_verify_final != NULL) + return token_specific.t_hmac_verify_final(tokdata, sess, + signature, sig_len); + + TRACE_ERROR("hmac-final is not supported\n"); + + return CKR_MECHANISM_INVALID; +} + +CK_RV ckm_generic_secret_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl) +{ + if (token_specific.t_generic_secret_key_gen == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + return token_specific.t_generic_secret_key_gen(tokdata, tmpl); +} diff --git a/usr/lib/common/mech_ssl3.c b/usr/lib/common/mech_ssl3.c new file mode 100644 index 0000000..0254083 --- /dev/null +++ b/usr/lib/common/mech_ssl3.c @@ -0,0 +1,1983 @@ +/* + * 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: mech_ssl3.c +// +// Mechanisms for SSL v3 support +// + +#include +#include // for memcmp() et al +#include +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "trace.h" + +#include + +CK_RV ssl3_kmd_process_mac_keys(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, + CK_OBJECT_HANDLE *client_handle, + CK_BYTE *client_value, + CK_OBJECT_HANDLE *server_handle, + CK_BYTE *server_value, CK_ULONG mac_len); + +CK_RV ssl3_kmd_process_write_keys(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, + CK_KEY_TYPE keytype, + CK_OBJECT_HANDLE *client_handle, + CK_BYTE *client_value, + CK_OBJECT_HANDLE *server_handle, + CK_BYTE *server_value, CK_ULONG write_len); + +// The 'ssl3_mac_*' routines are used with the following mechanisms +// +// CKM_SSL3_MD5_MAC +// CKM_SSL3_SHA1_MAC +// + +// +// +CK_RV ssl3_mac_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE hash[SHA1_HASH_SIZE]; + CK_BYTE *key_data = NULL; + CK_BYTE inner[48], outer[48]; + DIGEST_CONTEXT digest_ctx; + CK_MECHANISM digest_mech; + CK_ULONG key_bytes, hash_len, mac_len; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + mac_len = *(CK_ULONG *) ctx->mech.pParameter; + + if (length_only == TRUE) { + *out_data_len = mac_len; + return CKR_OK; + } + + if (*out_data_len < mac_len) { + *out_data_len = mac_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + rc = template_attribute_find(key_obj->template, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + key_bytes = attr->ulValueLen; + key_data = attr->pValue; + + // unlike an HMAC operation, we don't XOR the key with the 0x36 or 0x5C. + // we just append 48 bytes to the key data + // + memset(inner, 0x36, 48); + memset(outer, 0x5C, 48); + + if (ctx->mech.mechanism == CKM_SSL3_MD5_MAC) + digest_mech.mechanism = CKM_MD5; + else + digest_mech.mechanism = CKM_SHA_1; + + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + + // inner hash + // + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Init failed.\n"); + goto done; + } + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, key_data, + key_bytes); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest update failed.\n"); + goto done; + } + if (ctx->mech.mechanism == CKM_SSL3_MD5_MAC) { + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, inner, 48); + } else { + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, inner, 40); + } + if (rc != CKR_OK) { + TRACE_DEVEL("Digest update failed.\n"); + goto done; + } + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, in_data, + in_data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest update failed.\n"); + goto done; + } + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &digest_ctx, hash, + &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest final failed.\n"); + goto done; + } + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + + + // outer hash + // + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Init failed.\n"); + goto done; + } + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, key_data, + key_bytes); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest update failed.\n"); + goto done; + } + if (ctx->mech.mechanism == CKM_SSL3_MD5_MAC) + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, outer, 48); + else + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, outer, 40); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest update failed.\n"); + goto done; + } + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, hash, hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest update failed.\n"); + goto done; + } + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &digest_ctx, hash, + &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest final failed.\n"); + goto done; + } + memcpy(out_data, hash, mac_len); + *out_data_len = mac_len; + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +// +// +CK_RV ssl3_mac_sign_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *key_data = NULL; + SSL3_MAC_CONTEXT *context = NULL; + + CK_BYTE inner[48]; + CK_MECHANISM digest_mech; + CK_ULONG key_bytes; + CK_RV rc; + + + if (!sess || !ctx) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (SSL3_MAC_CONTEXT *) ctx->context; + + if (context->flag == FALSE) { + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + rc = template_attribute_find(key_obj->template, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + key_bytes = attr->ulValueLen; + key_data = attr->pValue; + + // unlike an HMAC operation, we don't XOR the key with the 0x36 or 0x5C. + // we just append 48 bytes to the key data + // + memset(inner, 0x36, 48); + + if (ctx->mech.mechanism == CKM_SSL3_MD5_MAC) + digest_mech.mechanism = CKM_MD5; + else + digest_mech.mechanism = CKM_SHA_1; + + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + // inner hash + // + rc = digest_mgr_init(tokdata, sess, &context->hash_context, + &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Init failed.\n"); + goto done; + } + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, + key_data, key_bytes); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest update failed.\n"); + goto done; + } + if (ctx->mech.mechanism == CKM_SSL3_MD5_MAC) + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, + inner, 48); + else + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, + inner, 40); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest update failed.\n"); + goto done; + } + context->flag = TRUE; + } + + + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, + in_data, in_data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest update failed.\n"); + goto done; + } + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +// +// +CK_RV ssl3_mac_sign_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *key_data = NULL; + CK_BYTE hash[SHA1_HASH_SIZE]; + SSL3_MAC_CONTEXT *context = NULL; + + CK_BYTE outer[48]; + CK_MECHANISM digest_mech; + CK_ULONG key_bytes, hash_len, mac_len; + CK_RV rc; + + + if (!sess || !ctx || !out_data_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + mac_len = *(CK_ULONG *) ctx->mech.pParameter; + + if (length_only == TRUE) { + *out_data_len = mac_len; + return CKR_OK; + } + + if (*out_data_len < mac_len) { + *out_data_len = mac_len; + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + return CKR_BUFFER_TOO_SMALL; + } + + context = (SSL3_MAC_CONTEXT *) ctx->context; + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + rc = template_attribute_find(key_obj->template, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + key_bytes = attr->ulValueLen; + key_data = attr->pValue; + + // finish the inner hash + // + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &context->hash_context, + hash, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Final failed.\n"); + goto done; + } + // now, do the outer hash + // + memset(context, 0x0, sizeof(SSL3_MAC_CONTEXT)); + + memset(outer, 0x5C, 48); + + if (ctx->mech.mechanism == CKM_SSL3_MD5_MAC) + digest_mech.mechanism = CKM_MD5; + else + digest_mech.mechanism = CKM_SHA_1; + + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = digest_mgr_init(tokdata, sess, &context->hash_context, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Init failed.\n"); + goto done; + } + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, + key_data, key_bytes); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Update failed.\n"); + goto done; + } + if (ctx->mech.mechanism == CKM_SSL3_MD5_MAC) + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, + outer, 48); + else + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, + outer, 40); + + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Update failed.\n"); + goto done; + } + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, hash, + hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Update failed.\n"); + goto done; + } + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &context->hash_context, + hash, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Final failed.\n"); + goto done; + } + memcpy(out_data, hash, mac_len); + *out_data_len = mac_len; + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + + +// This routine could replace the HMAC verification routines +// +CK_RV ssl3_mac_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) +{ + CK_BYTE mac[SHA1_HASH_SIZE]; + SIGN_VERIFY_CONTEXT mac_ctx; + CK_ULONG mac_len, len; + CK_RV rc; + + if (!sess || !ctx || !in_data || !signature) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + mac_len = *(CK_ULONG *) ctx->mech.pParameter; + + memset(&mac_ctx, 0, sizeof(SIGN_VERIFY_CONTEXT)); + + rc = sign_mgr_init(tokdata, sess, &mac_ctx, &ctx->mech, FALSE, ctx->key); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign Init failed.\n"); + goto error; + } + len = sizeof(mac); + rc = sign_mgr_sign(tokdata, sess, FALSE, &mac_ctx, + in_data, in_data_len, mac, &len); + if (rc != CKR_OK) { + TRACE_DEVEL("Sign failed.\n"); + goto error; + } + if ((len != mac_len) || (len != sig_len)) { + rc = CKR_SIGNATURE_LEN_RANGE; + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); + goto error; + } + + if (CRYPTO_memcmp(mac, signature, mac_len) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + rc = CKR_SIGNATURE_INVALID; + } +error: + sign_mgr_cleanup(&mac_ctx); + + return rc; +} + + +// +// +CK_RV ssl3_mac_verify_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *key_data = NULL; + SSL3_MAC_CONTEXT *context = NULL; + + CK_BYTE inner[48]; + CK_MECHANISM digest_mech; + CK_ULONG key_bytes; + CK_RV rc; + + + if (!sess || !ctx) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + context = (SSL3_MAC_CONTEXT *) ctx->context; + + if (context->flag == FALSE) { + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + rc = template_attribute_find(key_obj->template, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + key_bytes = attr->ulValueLen; + key_data = attr->pValue; + + // unlike an HMAC operation, we don't XOR the key with the 0x36 or 0x5C. + // we just append 48 bytes to the key data + // + memset(inner, 0x36, 48); + + if (ctx->mech.mechanism == CKM_SSL3_MD5_MAC) + digest_mech.mechanism = CKM_MD5; + else + digest_mech.mechanism = CKM_SHA_1; + + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + // inner hash + // + rc = digest_mgr_init(tokdata, sess, &context->hash_context, + &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Init failed.\n"); + goto done; + } + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, + key_data, key_bytes); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Update failed.\n"); + goto done; + } + if (ctx->mech.mechanism == CKM_SSL3_MD5_MAC) + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, + inner, 48); + else + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, + inner, 40); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Update failed.\n"); + goto done; + } + context->flag = TRUE; + } + + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, + in_data, in_data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Update failed.\n"); + goto done; + } + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +// +// +CK_RV ssl3_mac_verify_final(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG sig_len) +{ + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *key_data = NULL; + SSL3_MAC_CONTEXT *context = NULL; + CK_BYTE hash[SHA1_HASH_SIZE]; + + CK_BYTE outer[48]; + CK_MECHANISM digest_mech; + CK_ULONG key_bytes, hash_len, mac_len; + CK_RV rc; + + + if (!sess || !ctx || !signature) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + mac_len = *(CK_ULONG *) ctx->mech.pParameter; + + context = (SSL3_MAC_CONTEXT *) ctx->context; + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + rc = template_attribute_find(key_obj->template, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + key_bytes = attr->ulValueLen; + key_data = attr->pValue; + + // finish the inner hash + // + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &context->hash_context, + hash, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Final failed.\n"); + goto done; + } + // now, do the outer hash + // + memset(context, 0x0, sizeof(SSL3_MAC_CONTEXT)); + + memset(outer, 0x5C, 48); + + if (ctx->mech.mechanism == CKM_SSL3_MD5_MAC) + digest_mech.mechanism = CKM_MD5; + else + digest_mech.mechanism = CKM_SHA_1; + + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = digest_mgr_init(tokdata, sess, &context->hash_context, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Init failed.\n"); + goto done; + } + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, + key_data, key_bytes); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Update failed.\n"); + goto done; + } + if (ctx->mech.mechanism == CKM_SSL3_MD5_MAC) + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, + outer, 48); + else + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, + outer, 40); + + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Update failed.\n"); + goto done; + } + rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context, hash, + hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Update failed.\n"); + goto done; + } + hash_len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &context->hash_context, + hash, &hash_len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Final failed.\n"); + goto done; + } + if ((mac_len != sig_len) || (mac_len > hash_len)) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + rc = CKR_SIGNATURE_INVALID; + } else if (CRYPTO_memcmp(signature, hash, sig_len) != 0) { + rc = CKR_SIGNATURE_INVALID; + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + } + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +// +// +CK_RV ckm_ssl3_pre_master_key_gen(STDLL_TokData_t *tokdata, + TEMPLATE *tmpl, CK_MECHANISM *mech) +{ + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *value_len_attr = NULL; + CK_ATTRIBUTE *key_type_attr = NULL; + CK_ATTRIBUTE *class_attr = NULL; + CK_ATTRIBUTE *local_attr = NULL; + CK_ATTRIBUTE *derive_attr = NULL; + CK_VERSION *version = NULL; + CK_BYTE key[48]; + CK_ULONG rc; + + + rc = rng_generate(tokdata, key, 48); + if (rc != CKR_OK) { + TRACE_DEVEL("rng_generate failed.\n"); + return rc; + } + value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + 48); + value_len_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG)); + key_type_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); + class_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_OBJECT_CLASS)); + local_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + derive_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); + + if (!value_attr || !value_len_attr || !key_type_attr || + !class_attr || !local_attr || !derive_attr) { + if (value_attr) + free(value_attr); + if (value_len_attr) + free(value_len_attr); + if (key_type_attr) + free(key_type_attr); + if (class_attr) + free(class_attr); + if (local_attr) + free(local_attr); + if (derive_attr) + free(derive_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + version = (CK_VERSION *) mech->pParameter; + key[0] = version->major; + key[1] = version->minor; + + value_attr->type = CKA_VALUE; + value_attr->ulValueLen = 48; + value_attr->pValue = (CK_BYTE *) value_attr + sizeof(CK_ATTRIBUTE); + memcpy(value_attr->pValue, key, 48); + + value_len_attr->type = CKA_VALUE_LEN; + value_len_attr->ulValueLen = sizeof(CK_ULONG); + value_len_attr->pValue = (CK_BYTE *) value_len_attr + sizeof(CK_ATTRIBUTE); + *(CK_ULONG *) value_len_attr->pValue = 48; + + key_type_attr->type = CKA_KEY_TYPE; + key_type_attr->ulValueLen = sizeof(CK_KEY_TYPE); + key_type_attr->pValue = (CK_BYTE *) key_type_attr + sizeof(CK_ATTRIBUTE); + *(CK_ATTRIBUTE_TYPE *) key_type_attr->pValue = CKK_GENERIC_SECRET; + + class_attr->type = CKA_CLASS; + class_attr->ulValueLen = sizeof(CK_OBJECT_CLASS); + class_attr->pValue = (CK_BYTE *) class_attr + sizeof(CK_ATTRIBUTE); + *(CK_OBJECT_CLASS *) class_attr->pValue = CKO_SECRET_KEY; + + local_attr->type = CKA_LOCAL; + local_attr->ulValueLen = sizeof(CK_BBOOL); + local_attr->pValue = (CK_BYTE *) local_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) local_attr->pValue = TRUE; + + derive_attr->type = CKA_DERIVE; + derive_attr->ulValueLen = sizeof(CK_BBOOL); + derive_attr->pValue = (CK_BYTE *) derive_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) derive_attr->pValue = TRUE; + + template_update_attribute(tmpl, value_attr); + template_update_attribute(tmpl, value_len_attr); + template_update_attribute(tmpl, key_type_attr); + template_update_attribute(tmpl, class_attr); + template_update_attribute(tmpl, local_attr); + template_update_attribute(tmpl, derive_attr); + + return CKR_OK; +} + + +// +// +static CK_RV ssl3_sha_then_md5(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BYTE *secret, + CK_BYTE *firstRandom, + CK_ULONG firstRandomLen, + CK_BYTE *secondRandom, + CK_ULONG secondRandomLen, + CK_BYTE *variableData, + CK_ULONG variableDataLen, CK_BYTE *outBuff) +{ + DIGEST_CONTEXT digest_ctx; + CK_MECHANISM digest_mech; + CK_BYTE hash[SHA1_HASH_SIZE]; + CK_ULONG len; + CK_RV rc; + + // SHA(variableData + secret + firstRandom + secondRandom) + // + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + digest_mech.mechanism = CKM_SHA_1; + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Init failed.\n"); + return rc; + } + rc = digest_mgr_digest_update(tokdata, sess, + &digest_ctx, variableData, variableDataLen); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Update failed.\n"); + return rc; + } + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, secret, 48); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Update failed.\n"); + return rc; + } + rc = digest_mgr_digest_update(tokdata, sess, + &digest_ctx, firstRandom, firstRandomLen); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Update failed.\n"); + return rc; + } + rc = digest_mgr_digest_update(tokdata, sess, + &digest_ctx, secondRandom, secondRandomLen); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Update failed.\n"); + return rc; + } + len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &digest_ctx, hash, &len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Final failed.\n"); + return rc; + } + // MD5(secret + SHA(...)) + // + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + digest_mech.mechanism = CKM_MD5; + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Init failed.\n"); + return rc; + } + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, secret, 48); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Update failed.\n"); + return rc; + } + rc = digest_mgr_digest_update(tokdata, sess, &digest_ctx, hash, len); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Update failed.\n"); + return rc; + } + len = sizeof(hash); + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &digest_ctx, hash, &len); + + if (rc == CKR_OK) + memcpy(outBuff, hash, len); + else + TRACE_DEVEL("Digest Final failed.\n"); + + return rc; +} + +// +// +static CK_RV ssl3_md5_only(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BYTE *firstString, + CK_ULONG firstStringLen, + CK_BYTE *secondString, + CK_ULONG secondStringLen, + CK_BYTE *thirdString, + CK_ULONG thirdStringLen, CK_BYTE *outBuff) +{ + DIGEST_CONTEXT digest_ctx; + CK_MECHANISM digest_mech; + CK_ULONG len; + CK_RV rc; + + // If firstString is not NULL, + // + // MD5(firstString + secondString + thirdString) + // + // If firstString is NULL + // + // MD5(secondString + thirdString) + // + memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT)); + digest_mech.mechanism = CKM_MD5; + digest_mech.ulParameterLen = 0; + digest_mech.pParameter = NULL; + + rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Init failed.\n"); + return rc; + } + if (firstString != NULL) { + rc = digest_mgr_digest_update(tokdata, sess, + &digest_ctx, firstString, firstStringLen); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Update failed.\n"); + return rc; + } + } + + rc = digest_mgr_digest_update(tokdata, sess, + &digest_ctx, secondString, secondStringLen); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Update failed.\n"); + return rc; + } + rc = digest_mgr_digest_update(tokdata, sess, + &digest_ctx, thirdString, thirdStringLen); + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Update failed.\n"); + return rc; + } + len = MD5_HASH_SIZE; + rc = digest_mgr_digest_final(tokdata, sess, FALSE, &digest_ctx, outBuff, + &len); + + if (rc != CKR_OK) { + TRACE_DEVEL("Digest Final failed.\n"); + } + + return rc; +} + +// +// +CK_RV ssl3_master_key_derive(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_MECHANISM *mech, + CK_OBJECT_HANDLE base_key, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, CK_OBJECT_HANDLE *handle) +{ + OBJECT *derived_key_obj = NULL; + OBJECT *base_key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *value_len_attr = NULL; + CK_ATTRIBUTE *always_sens_attr = NULL; + CK_ATTRIBUTE *extract_attr = NULL; + CK_BYTE *base_key_value = NULL; + CK_BYTE key_data[48]; + CK_ULONG i, base_key_len; + CK_BBOOL flag; + CK_RV rc; + + CK_SSL3_MASTER_KEY_DERIVE_PARAMS *params = NULL; + CK_SSL3_RANDOM_DATA *random_data = NULL; + + + if (!sess || !mech) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + params = (CK_SSL3_MASTER_KEY_DERIVE_PARAMS *) mech->pParameter; + + rc = object_mgr_find_in_map1(tokdata, base_key, &base_key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + rc = template_attribute_find(base_key_obj->template, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto error; + } else { + base_key_len = attr->ulValueLen; + base_key_value = attr->pValue; + + if (base_key_len != 48) { + TRACE_ERROR("The base key's length is not 48.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto error; + } + } + + + // this mechanism implies the following attributes: + // CKA_CLASS : CKO_SECRET_KEY + // CKA_KEY_TYPE : CKK_GENERIC_SECRET + // CKA_VALUE_LEN : 48 + // but we need to make sure the caller didn't specify any + // wacky values. it would have been better if Cryptoki had forbidden + // these attributes from appearing in the template + // + for (i = 0, attr = pTemplate; i < ulCount; i++, attr++) { + CK_OBJECT_CLASS class; + CK_KEY_TYPE keytype; + CK_ULONG value_len; + + if (attr->type == CKA_CLASS) { + class = *(CK_OBJECT_CLASS *) attr->pValue; + if (class != CKO_SECRET_KEY) { + TRACE_ERROR("This operation requires a secret key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto error; + } + } else if (attr->type == CKA_KEY_TYPE) { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_GENERIC_SECRET) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto error; + } + } else if (attr->type == CKA_VALUE_LEN) { + value_len = *(CK_ULONG *) attr->pValue; + if (value_len != 48) { + TRACE_ERROR("The derived key's length is not 48.\n"); + rc = CKR_TEMPLATE_INCONSISTENT; + goto error; + } + } + } + + memset(key_data, 0x0, sizeof(key_data)); + + random_data = (CK_SSL3_RANDOM_DATA *) (¶ms->RandomInfo); + + // derive the master key data + // + rc = ssl3_sha_then_md5(tokdata, sess, + base_key_value, + random_data->pClientRandom, + random_data->ulClientRandomLen, + random_data->pServerRandom, + random_data->ulServerRandomLen, + (unsigned char *) "A", 1, key_data); + + if (rc != CKR_OK) { + TRACE_DEVEL("ssl3_sha_then_md5 failed.\n"); + goto error; + } + rc = ssl3_sha_then_md5(tokdata, sess, + base_key_value, + random_data->pClientRandom, + random_data->ulClientRandomLen, + random_data->pServerRandom, + random_data->ulServerRandomLen, + (unsigned char *) "BB", 2, &key_data[16]); + if (rc != CKR_OK) { + TRACE_DEVEL("ssl3_sha_then_md5 failed.\n"); + goto error; + } + rc = ssl3_sha_then_md5(tokdata, sess, + base_key_value, + random_data->pClientRandom, + random_data->ulClientRandomLen, + random_data->pServerRandom, + random_data->ulServerRandomLen, + (unsigned char *) "CCC", 3, &key_data[32]); + if (rc != CKR_OK) { + TRACE_DEVEL("ssl3_sha_then_md5 failed.\n"); + goto error; + } + // build the key skeleton + // + rc = object_mgr_create_skel(tokdata, sess, + pTemplate, ulCount, + MODE_DERIVE, + CKO_SECRET_KEY, CKK_GENERIC_SECRET, + &derived_key_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("Object Mgr Create Skeleton failed.\n"); + goto error; + } + + rc = build_attribute(CKA_VALUE, key_data, 48, &value_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to build CKA_VALUE attribute.\n"); + goto error; + } + rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE *) & base_key_len, + sizeof(CK_ULONG), &value_len_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to build CKA_VALUE_LEN attribute.\n"); + goto error; + } + // + // now, adjust the CKA_ALWAYS_SENSITIVE and CKA_NEVER_EXTRACTABLE + // attributes based on the corresponding values from the base key + // + + // if base key has ALWAYS_SENSITIVE = FALSE, then new key does too + // otherwise, the value of CKA_ALWAYS_SENSITIVE = CKA_SENSITIVE + // + rc = template_attribute_find(base_key_obj->template, CKA_ALWAYS_SENSITIVE, + &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_ALWAYS_SENSITIVE in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto error; + } + + flag = *(CK_BBOOL *) attr->pValue; + if (flag == TRUE) { + rc = template_attribute_find(derived_key_obj->template, CKA_SENSITIVE, + &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_SENSITIVE in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto error; + } + flag = *(CK_BBOOL *) attr->pValue; + } + + rc = build_attribute(CKA_ALWAYS_SENSITIVE, &flag, sizeof(CK_BBOOL), + &always_sens_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to build CKA_ALWAYS_SENSITIVE attribute.\n"); + goto error; + } + // if base key has NEVER_EXTRACTABLE = FASE, the new key does too + // otherwise, the value of CKA_NEVER_EXTRACTABLE = !CKA_EXTRACTABLE + // + rc = template_attribute_find(base_key_obj->template, CKA_NEVER_EXTRACTABLE, + &attr); + if (rc == FALSE) { + TRACE_DEVEL("Failed to build CKA_NEVER_EXTRACTABLE attribute.\n"); + rc = CKR_FUNCTION_FAILED; + goto error; + } + + flag = *(CK_BBOOL *) attr->pValue; + if (flag == TRUE) { + rc = template_attribute_find(derived_key_obj->template, CKA_EXTRACTABLE, + &attr); + if (rc == FALSE) { + TRACE_DEVEL("Failed to build CKA_EXTRACTABLE attribute.\n"); + rc = CKR_FUNCTION_FAILED; + goto error; + } + + flag = *(CK_BBOOL *) attr->pValue; + + flag = (~flag) & 0x1; + } + + rc = build_attribute(CKA_NEVER_EXTRACTABLE, &flag, sizeof(CK_BBOOL), + &extract_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to build CKA_NEVER_EXTRACTABLE attribute.\n"); + goto error; + } + template_update_attribute(derived_key_obj->template, value_attr); + template_update_attribute(derived_key_obj->template, value_len_attr); + template_update_attribute(derived_key_obj->template, always_sens_attr); + template_update_attribute(derived_key_obj->template, extract_attr); + + // at this point, the derived key is fully constructed...assign an + // object handle and store the key + // + rc = object_mgr_create_final(tokdata, sess, derived_key_obj, handle); + if (rc != CKR_OK) { + TRACE_DEVEL("Object Mgr create final failed.\n"); + object_free(derived_key_obj); + derived_key_obj = NULL; + object_put(tokdata, base_key_obj, TRUE); + base_key_obj = NULL; + return rc; // do NOT goto error + } + // should we destroy the base key? SSL3 says yes but that might + // occur in a separate call to C_DestroyObject + // + + object_put(tokdata, base_key_obj, TRUE); + base_key_obj = NULL; + + return CKR_OK; + +error: + if (value_attr) + free(value_attr); + if (value_len_attr) + free(value_len_attr); + if (always_sens_attr) + free(always_sens_attr); + if (extract_attr) + free(extract_attr); + if (derived_key_obj) + object_free(derived_key_obj); + + object_put(tokdata, base_key_obj, TRUE); + base_key_obj = NULL; + + return rc; +} + + +// +// +CK_RV ssl3_key_and_mac_derive(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_MECHANISM *mech, + CK_OBJECT_HANDLE base_key, + CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount) +{ + OBJECT *base_key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + + CK_BYTE *client_MAC_key_value = NULL; + CK_BYTE *server_MAC_key_value = NULL; + CK_BYTE *client_write_key_value = NULL; + CK_BYTE *server_write_key_value = NULL; + CK_BYTE *client_IV = NULL; + CK_BYTE *server_IV = NULL; + CK_KEY_TYPE keytype = 0xFFFFFFFF; + CK_BYTE variable_data[26]; + CK_BYTE key_block[(16 * 26) + (4 * 16)]; + CK_ULONG i, key_material_loop_count; + CK_ULONG iv_len = 0, MAC_len, write_len; + CK_RV rc; + + CK_BYTE *base_key_value = NULL; + CK_BBOOL base_sensitive; + CK_BBOOL base_always_sensitive; + CK_BBOOL base_extractable; + CK_BBOOL base_never_extractable; + + CK_OBJECT_HANDLE client_MAC_handle = 0; + CK_OBJECT_HANDLE server_MAC_handle = 0; + CK_OBJECT_HANDLE client_write_handle = 0; + CK_OBJECT_HANDLE server_write_handle = 0; + + CK_SSL3_KEY_MAT_PARAMS *params = NULL; + + ATTRIBUTE_PARSE_LIST base_attrs[] = { + {CKA_SENSITIVE, &base_sensitive, sizeof(CK_BBOOL), FALSE}, + {CKA_EXTRACTABLE, &base_extractable, sizeof(CK_BBOOL), FALSE}, + {CKA_ALWAYS_SENSITIVE, &base_always_sensitive, sizeof(CK_BBOOL), FALSE}, + {CKA_NEVER_EXTRACTABLE, + &base_never_extractable, sizeof(CK_BBOOL), FALSE}, + }; + + + if (!sess || !mech) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + params = (CK_SSL3_KEY_MAT_PARAMS *) mech->pParameter; + + rc = object_mgr_find_in_map1(tokdata, base_key, &base_key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + rc = template_attribute_find(base_key_obj->template, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto error; + } + + base_key_value = attr->pValue; + + template_attribute_find_multiple(base_key_obj->template, base_attrs, 4); + + for (i = 0; i < 4; i++) { + if (base_attrs[i].found == FALSE) { + TRACE_ERROR("Could not find attribute in the template\n"); + rc = CKR_FUNCTION_FAILED; + goto error; + } + } + + // The SSL3 spec says the IVs are 16 bytes long in the exportable case. + // For now, we'll barf if someone asks for an exportable output and asks + // for more than 128 bits of IV... + // + if (params->bIsExport != FALSE && params->ulIVSizeInBits > 128) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto error; + } + // the template must specify the key type for the client and server keys + // + // also, CKA_SENSITIVE, CKA_ALWAYS_SENSITIVE, CKA_EXTRACTABLE and + // CKA_NEVER_EXTRACTABLE, if present, are not allowed to differ from + // the base key. We also check for stupid stuff. + // + for (i = 0, attr = pTemplate; i < ulCount; i++, attr++) { + CK_BBOOL tmp; + + if (attr->type == CKA_KEY_TYPE) { + keytype = *(CK_KEY_TYPE *) attr->pValue; + } else if (attr->type == CKA_SENSITIVE) { + tmp = *(CK_BBOOL *) attr->pValue; + if (tmp != base_sensitive) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + rc = CKR_TEMPLATE_INCONSISTENT; + goto error; + } + } else if (attr->type == CKA_ALWAYS_SENSITIVE) { + tmp = *(CK_BBOOL *) attr->pValue; + if (tmp != base_always_sensitive) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + rc = CKR_TEMPLATE_INCONSISTENT; + goto error; + } + } else if (attr->type == CKA_EXTRACTABLE) { + tmp = *(CK_BBOOL *) attr->pValue; + if (tmp != base_extractable) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + rc = CKR_TEMPLATE_INCONSISTENT; + goto error; + } + } else if (attr->type == CKA_NEVER_EXTRACTABLE) { + tmp = *(CK_BBOOL *) attr->pValue; + if (tmp != base_never_extractable) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + rc = CKR_TEMPLATE_INCONSISTENT; + goto error; + } + } else if (attr->type == CKA_CLASS) { + CK_OBJECT_CLASS cl = *(CK_OBJECT_CLASS *) attr->pValue; + if (cl != CKO_SECRET_KEY) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + rc = CKR_TEMPLATE_INCONSISTENT; + goto error; + } + } + } + + // a key type must be specified for the client and server write keys + // + if (keytype == 0xFFFFFFFF) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + rc = CKR_TEMPLATE_INCOMPLETE; + goto error; + } + // figure out how much key material we need to generate + // + key_material_loop_count = 2 * ((params->ulMacSizeInBits + 7) / 8) + + 2 * ((params->ulKeySizeInBits + 7) / 8); + + if (params->bIsExport == FALSE) + key_material_loop_count += 2 * ((params->ulIVSizeInBits + 7) / 8); + + // we stop at 'ZZZZ....' presumably this is enough for all cases? + // + if (key_material_loop_count > 26 * 16) { + TRACE_DEVEL("key_material_loop_count is too big.\n"); + rc = CKR_FUNCTION_FAILED; + goto error; + } + key_material_loop_count = (key_material_loop_count + 15) / 16; + + // generate the key material + // + for (i = 0; i < key_material_loop_count; i++) { + memset(variable_data, ('A' + i), i + 1); + + rc = ssl3_sha_then_md5(tokdata, sess, + base_key_value, + params->RandomInfo.pServerRandom, + params->RandomInfo.ulServerRandomLen, + params->RandomInfo.pClientRandom, + params->RandomInfo.ulClientRandomLen, + variable_data, i + 1, &(key_block[i * 16])); + if (rc != CKR_OK) { + TRACE_DEVEL("ssl3_sha_then_md5 failed.\n"); + goto error; + } + } + + // Break key material into pieces + // + MAC_len = (params->ulMacSizeInBits + 7) / 8; + write_len = (params->ulKeySizeInBits + 7) / 8; // check this + + client_MAC_key_value = key_block; + server_MAC_key_value = client_MAC_key_value + MAC_len; + + client_write_key_value = server_MAC_key_value + MAC_len; + server_write_key_value = + client_write_key_value + (params->ulKeySizeInBits + 7) / 8; + + if (params->ulIVSizeInBits != 0) { + iv_len = (params->ulIVSizeInBits + 7) / 8; + client_IV = server_write_key_value + write_len; + server_IV = client_IV + iv_len; + } + // Exportable ciphers require additional processing + // + if (params->bIsExport == TRUE) { + rc = ssl3_md5_only(tokdata, sess, + client_write_key_value, + (params->ulKeySizeInBits + 7) / 8, + params->RandomInfo.pClientRandom, + params->RandomInfo.ulClientRandomLen, + params->RandomInfo.pServerRandom, + params->RandomInfo.ulServerRandomLen, + &(key_block[16 * 26])); + if (rc != CKR_OK) { + TRACE_DEVEL("ssl3_md5_only failed.\n"); + goto error; + } + client_write_key_value = &(key_block[16 * 26]); + + rc = ssl3_md5_only(tokdata, sess, + server_write_key_value, + (params->ulKeySizeInBits + 7) / 8, + params->RandomInfo.pServerRandom, + params->RandomInfo.ulServerRandomLen, + params->RandomInfo.pClientRandom, + params->RandomInfo.ulClientRandomLen, + &(key_block[16 * 26 + 16])); + if (rc != CKR_OK) { + TRACE_DEVEL("ssl3_md5_only failed.\n"); + goto error; + } + server_write_key_value = &(key_block[16 * 26 + 16]); + + if (params->ulIVSizeInBits != 0) { + rc = ssl3_md5_only(tokdata, sess, + NULL, + 0, + params->RandomInfo.pClientRandom, + params->RandomInfo.ulClientRandomLen, + params->RandomInfo.pServerRandom, + params->RandomInfo.ulServerRandomLen, + &(key_block[16 * 26 + 2 * 16])); + if (rc != CKR_OK) { + TRACE_DEVEL("ssl3_md5_only failed.\n"); + goto error; + } + client_IV = &(key_block[16 * 26 + 2 * 16]); + + rc = ssl3_md5_only(tokdata, sess, + NULL, + 0, + params->RandomInfo.pServerRandom, + params->RandomInfo.ulServerRandomLen, + params->RandomInfo.pClientRandom, + params->RandomInfo.ulClientRandomLen, + &(key_block[16 * 26 + 3 * 16])); + if (rc != CKR_OK) { + TRACE_DEVEL("ssl3_md5_only failed.\n"); + goto error; + } + server_IV = &(key_block[16 * 26 + 3 * 16]); + } + } + + + rc = ssl3_kmd_process_mac_keys(tokdata, sess, pTemplate, ulCount, + &client_MAC_handle, client_MAC_key_value, + &server_MAC_handle, server_MAC_key_value, + MAC_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ssl3_kmd_process_mac_keys failed.\n"); + goto error; + } + + rc = ssl3_kmd_process_write_keys(tokdata, sess, pTemplate, ulCount, keytype, + &client_write_handle, + client_write_key_value, + &server_write_handle, + server_write_key_value, write_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ssl3_kmd_process_write_keys failed.\n"); + goto error; + } + + params->pReturnedKeyMaterial->hClientMacSecret = client_MAC_handle; + params->pReturnedKeyMaterial->hServerMacSecret = server_MAC_handle; + params->pReturnedKeyMaterial->hClientKey = client_write_handle; + params->pReturnedKeyMaterial->hServerKey = server_write_handle; + + if (params->ulIVSizeInBits != 0) { + if (params->pReturnedKeyMaterial->pIVClient) + memcpy(params->pReturnedKeyMaterial->pIVClient, client_IV, iv_len); + + if (params->pReturnedKeyMaterial->pIVServer) + memcpy(params->pReturnedKeyMaterial->pIVServer, server_IV, iv_len); + +#if 0 + CK_BYTE *p1, *p2; + + p1 = (CK_BYTE *) malloc(iv_len); + p2 = (CK_BYTE *) malloc(iv_len); + + if (!p1 || !p2) { + rc = CKR_HOST_MEMORY; + goto error; + } + + memcpy(p1, client_IV, iv_len); + memcpy(p2, server_IV, iv_len); + + params->pReturnedKeyMaterial->pIVClient = p1; + params->pReturnedKeyMaterial->pIVServer = p2; +#endif + } + +error: + object_put(tokdata, base_key_obj, TRUE); + base_key_obj = NULL; + + return rc; +} + + +CK_RV ssl3_kmd_process_mac_keys(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, + CK_OBJECT_HANDLE *client_handle, + CK_BYTE *client_value, + CK_OBJECT_HANDLE *server_handle, + CK_BYTE *server_value, CK_ULONG mac_len) +{ + OBJECT *client_obj = NULL; + OBJECT *server_obj = NULL; + CK_ATTRIBUTE *client_val_attr = NULL; + CK_ATTRIBUTE *client_val_len_attr = NULL; + CK_ATTRIBUTE *server_val_attr = NULL; + CK_ATTRIBUTE *server_val_len_attr = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_ATTRIBUTE *new_attrs = NULL; + CK_ULONG i, cnt; + CK_ULONG true_vals[] = { CKA_SIGN, CKA_VERIFY, CKA_DERIVE }; + CK_ULONG false_vals[] = { CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP }; + CK_RV rc = 0; + + + // for the MAC keys, we want the following default values: + // CKA_SIGN, CKA_VERIFY, CKA_DERIVE = TRUE + // CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP = FALSE + // + // attributes are added in sequential order so we stick the defaults + // at the beginning so that they may be overridden by caller-specified + // values. + // + new_attrs = (CK_ATTRIBUTE *) malloc((ulCount + 7) * (sizeof(CK_ATTRIBUTE))); + if (!new_attrs) + goto error; + + // we have to treat these attributes a bit differently. normally, we + // allocate the CK_ATTRIBUTE and the value with a single malloc and just + // point the pValue member to the extra space. we can't do that here + // because we have to "emulate" the way attributes are passed in from the + // cryptoki application...as an array of CK_ATTRIBUTEs with no extra space + // (that is, pValue must be allocated separately). + // + attr = new_attrs; + for (i = 0; i < sizeof(true_vals) / sizeof(CK_ULONG); i++, attr++) { + attr->type = true_vals[i]; + attr->ulValueLen = sizeof(CK_BBOOL); + attr->pValue = (CK_BBOOL *) malloc(sizeof(CK_BBOOL)); + if (!attr->pValue) { + rc = CKR_HOST_MEMORY; + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto error; + } + *(CK_BBOOL *) attr->pValue = TRUE; + } + + for (i = 0; i < sizeof(false_vals) / sizeof(CK_ULONG); i++, attr++) { + attr->type = false_vals[i]; + attr->ulValueLen = sizeof(CK_BBOOL); + attr->pValue = (CK_BBOOL *) malloc(sizeof(CK_BBOOL)); + if (!attr->pValue) { + rc = CKR_HOST_MEMORY; + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto error; + } + *(CK_BBOOL *) attr->pValue = FALSE; + } + + for (i = 0, cnt = 0; i < ulCount; i++) { + if (pTemplate[i].type != CKA_KEY_TYPE && + pTemplate[i].type != CKA_VALUE && + pTemplate[i].type != CKA_VALUE_LEN) { + attr->type = pTemplate[i].type; + attr->ulValueLen = pTemplate[i].ulValueLen; + attr->pValue = (char *) malloc(attr->ulValueLen); + if (!attr->pValue) { + rc = CKR_HOST_MEMORY; + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto error; + } + memcpy(attr->pValue, pTemplate[i].pValue, attr->ulValueLen); + cnt++; + attr++; + } + } + + ulCount = 7 + cnt; + + // create the key skeletons + // + rc = object_mgr_create_skel(tokdata, sess, + new_attrs, ulCount, + MODE_DERIVE, + CKO_SECRET_KEY, + CKK_GENERIC_SECRET, &client_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("Object Mgr Create Skeleton failed.\n"); + goto error; + } + rc = object_mgr_create_skel(tokdata, sess, + new_attrs, ulCount, + MODE_DERIVE, + CKO_SECRET_KEY, + CKK_GENERIC_SECRET, &server_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("Object Mgr Create Skeleton failed.\n"); + goto error; + } + for (i = 0; i < ulCount; i++) + if (new_attrs[i].pValue) + free(new_attrs[i].pValue); + + free(new_attrs); + new_attrs = NULL; + + rc = build_attribute(CKA_VALUE, client_value, mac_len, &client_val_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to build CKA_VALUE attribute.\n"); + goto error; + } + rc = build_attribute(CKA_VALUE, server_value, mac_len, &server_val_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to build CKA_VALUE attribute.\n"); + goto error; + } + rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE *) & mac_len, sizeof(CK_ULONG), + &client_val_len_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to build CKA_VALUE_LEN attribute.\n"); + goto error; + } + rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE *) & mac_len, sizeof(CK_ULONG), + &server_val_len_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to build CKA_VALUE_LEN attribute.\n"); + goto error; + } + template_update_attribute(client_obj->template, client_val_attr); + template_update_attribute(client_obj->template, client_val_len_attr); + // the object owns the attributes now... + client_val_attr = NULL; + client_val_len_attr = NULL; + + template_update_attribute(server_obj->template, server_val_attr); + template_update_attribute(server_obj->template, server_val_len_attr); + // the object owns the attributes now... + server_val_attr = NULL; + server_val_len_attr = NULL; + + rc = object_mgr_create_final(tokdata, sess, client_obj, client_handle); + if (rc != CKR_OK) { + TRACE_DEVEL("Object Mgr Create Final failed.\n"); + goto error; + } + rc = object_mgr_create_final(tokdata, sess, server_obj, server_handle); + if (rc != CKR_OK) { + TRACE_DEVEL("Object Mgr Create Final failed.\n"); + object_mgr_destroy_object(tokdata, sess, *client_handle); + client_obj = NULL; + goto error; + } + + return CKR_OK; + +error: + *client_handle = 0; + *server_handle = 0; + + if (client_obj) { + object_free(client_obj); + client_val_attr = NULL; // these get freed with the object + client_val_len_attr = NULL; + } + + if (server_obj) { + object_free(server_obj); + server_val_attr = NULL; // these get freed with the object + server_val_len_attr = NULL; + } + + if (client_val_attr) + free(client_val_attr); + if (client_val_len_attr) + free(client_val_len_attr); + if (server_val_attr) + free(server_val_attr); + if (server_val_len_attr) + free(server_val_len_attr); + + if (new_attrs) { + for (i = 0; i < ulCount; i++) { + if (new_attrs[i].pValue) + free(new_attrs[i].pValue); + } + + free(new_attrs); + } + + return rc; +} + + +CK_RV ssl3_kmd_process_write_keys(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, + CK_KEY_TYPE keytype, + CK_OBJECT_HANDLE *client_handle, + CK_BYTE *client_value, + CK_OBJECT_HANDLE *server_handle, + CK_BYTE *server_value, CK_ULONG write_len) +{ + CK_ATTRIBUTE *client_val_attr = NULL; + CK_ATTRIBUTE *client_val_len_attr = NULL; + CK_ATTRIBUTE *server_val_attr = NULL; + CK_ATTRIBUTE *server_val_len_attr = NULL; + CK_ATTRIBUTE *new_attrs = NULL; + CK_ATTRIBUTE *attr = NULL; + OBJECT *client_obj = NULL; + OBJECT *server_obj = NULL; + CK_ULONG i, cnt; + CK_ULONG true_vals[] = { CKA_ENCRYPT, CKA_DECRYPT, CKA_DERIVE }; + CK_ULONG false_vals[] = { CKA_SIGN, CKA_VERIFY, CKA_WRAP, CKA_UNWRAP }; + CK_RV rc = CKR_HOST_MEMORY; + + // for the write keys, we want the following default values: + // CKA_ENCRYPT, CKA_DECRYPT, CKA_DERIVE = TRUE + // CKA_SIGN, CKA_VERIFY, CKA_WRAP, CKA_UNWRAP = FALSE + // + // attributes are added in sequential order so we stick the defaults + // at the beginning so that they may be overridden by caller-specified + // values. + // + new_attrs = (CK_ATTRIBUTE *) malloc((ulCount + 7) * (sizeof(CK_ATTRIBUTE))); + if (!new_attrs) + goto error; + + // we have to treat these attributes a bit differently. normally, we + // allocate the CK_ATTRIBUTE and the value with a single malloc and just + // point the pValue member to the extra space. we can't do that here because + // we have to "emulate" the way attributes are passed in from the cryptoki + // application...as an array of CK_ATTRIBUTEs with no extra space (that is, + // pValue must be allocated separately). + // + attr = new_attrs; + for (i = 0; i < sizeof(true_vals) / sizeof(CK_ULONG); i++, attr++) { + attr->type = true_vals[i]; + attr->ulValueLen = sizeof(CK_BBOOL); + attr->pValue = (CK_BBOOL *) malloc(sizeof(CK_BBOOL)); + if (!attr->pValue) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto error; + } + *(CK_BBOOL *) attr->pValue = TRUE; + } + + for (i = 0; i < sizeof(false_vals) / sizeof(CK_ULONG); i++, attr++) { + attr->type = false_vals[i]; + attr->ulValueLen = sizeof(CK_BBOOL); + attr->pValue = (CK_BBOOL *) malloc(sizeof(CK_BBOOL)); + if (!attr->pValue) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto error; + } + *(CK_BBOOL *) attr->pValue = FALSE; + } + + for (i = 0, cnt = 0; i < ulCount; i++) { + if (pTemplate[i].type != CKA_KEY_TYPE && + pTemplate[i].type != CKA_VALUE && + pTemplate[i].type != CKA_VALUE_LEN) { + attr->type = pTemplate[i].type; + attr->ulValueLen = pTemplate[i].ulValueLen; + attr->pValue = (char *) malloc(attr->ulValueLen); + if (!attr->pValue) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto error; + } + memcpy(attr->pValue, pTemplate[i].pValue, attr->ulValueLen); + cnt++; + attr++; + } + } + + ulCount = 7 + cnt; + + rc = object_mgr_create_skel(tokdata, sess, + new_attrs, ulCount, + MODE_DERIVE, + CKO_SECRET_KEY, keytype, &client_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("Object Mgr Create Skeleton failed.\n"); + goto error; + } + rc = object_mgr_create_skel(tokdata, sess, + new_attrs, ulCount, + MODE_DERIVE, + CKO_SECRET_KEY, keytype, &server_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("Object Mgr Create Skeleton failed.\n"); + goto error; + } + for (i = 0; i < ulCount; i++) { + if (new_attrs[i].pValue) + free(new_attrs[i].pValue); + } + + free(new_attrs); + new_attrs = NULL; + + rc = build_attribute(CKA_VALUE, client_value, write_len, &client_val_attr); + rc |= build_attribute(CKA_VALUE, server_value, write_len, &server_val_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to build CKA_VALUE attribute.\n"); + goto error; + } + switch (keytype) { + case CKK_GENERIC_SECRET: + case CKK_DES: + case CKK_DES2: + case CKK_DES3: + case CKK_RC2: + case CKK_RC4: + case CKK_RC5: + case CKK_CAST: + case CKK_CAST3: + case CKK_CAST5: + rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE *) & write_len, + sizeof(CK_ULONG), &client_val_len_attr); + rc |= + build_attribute(CKA_VALUE_LEN, (CK_BYTE *) & write_len, + sizeof(CK_ULONG), &server_val_len_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to build CKA_VALUE_LEN attribute.\n"); + goto error; + } + rc = template_validate_attribute(tokdata, client_obj->template, + client_val_len_attr, + CKO_SECRET_KEY, keytype, MODE_DERIVE); + rc |= template_validate_attribute(tokdata, server_obj->template, + server_val_len_attr, + CKO_SECRET_KEY, keytype, MODE_DERIVE); + + // for these I use MODE_CREATE because I want to validate the + // value/length. no othe modes are allowed to mess wiht CKA_VALUE (see + // for instance, des_validate_attribute()) + // + rc |= template_validate_attribute(tokdata, client_obj->template, + client_val_attr, + CKO_SECRET_KEY, keytype, MODE_CREATE); + rc |= template_validate_attribute(tokdata, server_obj->template, + server_val_attr, + CKO_SECRET_KEY, keytype, MODE_CREATE); + if (rc != CKR_OK) { + TRACE_DEVEL("template_validate_attribute failed.\n"); + goto error; + } + template_update_attribute(client_obj->template, client_val_attr); + template_update_attribute(server_obj->template, server_val_attr); + template_update_attribute(client_obj->template, client_val_len_attr); + template_update_attribute(server_obj->template, server_val_len_attr); + + // the object owns the attributes now... + // + client_val_attr = NULL; + server_val_attr = NULL; + client_val_len_attr = NULL; + server_val_len_attr = NULL; + break; + default: + rc = template_validate_attribute(tokdata, client_obj->template, + client_val_attr, + CKO_SECRET_KEY, keytype, MODE_CREATE); + rc |= template_validate_attribute(tokdata, server_obj->template, + server_val_attr, + CKO_SECRET_KEY, keytype, MODE_CREATE); + if (rc != CKR_OK) { + TRACE_DEVEL("template_validate_attribute failed.\n"); + goto error; + } + template_update_attribute(client_obj->template, client_val_attr); + template_update_attribute(server_obj->template, server_val_attr); + + // the object owns the attributes now... + // + client_val_attr = NULL; + server_val_attr = NULL; + } + + + // finally, assign a handle to each key + // + rc = object_mgr_create_final(tokdata, sess, client_obj, client_handle); + if (rc != CKR_OK) { + TRACE_DEVEL("Object Mgr Create Final failed.\n"); + goto error; + } + rc = object_mgr_create_final(tokdata, sess, server_obj, server_handle); + if (rc != CKR_OK) { + TRACE_DEVEL("Object Mgr Create Final failed.\n"); + object_mgr_destroy_object(tokdata, sess, *client_handle); + client_obj = NULL; + goto error; + } + + return CKR_OK; + +error: + *client_handle = 0; + *server_handle = 0; + + if (client_obj) + object_free(client_obj); + + if (server_obj) + object_free(server_obj); + + // the only way these guys are non-NULL is if they were created but + // not yet to added to an object + // + if (client_val_attr) + free(client_val_attr); + if (client_val_len_attr) + free(client_val_len_attr); + if (server_val_attr) + free(server_val_attr); + if (server_val_len_attr) + free(server_val_len_attr); + + if (new_attrs) { + for (i = 0; i < ulCount; i++) { + if (new_attrs[i].pValue) + free(new_attrs[i].pValue); + } + + free(new_attrs); + } + + return rc; +} diff --git a/usr/lib/common/new_host.c b/usr/lib/common/new_host.c new file mode 100644 index 0000000..93ada56 --- /dev/null +++ b/usr/lib/common/new_host.c @@ -0,0 +1,4013 @@ +/* + * 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 + */ + +/*************************************************************************** + Change Log + ========== + 4/25/03 Kapil Sood (kapil@corrent.com) + Added DH key pair generation and DH shared key derivation + functions. + + + +****************************************************************************/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "stdll.h" + +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "pkcs32.h" +#include "trace.h" +#include "slotmgr.h" + +#include "../api/apiproto.h" + +void SC_SetFunctionList(void); +CK_RV SC_Finalize(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, SLOT_INFO *sinfp, + struct trace_handle_t *t, CK_BBOOL in_fork_initializer); + +/* verify that the mech specified is in the + * mech list for this token... + */ +CK_RV valid_mech(STDLL_TokData_t *tokdata, CK_MECHANISM_PTR m, CK_FLAGS f) +{ + CK_RV rc; + CK_MECHANISM_INFO info; + + if (m && token_specific.t_get_mechanism_info) { + memset(&info, 0, sizeof(info)); + rc = token_specific.t_get_mechanism_info(tokdata, m->mechanism, &info); + if (rc != CKR_OK || !(info.flags & (f))) + return CKR_MECHANISM_INVALID; + } + + return CKR_OK; +} + + +/* In an STDLL this is called once for each card in the system + * therefore the initialized only flags certain one time things. + */ +CK_RV ST_Initialize(API_Slot_t *sltp, CK_SLOT_ID SlotNumber, + SLOT_INFO *sinfp, struct trace_handle_t t) +{ + CK_RV rc = CKR_OK; + char abs_tokdir_name[PATH_MAX]; + + if ((rc = check_user_and_group()) != CKR_OK) + return rc; + + /* set trace info */ + set_trace(t); + + if (sltp->TokData != NULL) { + TRACE_ERROR("Already initialized.\n"); + return CKR_CRYPTOKI_ALREADY_INITIALIZED; + } + + /* + * Create separate memory area for each token specific data + */ + sltp->TokData = (STDLL_TokData_t *) calloc(1, sizeof(STDLL_TokData_t)); + if (!sltp->TokData) { + TRACE_ERROR("Allocating host memory failed.\n"); + return CKR_HOST_MEMORY; + } + + 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); + + 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); + + if (strlen(sinfp->tokname)) { + sprintf(abs_tokdir_name, "%s/%s", CONFIG_PATH, sinfp->tokname); + TRACE_DEVEL("Token directory: %s\n", abs_tokdir_name); + init_data_store(sltp->TokData, (char *) abs_tokdir_name, + sltp->TokData->data_store); + } else { + init_data_store(sltp->TokData, (char *) PK_DIR, + sltp->TokData->data_store); + } + + sltp->TokData->version = sinfp->version; + TRACE_DEVEL("Token version: %u.%u\n", + (unsigned int)(sinfp->version >> 16), + (unsigned int)(sinfp->version & 0xffff)); + + /* Initialize Lock */ + if (XProcLock_Init(sltp->TokData) != CKR_OK) { + TRACE_ERROR("Thread lock failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Create lockfile */ + if (CreateXProcLock(sinfp->tokname, sltp->TokData) != CKR_OK) { + TRACE_ERROR("Process lock failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Handle global initialization issues first if we have not + * been initialized. + */ + if (sltp->TokData->initialized == FALSE) { + rc = attach_shm(sltp->TokData, SlotNumber); + if (rc != CKR_OK) { + TRACE_ERROR("Could not attach to shared memory.\n"); + goto done; + } + + sltp->TokData->nv_token_data = + &(sltp->TokData->global_shm->nv_token_data); + SC_SetFunctionList(); + + /* Always call the token_specific_init function.... */ + rc = token_specific.t_init(sltp->TokData, SlotNumber, sinfp->confname); + if (rc != 0) { + sltp->FcnList = NULL; + detach_shm(sltp->TokData, 0); + if (sltp->TokData) + free(sltp->TokData); + sltp->TokData = NULL; + TRACE_DEVEL("Token Specific Init failed.\n"); + goto done; + } + sltp->TokData->initialized = TRUE; + } + + rc = load_token_data(sltp->TokData, SlotNumber); + if (rc != CKR_OK) { + sltp->FcnList = NULL; + if (sltp->TokData) + free(sltp->TokData); + sltp->TokData = NULL; + TRACE_DEVEL("Failed to load token data. (rc=0x%02lx)\n", rc); + goto done; + } + + rc = XProcLock(sltp->TokData); + if (rc != CKR_OK) + goto done; + + /* no need to return error here, we load the token data we can + * and syslog the rest + */ + load_public_token_objects(sltp->TokData); + + sltp->TokData->global_shm->publ_loaded = TRUE; + + rc = XProcUnLock(sltp->TokData); + if (rc != CKR_OK) + goto done; + + init_slotInfo(&(sltp->TokData->slot_info)); + + (sltp->FcnList) = &function_list; + +done: + if (rc != CKR_OK && sltp->TokData != NULL) { + if (sltp->TokData->initialized) { + SC_Finalize(sltp->TokData, SlotNumber, sinfp, NULL, 0); + } else { + CloseXProcLock(sltp->TokData); + free(sltp->TokData); + sltp->TokData = NULL; + } + } + + return rc; +} + +/* What does this really have to do in this new token... probably + * need to close the adapters that are opened, and clear the other + * stuff + */ +CK_RV SC_Finalize(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, SLOT_INFO *sinfp, + struct trace_handle_t *t, CK_BBOOL in_fork_initializer) +{ + CK_RV rc = CKR_OK; + + UNUSED(sid); + UNUSED(sinfp); + + if (t != NULL) + set_trace(*t); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + tokdata->initialized = FALSE; + + session_mgr_close_all_sessions(tokdata); + object_mgr_purge_token_objects(tokdata); + + /* Finally free the nodes on free list. */ + bt_destroy(&tokdata->sess_btree); + bt_destroy(&tokdata->object_map_btree); + bt_destroy(&tokdata->sess_obj_btree); + bt_destroy(&tokdata->priv_token_obj_btree); + bt_destroy(&tokdata->publ_token_obj_btree); + +#ifdef ENABLE_LOCKS + pthread_rwlock_destroy(&tokdata->sess_list_rwlock); +#endif + pthread_mutex_destroy(&tokdata->login_mutex); + + detach_shm(tokdata, in_fork_initializer); + /* close spin lock file */ + CloseXProcLock(tokdata); + if (token_specific.t_final != NULL) { + rc = token_specific.t_final(tokdata, in_fork_initializer); + if (rc != CKR_OK) { + TRACE_ERROR("Token specific final call failed.\n"); + return rc; + } + } + + final_data_store(tokdata); + + if (tokdata) + free(tokdata); + + return rc; +} + +CK_RV SC_GetTokenInfo(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, + CK_TOKEN_INFO_PTR pInfo) +{ + CK_RV rc = CKR_OK; + time_t now; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + if (!pInfo) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + if (sid >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + rc = CKR_SLOT_ID_INVALID; + goto done; + } + copy_token_contents_sensibly(pInfo, tokdata->nv_token_data); + + /* Set the time */ + now = time((time_t *) NULL); + strftime((char *) pInfo->utcTime, 16, "%Y%m%d%H%M%S", localtime(&now)); + pInfo->utcTime[14] = '0'; + pInfo->utcTime[15] = '0'; + +done: + TRACE_INFO("C_GetTokenInfo: rc = 0x%08lx\n", rc); + + return rc; +} + +CK_RV SC_WaitForSlotEvent(STDLL_TokData_t *tokdata, CK_FLAGS flags, + CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved) +{ + UNUSED(flags); + UNUSED(pSlot); + UNUSED(pReserved); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + +/* + * Get the mechanism type list for the current token. + */ +CK_RV SC_GetMechanismList(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, + CK_MECHANISM_TYPE_PTR pMechList, CK_ULONG_PTR count) +{ + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto out; + } + if (count == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto out; + } + if (sid >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + rc = CKR_SLOT_ID_INVALID; + goto out; + } + if (!token_specific.t_get_mechanism_list) { + TRACE_ERROR("token specific GetMechanismList doesn't exist.\n"); + rc = CKR_GENERAL_ERROR; + goto out; + } + rc = token_specific.t_get_mechanism_list(tokdata, pMechList, count); + if (rc == CKR_OK) { + /* To accomodate certain special cases, we may need to + * make adjustments to the token's mechanism list. + */ + mechanism_list_transformations(pMechList, count); + } + +out: + TRACE_INFO("C_GetMechanismList: rc = 0x%08lx, # mechanisms: %lu\n", + rc, (count ? *count : 0)); + + return rc; +} + +/* + * Get the mechanism info for the current type and token. + */ +CK_RV SC_GetMechanismInfo(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, + CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo) +{ + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto out; + } + if (pInfo == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto out; + } + if (sid >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + rc = CKR_SLOT_ID_INVALID; + goto out; + } + if (!token_specific.t_get_mechanism_info) { + TRACE_ERROR("token specific GetMechanismInfo doesn't exist.\n"); + rc = CKR_GENERAL_ERROR; + goto out; + } + rc = token_specific.t_get_mechanism_info(tokdata, type, pInfo); + +out: + TRACE_INFO("C_GetMechanismInfo: rc = 0x%08lx, mech type = 0x%08lx\n", + rc, type); + + return rc; +} + +/* + * This routine should only be called if no other processes are + * attached to the token. we need to somehow check that this is the + * only process Meta API should prevent this since it knows session + * states in the shared memory. +*/ +CK_RV SC_InitToken(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, CK_CHAR_PTR pPin, + CK_ULONG ulPinLen, CK_CHAR_PTR pLabel) +{ + CK_RV rc = CKR_OK; + CK_BYTE hash_sha[SHA1_HASH_SIZE]; + unsigned char login_key[32]; + TOKEN_DATA_VERSION *dat; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + if (!pPin || !pLabel) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + if (pthread_mutex_lock(&tokdata->login_mutex)) { + TRACE_ERROR("Failed to get mutex lock.\n"); + return CKR_FUNCTION_FAILED; + } + + if (tokdata->nv_token_data->token_info.flags & CKF_SO_PIN_LOCKED) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LOCKED)); + rc = CKR_PIN_LOCKED; + goto done; + } + + /* Check if token has a specific handler for this, otherwise fall back + * to default behaviour. + */ + if (token_specific.t_init_token) { + rc = token_specific.t_init_token(tokdata, sid, pPin, ulPinLen, pLabel); + if (rc != CKR_OK) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + } + goto done; + } + + dat = &tokdata->nv_token_data->dat; + if (tokdata->version < TOK_NEW_DATA_STORE) { + rc = compute_sha1(tokdata, pPin, ulPinLen, hash_sha); + if (memcmp(tokdata->nv_token_data->so_pin_sha, hash_sha, SHA1_HASH_SIZE) + != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + } else { + rc = PKCS5_PBKDF2_HMAC((char *)pPin, ulPinLen, + dat->so_login_salt, 64, + dat->so_login_it, EVP_sha512(), + 256 / 8, login_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + if (CRYPTO_memcmp(dat->so_login_key, login_key, 32) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + } + + /* Before we reconstruct all the data, we should delete the + * token objects from the filesystem. + */ + object_mgr_destroy_token_objects(tokdata); + delete_token_data(tokdata); + + load_token_data(tokdata, sid); + init_slotInfo(&(tokdata->slot_info)); + if (tokdata->version < TOK_NEW_DATA_STORE) { + memcpy(tokdata->nv_token_data->so_pin_sha, hash_sha, SHA1_HASH_SIZE); + } else { + memcpy(dat->so_login_key, login_key, 32); + } + tokdata->nv_token_data->token_info.flags |= CKF_TOKEN_INITIALIZED; + memcpy(tokdata->nv_token_data->token_info.label, pLabel, 32); + + rc = save_token_data(tokdata, sid); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to save token data.\n"); + goto done; + } + +done: + TRACE_INFO("C_InitToken: rc = 0x%08lx\n", rc); + + pthread_mutex_unlock(&tokdata->login_mutex); + + return rc; +} + + +CK_RV SC_InitPIN(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_CHAR_PTR pPin, CK_ULONG ulPinLen) +{ + SESSION *sess = NULL; + CK_BYTE hash_sha[SHA1_HASH_SIZE]; + CK_BYTE hash_md5[MD5_HASH_SIZE]; + CK_RV rc = CKR_OK; + CK_FLAGS_32 *flags = NULL; + TOKEN_DATA_VERSION *dat; + unsigned char login_key[32], wrap_key[32], login_salt[64], wrap_salt[64]; + uint64_t login_it, wrap_it; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + if (!pPin) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + if (pthread_mutex_lock(&tokdata->login_mutex)) { + TRACE_ERROR("Failed to get mutex lock.\n"); + return CKR_FUNCTION_FAILED; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + if (pin_locked(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LOCKED)); + rc = CKR_PIN_LOCKED; + goto done; + } + if (sess->session_info.state != CKS_RW_SO_FUNCTIONS) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + + /* Check if token has a specific handler for this, otherwise fall back + * to default behaviour. + */ + if (token_specific.t_init_pin) { + rc = token_specific.t_init_pin(tokdata, sess, pPin, ulPinLen); + if (rc == CKR_OK) { + flags = &tokdata->nv_token_data->token_info.flags; + *flags &= ~(CKF_USER_PIN_LOCKED | + CKF_USER_PIN_FINAL_TRY | CKF_USER_PIN_COUNT_LOW); + + rc = save_token_data(tokdata, sess->session_info.slotID); + if (rc != CKR_OK) + TRACE_DEVEL("Failed to save token data.\n"); + } + goto done; + } + + if ((ulPinLen < MIN_PIN_LEN) || (ulPinLen > MAX_PIN_LEN)) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LEN_RANGE)); + rc = CKR_PIN_LEN_RANGE; + goto done; + } + + + dat = &tokdata->nv_token_data->dat; + if (tokdata->version < TOK_NEW_DATA_STORE) { + /* compute the SHA and MD5 hashes of the user pin */ + rc = compute_sha1(tokdata, pPin, ulPinLen, hash_sha); + rc |= compute_md5(tokdata, pPin, ulPinLen, hash_md5); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to compute sha or md5 for user pin.\n"); + goto done; + } + } else { + login_it = USER_KDF_LOGIN_IT; + memcpy(login_salt, USER_KDF_LOGIN_PURPOSE, 32); + rng_generate(tokdata, login_salt + 32, 32); + + rc = PKCS5_PBKDF2_HMAC((char *)pPin, ulPinLen, + login_salt, 64, + login_it, EVP_sha512(), + 256 / 8, login_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + wrap_it = USER_KDF_WRAP_IT; + memcpy(wrap_salt, USER_KDF_WRAP_PURPOSE, 32); + rng_generate(tokdata, wrap_salt + 32, 32); + + rc = PKCS5_PBKDF2_HMAC((char *)pPin, ulPinLen, + wrap_salt, 64, + wrap_it, EVP_sha512(), + 256 / 8, wrap_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + } + + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get process lock.\n"); + goto done; + } + + if (tokdata->version < TOK_NEW_DATA_STORE) { + memcpy(tokdata->nv_token_data->user_pin_sha, hash_sha, SHA1_HASH_SIZE); + } else { + memcpy(dat->user_login_key, login_key, 256 / 8); + memcpy(dat->user_login_salt, login_salt, 64); + dat->user_login_it = login_it; + } + + tokdata->nv_token_data->token_info.flags |= CKF_USER_PIN_INITIALIZED; + tokdata->nv_token_data->token_info.flags &= ~(CKF_USER_PIN_TO_BE_CHANGED); + tokdata->nv_token_data->token_info.flags &= ~(CKF_USER_PIN_LOCKED); + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release process lock.\n"); + goto done; + } + + if (tokdata->version < TOK_NEW_DATA_STORE) { + memcpy(tokdata->user_pin_md5, hash_md5, MD5_HASH_SIZE); + } else { + memcpy(tokdata->user_wrap_key, wrap_key, 256 / 8); + memcpy(dat->user_wrap_salt, wrap_salt, 64); + dat->user_wrap_it = wrap_it; + } + + rc = save_token_data(tokdata, sess->session_info.slotID); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to save token data.\n"); + goto done; + } + + rc = save_masterkey_user(tokdata); + if (rc != CKR_OK) + TRACE_DEVEL("Failed to save user's masterkey.\n"); + +done: + TRACE_INFO("C_InitPin: rc = 0x%08lx, session = %lu\n", + rc, sSession->sessionh); + + pthread_mutex_unlock(&tokdata->login_mutex); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + +CK_RV SC_SetPIN(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_CHAR_PTR pOldPin, CK_ULONG ulOldLen, CK_CHAR_PTR pNewPin, + CK_ULONG ulNewLen) +{ + SESSION *sess = NULL; + CK_BYTE old_hash_sha[SHA1_HASH_SIZE]; + CK_BYTE new_hash_sha[SHA1_HASH_SIZE]; + CK_BYTE hash_md5[MD5_HASH_SIZE]; + CK_RV rc = CKR_OK; + TOKEN_DATA_VERSION *dat; + unsigned char old_login_key[32], new_login_key[32], new_wrap_key[32], + new_login_key_old_salt[32], login_salt[64], wrap_salt[64]; + uint64_t login_it, wrap_it; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (pthread_mutex_lock(&tokdata->login_mutex)) { + TRACE_ERROR("Failed to get mutex lock.\n"); + return CKR_FUNCTION_FAILED; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + if (pin_locked(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LOCKED)); + rc = CKR_PIN_LOCKED; + goto done; + } + + /* Check if token has a specific handler for this, otherwise fall back + * to default behaviour. + */ + if (token_specific.t_set_pin) { + rc = token_specific.t_set_pin(tokdata, sess, pOldPin, ulOldLen, + pNewPin, ulNewLen); + goto done; + } + + if ((ulNewLen < MIN_PIN_LEN) || (ulNewLen > MAX_PIN_LEN)) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LEN_RANGE)); + rc = CKR_PIN_LEN_RANGE; + goto done; + } + + dat = &tokdata->nv_token_data->dat; + if (tokdata->version < TOK_NEW_DATA_STORE) { + rc = compute_sha1(tokdata, pOldPin, ulOldLen, old_hash_sha); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to compute sha for old pin.\n"); + goto done; + } + } + + /* From the PKCS#11 2.20 spec: "C_SetPIN modifies the PIN of + * the user that is currently logged in, or the CKU_USER PIN + * if the session is not logged in." A non R/W session fails + * with CKR_SESSION_READ_ONLY. + */ + if ((sess->session_info.state == CKS_RW_USER_FUNCTIONS) || + (sess->session_info.state == CKS_RW_PUBLIC_SESSION)) { + + if (tokdata->version < TOK_NEW_DATA_STORE) { + if (memcmp(tokdata->nv_token_data->user_pin_sha, old_hash_sha, + SHA1_HASH_SIZE) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + rc = compute_sha1(tokdata, pNewPin, ulNewLen, new_hash_sha); + rc |= compute_md5(tokdata, pNewPin, ulNewLen, hash_md5); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to compute hash for new pin.\n"); + goto done; + } + /* The old PIN matches, now make sure its different + * than the new and is not the default. */ + if ((memcmp(old_hash_sha, new_hash_sha, SHA1_HASH_SIZE) == 0) || + (memcmp(new_hash_sha, default_user_pin_sha, SHA1_HASH_SIZE) + == 0)) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INVALID)); + rc = CKR_PIN_INVALID; + goto done; + } + } else { + login_it = USER_KDF_LOGIN_IT; + memcpy(login_salt, USER_KDF_LOGIN_PURPOSE, 32); + rng_generate(tokdata, login_salt + 32, 32); + + rc = PKCS5_PBKDF2_HMAC((char *)pNewPin, ulNewLen, + login_salt, 64, + login_it, EVP_sha512(), + 256 / 8, new_login_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + wrap_it = USER_KDF_WRAP_IT; + memcpy(wrap_salt, USER_KDF_WRAP_PURPOSE, 32); + rng_generate(tokdata, wrap_salt + 32, 32); + + rc = PKCS5_PBKDF2_HMAC((char *)pNewPin, ulNewLen, + wrap_salt, 64, + wrap_it, EVP_sha512(), + 256 / 8, new_wrap_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + rc = PKCS5_PBKDF2_HMAC((char *)pOldPin, ulOldLen, + dat->user_login_salt, 64, + dat->user_login_it, EVP_sha512(), + 256 / 8, old_login_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + rc = PKCS5_PBKDF2_HMAC((char *)pNewPin, ulNewLen, + dat->user_login_salt, 64, + dat->user_login_it, EVP_sha512(), + 256 / 8, new_login_key_old_salt); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (CRYPTO_memcmp(dat->user_login_key, + old_login_key, 256 / 8) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INVALID)); + rc = CKR_PIN_INVALID; + goto done; + } + /* The old PIN matches, now make sure its different + * than the new and is not the default. */ + if (CRYPTO_memcmp(old_login_key, + new_login_key_old_salt, 256 / 8) == 0) + { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INVALID)); + rc = CKR_PIN_INVALID; + goto done; + } + } + + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to get process lock.\n"); + goto done; + } + + if (tokdata->version < TOK_NEW_DATA_STORE) { + memcpy(tokdata->nv_token_data->user_pin_sha, new_hash_sha, + SHA1_HASH_SIZE); + memcpy(tokdata->user_pin_md5, hash_md5, MD5_HASH_SIZE); + } else { + memcpy(dat->user_login_key, new_login_key, 256 / 8); + memcpy(dat->user_login_salt, login_salt, 64); + dat->user_login_it = login_it; + memcpy(tokdata->user_wrap_key, new_wrap_key, 256 / 8); + memcpy(dat->user_wrap_salt, wrap_salt, 64); + dat->user_wrap_it = wrap_it; + } + + tokdata->nv_token_data->token_info.flags &= + ~(CKF_USER_PIN_TO_BE_CHANGED); + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release process lock.\n"); + goto done; + } + + rc = save_token_data(tokdata, sess->session_info.slotID); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to save token data.\n"); + goto done; + } + rc = save_masterkey_user(tokdata); + } else if (sess->session_info.state == CKS_RW_SO_FUNCTIONS) { + + if (tokdata->version < TOK_NEW_DATA_STORE) { + if (memcmp(tokdata->nv_token_data->so_pin_sha, old_hash_sha, + SHA1_HASH_SIZE) != 0) { + rc = CKR_PIN_INCORRECT; + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + goto done; + } + rc = compute_sha1(tokdata, pNewPin, ulNewLen, new_hash_sha); + rc |= compute_md5(tokdata, pNewPin, ulNewLen, hash_md5); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to compute hash for new pin.\n"); + goto done; + } + /* The old PIN matches, now make sure its different + * than the new and is not the default. + */ + if ((memcmp(old_hash_sha, new_hash_sha, SHA1_HASH_SIZE) == 0) || + (memcmp(new_hash_sha, default_so_pin_sha, SHA1_HASH_SIZE) + == 0)) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INVALID)); + rc = CKR_PIN_INVALID; + goto done; + } + } else { + login_it = SO_KDF_LOGIN_IT; + memcpy(login_salt, SO_KDF_LOGIN_PURPOSE, 32); + rng_generate(tokdata, login_salt + 32, 32); + + rc = PKCS5_PBKDF2_HMAC((char *)pNewPin, ulNewLen, + login_salt, 64, + login_it, EVP_sha512(), + 256 / 8, new_login_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + wrap_it = SO_KDF_WRAP_IT; + memcpy(wrap_salt, SO_KDF_WRAP_PURPOSE, 32); + rng_generate(tokdata, wrap_salt + 32, 32); + + rc = PKCS5_PBKDF2_HMAC((char *)pNewPin, ulNewLen, + wrap_salt, 64, + wrap_it, EVP_sha512(), + 256 / 8, new_wrap_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + rc = PKCS5_PBKDF2_HMAC((char *)pOldPin, ulOldLen, + dat->so_login_salt, 64, + dat->so_login_it, EVP_sha512(), + 256 / 8, old_login_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + rc = PKCS5_PBKDF2_HMAC((char *)pNewPin, ulNewLen, + dat->so_login_salt, 64, + dat->so_login_it, EVP_sha512(), + 256 / 8, new_login_key_old_salt); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (CRYPTO_memcmp(dat->so_login_key, + old_login_key, 256 / 8) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INVALID)); + rc = CKR_PIN_INVALID; + goto done; + } + /* The old PIN matches, now make sure its different + * than the new and is not the default. */ + if (CRYPTO_memcmp(new_login_key_old_salt, + old_login_key, 256 / 8) == 0) + { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INVALID)); + rc = CKR_PIN_INVALID; + goto done; + } + } + + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to get process lock.\n"); + goto done; + } + + if (tokdata->version < TOK_NEW_DATA_STORE) { + memcpy(tokdata->nv_token_data->so_pin_sha, new_hash_sha, + SHA1_HASH_SIZE); + memcpy(tokdata->so_pin_md5, hash_md5, MD5_HASH_SIZE); + } else { + memcpy(dat->so_login_key, new_login_key, 256 / 8); + memcpy(dat->so_login_salt, login_salt, 64); + dat->so_login_it = login_it; + memcpy(tokdata->so_wrap_key, new_wrap_key, 256 / 8); + memcpy(dat->so_wrap_salt, wrap_salt, 64); + dat->so_wrap_it = wrap_it; + } + + tokdata->nv_token_data->token_info.flags &= ~(CKF_SO_PIN_TO_BE_CHANGED); + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release process lock.\n"); + goto done; + } + + rc = save_token_data(tokdata, sess->session_info.slotID); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to save token data.\n"); + goto done; + } + + rc = save_masterkey_so(tokdata); + if (rc != CKR_OK) + TRACE_DEVEL("Failed to save SO's masterkey.\n"); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY)); + rc = CKR_SESSION_READ_ONLY; + } + +done: + TRACE_INFO("C_SetPin: rc = 0x%08lx, session = %lu\n", + rc, sSession->sessionh); + + pthread_mutex_unlock(&tokdata->login_mutex); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + +CK_RV SC_OpenSession(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, CK_FLAGS flags, + CK_SESSION_HANDLE_PTR phSession) +{ + CK_RV rc = CKR_OK; + SESSION *sess; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + if (phSession == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + if (sid >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + return CKR_SLOT_ID_INVALID; + } + flags |= CKF_SERIAL_SESSION; + if ((flags & CKF_RW_SESSION) == 0) { + if (session_mgr_so_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_WRITE_SO_EXISTS)); + return CKR_SESSION_READ_WRITE_SO_EXISTS; + } + } + + rc = session_mgr_new(tokdata, flags, sid, phSession); + if (rc != CKR_OK) { + TRACE_DEVEL("session_mgr_new() failed\n"); + return rc; + } + + sess = session_mgr_find(tokdata, *phSession); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + return CKR_SESSION_HANDLE_INVALID; + } + + sess->handle = *phSession; + + TRACE_INFO("C_OpenSession: rc = 0x%08lx sess = %lu\n", rc, sess->handle); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + +CK_RV SC_CloseSession(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BBOOL in_fork_initializer) +{ + CK_RV rc = CKR_OK; + + UNUSED(in_fork_initializer); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + rc = session_mgr_close_session(tokdata, sSession->sessionh); + +done: + TRACE_INFO("C_CloseSession: rc = 0x%08lx, sess = %lu\n", + rc, sSession->sessionh); + + return rc; +} + +CK_RV SC_CloseAllSessions(STDLL_TokData_t *tokdata, CK_SLOT_ID sid) +{ + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + rc = session_mgr_close_all_sessions(tokdata); + if (rc != CKR_OK) + TRACE_DEVEL("session_mgr_close_all_sessions() failed.\n"); + +done: + TRACE_INFO("C_CloseAllSessions: rc = 0x%08lx, slot = %lu\n", rc, sid); + + return rc; +} + +CK_RV SC_GetSessionInfo(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_SESSION_INFO_PTR pInfo) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pInfo) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + memcpy(pInfo, &sess->session_info, sizeof(CK_SESSION_INFO)); + +done: + TRACE_INFO("C_GetSessionInfo: sess = %lu\n", sSession->sessionh); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + +CK_RV SC_GetOperationState(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pOperationState, + CK_ULONG_PTR pulOperationStateLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pulOperationStateLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (!pOperationState) + length_only = TRUE; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + rc = session_mgr_get_op_state(sess, length_only, pOperationState, + pulOperationStateLen); + if (rc != CKR_OK) + TRACE_DEVEL("session_mgr_get_op_state() failed.\n"); + +done: + TRACE_INFO("C_GetOperationState: rc = 0x%08lx, sess = %lu\n", + rc, sSession->sessionh); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_SetOperationState(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pOperationState, + CK_ULONG ulOperationStateLen, + CK_OBJECT_HANDLE hEncryptionKey, + CK_OBJECT_HANDLE hAuthenticationKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pOperationState || (ulOperationStateLen == 0)) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + rc = session_mgr_set_op_state(sess, hEncryptionKey, hAuthenticationKey, + pOperationState, ulOperationStateLen); + + if (rc != CKR_OK) + TRACE_DEVEL("session_mgr_set_op_state() failed.\n"); + +done: + TRACE_INFO("C_SetOperationState: rc = 0x%08lx, sess = %lu\n", + rc, sSession->sessionh); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Login(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_USER_TYPE userType, CK_CHAR_PTR pPin, CK_ULONG ulPinLen) +{ + SESSION *sess = NULL; + CK_FLAGS_32 *flags = NULL; + CK_BYTE hash_sha[SHA1_HASH_SIZE]; + CK_RV rc = CKR_OK; + unsigned char login_key[32], wrap_key[32]; + TOKEN_DATA_VERSION *dat; + + /* In v2.11, logins should be exclusive, since token + * specific flags may need to be set for a bad login. - KEY + */ + if (pthread_mutex_lock(&tokdata->login_mutex)) { + TRACE_ERROR("Failed to get mutex lock.\n"); + return CKR_FUNCTION_FAILED; + } + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + flags = &tokdata->nv_token_data->token_info.flags; + + if (!pPin || ulPinLen > MAX_PIN_LEN) { + set_login_flags(userType, flags); + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + + /* PKCS #11 v2.01 requires that all sessions have the same login status: + * --> all sessions are public, all are SO or all are USER + */ + if (userType == CKU_USER) { + if (session_mgr_so_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_ANOTHER_ALREADY_LOGGED_IN)); + rc = CKR_USER_ANOTHER_ALREADY_LOGGED_IN; + } + if (session_mgr_user_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_ALREADY_LOGGED_IN)); + rc = CKR_USER_ALREADY_LOGGED_IN; + } + } else if (userType == CKU_SO) { + if (session_mgr_user_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_ANOTHER_ALREADY_LOGGED_IN)); + rc = CKR_USER_ANOTHER_ALREADY_LOGGED_IN; + } + if (session_mgr_so_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_ALREADY_LOGGED_IN)); + rc = CKR_USER_ALREADY_LOGGED_IN; + } + if (session_mgr_readonly_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY_EXISTS)); + rc = CKR_SESSION_READ_ONLY_EXISTS; + } + } else { + rc = CKR_USER_TYPE_INVALID; + TRACE_ERROR("%s\n", ock_err(ERR_USER_TYPE_INVALID)); + } + if (rc != CKR_OK) + goto done; + + dat = &tokdata->nv_token_data->dat; + + if (userType == CKU_USER) { + if (*flags & CKF_USER_PIN_LOCKED) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LOCKED)); + rc = CKR_PIN_LOCKED; + goto done; + } + + /* Check if token has a specific handler for this, otherwise + * fall back to default behaviour. + */ + if (token_specific.t_login) { + // call the pluggable login function here - KEY + rc = token_specific.t_login(tokdata, sess, userType, + pPin, ulPinLen); + if (rc == CKR_OK) { + *flags &= ~(CKF_USER_PIN_LOCKED | + CKF_USER_PIN_FINAL_TRY | CKF_USER_PIN_COUNT_LOW); + } else if (rc == CKR_PIN_INCORRECT) { + set_login_flags(userType, flags); + } + goto done; + } + + if (tokdata->version < TOK_NEW_DATA_STORE) { + if (memcmp(tokdata->nv_token_data->user_pin_sha, + "00000000000000000000", SHA1_HASH_SIZE) == 0) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_PIN_NOT_INITIALIZED)); + rc = CKR_USER_PIN_NOT_INITIALIZED; + goto done; + } + + rc = compute_sha1(tokdata, pPin, ulPinLen, hash_sha); + if (memcmp(tokdata->nv_token_data->user_pin_sha, hash_sha, + SHA1_HASH_SIZE) != 0) { + set_login_flags(userType, flags); + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + /* Successful login, clear flags */ + *flags &= ~(CKF_USER_PIN_LOCKED | + CKF_USER_PIN_FINAL_TRY | CKF_USER_PIN_COUNT_LOW); + + compute_md5(tokdata, pPin, ulPinLen, tokdata->user_pin_md5); + memset(tokdata->so_pin_md5, 0x0, MD5_HASH_SIZE); + } else { + rc = PKCS5_PBKDF2_HMAC((char *)pPin, ulPinLen, + dat->user_login_salt, 64, + dat->user_login_it, EVP_sha512(), + 256 / 8, login_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + rc = PKCS5_PBKDF2_HMAC((char *)pPin, ulPinLen, + dat->user_wrap_salt, 64, + dat->user_wrap_it, EVP_sha512(), + 256 / 8, wrap_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (CRYPTO_memcmp(dat->user_login_key, + login_key, 256 / 8) != 0) { + set_login_flags(userType, flags); + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + + /* Successful login, clear flags */ + *flags &= ~(CKF_USER_PIN_LOCKED | + CKF_USER_PIN_FINAL_TRY | CKF_USER_PIN_COUNT_LOW); + + memcpy(tokdata->user_wrap_key, wrap_key, 256 / 8); + memset(tokdata->so_wrap_key, 0, 256 / 8); + } + + rc = load_masterkey_user(tokdata); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to load user's masterkey.\n"); + goto done; + } + + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get process lock.\n"); + goto done; + } + + /* no need to return error here, we load the token data + * we can and syslog the rest + */ + load_private_token_objects(tokdata); + + tokdata->global_shm->priv_loaded = TRUE; + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release process lock.\n"); + goto done; + } + } else { + if (*flags & CKF_SO_PIN_LOCKED) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LOCKED)); + rc = CKR_PIN_LOCKED; + goto done; + } + + /* Check if token has a specific handler for this, otherwise + * fall back to default behaviour. + */ + if (token_specific.t_login) { + /* call the pluggable login function here - KEY */ + rc = token_specific.t_login(tokdata, sess, userType, + pPin, ulPinLen); + if (rc == CKR_OK) { + *flags &= ~(CKF_SO_PIN_LOCKED | + CKF_SO_PIN_FINAL_TRY | CKF_SO_PIN_COUNT_LOW); + } else if (rc == CKR_PIN_INCORRECT) { + set_login_flags(userType, flags); + } + goto done; + } + + if (tokdata->version < TOK_NEW_DATA_STORE) { + rc = compute_sha1(tokdata, pPin, ulPinLen, hash_sha); + if (memcmp(tokdata->nv_token_data->so_pin_sha, hash_sha, SHA1_HASH_SIZE) + != 0) { + set_login_flags(userType, flags); + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + /* Successful login, clear flags */ + *flags &= ~(CKF_SO_PIN_LOCKED | CKF_SO_PIN_FINAL_TRY | + CKF_SO_PIN_COUNT_LOW); + + compute_md5(tokdata, pPin, ulPinLen, tokdata->so_pin_md5); + memset(tokdata->user_pin_md5, 0x0, MD5_HASH_SIZE); + } else { + rc = PKCS5_PBKDF2_HMAC((char *)pPin, ulPinLen, + dat->so_login_salt, 64, + dat->so_login_it, EVP_sha512(), + 256 / 8, login_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + rc = PKCS5_PBKDF2_HMAC((char *)pPin, ulPinLen, + dat->so_wrap_salt, 64, + dat->so_wrap_it, EVP_sha512(), + 256 / 8, wrap_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (CRYPTO_memcmp(dat->so_login_key, + login_key, 256 / 8) != 0) { + set_login_flags(userType, flags); + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + + /* Successful login, clear flags */ + *flags &= ~(CKF_SO_PIN_LOCKED | CKF_SO_PIN_FINAL_TRY | + CKF_SO_PIN_COUNT_LOW); + + memcpy(tokdata->so_wrap_key, wrap_key, 256 / 8); + memset(tokdata->user_wrap_key, 0, 256 / 8); + } + + rc = load_masterkey_so(tokdata); + if (rc != CKR_OK) + TRACE_DEVEL("Failed to load SO's masterkey.\n"); + } + +done: + if (rc == CKR_OK) { + rc = session_mgr_login_all(tokdata, userType); + if (rc != CKR_OK) + TRACE_DEVEL("session_mgr_login_all failed.\n"); + } + + TRACE_INFO("C_Login: rc = 0x%08lx\n", rc); + if (sess) + save_token_data(tokdata, sess->session_info.slotID); + + pthread_mutex_unlock(&tokdata->login_mutex); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Logout(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (pthread_mutex_lock(&tokdata->login_mutex)) { + TRACE_ERROR("Failed to get mutex lock.\n"); + return CKR_FUNCTION_FAILED; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + /* all sessions have the same state so we just have to check one */ + if (session_mgr_public_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + + rc = session_mgr_logout_all(tokdata); + if (rc != CKR_OK) + TRACE_DEVEL("session_mgr_logout_all failed.\n"); + + /* Check if token has a specific handler for this, otherwise fall back + * to default behaviour. + */ + if (token_specific.t_logout) { + rc = token_specific.t_logout(tokdata); + goto done; + } + + memset(tokdata->user_pin_md5, 0x0, MD5_HASH_SIZE); + memset(tokdata->so_pin_md5, 0x0, MD5_HASH_SIZE); + + object_mgr_purge_private_token_objects(tokdata); + +done: + TRACE_INFO("C_Logout: rc = 0x%08lx\n", rc); + + pthread_mutex_unlock(&tokdata->login_mutex); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_CreateObject(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phObject) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags)) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = object_mgr_add(tokdata, sess, pTemplate, ulCount, phObject); + if (rc != CKR_OK) + TRACE_DEVEL("object_mgr_add() failed.\n"); + +done: + if (sess != NULL) + session_mgr_put(tokdata, sess); + + TRACE_INFO("C_CreateObject: rc = 0x%08lx\n", rc); + +#ifdef DEBUG + CK_ULONG i; + + for (i = 0; i < ulCount; i++) { + if (pTemplate[i].type == CKA_CLASS) { + TRACE_DEBUG("Object Type: 0x%02lx\n", + *((CK_ULONG *) pTemplate[i].pValue)); + } + } + if (rc == CKR_OK) + TRACE_DEBUG("Handle: %lu\n", *phObject); +#endif + + return rc; +} + + +CK_RV SC_CopyObject(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = object_mgr_copy(tokdata, sess, pTemplate, ulCount, hObject, + phNewObject); + if (rc != CKR_OK) + TRACE_DEVEL("object_mgr_copy() failed\n"); + +done: + if (sess != NULL) + session_mgr_put(tokdata, sess); + + TRACE_INFO("C_CopyObject:rc = 0x%08lx,old handle = %lu, " + "new handle = %lu\n", rc, hObject, *phNewObject); + + return rc; +} + + +CK_RV SC_DestroyObject(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE hObject) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = object_mgr_destroy_object(tokdata, sess, hObject); + if (rc != CKR_OK) + TRACE_DEVEL("object_mgr_destroy_object() failed\n"); + +done: + if (sess != NULL) + session_mgr_put(tokdata, sess); + + TRACE_INFO("C_DestroyObject: rc = 0x%08lx, handle = %lu\n", rc, hObject); + + return rc; +} + + +CK_RV SC_GetObjectSize(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + rc = object_mgr_get_object_size(tokdata, hObject, pulSize); + if (rc != CKR_OK) + TRACE_ERROR("object_mgr_get_object_size() failed.\n"); + +done: + TRACE_INFO("C_GetObjectSize: rc = 0x%08lx, handle = %lu\n", rc, hObject); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_GetAttributeValue(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + rc = object_mgr_get_attribute_values(tokdata, sess, hObject, pTemplate, + ulCount); + if (rc != CKR_OK) + TRACE_DEVEL("object_mgr_get_attribute_value() failed.\n"); + +done: + TRACE_INFO("C_GetAttributeValue: rc = 0x%08lx, handle = %lu\n", + rc, hObject); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *ptr = NULL; + CK_ULONG i; + + attr = pTemplate; + for (i = 0; i < ulCount; i++, attr++) { + ptr = (CK_BYTE *) attr->pValue; + + TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + + if (attr->ulValueLen != (CK_ULONG) (-1) && (ptr != NULL)) + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } +#endif + + return rc; +} + + +CK_RV SC_SetAttributeValue(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + rc = object_mgr_set_attribute_values(tokdata, sess, hObject, pTemplate, + ulCount); + if (rc != CKR_OK) + TRACE_DEVEL("object_mgr_set_attribute_values() failed.\n"); + +done: + TRACE_INFO("C_SetAttributeValue: rc = 0x%08lx, handle = %lu\n", + rc, hObject); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_ULONG i; + + attr = pTemplate; + for (i = 0; i < ulCount; i++, attr++) { + CK_BYTE *ptr = (CK_BYTE *) attr->pValue; + + TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + + if (attr->ulValueLen != (CK_ULONG) (-1) && (ptr != NULL)) + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } +#endif + + return rc; +} + + +CK_RV SC_FindObjectsInit(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->find_active == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + rc = object_mgr_find_init(tokdata, sess, pTemplate, ulCount); + +done: + TRACE_INFO("C_FindObjectsInit: rc = 0x%08lx\n", rc); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_ULONG i; + + attr = pTemplate; + for (i = 0; i < ulCount; i++, attr++) { + CK_BYTE *ptr = (CK_BYTE *) attr->pValue; + + TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + + if (attr->ulValueLen != (CK_ULONG) (-1) && (ptr != NULL)) + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } +#endif + + return rc; +} + + +CK_RV SC_FindObjects(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, + CK_ULONG_PTR pulObjectCount) +{ + SESSION *sess = NULL; + CK_ULONG count = 0; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!phObject || !pulObjectCount) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->find_active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!sess->find_list) { + TRACE_DEVEL("sess->find_list is NULL.\n"); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + count = MIN(ulMaxObjectCount, (sess->find_count - sess->find_idx)); + + memcpy(phObject, sess->find_list + sess->find_idx, + count * sizeof(CK_OBJECT_HANDLE)); + *pulObjectCount = count; + + sess->find_idx += count; + rc = CKR_OK; + +done: + TRACE_INFO("C_FindObjects: rc = 0x%08lx, returned %lu objects\n", + rc, count); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_FindObjectsFinal(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->find_active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (sess->find_list) + free(sess->find_list); + + sess->find_list = NULL; + sess->find_len = 0; + sess->find_idx = 0; + sess->find_active = FALSE; + + rc = CKR_OK; + +done: + TRACE_INFO("C_FindObjectsFinal: rc = 0x%08lx\n", rc); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_EncryptInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_ENCRYPT); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->encr_ctx.active == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + rc = encr_mgr_init(tokdata, sess, &sess->encr_ctx, OP_ENCRYPT_INIT, + pMechanism, hKey); + +done: + TRACE_INFO("C_EncryptInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)(-1))); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Encrypt(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pData, CK_ULONG ulDataLen, + CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (!pData || !pulEncryptedDataLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (sess->encr_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pEncryptedData) + length_only = TRUE; + + rc = encr_mgr_encrypt(tokdata, sess, length_only, &sess->encr_ctx, pData, + ulDataLen, pEncryptedData, pulEncryptedDataLen); + if (rc != CKR_OK) + TRACE_DEVEL("encr_mgr_encrypt() failed.\n"); + +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { + if (sess) + encr_mgr_cleanup(&sess->encr_ctx); + } + + TRACE_INFO("C_Encrypt: rc = 0x%08lx, sess = %ld, amount = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulDataLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_EncryptUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if ((!pPart && ulPartLen != 0) || !pulEncryptedPartLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (sess->encr_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pEncryptedPart) + length_only = TRUE; + + rc = encr_mgr_encrypt_update(tokdata, sess, length_only, + &sess->encr_ctx, pPart, ulPartLen, + pEncryptedPart, pulEncryptedPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("encr_mgr_encrypt_update() failed.\n"); + +done: + if (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL) { + if (sess) + encr_mgr_cleanup(&sess->encr_ctx); + } + + TRACE_INFO("C_EncryptUpdate: rc = 0x%08lx, sess = %ld, amount = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_EncryptFinal(STDLL_TokData_t * tokdata, ST_SESSION_HANDLE * sSession, + CK_BYTE_PTR pLastEncryptedPart, + CK_ULONG_PTR pulLastEncryptedPartLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (!pulLastEncryptedPartLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (sess->encr_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pLastEncryptedPart) + length_only = TRUE; + + rc = encr_mgr_encrypt_final(tokdata, sess, length_only, &sess->encr_ctx, + pLastEncryptedPart, pulLastEncryptedPartLen); + if (rc != CKR_OK) + TRACE_ERROR("encr_mgr_encrypt_final() failed.\n"); + +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { + if (sess) + encr_mgr_cleanup(&sess->encr_ctx); + } + + TRACE_INFO("C_EncryptFinal: rc = 0x%08lx, sess = %ld\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DecryptInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_DECRYPT); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->decr_ctx.active == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + rc = decr_mgr_init(tokdata, sess, &sess->decr_ctx, OP_DECRYPT_INIT, + pMechanism, hKey); + if (rc != CKR_OK) + TRACE_DEVEL("decr_mgr_init() failed.\n"); + +done: + TRACE_INFO("C_DecryptInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)-1)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Decrypt(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, + CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (!pEncryptedData || !pulDataLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (sess->decr_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pData) + length_only = TRUE; + + rc = decr_mgr_decrypt(tokdata, sess, length_only, &sess->decr_ctx, + pEncryptedData, ulEncryptedDataLen, pData, + pulDataLen); + if (rc != CKR_OK) + TRACE_DEVEL("decr_mgr_decrypt() failed.\n"); + +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { + if (sess) + decr_mgr_cleanup(&sess->decr_ctx); + } + + TRACE_INFO("C_Decrypt: rc = 0x%08lx, sess = %ld, amount = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + ulEncryptedDataLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DecryptUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, + CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if ((!pEncryptedPart && ulEncryptedPartLen != 0) || !pulPartLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (sess->decr_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pPart) + length_only = TRUE; + + rc = decr_mgr_decrypt_update(tokdata, sess, length_only, + &sess->decr_ctx, pEncryptedPart, + ulEncryptedPartLen, pPart, pulPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("decr_mgr_decrypt_update() failed.\n"); + +done: + if (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL && sess != NULL) { + if (sess) + decr_mgr_cleanup(&sess->decr_ctx); + } + + TRACE_INFO("C_DecryptUpdate: rc = 0x%08lx, sess = %ld, amount = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + ulEncryptedPartLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DecryptFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (!pulLastPartLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (sess->decr_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pLastPart) + length_only = TRUE; + + rc = decr_mgr_decrypt_final(tokdata, sess, length_only, &sess->decr_ctx, + pLastPart, pulLastPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("decr_mgr_decrypt_final() failed.\n"); + +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { + if (sess) + decr_mgr_cleanup(&sess->decr_ctx); + } + + TRACE_INFO("C_DecryptFinal: rc = 0x%08lx, sess = %ld, amount = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pulLastPartLen ? *pulLastPartLen : 0)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DigestInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_DIGEST); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->digest_ctx.active == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + rc = digest_mgr_init(tokdata, sess, &sess->digest_ctx, pMechanism); + if (rc != CKR_OK) + TRACE_DEVEL("digest_mgr_init() failed.\n"); + +done: + TRACE_INFO("C_DigestInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)-1)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Digest(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, + CK_ULONG_PTR pulDigestLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->digest_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pDigest) + length_only = TRUE; + + rc = digest_mgr_digest(tokdata, sess, length_only, &sess->digest_ctx, + pData, ulDataLen, pDigest, pulDigestLen); + if (rc != CKR_OK) + TRACE_DEVEL("digest_mgr_digest() failed.\n"); + +done: + TRACE_INFO("C_Digest: rc = 0x%08lx, sess = %ld, datalen = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulDataLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DigestUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->digest_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + /* If there is data to hash, do so. */ + if (ulPartLen) { + rc = digest_mgr_digest_update(tokdata, sess, &sess->digest_ctx, + pPart, ulPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("digest_mgr_digest_update() failed.\n"); + } + +done: + TRACE_INFO("C_DigestUpdate: rc = 0x%08lx, sess = %ld, datalen = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DigestKey(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE hKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->digest_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + rc = digest_mgr_digest_key(tokdata, sess, &sess->digest_ctx, hKey); + if (rc != CKR_OK) + TRACE_DEVEL("digest_mgr_digest_key() failed.\n"); + +done: + TRACE_INFO("C_DigestKey: rc = 0x%08lx, sess = %ld, key = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, hKey); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DigestFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->digest_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pDigest) + length_only = TRUE; + + rc = digest_mgr_digest_final(tokdata, sess, length_only, + &sess->digest_ctx, pDigest, pulDigestLen); + if (rc != CKR_OK) + TRACE_ERROR("digest_mgr_digest_final() failed.\n"); + +done: + TRACE_INFO("C_DigestFinal: rc = 0x%08lx, sess = %ld\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_SignInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_SIGN); + if (rc != CKR_OK) + goto done; + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->sign_ctx.active == TRUE) { + rc = CKR_OPERATION_ACTIVE; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + goto done; + } + + rc = sign_mgr_init(tokdata, sess, &sess->sign_ctx, pMechanism, FALSE, hKey); + if (rc != CKR_OK) + TRACE_DEVEL("sign_mgr_init() failed.\n"); + +done: + TRACE_INFO("C_SignInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)-1)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Sign(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG_PTR pulSignatureLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pData || !pulSignatureLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->sign_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pSignature) + length_only = TRUE; + + rc = sign_mgr_sign(tokdata, sess, length_only, &sess->sign_ctx, pData, + ulDataLen, pSignature, pulSignatureLen); + if (rc != CKR_OK) + TRACE_DEVEL("sign_mgr_sign() failed.\n"); + +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) + sign_mgr_cleanup(&sess->sign_ctx); + + TRACE_INFO("C_Sign: rc = 0x%08lx, sess = %ld, datalen = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulDataLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_SignUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pPart && ulPartLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->sign_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + rc = sign_mgr_sign_update(tokdata, sess, &sess->sign_ctx, pPart, ulPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("sign_mgr_sign_update() failed.\n"); + +done: + if (rc != CKR_OK) + sign_mgr_cleanup(&sess->sign_ctx); + + TRACE_INFO("C_SignUpdate: rc = 0x%08lx, sess = %ld, datalen = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_SignFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pulSignatureLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->sign_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pSignature) + length_only = TRUE; + + rc = sign_mgr_sign_final(tokdata, sess, length_only, &sess->sign_ctx, + pSignature, pulSignatureLen); + if (rc != CKR_OK) + TRACE_ERROR("sign_mgr_sign_final() failed.\n"); + +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) + sign_mgr_cleanup(&sess->sign_ctx); + + TRACE_INFO("C_SignFinal: rc = 0x%08lx, sess = %ld\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_SignRecoverInit(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_SIGN_RECOVER); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->sign_ctx.active == TRUE) { + rc = CKR_OPERATION_ACTIVE; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + goto done; + } + + rc = sign_mgr_init(tokdata, sess, &sess->sign_ctx, pMechanism, TRUE, hKey); + if (rc != CKR_OK) + TRACE_DEVEL("sign_mgr_init() failed.\n"); + +done: + TRACE_INFO("C_SignRecoverInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)-1)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_SignRecover(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pData, CK_ULONG ulDataLen, + CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pData || !pulSignatureLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if ((sess->sign_ctx.active == FALSE) || (sess->sign_ctx.recover == FALSE)) { + rc = CKR_OPERATION_NOT_INITIALIZED; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + goto done; + } + + if (!pSignature) + length_only = TRUE; + + rc = sign_mgr_sign_recover(tokdata, sess, length_only, &sess->sign_ctx, + pData, ulDataLen, pSignature, pulSignatureLen); + if (rc != CKR_OK) + TRACE_DEVEL("sign_mgr_sign_recover() failed.\n"); + +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) + sign_mgr_cleanup(&sess->sign_ctx); + + TRACE_INFO("C_SignRecover: rc = 0x%08lx, sess = %ld, datalen = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulDataLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_VerifyInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_VERIFY); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->verify_ctx.active == TRUE) { + rc = CKR_OPERATION_ACTIVE; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + goto done; + } + + rc = verify_mgr_init(tokdata, sess, &sess->verify_ctx, pMechanism, + FALSE, hKey); + if (rc != CKR_OK) + TRACE_DEVEL("verify_mgr_init() failed.\n"); + +done: + TRACE_INFO("C_VerifyInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)-1)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Verify(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG ulSignatureLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pData || !pSignature) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->verify_ctx.active == FALSE) { + rc = CKR_OPERATION_NOT_INITIALIZED; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + goto done; + } + + rc = verify_mgr_verify(tokdata, sess, &sess->verify_ctx, pData, + ulDataLen, pSignature, ulSignatureLen); + if (rc != CKR_OK) + TRACE_DEVEL("verify_mgr_verify() failed.\n"); + +done: + verify_mgr_cleanup(&sess->verify_ctx); + + TRACE_INFO("C_Verify: rc = 0x%08lx, sess = %ld, datalen = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulDataLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_VerifyUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pPart && ulPartLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->verify_ctx.active == FALSE) { + rc = CKR_OPERATION_NOT_INITIALIZED; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + goto done; + } + + rc = verify_mgr_verify_update(tokdata, sess, &sess->verify_ctx, pPart, + ulPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("verify_mgr_verify_update() failed.\n"); + +done: + if (rc != CKR_OK) + verify_mgr_cleanup(&sess->verify_ctx); + + TRACE_INFO("C_VerifyUpdate: rc = 0x%08lx, sess = %ld, datalen = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_VerifyFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pSignature) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->verify_ctx.active == FALSE) { + rc = CKR_OPERATION_NOT_INITIALIZED; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + goto done; + } + + rc = verify_mgr_verify_final(tokdata, sess, &sess->verify_ctx, + pSignature, ulSignatureLen); + if (rc != CKR_OK) + TRACE_DEVEL("verify_mgr_verify_final() failed.\n"); + +done: + verify_mgr_cleanup(&sess->verify_ctx); + + TRACE_INFO("C_VerifyFinal: rc = 0x%08lx, sess = %ld\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_VerifyRecoverInit(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_VERIFY_RECOVER); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->verify_ctx.active == TRUE) { + rc = CKR_OPERATION_ACTIVE; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + goto done; + } + + rc = verify_mgr_init(tokdata, sess, &sess->verify_ctx, pMechanism, + TRUE, hKey); + if (rc != CKR_OK) + TRACE_DEVEL("verify_mgr_init() failed.\n"); + +done: + TRACE_INFO("C_VerifyRecoverInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)-1)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_VerifyRecover(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen, + CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pSignature || !pulDataLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if ((sess->verify_ctx.active == FALSE) || + (sess->verify_ctx.recover == FALSE)) { + rc = CKR_OPERATION_NOT_INITIALIZED; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + goto done; + } + + if (!pData) + length_only = TRUE; + + rc = verify_mgr_verify_recover(tokdata, sess, length_only, + &sess->verify_ctx, pSignature, + ulSignatureLen, pData, pulDataLen); + if (rc != CKR_OK) + TRACE_DEVEL("verify_mgr_verify_recover() failed.\n"); + +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) + verify_mgr_cleanup(&sess->verify_ctx); + + TRACE_INFO("C_VerifyRecover: rc = 0x%08lx, sess = %ld, recover len = %lu, " + "length_only = %d\n", rc, + (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pulDataLen ? *pulDataLen : 0), length_only); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DigestEncryptUpdate(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, CK_BYTE_PTR pPart, + CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen) +{ + UNUSED(sSession); + UNUSED(pPart); + UNUSED(ulPartLen); + UNUSED(pEncryptedPart); + UNUSED(pulEncryptedPartLen); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV SC_DecryptDigestUpdate(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, + CK_ULONG_PTR pulPartLen) +{ + UNUSED(sSession); + UNUSED(pEncryptedPart); + UNUSED(ulEncryptedPartLen); + UNUSED(pPart); + UNUSED(pulPartLen); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV SC_SignEncryptUpdate(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, CK_BYTE_PTR pPart, + CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen) +{ + UNUSED(sSession); + UNUSED(pPart); + UNUSED(ulPartLen); + UNUSED(pEncryptedPart); + UNUSED(pulEncryptedPartLen); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV SC_DecryptVerifyUpdate(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, + CK_ULONG_PTR pulPartLen) +{ + UNUSED(sSession); + UNUSED(pEncryptedPart); + UNUSED(ulEncryptedPartLen); + UNUSED(pPart); + UNUSED(pulPartLen); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV SC_GenerateKey(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism || !phKey || (pTemplate == NULL && ulCount != 0)) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_GENERATE); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = key_mgr_generate_key(tokdata, sess, pMechanism, pTemplate, + ulCount, phKey); + if (rc != CKR_OK) + TRACE_DEVEL("key_mgr_generate_key() failed.\n"); + +done: + TRACE_INFO("C_GenerateKey: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", rc, + (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)-1)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_ULONG i; + + attr = pTemplate; + if (attr != NULL) { + for (i = 0; i < ulCount; i++, attr++) { + CK_BYTE *ptr = (CK_BYTE *) attr->pValue; + TRACE_DEBUG("%lu: Attribute type: 0x%08lx,Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + if (attr->ulValueLen != ((CK_ULONG) - 1) && (ptr != NULL)) { + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } + } + } else { + TRACE_DEBUG("No attributes\n"); + } +#endif + + return rc; +} + + +CK_RV SC_GenerateKeyPair(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, + CK_ATTRIBUTE_PTR pPublicKeyTemplate, + CK_ULONG ulPublicKeyAttributeCount, + CK_ATTRIBUTE_PTR pPrivateKeyTemplate, + CK_ULONG ulPrivateKeyAttributeCount, + CK_OBJECT_HANDLE_PTR phPublicKey, + CK_OBJECT_HANDLE_PTR phPrivateKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism || !phPublicKey || !phPrivateKey || + (!pPublicKeyTemplate && (ulPublicKeyAttributeCount != 0)) || + (!pPrivateKeyTemplate && (ulPrivateKeyAttributeCount != 0))) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_GENERATE_KEY_PAIR); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = key_mgr_generate_key_pair(tokdata, sess, pMechanism, + pPublicKeyTemplate, + ulPublicKeyAttributeCount, + pPrivateKeyTemplate, + ulPrivateKeyAttributeCount, + phPublicKey, phPrivateKey); + if (rc != CKR_OK) + TRACE_DEVEL("key_mgr_generate_key_pair() failed.\n"); + +done: + TRACE_INFO("C_GenerateKeyPair: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : ((CK_LONG) sess->handle), + (pMechanism ? pMechanism->mechanism : (CK_ULONG)-1)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_ULONG i; + + if (rc == CKR_OK) { + TRACE_DEBUG("Public handle: %lu, Private handle: %lu\n", + *phPublicKey, *phPrivateKey); + } + + TRACE_DEBUG("Public Template:\n"); + attr = pPublicKeyTemplate; + if (attr != NULL) { + for (i = 0; i < ulPublicKeyAttributeCount; i++, attr++) { + CK_BYTE *ptr = (CK_BYTE *) attr->pValue; + TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + if (attr->ulValueLen != ((CK_ULONG) - 1) && (ptr != NULL)) + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } + } else { + TRACE_DEBUG("No Attributes\n"); + } + + TRACE_DEBUG("Private Template:\n"); + attr = pPublicKeyTemplate; + if (attr != NULL) { + for (i = 0; i < ulPublicKeyAttributeCount; i++, attr++) { + CK_BYTE *ptr = (CK_BYTE *) attr->pValue; + TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + if (attr->ulValueLen != (CK_ULONG) (-1) && (ptr != NULL)) + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } + } else { + TRACE_DEBUG("No Attributes\n"); + } +#endif + + return rc; +} + + +CK_RV SC_WrapKey(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey, + CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey, + CK_ULONG_PTR pulWrappedKeyLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism || !pulWrappedKeyLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_WRAP); + if (rc != CKR_OK) + goto done; + + if (!pWrappedKey) + length_only = TRUE; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = key_mgr_wrap_key(tokdata, sess, length_only, pMechanism, + hWrappingKey, hKey, pWrappedKey, pulWrappedKeyLen); + if (rc != CKR_OK) + TRACE_DEVEL("key_mgr_wrap_key() failed.\n"); + +done: + TRACE_INFO("C_WrapKey: rc = 0x%08lx, sess = %ld, encrypting key = %lu, " + "wrapped key = %lu\n", rc, + (sess == NULL) ? -1 : (CK_LONG) sess->handle, + hWrappingKey, hKey); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_UnwrapKey(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey, + CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism || !pWrappedKey || (!pTemplate && ulCount != 0) || !phKey) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_UNWRAP); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = key_mgr_unwrap_key(tokdata, sess, pMechanism, pTemplate, ulCount, + pWrappedKey, ulWrappedKeyLen, hUnwrappingKey, + phKey); + if (rc != CKR_OK) + TRACE_DEVEL("key_mgr_unwrap_key() failed.\n"); + +done: + TRACE_INFO("C_UnwrapKey: rc = 0x%08lx, sess = %ld, decrypting key = %lu," + "unwrapped key = %lu\n", rc, + (sess == NULL) ? -1 : (CK_LONG) sess->handle, + hUnwrappingKey, (phKey ? *phKey : 0)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *ptr = NULL; + CK_ULONG i; + + attr = pTemplate; + if (attr != NULL) { + for (i = 0; i < ulCount; i++, attr++) { + ptr = (CK_BYTE *) attr->pValue; + TRACE_DEBUG("%lu: Attribute type: 0x%08lx,Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + if (attr->ulValueLen != ((CK_ULONG) - 1) && (ptr != NULL)) { + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } + } + } else { + TRACE_DEBUG("No attributes\n"); + } +#endif + + return rc; +} + + +CK_RV SC_DeriveKey(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism || (!pTemplate && ulCount != 0)) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + if (pMechanism->mechanism != CKM_SSL3_KEY_AND_MAC_DERIVE && !phKey) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_DERIVE); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = key_mgr_derive_key(tokdata, sess, pMechanism, hBaseKey, phKey, + pTemplate, ulCount); + if (rc != CKR_OK) + TRACE_DEVEL("key_mgr_derive_key() failed.\n"); + +done: + TRACE_INFO("C_DeriveKey: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)(-1))); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *ptr = NULL; + CK_ULONG i; + + if (rc == CKR_OK) { + switch (pMechanism->mechanism) { + case CKM_SSL3_KEY_AND_MAC_DERIVE: + { + CK_SSL3_KEY_MAT_PARAMS *pReq; + CK_SSL3_KEY_MAT_OUT *pPtr; + pReq = (CK_SSL3_KEY_MAT_PARAMS *) pMechanism->pParameter; + pPtr = pReq->pReturnedKeyMaterial; + + TRACE_DEBUG("Client MAC key: %lu, Server MAC key: %lu, " + "Client Key: %lu, Server Key: %lu\n", + pPtr->hClientMacSecret, + pPtr->hServerMacSecret, pPtr->hClientKey, + pPtr->hServerKey); + } + break; + case CKM_DH_PKCS_DERIVE: + TRACE_DEBUG("DH Shared Secret:\n"); + break; + default: + TRACE_DEBUG("Derived key: %lu\n", *phKey); + } + } + + attr = pTemplate; + if (attr != NULL) { + for (i = 0; i < ulCount; i++, attr++) { + ptr = (CK_BYTE *) attr->pValue; + TRACE_DEBUG("%lu: Attribute type: 0x%08lx,Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + if (attr->ulValueLen != ((CK_ULONG) - 1) && (ptr != NULL)) { + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } + } + } else { + TRACE_DEBUG("No attributes\n"); + } +#endif /* DEBUG */ + return rc; +} + + +CK_RV SC_SeedRandom(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen) +{ + UNUSED(sSession); + UNUSED(pSeed); + UNUSED(ulSeedLen); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_RANDOM_SEED_NOT_SUPPORTED)); + + return CKR_RANDOM_SEED_NOT_SUPPORTED; +} + + +CK_RV SC_GenerateRandom(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pRandomData && ulRandomLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + rc = rng_generate(tokdata, pRandomData, ulRandomLen); + if (rc != CKR_OK) + TRACE_DEVEL("rng_generate() failed.\n"); + +done: + TRACE_INFO("C_GenerateRandom: rc = 0x%08lx, %lu bytes\n", rc, ulRandomLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_GetFunctionStatus(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession) +{ + UNUSED(sSession); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_PARALLEL)); + + return CKR_FUNCTION_NOT_PARALLEL; +} + + +CK_RV SC_CancelFunction(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession) +{ + UNUSED(sSession); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_PARALLEL)); + + return CKR_FUNCTION_NOT_PARALLEL; +} + + +void SC_SetFunctionList(void) +{ + function_list.ST_Initialize = ST_Initialize; + function_list.ST_GetTokenInfo = SC_GetTokenInfo; + function_list.ST_GetMechanismList = SC_GetMechanismList; + function_list.ST_GetMechanismInfo = SC_GetMechanismInfo; + function_list.ST_InitToken = SC_InitToken; + function_list.ST_InitPIN = SC_InitPIN; + function_list.ST_SetPIN = SC_SetPIN; + function_list.ST_OpenSession = SC_OpenSession; + function_list.ST_CloseSession = SC_CloseSession; + function_list.ST_GetSessionInfo = SC_GetSessionInfo; + function_list.ST_GetOperationState = SC_GetOperationState; + function_list.ST_SetOperationState = SC_SetOperationState; + function_list.ST_Login = SC_Login; + function_list.ST_Logout = SC_Logout; + function_list.ST_CreateObject = SC_CreateObject; + function_list.ST_CopyObject = SC_CopyObject; + function_list.ST_DestroyObject = SC_DestroyObject; + function_list.ST_GetObjectSize = SC_GetObjectSize; + function_list.ST_GetAttributeValue = SC_GetAttributeValue; + function_list.ST_SetAttributeValue = SC_SetAttributeValue; + function_list.ST_FindObjectsInit = SC_FindObjectsInit; + function_list.ST_FindObjects = SC_FindObjects; + function_list.ST_FindObjectsFinal = SC_FindObjectsFinal; + function_list.ST_EncryptInit = SC_EncryptInit; + function_list.ST_Encrypt = SC_Encrypt; + function_list.ST_EncryptUpdate = SC_EncryptUpdate; + function_list.ST_EncryptFinal = SC_EncryptFinal; + function_list.ST_DecryptInit = SC_DecryptInit; + function_list.ST_Decrypt = SC_Decrypt; + function_list.ST_DecryptUpdate = SC_DecryptUpdate; + function_list.ST_DecryptFinal = SC_DecryptFinal; + function_list.ST_DigestInit = SC_DigestInit; + function_list.ST_Digest = SC_Digest; + function_list.ST_DigestUpdate = SC_DigestUpdate; + function_list.ST_DigestKey = SC_DigestKey; + function_list.ST_DigestFinal = SC_DigestFinal; + function_list.ST_SignInit = SC_SignInit; + function_list.ST_Sign = SC_Sign; + function_list.ST_SignUpdate = SC_SignUpdate; + function_list.ST_SignFinal = SC_SignFinal; + function_list.ST_SignRecoverInit = SC_SignRecoverInit; + function_list.ST_SignRecover = SC_SignRecover; + function_list.ST_VerifyInit = SC_VerifyInit; + function_list.ST_Verify = SC_Verify; + function_list.ST_VerifyUpdate = SC_VerifyUpdate; + function_list.ST_VerifyFinal = SC_VerifyFinal; + function_list.ST_VerifyRecoverInit = SC_VerifyRecoverInit; + function_list.ST_VerifyRecover = SC_VerifyRecover; + function_list.ST_DigestEncryptUpdate = NULL; // SC_DigestEncryptUpdate; + function_list.ST_DecryptDigestUpdate = NULL; // SC_DecryptDigestUpdate; + function_list.ST_SignEncryptUpdate = NULL; //SC_SignEncryptUpdate; + function_list.ST_DecryptVerifyUpdate = NULL; // SC_DecryptVerifyUpdate; + function_list.ST_GenerateKey = SC_GenerateKey; + function_list.ST_GenerateKeyPair = SC_GenerateKeyPair; + function_list.ST_WrapKey = SC_WrapKey; + function_list.ST_UnwrapKey = SC_UnwrapKey; + function_list.ST_DeriveKey = SC_DeriveKey; + function_list.ST_SeedRandom = SC_SeedRandom; + function_list.ST_GenerateRandom = SC_GenerateRandom; + function_list.ST_GetFunctionStatus = NULL; // SC_GetFunctionStatus; + function_list.ST_CancelFunction = NULL; // SC_CancelFunction; +} diff --git a/usr/lib/common/obj_mgr.c b/usr/lib/common/obj_mgr.c new file mode 100644 index 0000000..3e4ba3b --- /dev/null +++ b/usr/lib/common/obj_mgr.c @@ -0,0 +1,2373 @@ +/* + * 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: obj_mgr.c +// +// Object manager related functions +// + +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "trace.h" + +#include "../api/apiproto.h" + +CK_RV object_mgr_add(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, CK_OBJECT_HANDLE *handle) +{ + OBJECT *o = NULL; + CK_BBOOL priv_obj, sess_obj, added = FALSE, locked = FALSE; + CK_RV rc; + unsigned long obj_handle; + + if (!sess || !pTemplate || !handle) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_ARGUMENTS_BAD; + } + + rc = object_create(tokdata, pTemplate, ulCount, &o); + if (rc != CKR_OK) { + TRACE_DEVEL("Object Create failed.\n"); + goto done; + } + + if (token_specific.t_object_add != NULL) { + rc = token_specific.t_object_add(tokdata, sess, o); + if (rc != CKR_OK) { + TRACE_DEVEL("Token specific object add failed.\n"); + goto done; + } + } + + // check whether session has permissions to create the object, etc + // + // Object R/O R/W R/O R/W R/W + // Type Public Public User User SO + // ------------------------------------------------------------- + // Public session R/W R/W R/W R/W R/W + // Private session R/W R/W + // Public token R/O R/W R/O R/W R/W + // Private token R/O R/W + // + sess_obj = object_is_session_object(o); + priv_obj = object_is_private(o); + + if (sess->session_info.state == CKS_RO_PUBLIC_SESSION) { + if (priv_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + + if (!sess_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY)); + rc = CKR_SESSION_READ_ONLY; + goto done; + } + } + + if (sess->session_info.state == CKS_RO_USER_FUNCTIONS) { + if (!sess_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY)); + rc = CKR_SESSION_READ_ONLY; + goto done; + } + } + + if (sess->session_info.state == CKS_RW_PUBLIC_SESSION) { + if (priv_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + } + + if (sess->session_info.state == CKS_RW_SO_FUNCTIONS) { + if (priv_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + } + // okay, object is created and the session permissions look okay. + // add the object to the appropriate list and assign an object handle + // + + if (sess_obj) { + o->session = sess; + memset(o->name, 0x00, sizeof(CK_BYTE) * 8); + + if ((obj_handle = bt_node_add(&tokdata->sess_obj_btree, o)) == 0) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + } else { + CK_BYTE current[8]; + CK_BYTE next[8]; + + // we'll be modifying nv_token_data so we should protect this part with + // the 'XProcLock' + // + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get Process Lock.\n"); + goto done; + } + locked = TRUE; + + // Determine if we have already reached our Max Token Objects + // + if (priv_obj) { + if (tokdata->global_shm->num_priv_tok_obj >= MAX_TOK_OBJS) { + rc = CKR_HOST_MEMORY; + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto done; + } + } else { + if (tokdata->global_shm->num_publ_tok_obj >= MAX_TOK_OBJS) { + rc = CKR_HOST_MEMORY; + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto done; + } + } + + memcpy(current, &tokdata->nv_token_data->next_token_object_name, 8); + + o->session = NULL; + memcpy(&o->name, current, 8); + + rc = compute_next_token_obj_name(current, next); + if (rc != CKR_OK) { + // TODO: handle error, check if rc is a valid per spec + goto done; + } + memcpy(&tokdata->nv_token_data->next_token_object_name, next, 8); + + rc = save_token_object(tokdata, o); + if (rc != CKR_OK) { + // TODO: handle error, check if rc is a valid per spec + goto done; + } + // add the object identifier to the shared memory segment + // + object_mgr_add_to_shm(o, tokdata->global_shm); + + // save_token_data has to lock the mutex itself because it's used + // elsewhere + rc = save_token_data(tokdata, sess->session_info.slotID); + if (rc != CKR_OK) { + // TODO: handle error, check if rc is a valid per spec + goto done; + } + + // now, store the object in the appropriate btree + // + if (priv_obj) + obj_handle = bt_node_add(&tokdata->priv_token_obj_btree, o); + else + obj_handle = bt_node_add(&tokdata->publ_token_obj_btree, o); + + if (!obj_handle) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + } + added = TRUE; + + rc = object_mgr_add_to_map(tokdata, sess, o, obj_handle, handle); + if (rc != CKR_OK) { + // we need to remove the object from whatever btree we just added it to + if (sess_obj) { + // put the binary tree node which holds o on the free list, but + // pass NULL here, so that o (the binary tree node's value pointer) + // isn't touched. It is free'd below + bt_node_free(&tokdata->sess_obj_btree, obj_handle, FALSE); + } else { + // we'll want to delete the token object file too! + // + delete_token_object(tokdata, o); + + if (priv_obj) { + // put the binary tree node which holds o on the free list, but + // pass NULL here, so that o (the binary tree node's value + // pointer) isn't touched. It is free'd below + bt_node_free(&tokdata->priv_token_obj_btree, obj_handle, FALSE); + } else { + // put the binary tree node which holds o on the free list, but + // pass NULL here, so that o (the binary tree node's value + // pointer) isn't touched. It is free'd below + bt_node_free(&tokdata->publ_token_obj_btree, obj_handle, FALSE); + } + + object_mgr_del_from_shm(o, tokdata->global_shm); + } + } + + +done: + if ((rc != CKR_OK) && (o != NULL)) { + if (!added) + object_free(o); + else + object_put(tokdata, o, FALSE); + o = NULL; + } + + if (locked) { + if (rc == CKR_OK) { + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release Process Lock.\n"); + } + } else { + /* return error that occurred first */ + XProcUnLock(tokdata); + } + } + + return rc; +} + + +// object_mgr_add_to_map() +// +CK_RV object_mgr_add_to_map(STDLL_TokData_t *tokdata, + SESSION *sess, + OBJECT *obj, + unsigned long obj_handle, + CK_OBJECT_HANDLE *map_handle) +{ + OBJECT_MAP *map_node = NULL; + + UNUSED(tokdata); + + if (!sess || !obj || !map_handle) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + // + // this guy doesn't lock a mutex because it's calling routines should have + // already locked it + // + + map_node = (OBJECT_MAP *) malloc(sizeof(OBJECT_MAP)); + if (!map_node) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + map_node->session = sess; + + if (obj->session != NULL) + map_node->is_session_obj = TRUE; + else + map_node->is_session_obj = FALSE; + + map_node->is_private = object_is_private(obj); + + // map_node->obj_handle will store the index of the btree node in one of + // these lists: + // publ_token_obj_btree - for public token object + // priv_token_obj_btree - for private token objects + // sess_obj_btree - for session objects + // + // *map_handle, the application's CK_OBJECT_HANDLE, will then be the index + // of the btree node in the object_map_btree + // + map_node->obj_handle = obj_handle; + *map_handle = bt_node_add(&tokdata->object_map_btree, map_node); + + if (*map_handle == 0) { + free(map_node); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + obj->map_handle = *map_handle; + + return CKR_OK; +} + + +// object_mgr_copy() +// +// algorithm: +// 1) find the old object +// 2) get the template from the old object +// 3) merge in the new object's template +// 4) perform class-specific sanity checks +// +CK_RV object_mgr_copy(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, + CK_OBJECT_HANDLE old_handle, + CK_OBJECT_HANDLE *new_handle) +{ + OBJECT *old_obj = NULL; + OBJECT *new_obj = NULL; + CK_BBOOL priv_obj; + CK_BBOOL sess_obj; + CK_BBOOL added = FALSE, locked = FALSE; + CK_RV rc; + unsigned long obj_handle; + + if (!sess || (!pTemplate && ulCount) || !new_handle) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + + rc = object_mgr_find_in_map1(tokdata, old_handle, &old_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_find_in_map1 failed.\n"); + goto done; + } + rc = object_copy(tokdata, pTemplate, ulCount, old_obj, &new_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("Object Copy failed.\n"); + goto done; + } + + // check whether session has permissions to create the object, etc + // + // Object R/O R/W R/O R/W R/W + // Type Public Public User User SO + // ------------------------------------------------------------- + // Public session R/W R/W R/W R/W R/W + // Private session R/W R/W + // Public token R/O R/W R/O R/W R/W + // Private token R/O R/W + // + sess_obj = object_is_session_object(new_obj); + priv_obj = object_is_private(new_obj); + + if (sess->session_info.state == CKS_RO_PUBLIC_SESSION) { + if (priv_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + + if (!sess_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY)); + rc = CKR_SESSION_READ_ONLY; + goto done; + } + } + + if (sess->session_info.state == CKS_RO_USER_FUNCTIONS) { + if (!sess_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY)); + rc = CKR_SESSION_READ_ONLY; + goto done; + } + } + + if (sess->session_info.state == CKS_RW_PUBLIC_SESSION) { + if (priv_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + } + + if (sess->session_info.state == CKS_RW_SO_FUNCTIONS) { + if (priv_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + } + // okay, object is created and the session permissions look okay. + // add the object to the appropriate list and assign an object handle + // + + if (sess_obj) { + new_obj->session = sess; + memset(&new_obj->name, 0x00, sizeof(CK_BYTE) * 8); + + if ((obj_handle = bt_node_add(&tokdata->sess_obj_btree, new_obj)) == 0) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + } else { + CK_BYTE current[8]; + CK_BYTE next[8]; + + // we'll be modifying nv_token_data so we should protect this part + // with 'XProcLock' + // + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get Process Lock.\n"); + goto done; + } + locked = TRUE; + + // Determine if we have already reached our Max Token Objects + // + if (priv_obj) { + if (tokdata->global_shm->num_priv_tok_obj >= MAX_TOK_OBJS) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + } else { + if (tokdata->global_shm->num_publ_tok_obj >= MAX_TOK_OBJS) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + } + memcpy(current, &tokdata->nv_token_data->next_token_object_name, 8); + + new_obj->session = NULL; + memcpy(&new_obj->name, current, 8); + + compute_next_token_obj_name(current, next); + memcpy(&tokdata->nv_token_data->next_token_object_name, next, 8); + + save_token_object(tokdata, new_obj); + + // add the object identifier to the shared memory segment + // + object_mgr_add_to_shm(new_obj, tokdata->global_shm); + + save_token_data(tokdata, sess->session_info.slotID); + + // now, store the object in the token object btree + // + if (priv_obj) + obj_handle = bt_node_add(&tokdata->priv_token_obj_btree, new_obj); + else + obj_handle = bt_node_add(&tokdata->publ_token_obj_btree, new_obj); + + if (!obj_handle) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + } + added = TRUE; + + rc = object_mgr_add_to_map(tokdata, sess, new_obj, obj_handle, new_handle); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_add_to_map failed.\n"); + + // this is messy but we need to remove the object from whatever + // list we just added it to + // + if (sess_obj) { + // put the binary tree node which holds new_obj on the free list, + // but pass NULL here, so that new_obj (the binary tree node's value + // pointer) isn't touched. It is free'd below + bt_node_free(&tokdata->sess_obj_btree, obj_handle, FALSE); + } else { + delete_token_object(tokdata, new_obj); + + if (priv_obj) { + // put the binary tree node which holds new_obj on the free + // list, but pass NULL here, so that new_obj (the binary tree + // node's value pointer) isn't touched. It is free'd below + bt_node_free(&tokdata->priv_token_obj_btree, obj_handle, FALSE); + } else { + // put the binary tree node which holds new_obj on the free + // list, but pass NULL here, so that new_obj (the binary tree + // node's value pointer) isn't touched. It is free'd below + bt_node_free(&tokdata->publ_token_obj_btree, obj_handle, FALSE); + } + + object_mgr_del_from_shm(new_obj, tokdata->global_shm); + } + } + +done: + if ((rc != CKR_OK) && (new_obj != NULL)) { + if (!added) + object_free(new_obj); + else + object_put(tokdata, new_obj, FALSE); + new_obj = NULL; + } + object_put(tokdata, old_obj, TRUE); + old_obj = NULL; + + if (locked) { + if (rc == CKR_OK) { + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release Process Lock.\n"); + goto done; + } + } else { + /* return error that occurred first */ + XProcUnLock(tokdata); + } + } + + return rc; +} + + +// determines whether the session is allowed to create an object. creates +// the object but doesn't add the object to any object lists or to the +// process' object map. +// +CK_RV object_mgr_create_skel(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, + CK_ULONG mode, + CK_ULONG obj_type, + CK_ULONG sub_class, OBJECT **obj) +{ + OBJECT *o = NULL; + CK_RV rc; + CK_BBOOL priv_obj; + CK_BBOOL sess_obj; + + if (!sess || !obj) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (!pTemplate && (ulCount != 0)) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + // + // we don't need to lock mutex for this routine + // + + rc = object_create_skel(tokdata, pTemplate, ulCount, + mode, obj_type, sub_class, &o); + if (rc != CKR_OK) { + TRACE_DEVEL("object_create_skel failed.\n"); + return rc; + } + sess_obj = object_is_session_object(o); + priv_obj = object_is_private(o); + + if (sess->session_info.state == CKS_RO_PUBLIC_SESSION) { + if (priv_obj) { + object_free(o); + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + return CKR_USER_NOT_LOGGED_IN; + } + + if (!sess_obj) { + object_free(o); + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY)); + return CKR_SESSION_READ_ONLY; + } + } + + if (sess->session_info.state == CKS_RO_USER_FUNCTIONS) { + if (!sess_obj) { + object_free(o); + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY)); + return CKR_SESSION_READ_ONLY; + } + } + + if (sess->session_info.state == CKS_RW_PUBLIC_SESSION) { + if (priv_obj) { + object_free(o); + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + return CKR_USER_NOT_LOGGED_IN; + } + } + + if (sess->session_info.state == CKS_RW_SO_FUNCTIONS) { + if (priv_obj) { + object_free(o); + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + return CKR_USER_NOT_LOGGED_IN; + } + } + + *obj = o; + + return CKR_OK; +} + +/* + * Finalizes the object creation and adds the object into the appropriate + * btree and also the object map btree. + * When this function succeeds, object obj must not be freed! It has been added + * to the btree and thus must be kept intact. + * When this function fails, then the object obj must be freed by the caller + * using object_free() (not object_put() nor bt_put_node_value() !) + */ +CK_RV object_mgr_create_final(STDLL_TokData_t *tokdata, + SESSION *sess, + OBJECT *obj, CK_OBJECT_HANDLE *handle) +{ + CK_BBOOL sess_obj; + CK_BBOOL priv_obj; + CK_BBOOL locked = FALSE; + CK_RV rc; + unsigned long obj_handle; + + if (!sess || !obj || !handle) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + + sess_obj = object_is_session_object(obj); + priv_obj = object_is_private(obj); + + if (sess_obj) { + obj->session = sess; + memset(obj->name, 0x0, sizeof(CK_BYTE) * 8); + + if ((obj_handle = bt_node_add(&tokdata->sess_obj_btree, obj)) == 0) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + } else { + CK_BYTE current[8]; + CK_BYTE next[8]; + + // we'll be modifying nv_token_data so we should protect this part + // with 'XProcLock' + // + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get Process Lock.\n"); + return rc; + } + locked = TRUE; + + // Determine if we have already reached our Max Token Objects + // + if (priv_obj) { + if (tokdata->global_shm->num_priv_tok_obj >= MAX_TOK_OBJS) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + } else { + if (tokdata->global_shm->num_publ_tok_obj >= MAX_TOK_OBJS) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + } + memcpy(current, &tokdata->nv_token_data->next_token_object_name, 8); + + obj->session = NULL; + memcpy(&obj->name, current, 8); + + compute_next_token_obj_name(current, next); + memcpy(&tokdata->nv_token_data->next_token_object_name, next, 8); + + save_token_object(tokdata, obj); + + // add the object identifier to the shared memory segment + // + object_mgr_add_to_shm(obj, tokdata->global_shm); + + save_token_data(tokdata, sess->session_info.slotID); + + // now, store the object in the token object btree + // + if (priv_obj) + obj_handle = bt_node_add(&tokdata->priv_token_obj_btree, obj); + else + obj_handle = bt_node_add(&tokdata->publ_token_obj_btree, obj); + + if (!obj_handle) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + } + + rc = object_mgr_add_to_map(tokdata, sess, obj, obj_handle, handle); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_add_to_map failed.\n"); + // this is messy but we need to remove the object from whatever + // list we just added it to + // + if (sess_obj) { + // put the binary tree node which holds obj on the free list, but + // pass NULL here, so that obj (the binary tree node's value + // pointer) isn't touched. + // It is free'd by the caller of object_mgr_create_final + bt_node_free(&tokdata->sess_obj_btree, obj_handle, FALSE); + } else { + delete_token_object(tokdata, obj); + + if (priv_obj) { + // put the binary tree node which holds obj on the free list, + // but pass NULL here, so that obj (the binary tree node's value + // pointer) isn't touched. It is free'd by the caller of + // object_mgr_create_final + bt_node_free(&tokdata->priv_token_obj_btree, obj_handle, FALSE); + } else { + // put the binary tree node which holds obj on the free list, + // but pass NULL here, so that obj (the binary tree node's value + // pointer) isn't touched. It is free'd by the caller of + // object_mgr_create_final + bt_node_free(&tokdata->publ_token_obj_btree, obj_handle, FALSE); + } + + object_mgr_del_from_shm(obj, tokdata->global_shm); + } + } + +done: + if (locked) { + if (rc == CKR_OK) { + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release Process Lock.\n"); + } + } else { + /* return error that occurred first */ + XProcUnLock(tokdata); + } + } + + return rc; +} + +CK_RV object_mgr_destroy_object(STDLL_TokData_t *tokdata, + SESSION *sess, CK_OBJECT_HANDLE handle) +{ + CK_RV rc = CKR_OK; + OBJECT_MAP *map; + OBJECT *o = NULL; + CK_BBOOL locked = FALSE; + + UNUSED(sess); + + /* Don't use a delete callback, the map will be freed below */ + map = bt_node_free(&tokdata->object_map_btree, handle, FALSE); + if (map == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); + return CKR_OBJECT_HANDLE_INVALID; + } + + if (map->is_session_obj) { + bt_node_free(&tokdata->sess_obj_btree, map->obj_handle, TRUE); + } else { + if (XProcLock(tokdata)) { + TRACE_ERROR("Failed to get Process Lock.\n"); + return CKR_CANT_LOCK; + } + locked = TRUE; + + if (map->is_private) + o = bt_get_node_value(&tokdata->priv_token_obj_btree, + map->obj_handle); + else + o = bt_get_node_value(&tokdata->publ_token_obj_btree, + map->obj_handle); + + if (!o) { + rc = CKR_OBJECT_HANDLE_INVALID; + goto done; + } + + + delete_token_object(tokdata, o); + + DUMP_SHM(tokdata->global_shm, "before"); + object_mgr_del_from_shm(o, tokdata->global_shm); + DUMP_SHM(tokdata->global_shm, "after"); + + if (map->is_private) { + bt_put_node_value(&tokdata->priv_token_obj_btree, o); + bt_node_free(&tokdata->priv_token_obj_btree, map->obj_handle, TRUE); + } else { + bt_put_node_value(&tokdata->publ_token_obj_btree, o); + bt_node_free(&tokdata->publ_token_obj_btree, map->obj_handle, TRUE); + } + o = NULL; + } + +done: + if (o != NULL) { + if (map->is_private) + bt_put_node_value(&tokdata->priv_token_obj_btree, o); + else + bt_put_node_value(&tokdata->publ_token_obj_btree, o); + o = NULL; + } + + bt_put_node_value(&tokdata->object_map_btree, map); + + if (locked) { + if (rc == CKR_OK) { + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release Process Lock.\n"); + } + } else { + /* return error that occurred first */ + XProcUnLock(tokdata); + } + } + + return rc; +} + +/* delete_token_obj_cb + * + * Callback to delete an object if its a token object + */ +void delete_token_obj_cb(STDLL_TokData_t *tokdata, void *node, + unsigned long map_handle, void *p3) +{ + OBJECT_MAP *map = (OBJECT_MAP *) node; + OBJECT *o = NULL; + CK_BBOOL locked = FALSE; + + UNUSED(p3); + + if (!(map->is_session_obj)) { + if (map->is_private) + o = bt_get_node_value(&tokdata->priv_token_obj_btree, + map->obj_handle); + else + o = bt_get_node_value(&tokdata->publ_token_obj_btree, + map->obj_handle); + + if (!o) + goto done; + + /* Use the same calling convention as the old code, if + * XProcLock fails, don't delete from shm and don't free + * the object in its other btree + */ + if (XProcLock(tokdata)) { + TRACE_ERROR("Failed to get Process Lock.\n"); + goto done; + } + locked = TRUE; + + delete_token_object(tokdata, o); + + object_mgr_del_from_shm(o, tokdata->global_shm); + + if (map->is_private) { + bt_put_node_value(&tokdata->priv_token_obj_btree, o); + bt_node_free(&tokdata->priv_token_obj_btree, map->obj_handle, TRUE); + } + else { + bt_put_node_value(&tokdata->publ_token_obj_btree, o); + bt_node_free(&tokdata->publ_token_obj_btree, map->obj_handle, TRUE); + } + o = NULL; + } + +done: + if (o != NULL) { + if (map->is_private) + bt_put_node_value(&tokdata->priv_token_obj_btree, o); + else + bt_put_node_value(&tokdata->publ_token_obj_btree, o); + o = NULL; + } + /* delete @node from this btree */ + bt_node_free(&tokdata->object_map_btree, map_handle, TRUE); + + if (locked) { + if (XProcUnLock(tokdata)) { + TRACE_ERROR("Failed to release Process Lock.\n"); + } + } +} + +// this routine will destroy all token objects in the system +// +CK_RV object_mgr_destroy_token_objects(STDLL_TokData_t *tokdata) +{ + CK_RV rc; + + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get Process Lock.\n"); + goto done; + } + + bt_for_each_node(tokdata, &tokdata->object_map_btree, delete_token_obj_cb, + NULL); + + // now we want to purge the token object list in shared memory + // + tokdata->global_shm->num_priv_tok_obj = 0; + tokdata->global_shm->num_publ_tok_obj = 0; + + memset(&tokdata->global_shm->publ_tok_objs, 0x0, + MAX_TOK_OBJS * sizeof(TOK_OBJ_ENTRY)); + memset(&tokdata->global_shm->priv_tok_objs, 0x0, + MAX_TOK_OBJS * sizeof(TOK_OBJ_ENTRY)); + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release Process Lock.\n"); + goto done; + } + +done: + return rc; +} + + + + + +// object_mgr_find_in_map_nocache() +// +// Locates the specified object in the map +// without going and checking for cache update +// +// The returned Object must be put back (using object_put()) by the +// caller to decrease the reference count! +// +// The returned object is locked (depending on lock_type), and must be unlocked +// by the caller! +// +CK_RV object_mgr_find_in_map_nocache(STDLL_TokData_t *tokdata, + CK_OBJECT_HANDLE handle, OBJECT **ptr, + OBJ_LOCK_TYPE lock_type) +{ + OBJECT_MAP *map = NULL; + OBJECT *obj = NULL; + CK_RV rc = CKR_OK; + + + if (!ptr) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + + if (!handle) { + TRACE_ERROR("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); + return CKR_OBJECT_HANDLE_INVALID; + } + // + // no mutex here. the calling function should have locked the mutex + // + + map = bt_get_node_value(&tokdata->object_map_btree, handle); + if (!map) { + TRACE_ERROR("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); + return CKR_OBJECT_HANDLE_INVALID; + } + + if (map->is_session_obj) + obj = bt_get_node_value(&tokdata->sess_obj_btree, map->obj_handle); + else if (map->is_private) + obj = bt_get_node_value(&tokdata->priv_token_obj_btree, map->obj_handle); + else + obj = bt_get_node_value(&tokdata->publ_token_obj_btree, map->obj_handle); + + bt_put_node_value(&tokdata->object_map_btree, map); + map = NULL; + + if (!obj) { + TRACE_ERROR("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); + return CKR_OBJECT_HANDLE_INVALID; + } + + rc = object_lock(obj, lock_type); + if (rc != CKR_OK) { + object_put(tokdata, obj, FALSE); + obj = NULL; + return rc; + } + + *ptr = obj; + + return rc; +} + +// object_mgr_find_in_map1() +// +// Locates the specified object in the map +// +// The returned Object must be put back (using object_put()) by the +// caller to decrease the reference count! +// +// The returned object is locked (depending on lock_type), and must be unlocked +// by the caller! +// +CK_RV object_mgr_find_in_map1(STDLL_TokData_t *tokdata, + CK_OBJECT_HANDLE handle, OBJECT **ptr, + OBJ_LOCK_TYPE lock_type) +{ + OBJECT_MAP *map = NULL; + OBJECT *obj = NULL; + CK_RV rc = CKR_OK; + CK_BBOOL session_obj, locked = FALSE; + + if (!ptr) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + + map = bt_get_node_value(&tokdata->object_map_btree, handle); + if (!map) { + TRACE_ERROR("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); + return CKR_OBJECT_HANDLE_INVALID; + } + + session_obj = map->is_session_obj; + if (map->is_session_obj) + obj = bt_get_node_value(&tokdata->sess_obj_btree, map->obj_handle); + else if (map->is_private) + obj = bt_get_node_value(&tokdata->priv_token_obj_btree, map->obj_handle); + else + obj = bt_get_node_value(&tokdata->publ_token_obj_btree, map->obj_handle); + + bt_put_node_value(&tokdata->object_map_btree, map); + map = NULL; + + if (!obj) { + TRACE_ERROR("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); + return CKR_OBJECT_HANDLE_INVALID; + } + + /* SAB XXX Fix me.. need to make it more efficient than just looking + * for the object to be changed. set a global flag that contains the + * ref count to all objects.. if the shm ref count changes, then we + * update the object. if not + */ + + /* Note: Each C_Initialize call loads up the public token objects + * and build corresponding tree(s). The same for private token objects + * upon successful C_Login. Since token objects can be shared, it is + * possible another process or session has deleted a token object. + * 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); + if (rc != CKR_OK) + goto done; + locked = TRUE; + + rc = object_mgr_check_shm(tokdata, obj); + 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); + if (rc != CKR_OK) + goto done; + locked = FALSE; + } + + rc = object_lock(obj, lock_type); + if (rc != CKR_OK) + goto done; + +done: + if (rc == CKR_OK) { + *ptr = obj; + } else { + object_put(tokdata, obj, locked); + obj = NULL; + } + + return rc; +} + +void find_obj_cb(STDLL_TokData_t *tokdata, void *node, + unsigned long map_handle, void *p3) +{ + OBJECT_MAP *map = (OBJECT_MAP *) node; + OBJECT *obj; + struct find_args *fa = (struct find_args *) p3; + + UNUSED(tokdata); + + if (fa->done) + return; + + if (map->is_session_obj) + obj = bt_get_node_value(&tokdata->sess_obj_btree, map->obj_handle); + else if (map->is_private) + obj = bt_get_node_value(&tokdata->priv_token_obj_btree, map->obj_handle); + else + obj = bt_get_node_value(&tokdata->publ_token_obj_btree, map->obj_handle); + + if (!obj) + return; + + /* if this object is the one we're looking for (matches p3->obj), return + * its map_handle in p3->map_handle */ + if (obj == fa->obj) { + fa->map_handle = map_handle; + fa->done = TRUE; + } + + if (map->is_session_obj) + bt_put_node_value(&tokdata->sess_obj_btree, obj); + else if (map->is_private) + bt_put_node_value(&tokdata->priv_token_obj_btree, obj); + else + bt_put_node_value(&tokdata->publ_token_obj_btree, obj); + obj = NULL; +} + +// object_mgr_find_in_map2() +// +// The caller must already have locked the passed object (READ_LOCK)! +// +CK_RV object_mgr_find_in_map2(STDLL_TokData_t *tokdata, + OBJECT *obj, CK_OBJECT_HANDLE *handle) +{ + struct find_args fa; + CK_RV rc; + + if (!obj || !handle) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + + fa.done = FALSE; + fa.obj = obj; + fa.map_handle = 0; + + // pass the fa structure with the values to operate on in the find_obj_cb + // function + bt_for_each_node(tokdata, &tokdata->object_map_btree, find_obj_cb, &fa); + + if (fa.done == FALSE || fa.map_handle == 0) { + return CKR_OBJECT_HANDLE_INVALID; + } + + *handle = fa.map_handle; + + if (!object_is_session_object(obj)) { + rc = object_mgr_check_shm(tokdata, obj); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_check_shm failed.\n"); + return rc; + } + } + + return CKR_OK; +} + +void find_build_list_cb(STDLL_TokData_t *tokdata, void *node, + unsigned long obj_handle, void *p3) +{ + OBJECT *obj = (OBJECT *) node; + struct find_build_list_args *fa = (struct find_build_list_args *) p3; + CK_OBJECT_HANDLE map_handle; + CK_ATTRIBUTE *attr; + CK_BBOOL match = FALSE; + CK_RV rc; + + if (object_lock(obj, READ_LOCK) != CKR_OK) + return; + + if ((object_is_private(obj) == FALSE) || (fa->public_only == FALSE)) { + // if the user doesn't specify any template attributes then we return + // all objects + // + if (fa->pTemplate == NULL || fa->ulCount == 0) + match = TRUE; + else + match = template_compare(fa->pTemplate, fa->ulCount, obj->template); + } + // if we have a match, find the object in the map (add it if necessary) + // then add the object to the list of found objects // + if (match) { + rc = object_mgr_find_in_map2(tokdata, obj, &map_handle); + if (rc != CKR_OK) { + rc = object_mgr_add_to_map(tokdata, fa->sess, obj, obj_handle, + &map_handle); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_add_to_map failed.\n"); + goto done; + } + } + // If hw_feature is false here, we need to filter out all objects + // that have the CKO_HW_FEATURE attribute set. - KEY + if ((fa->hw_feature == FALSE) && + (template_attribute_find(obj->template, CKA_CLASS, &attr) == + TRUE)) { + if (attr->pValue == NULL) { + TRACE_DEVEL("%s\n", ock_err(ERR_GENERAL_ERROR)); + goto done; + } + if (*(CK_OBJECT_CLASS *) attr->pValue == CKO_HW_FEATURE) + goto done; + } + + /* Don't find objects that have been created with the CKA_HIDDEN + * attribute set */ + if ((fa->hidden_object == FALSE) && + (template_attribute_find(obj->template, CKA_HIDDEN, &attr) == + TRUE)) { + if (*(CK_BBOOL *) attr->pValue == TRUE) + goto done; + } + + fa->sess->find_list[fa->sess->find_count] = map_handle; + fa->sess->find_count++; + + if (fa->sess->find_count >= fa->sess->find_len) { + fa->sess->find_len += 15; + fa->sess->find_list = + (CK_OBJECT_HANDLE *) realloc(fa->sess->find_list, + fa->sess->find_len * + sizeof(CK_OBJECT_HANDLE)); + if (!fa->sess->find_list) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto done; + } + } + } + +done: + object_unlock(obj); +} + +CK_RV object_mgr_find_init(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount) +{ + struct find_build_list_args fa; + CK_ULONG i; + CK_RV rc; + // it is possible the pTemplate == NULL + // + + if (!sess) { + TRACE_ERROR("Invalid function argument.\n"); + return CKR_FUNCTION_FAILED; + } + if (sess->find_active != FALSE) { + return CKR_OPERATION_ACTIVE; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + } + // initialize the found object list. if it doesn't exist, allocate + // a list big enough for 10 handles. we'll reallocate if we need more + // + if (sess->find_list != NULL) { + memset(sess->find_list, 0x0, sess->find_len * sizeof(CK_OBJECT_HANDLE)); + } else { + sess->find_list = + (CK_OBJECT_HANDLE *) malloc(10 * sizeof(CK_OBJECT_HANDLE)); + if (!sess->find_list) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } else { + memset(sess->find_list, 0x0, 10 * sizeof(CK_OBJECT_HANDLE)); + sess->find_len = 10; + } + } + + sess->find_count = 0; + sess->find_idx = 0; + + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get Process Lock.\n"); + return rc; + } + + object_mgr_update_from_shm(tokdata); + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release Process Lock.\n"); + return rc; + } + + fa.hw_feature = FALSE; + fa.hidden_object = FALSE; + fa.sess = sess; + fa.pTemplate = pTemplate; + fa.ulCount = ulCount; + + // which objects can be returned: + // + // Public Session: public session objects, public token objects + // User Session: all session objects, all token objects + // SO session: public session objects, public token objects + // + // PKCS#11 v2.11 (pg. 79): "When searching using C_FindObjectsInit + // and C_FindObjects, hardware feature objects are not returned + // unless the CKA_CLASS attribute in the template has the value + // CKO_HW_FEATURE." So, we check for CKO_HW_FEATURE and if its set, + // we'll find these objects below. - KEY + for (i = 0; i < ulCount; i++) { + if (pTemplate[i].type == CKA_CLASS) { + if (*(CK_ULONG *) pTemplate[i].pValue == CKO_HW_FEATURE) { + fa.hw_feature = TRUE; + } + } + + /* only find CKA_HIDDEN objects if its specified in the template. */ + if (pTemplate[i].type == CKA_HIDDEN) { + if (*(CK_BBOOL *) pTemplate[i].pValue == TRUE) { + fa.hidden_object = TRUE; + } + } + } + + switch (sess->session_info.state) { + case CKS_RO_PUBLIC_SESSION: + case CKS_RW_PUBLIC_SESSION: + case CKS_RW_SO_FUNCTIONS: + fa.public_only = TRUE; + + bt_for_each_node(tokdata, &tokdata->publ_token_obj_btree, + find_build_list_cb, &fa); + bt_for_each_node(tokdata, &tokdata->sess_obj_btree, find_build_list_cb, + &fa); + break; + case CKS_RO_USER_FUNCTIONS: + case CKS_RW_USER_FUNCTIONS: + fa.public_only = FALSE; + + bt_for_each_node(tokdata, &tokdata->priv_token_obj_btree, + find_build_list_cb, &fa); + bt_for_each_node(tokdata, &tokdata->publ_token_obj_btree, + find_build_list_cb, &fa); + bt_for_each_node(tokdata, &tokdata->sess_obj_btree, find_build_list_cb, + &fa); + break; + } + + sess->find_active = TRUE; + + return CKR_OK; +} + +// +// +CK_RV object_mgr_find_final(SESSION *sess) +{ + if (!sess) { + TRACE_ERROR("Invalid function argument.\n"); + return CKR_FUNCTION_FAILED; + } + if (sess->find_active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + free(sess->find_list); + sess->find_list = NULL; + sess->find_count = 0; + sess->find_idx = 0; + sess->find_active = FALSE; + + return CKR_OK; +} + + +// +// +CK_RV object_mgr_get_attribute_values(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_OBJECT_HANDLE handle, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount) +{ + OBJECT *obj; + CK_BBOOL priv_obj; + CK_RV rc; + + if (!pTemplate) { + TRACE_ERROR("Invalid function argument.\n"); + return CKR_FUNCTION_FAILED; + } + + rc = object_mgr_find_in_map1(tokdata, handle, &obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_find_in_map1 failed.\n"); + return rc; + } + priv_obj = object_is_private(obj); + + if (priv_obj == TRUE) { + if (sess->session_info.state == CKS_RO_PUBLIC_SESSION || + sess->session_info.state == CKS_RW_PUBLIC_SESSION) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + } + + rc = object_get_attribute_values(obj, pTemplate, ulCount); + if (rc != CKR_OK) + TRACE_DEVEL("object_get_attribute_values failed.\n"); + +done: + object_put(tokdata, obj, TRUE); + obj = NULL; + + return rc; +} + + +// +// +CK_RV object_mgr_get_object_size(STDLL_TokData_t *tokdata, + CK_OBJECT_HANDLE handle, CK_ULONG *size) +{ + OBJECT *obj; + CK_RV rc; + + rc = object_mgr_find_in_map1(tokdata, handle, &obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_find_in_map1 failed.\n"); + return rc; + } + + *size = object_get_size(obj); + + object_put(tokdata, obj, TRUE); + obj = NULL; + + return rc; +} + +void purge_session_obj_cb(STDLL_TokData_t *tokdata, void *node, + unsigned long obj_handle, void *p3) +{ + OBJECT *obj = (OBJECT *) node; + struct purge_args *pa = (struct purge_args *) p3; + CK_BBOOL del = FALSE; + + UNUSED(tokdata); + + if (obj->session == pa->sess) { + if (object_lock(obj, READ_LOCK) != CKR_OK) + return; + + if (pa->type == PRIVATE) { + if (object_is_private(obj)) + del = TRUE; + } else if (pa->type == PUBLIC) { + if (object_is_public(obj)) + del = TRUE; + } else if (pa->type == ALL) { + del = TRUE; + } + + object_unlock(obj); + + if (del == TRUE) { + if (obj->map_handle) + bt_node_free(&tokdata->object_map_btree, obj->map_handle, TRUE); + + bt_node_free(&tokdata->sess_obj_btree, obj_handle, TRUE); + } + } +} + +// object_mgr_purge_session_objects() +// +// Args: SESSION * +// SESS_OBJ_TYPE: can be ALL, PRIVATE or PUBLIC +// +// Remove all session objects owned by the specified session satisfying +// the 'type' requirements +// +CK_BBOOL object_mgr_purge_session_objects(STDLL_TokData_t *tokdata, + SESSION *sess, SESS_OBJ_TYPE type) +{ + struct purge_args pa = { sess, type }; + + UNUSED(tokdata); + + if (!sess) + return FALSE; + + bt_for_each_node(tokdata, &tokdata->sess_obj_btree, purge_session_obj_cb, + &pa); + + return TRUE; +} + +/* purge_token_obj_cb + * + * @p3 is the btree we're purging from + */ +void purge_token_obj_cb(STDLL_TokData_t *tokdata, void *node, + unsigned long obj_handle, void *p3) +{ + OBJECT *obj = (OBJECT *) node; + struct btree *t = (struct btree *) p3; + + UNUSED(tokdata); + + if (obj->map_handle) + bt_node_free(&tokdata->object_map_btree, obj->map_handle, TRUE); + + bt_node_free(t, obj_handle, TRUE); +} + +// this routine cleans up the list of token objects. in general, we don't +// need to do this but when tracing memory leaks, it's best that we free +// everything that we've allocated +// +CK_BBOOL object_mgr_purge_token_objects(STDLL_TokData_t *tokdata) +{ + bt_for_each_node(tokdata, &tokdata->priv_token_obj_btree, purge_token_obj_cb, + &tokdata->priv_token_obj_btree); + bt_for_each_node(tokdata, &tokdata->publ_token_obj_btree, purge_token_obj_cb, + &tokdata->publ_token_obj_btree); + + return TRUE; +} + + +CK_BBOOL object_mgr_purge_private_token_objects(STDLL_TokData_t *tokdata) +{ + bt_for_each_node(tokdata, &tokdata->priv_token_obj_btree, purge_token_obj_cb, + &tokdata->priv_token_obj_btree); + + return TRUE; +} + +// +// +CK_RV object_mgr_restore_obj(STDLL_TokData_t *tokdata, CK_BYTE *data, + OBJECT *oldObj) +{ + return object_mgr_restore_obj_withSize(tokdata, data, oldObj, -1); +} + +// +//Modified verrsion of object_mgr_restore_obj to bounds check +//If data_size==-1, won't check bounds +CK_RV object_mgr_restore_obj_withSize(STDLL_TokData_t *tokdata, CK_BYTE *data, + OBJECT *oldObj, int data_size) +{ + OBJECT *obj = NULL; + CK_BBOOL priv; + CK_RV rc, tmp; + + if (!data) { + TRACE_ERROR("Invalid function argument.\n"); + return CKR_FUNCTION_FAILED; + } + // The calling stack MUST have the mutex + // to many grab it now. + + if (oldObj != NULL) { + obj = oldObj; + rc = object_restore_withSize(data, &obj, TRUE, data_size); + } else { + rc = object_restore_withSize(data, &obj, FALSE, data_size); + if (rc == CKR_OK) { + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get Process Lock.\n"); + return rc; + } + + priv = object_is_private(obj); + + if (priv) { + if (!bt_node_add(&tokdata->priv_token_obj_btree, obj)) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto unlock; + } + } else { + if (!bt_node_add(&tokdata->publ_token_obj_btree, obj)) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto unlock; + } + } + + if (priv) { + if (tokdata->global_shm->priv_loaded == FALSE) { + if (tokdata->global_shm->num_priv_tok_obj < MAX_TOK_OBJS) { + object_mgr_add_to_shm(obj, tokdata->global_shm); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + } + } + } else { + if (tokdata->global_shm->publ_loaded == FALSE) { + if (tokdata->global_shm->num_publ_tok_obj < MAX_TOK_OBJS) { + object_mgr_add_to_shm(obj, tokdata->global_shm); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + } + } + } + +unlock: + tmp = XProcUnLock(tokdata); + if (tmp != CKR_OK) + TRACE_ERROR("Failed to release Process Lock.\n"); + if (rc == CKR_OK) + rc = tmp; + } else { + TRACE_DEVEL("object_restore_withSize failed.\n"); + } + } + + return rc; +} + + +// +// +CK_RV object_mgr_set_attribute_values(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_OBJECT_HANDLE handle, + CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount) +{ + OBJECT *obj; + CK_BBOOL sess_obj, priv_obj; + CK_BBOOL modifiable; + CK_RV rc; + + + if (!pTemplate) { + TRACE_ERROR("Invalid function argument.\n"); + return CKR_FUNCTION_FAILED; + } + + rc = object_mgr_find_in_map1(tokdata, handle, &obj, WRITE_LOCK); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_find_in_map1 failed.\n"); + return rc; + } + // determine whether the session is allowed to modify the object + // + modifiable = object_is_modifiable(obj); + sess_obj = object_is_session_object(obj); + priv_obj = object_is_private(obj); + + // if object is not modifiable, it doesn't matter what kind of session + // is issuing the request... + // + if (!modifiable) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + rc = CKR_ATTRIBUTE_READ_ONLY; + goto done; + } + if (sess->session_info.state == CKS_RO_PUBLIC_SESSION) { + if (priv_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + if (!sess_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY)); + rc = CKR_SESSION_READ_ONLY; + goto done; + } + } + + if (sess->session_info.state == CKS_RO_USER_FUNCTIONS) { + if (!sess_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY)); + rc = CKR_SESSION_READ_ONLY; + goto done; + } + } + + if (sess->session_info.state == CKS_RW_PUBLIC_SESSION) { + if (priv_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + } + + if (sess->session_info.state == CKS_RW_SO_FUNCTIONS) { + if (priv_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + } + + + rc = object_set_attribute_values(tokdata, obj, pTemplate, ulCount); + if (rc != CKR_OK) { + TRACE_DEVEL("object_set_attribute_values failed.\n"); + goto done; + } + // okay. the object has been updated. if it's a session object, + // we're finished. if it's a token object, we need to update + // non-volatile storage. + // + if (!sess_obj) { + TOK_OBJ_ENTRY *entry = NULL; + CK_ULONG index; + + // I still think there's a race condition here if two processes are + // updating the same token object at the same time. I don't know how + // to solve this short of assigning each token object it's own mutex... + // + obj->count_lo++; + if (obj->count_lo == 0) + obj->count_hi++; + + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get Process Lock.\n"); + goto done; + } + + save_token_object(tokdata, obj); + + if (priv_obj) { + rc = object_mgr_search_shm_for_obj(tokdata->global_shm-> + priv_tok_objs, 0, + tokdata->global_shm-> + num_priv_tok_obj - 1, obj, + &index); + + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_search_shm_for_obj failed.\n"); + XProcUnLock(tokdata); + goto done; + } + + entry = &tokdata->global_shm->priv_tok_objs[index]; + } else { + rc = object_mgr_search_shm_for_obj(tokdata->global_shm-> + publ_tok_objs, 0, + tokdata->global_shm-> + num_publ_tok_obj - 1, obj, + &index); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_search_shm_for_obj failed.\n"); + XProcUnLock(tokdata); + goto done; + } + + entry = &tokdata->global_shm->publ_tok_objs[index]; + } + + entry->count_lo = obj->count_lo; + entry->count_hi = obj->count_hi; + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release Process Lock.\n"); + goto done; + } + } + +done: + object_put(tokdata, obj, TRUE); + obj = NULL; + + return rc; +} + + +// +// +void object_mgr_add_to_shm(OBJECT *obj, LW_SHM_TYPE *global_shm) +{ + // TODO: Can't this function fail? + TOK_OBJ_ENTRY *entry = NULL; + CK_BBOOL priv; + + // the calling routine is responsible for locking the global_shm mutex + // + priv = object_is_private(obj); + + if (priv) + entry = &global_shm->priv_tok_objs[global_shm->num_priv_tok_obj]; + else + entry = &global_shm->publ_tok_objs[global_shm->num_publ_tok_obj]; + + entry->deleted = FALSE; + entry->count_lo = 0; + entry->count_hi = 0; + memcpy(entry->name, obj->name, 8); + + if (priv) { + global_shm->num_priv_tok_obj++; + object_mgr_sort_priv_shm(); + } else { + global_shm->num_publ_tok_obj++; + object_mgr_sort_publ_shm(); + } + + return; +} + + +// +// +CK_RV object_mgr_del_from_shm(OBJECT *obj, LW_SHM_TYPE *global_shm) +{ + CK_ULONG index, count; + CK_BBOOL priv; + CK_RV rc; + + + // the calling routine is responsible for locking the global_shm mutex + // + + priv = object_is_private(obj); + + if (priv) { + rc = object_mgr_search_shm_for_obj(global_shm->priv_tok_objs, + 0, global_shm->num_priv_tok_obj - 1, + obj, &index); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_search_shm_for_obj failed.\n"); + return rc; + } + // Since the number of objects starts at 1 and index starts at zero, we + // decrement before we get count. This eliminates the need to perform + // this operation later as well as decrementing the number of objects. + // (i.e. If we have 10 objects, num will be 10 but the last index is 9. + // If we want to delete the last object we need to subtract 9 from 9 not + // 10 from 9.) + // + global_shm->num_priv_tok_obj--; + if (index > global_shm->num_priv_tok_obj) { + count = index - global_shm->num_priv_tok_obj; + } else { + count = global_shm->num_priv_tok_obj - index; + } + + if (count > 0) { + // If we aren't deleting the last element in the list + // Move up count number of elements effectively deleting the index + // NB: memmove is required since the copied regions may overlap + memmove((char *) &global_shm->priv_tok_objs[index], + (char *) &global_shm->priv_tok_objs[index + 1], + sizeof(TOK_OBJ_ENTRY) * count); + // We need to zero out the last entry... Since the memcopy + // does not zero it out... + memset((char *) &global_shm-> + priv_tok_objs[global_shm->num_priv_tok_obj + 1], 0, + sizeof(TOK_OBJ_ENTRY)); + } else { + // We are deleting the last element which is in num_priv_tok_obj + memset((char *) &global_shm-> + priv_tok_objs[global_shm->num_priv_tok_obj], 0, + sizeof(TOK_OBJ_ENTRY)); + } + } else { + rc = object_mgr_search_shm_for_obj(global_shm->publ_tok_objs, + 0, global_shm->num_publ_tok_obj - 1, + obj, &index); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_search_shm_for_obj failed.\n"); + return rc; + } + global_shm->num_publ_tok_obj--; + + + if (index > global_shm->num_publ_tok_obj) { + count = index - global_shm->num_publ_tok_obj; + } else { + count = global_shm->num_publ_tok_obj - index; + } + + if (count > 0) { + // NB: memmove is required since the copied regions may overlap + memmove((char *) &global_shm->publ_tok_objs[index], + (char *) &global_shm->publ_tok_objs[index + 1], + sizeof(TOK_OBJ_ENTRY) * count); + // We need to zero out the last entry... Since the memcopy + // does not zero it out... + memset((char *) &global_shm-> + publ_tok_objs[global_shm->num_publ_tok_obj + 1], 0, + sizeof(TOK_OBJ_ENTRY)); + } else { + memset((char *) &global_shm-> + publ_tok_objs[global_shm->num_publ_tok_obj], 0, + sizeof(TOK_OBJ_ENTRY)); + } + } + + // + // object list is still sorted...so no need to re-sort + // + + return CKR_OK; +} + + +// The object must hold the READ lock when this function is called! +// +CK_RV object_mgr_check_shm(STDLL_TokData_t *tokdata, OBJECT *obj) +{ + TOK_OBJ_ENTRY *entry = NULL; + CK_BBOOL priv, rd_locked = TRUE, wr_locked = FALSE; + CK_ULONG index; + CK_RV rc; + + priv = object_is_private(obj); + +retry: + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get Process Lock.\n"); + return rc; + } + + if (priv) { + /* first check the object count. If it is 0, then just return. */ + if (tokdata->global_shm->num_priv_tok_obj == 0) { + TRACE_ERROR("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); + rc = CKR_OBJECT_HANDLE_INVALID; + goto done; + } + rc = object_mgr_search_shm_for_obj(tokdata->global_shm->priv_tok_objs, + 0, + tokdata->global_shm-> + num_priv_tok_obj - 1, obj, &index); + if (rc != CKR_OK) { + TRACE_ERROR("object_mgr_search_shm_for_obj failed.\n"); + goto done; + } + entry = &tokdata->global_shm->priv_tok_objs[index]; + } else { + /* first check the object count. If it is 0, then just return. */ + if (tokdata->global_shm->num_publ_tok_obj == 0) { + TRACE_ERROR("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); + rc = CKR_OBJECT_HANDLE_INVALID; + goto done; + } + rc = object_mgr_search_shm_for_obj(tokdata->global_shm->publ_tok_objs, + 0, + tokdata->global_shm->num_publ_tok_obj + - 1, + obj, &index); + if (rc != CKR_OK) { + TRACE_ERROR("object_mgr_search_shm_for_obj failed.\n"); + goto done; + } + entry = &tokdata->global_shm->publ_tok_objs[index]; + } + + if ((obj->count_hi == entry->count_hi) + && (obj->count_lo == entry->count_lo)) { + rc = CKR_OK; + goto done; + } + + /* We need to acquire the WRITE lock on the object because we are modifying + * the attributes. Since the object already holds the READ lock, we need to + * unlock it first, then get the WRITE lock, and finally unlock again and + * get the READ lock again. The caller assumes that the object still holds + * the READ lock when we return. + * + * We must not hold the XProcLock when trying to get the WRITE lock on the + * Objects. This might cause a deadlock, if another thread holds a READ or + * WRITE lock on the object, and is also trying to get the XProcLock. + */ + + if (rd_locked) { + rc = object_unlock(obj); + if (rc != CKR_OK) + goto done; + rd_locked = FALSE; + } + + if (!wr_locked) { + /* Try to get the WRITE lock, although we hold the XProcLock. If we get + * it we take the fast path, if not, we release the XProcLock, then get + * the WRITE lock and then get the XProcLock again. Since we have + * released the XProcLock, we then need to re-do the SHM checking. + */ + if (pthread_rwlock_trywrlock(&obj->template_rwlock) != 0) { + /* Did not get the WRITE lock */ + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release Process Lock.\n"); + goto done; + } + + rc = object_lock(obj, WRITE_LOCK); + if (rc != CKR_OK) + goto done; + wr_locked = TRUE; + + goto retry; + } + + wr_locked = TRUE; + } + + /* If we reach here, we do have the WRITE lock on the object */ + + rc = reload_token_object(tokdata, obj); + if (rc != CKR_OK) + goto done; + + 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) { + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release Process Lock.\n"); + } + } else { + XProcUnLock(tokdata); + } + + if (wr_locked) + object_unlock(obj); + if (!rd_locked) { + if (rc == CKR_OK) + rc = object_lock(obj, READ_LOCK); + else + object_lock(obj, READ_LOCK); + } + + return rc; +} + + +// I'd use the standard bsearch() routine but I want an index, not a pointer. +// Converting the pointer to an index might cause problems when switching +// to a 64-bit environment... +// +CK_RV object_mgr_search_shm_for_obj(TOK_OBJ_ENTRY *obj_list, + CK_ULONG lo, + CK_ULONG hi, OBJECT *obj, CK_ULONG *index) +{ +// SAB XXX reduce the search time since this is what seems to be burning cycles + CK_ULONG idx; + + UNUSED(lo); + + if (obj->index == 0) { + for (idx = 0; idx <= hi; idx++) { + if (memcmp(obj->name, obj_list[idx].name, 8) == 0) { + *index = idx; + obj->index = idx; + return CKR_OK; + } + } + } else { + // SAB better double check + if (memcmp(obj->name, obj_list[obj->index].name, 8) == 0) { + *index = obj->index; + return CKR_OK; + } else { + // something is hosed.. go back to the brute force method + for (idx = 0; idx <= hi; idx++) { + if (memcmp(obj->name, obj_list[idx].name, 8) == 0) { + *index = idx; + obj->index = idx; + return CKR_OK; + } + } + } + } + + TRACE_ERROR("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); + + return CKR_OBJECT_HANDLE_INVALID; +} + + +// +// +CK_RV object_mgr_sort_priv_shm(void) +{ + // for now, we assume the list is sorted by design. this is not unreasonable + // since new object handles are assigned in increasing order. problems + // will arise after 36^8 token objects have been created... + // + return CKR_OK; +} + + +// +// +CK_RV object_mgr_sort_publ_shm(void) +{ + // for now, we assume the list is sorted by design. this is not unreasonable + // since new object handles are assigned in increasing order. problems + // will arise after 36^8 token objects have been created... + // + return CKR_OK; +} + + +// this routine scans the local token object lists and updates any objects that +// have changed. it also adds any new token objects that have been added by +// other processes and deletes any objects that have been deleted by other +// processes +// +CK_RV object_mgr_update_from_shm(STDLL_TokData_t *tokdata) +{ + object_mgr_update_publ_tok_obj_from_shm(tokdata); + object_mgr_update_priv_tok_obj_from_shm(tokdata); + + return CKR_OK; +} + +void delete_objs_from_btree_cb(STDLL_TokData_t *tokdata, void *node, + unsigned long obj_handle, void *p3) +{ + struct update_tok_obj_args *ua = (struct update_tok_obj_args *) p3; + TOK_OBJ_ENTRY *shm_te = NULL; + OBJECT *obj = (OBJECT *) node; + CK_ULONG index; + + UNUSED(tokdata); + + /* for each TOK_OBJ_ENTRY in the SHM list */ + for (index = 0; index < *(ua->num_entries); index++) { + shm_te = &(ua->entries[index]); + + /* found it, return */ + if (!memcmp(obj->name, shm_te->name, 8)) { + return; + } + } + + /* didn't find it in SHM, delete it from its btree and the object map */ + bt_node_free(&tokdata->object_map_btree, obj->map_handle, TRUE); + bt_node_free(ua->t, obj_handle, TRUE); +} + +void find_by_name_cb(STDLL_TokData_t *tokdata, void *node, + unsigned long obj_handle, void *p3) +{ + OBJECT *obj = (OBJECT *) node; + struct find_by_name_args *fa = (struct find_by_name_args *) p3; + + UNUSED(tokdata); + UNUSED(obj_handle); + + if (fa->done) + return; + + if (!memcmp(obj->name, fa->name, 8)) { + fa->done = TRUE; + } +} + +CK_RV object_mgr_update_publ_tok_obj_from_shm(STDLL_TokData_t *tokdata) +{ + struct update_tok_obj_args ua; + struct find_by_name_args fa; + TOK_OBJ_ENTRY *shm_te = NULL; + CK_ULONG index; + OBJECT *new_obj; + CK_RV rc; + + ua.entries = tokdata->global_shm->publ_tok_objs; + ua.num_entries = &(tokdata->global_shm->num_publ_tok_obj); + ua.t = &tokdata->publ_token_obj_btree; + + /* delete any objects not in SHM from the btree */ + bt_for_each_node(tokdata, &tokdata->publ_token_obj_btree, + delete_objs_from_btree_cb, &ua); + + /* for each item in SHM, add it to the btree if its not there */ + for (index = 0; index < tokdata->global_shm->num_publ_tok_obj; index++) { + shm_te = &tokdata->global_shm->publ_tok_objs[index]; + + fa.done = FALSE; + fa.name = shm_te->name; + + /* find an object from SHM in the btree */ + bt_for_each_node(tokdata, &tokdata->publ_token_obj_btree, + find_by_name_cb, &fa); + + /* we didn't find it in the btree, so add it */ + if (fa.done == FALSE) { + new_obj = (OBJECT *) malloc(sizeof(OBJECT)); + memset(new_obj, 0x0, sizeof(OBJECT)); + + rc = object_init_lock(new_obj); + if (rc != CKR_OK) { + free(new_obj); + continue; + } + + memcpy(new_obj->name, shm_te->name, 8); + rc = reload_token_object(tokdata, new_obj); + if (rc == CKR_OK) + bt_node_add(&tokdata->publ_token_obj_btree, new_obj); + else + object_free(new_obj); + } + } + + return CKR_OK; +} + +CK_RV object_mgr_update_priv_tok_obj_from_shm(STDLL_TokData_t *tokdata) +{ + struct update_tok_obj_args ua; + struct find_by_name_args fa; + TOK_OBJ_ENTRY *shm_te = NULL; + CK_ULONG index; + OBJECT *new_obj; + CK_RV rc; + + // SAB XXX don't bother doing this call if we are not in the correct + // login state + if (!session_mgr_user_session_exists(tokdata)) + return CKR_OK; + + ua.entries = tokdata->global_shm->priv_tok_objs; + ua.num_entries = &(tokdata->global_shm->num_priv_tok_obj); + ua.t = &tokdata->priv_token_obj_btree; + + /* delete any objects not in SHM from the btree */ + bt_for_each_node(tokdata, &tokdata->priv_token_obj_btree, delete_objs_from_btree_cb, + &ua); + + /* for each item in SHM, add it to the btree if its not there */ + for (index = 0; index < tokdata->global_shm->num_priv_tok_obj; index++) { + shm_te = &tokdata->global_shm->priv_tok_objs[index]; + + fa.done = FALSE; + fa.name = shm_te->name; + + /* find an object from SHM in the btree */ + bt_for_each_node(tokdata, &tokdata->priv_token_obj_btree, find_by_name_cb, &fa); + + /* we didn't find it in the btree, so add it */ + if (fa.done == FALSE) { + new_obj = (OBJECT *) malloc(sizeof(OBJECT)); + memset(new_obj, 0x0, sizeof(OBJECT)); + + rc = object_init_lock(new_obj); + if (rc != CKR_OK) { + free(new_obj); + continue; + } + + memcpy(new_obj->name, shm_te->name, 8); + rc = reload_token_object(tokdata, new_obj); + if (rc == CKR_OK) + bt_node_add(&tokdata->priv_token_obj_btree, new_obj); + else + object_free(new_obj); + } + } + + return CKR_OK; +} + +// SAB FIXME FIXME + +void purge_map_by_type_cb(STDLL_TokData_t *tokdata, void *node, + unsigned long map_handle, void *p3) +{ + OBJECT_MAP *map = (OBJECT_MAP *) node; + SESS_OBJ_TYPE type = *(SESS_OBJ_TYPE *) p3; + + if (type == PRIVATE) { + if (map->is_private) { + bt_node_free(&tokdata->object_map_btree, map_handle, TRUE); + } + } else if (type == PUBLIC) { + if (!map->is_private) { + bt_node_free(&tokdata->object_map_btree, map_handle, TRUE); + } + } +} + +CK_BBOOL object_mgr_purge_map(STDLL_TokData_t *tokdata, + SESSION *sess, SESS_OBJ_TYPE type) +{ + UNUSED(sess); + + bt_for_each_node(tokdata, &tokdata->object_map_btree, purge_map_by_type_cb, &type); + return TRUE; +} + +/* Put back the object using its btree */ +CK_RV object_put(STDLL_TokData_t *tokdata, OBJECT *obj, CK_BBOOL unlock) +{ + CK_BBOOL sess, priv; + CK_RV rc; + + if (obj == NULL) + return CKR_OBJECT_HANDLE_INVALID; + + if (!unlock) { + rc = object_lock(obj, READ_LOCK); + if (rc != CKR_OK) + return rc; + } + + sess = object_is_session_object(obj); + priv = object_is_private(obj); + + if (unlock) { + rc= object_unlock(obj); + if (rc != CKR_OK) + return rc; + } + + if (sess) + bt_put_node_value(&tokdata->sess_obj_btree, obj); + else if (priv) + bt_put_node_value(&tokdata->priv_token_obj_btree, obj); + else + bt_put_node_value(&tokdata->publ_token_obj_btree, obj); + + return CKR_OK; +} + +#ifdef DEBUG +void dump_shm(LW_SHM_TYPE *global_shm, const char *s) +{ + CK_ULONG i; + TRACE_DEBUG("%s: dump_shm priv:\n", s); + + for (i = 0; i < global_shm->num_priv_tok_obj; i++) { + TRACE_DEBUG("[%lu]: %.8s\n", i, global_shm->priv_tok_objs[i].name); + } + TRACE_DEBUG("%s: dump_shm publ:\n", s); + for (i = 0; i < global_shm->num_publ_tok_obj; i++) { + TRACE_DEBUG("[%lu]: %.8s\n", i, global_shm->publ_tok_objs[i].name); + } +} +#endif diff --git a/usr/lib/common/object.c b/usr/lib/common/object.c new file mode 100644 index 0000000..367670a --- /dev/null +++ b/usr/lib/common/object.c @@ -0,0 +1,787 @@ +/* + * 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: object.c +// +// Object manager related functions +// +// Functions contained within: +// +// object_create +// object_free +// object_is_modifiable +// object_is_private +// object_is_token_object +// object_is_session_object +// + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "pkcs32.h" +#include "trace.h" + +// object_create() +// +// Args: void * attributes : (INPUT) pointer to data block containing +// ATTRIBUTEs +// OBJECT * obj : (OUTPUT) destination object +// +// Creates an object with the specified attributes. Verifies that all required +// attributes are present and adds any missing attributes that have +// Cryptoki-defined default values. This routine does not check whether the +// session is authorized to create the object. That is done elsewhere +// (see object_mgr_create()) +// +CK_RV object_create(STDLL_TokData_t * tokdata, + CK_ATTRIBUTE * pTemplate, CK_ULONG ulCount, OBJECT ** obj) +{ + OBJECT *o = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL class_given = FALSE; + CK_BBOOL subclass_given = FALSE; + CK_ULONG class = 0xFFFFFFFF, subclass = 0xFFFFFFFF; + CK_RV rc; + unsigned int i; + + if (!pTemplate) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + // extract the object class and subclass + // + attr = pTemplate; + for (i = 0; i < ulCount; i++, attr++) { + if (attr->type == CKA_CLASS) { + class = *(CK_OBJECT_CLASS *) attr->pValue; + class_given = TRUE; + } + + if (attr->type == CKA_CERTIFICATE_TYPE) { + subclass = *(CK_CERTIFICATE_TYPE *) attr->pValue; + subclass_given = TRUE; + } + + if (attr->type == CKA_KEY_TYPE) { + subclass = *(CK_KEY_TYPE *) attr->pValue; + subclass_given = TRUE; + } + + if (attr->type == CKA_HW_FEATURE_TYPE) { + subclass = *(CK_HW_FEATURE_TYPE *) attr->pValue; + subclass_given = TRUE; + } + } + + if (class_given == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + // Return CKR_ATTRIBUTE_TYPE_INVALID when trying to create a + // vendor-defined object. + if (class >= CKO_VENDOR_DEFINED) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID)); + return CKR_ATTRIBUTE_TYPE_INVALID; + } + + if (class != CKO_DATA && subclass_given != TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + rc = object_create_skel(tokdata, pTemplate, ulCount, + MODE_CREATE, class, subclass, &o); + if (rc != CKR_OK) { + TRACE_DEVEL("object_create_skel failed.\n"); + return rc; + } + + *obj = o; + return CKR_OK; +} + + +// object_copy() +// +// Args: OBJECT * old_obj : (INPUT) pointer to the source object +// void * attributes : (INPUT) pointer to data block containing +// additional ATTRIBUTEs +// CK_ULONG count : (INPUT) number of new attributes +// OBJECT ** new_obj : (OUTPUT) destination object +// +// Builds a copy of the specified object. The new object gets the original +// object's attribute template plus any additional attributes that are specified +// Verifies that all required attributes are present. This routine does not +// check whether the session is authorized to copy the object -- routines at +// the individual object level don't have the concept of "session". These checks +// are done by the object manager. +// +// The old_obj must hold the READ lock! +// +CK_RV object_copy(STDLL_TokData_t * tokdata, + CK_ATTRIBUTE * pTemplate, + CK_ULONG ulCount, OBJECT * old_obj, OBJECT ** new_obj) +{ + TEMPLATE *tmpl = NULL; + TEMPLATE *new_tmpl = NULL; + OBJECT *o = NULL; + CK_BBOOL found; + CK_ULONG class, subclass; + CK_RV rc; + + + if (!old_obj || (!pTemplate && ulCount) || !new_obj) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + o = (OBJECT *) malloc(sizeof(OBJECT)); + tmpl = (TEMPLATE *) malloc(sizeof(TEMPLATE)); + new_tmpl = (TEMPLATE *) malloc(sizeof(TEMPLATE)); + + if (!o || !tmpl || !new_tmpl) { + rc = CKR_HOST_MEMORY; + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + if (o) + free(o); + if (tmpl) + free(tmpl); + if (new_tmpl) + free(new_tmpl); + + return rc; // do not goto done -- memory might not be initialized + } + + memset(o, 0x0, sizeof(OBJECT)); + memset(tmpl, 0x0, sizeof(TEMPLATE)); + memset(new_tmpl, 0x0, sizeof(TEMPLATE)); + + rc = object_init_lock(o); + if (rc != CKR_OK) + goto error; + + // copy the original object's attribute template + // + rc = template_copy(tmpl, old_obj->template); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to copy template.\n"); + goto error; + } + rc = template_add_attributes(new_tmpl, pTemplate, ulCount); + if (rc != CKR_OK) { + TRACE_DEVEL("template_add_attributes failed.\n"); + goto error; + } + // at this point, the new object has the list of attributes. we need + // to do some more checking now: + // 1) invalid attribute values + // 2) missing required attributes + // 3) attributes inappropriate for the object class + // 4) conflicting attributes/values + // + + found = template_get_class(tmpl, &class, &subclass); + if (found == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS in object's template.\n"); + rc = CKR_TEMPLATE_INCONSISTENT; + goto error; + } + + // the user cannot change object classes so we assume the existing + // object attributes are valid. we still need to check the new attributes. + // we cannot merge the new attributes in with the old ones and then check + // for validity because some attributes are added internally and are not + // allowed to be specified by the user (ie. CKA_LOCAL for key types) but + // may still be part of the old template. + // + rc = template_validate_attributes(tokdata, new_tmpl, class, subclass, + MODE_COPY); + if (rc != CKR_OK) { + TRACE_DEVEL("template_validate_attributes failed.\n"); + goto error; + } + // merge in the new attributes + // + rc = template_merge(tmpl, &new_tmpl); + if (rc != CKR_OK) { + TRACE_DEVEL("template_merge failed.\n"); + goto error; + } + // do we need this? since an attribute cannot be removed, the original + // object's template (contained in tmpl) already has the required attributes + // present + // + rc = template_check_required_attributes(tmpl, class, subclass, MODE_COPY); + if (rc != CKR_OK) { + TRACE_ERROR("template_check_required_attributes failed.\n"); + goto error; + } + // at this point, we should have a valid object with correct attributes + // + o->template = tmpl; + *new_obj = o; + + return CKR_OK; + +error: + if (tmpl) + template_free(tmpl); + if (new_tmpl) + template_free(new_tmpl); + if (o) + object_free(o); + + return rc; +} + + +// object_flatten() - this is still used when saving token objects +// +CK_RV object_flatten(OBJECT * obj, CK_BYTE ** data, CK_ULONG * len) +{ + CK_BYTE *buf = NULL; + CK_ULONG tmpl_len, total_len; + CK_ULONG offset; + CK_ULONG_32 count; + CK_OBJECT_CLASS_32 class32; + long rc; + + if (!obj) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + count = template_get_count(obj->template); + tmpl_len = template_get_compressed_size(obj->template); + + total_len = tmpl_len + sizeof(CK_OBJECT_CLASS_32) + sizeof(CK_ULONG_32) + 8; + + buf = (CK_BYTE *) malloc(total_len); + if (!buf) { // SAB XXX FIXME This was DATA + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + memset((CK_BYTE *) buf, 0x0, total_len); + + offset = 0; + + class32 = obj->class; + memcpy(buf + offset, &class32, sizeof(CK_OBJECT_CLASS_32)); + offset += sizeof(CK_OBJECT_CLASS_32); + + memcpy(buf + offset, &count, sizeof(CK_ULONG_32)); + offset += sizeof(CK_ULONG_32); + + memcpy(buf + offset, &obj->name, sizeof(CK_BYTE) * 8); + offset += 8; + rc = template_flatten(obj->template, buf + offset); + if (rc != CKR_OK) { + free(buf); + return rc; + } + + *data = buf; + *len = total_len; + + return CKR_OK; +} + + + +// object_free() +// +// does what it says... +// +void object_free(OBJECT * obj) +{ + /* refactorization here to do actual free - fix from coverity scan */ + if (obj) { + if (obj->template) + template_free(obj->template); + object_destroy_lock(obj); + free(obj); + } +} + +//call_object_free() +//This function is added to silence the compiler during implicit void (*)(void*) +//function pointer casting in call back functions. +// +void call_object_free(void *ptr) +{ + if (ptr) + object_free((OBJECT *) ptr); +} + +// object_is_modifiable() +// +CK_BBOOL object_is_modifiable(OBJECT * obj) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL modifiable; + CK_BBOOL found; + + found = template_attribute_find(obj->template, CKA_MODIFIABLE, &attr); + if (found == FALSE) + return TRUE; // should always be found but we default to TRUE + + //axelrh: prevent dereferencing NULL from bad parse + if (attr->pValue == NULL) + return TRUE; //default to TRUE + + modifiable = *(CK_BBOOL *) attr->pValue; + + return modifiable; +} + + +// object_is_private() +// +// an is_private member should probably be added to OBJECT +// +CK_BBOOL object_is_private(OBJECT * obj) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL priv; + CK_BBOOL found; + + found = template_attribute_find(obj->template, CKA_PRIVATE, &attr); + if (found == FALSE) { + return TRUE; // should always be found but we default to TRUE + } + if (attr == NULL) + return TRUE; + + + //axelrh: prevent segfault caused by 0-len attribute + //that has a null pValue + CK_BBOOL *bboolPtr = (CK_BBOOL *) attr->pValue; + if (bboolPtr == NULL) + return TRUE; //default + + priv = *(bboolPtr); + + return priv; +} + + +// object_is_public() +// +CK_BBOOL object_is_public(OBJECT * obj) +{ + CK_BBOOL rc; + + rc = object_is_private(obj); + + if (rc) + return FALSE; + + return TRUE; +} + + +// object_is_token_object() +// +CK_BBOOL object_is_token_object(OBJECT * obj) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL is_token; + CK_BBOOL found; + + found = template_attribute_find(obj->template, CKA_TOKEN, &attr); + if (found == FALSE) + return FALSE; + + //axelrh: prevent dereferencing NULL from bad parse + if (attr->pValue == NULL) + return FALSE; + + is_token = *(CK_BBOOL *) attr->pValue; + + return is_token; +} + + +// object_is_session_object() +// +CK_BBOOL object_is_session_object(OBJECT * obj) +{ + CK_BBOOL rc; + + rc = object_is_token_object(obj); + + if (rc) + return FALSE; + else + return TRUE; +} + + +// object_get_size() +// +CK_ULONG object_get_size(OBJECT * obj) +{ + CK_ULONG size; + + size = sizeof(OBJECT) + template_get_size(obj->template); + + return size; +} + + +// +// +CK_RV object_get_attribute_values(OBJECT * obj, + CK_ATTRIBUTE * pTemplate, CK_ULONG ulCount) +{ + TEMPLATE *obj_tmpl = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_ULONG i; + CK_BBOOL flag; + CK_RV rc; + + rc = CKR_OK; + + obj_tmpl = obj->template; + + for (i = 0; i < ulCount; i++) { + flag = template_check_exportability(obj_tmpl, pTemplate[i].type); + if (flag == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_SENSITIVE)); + rc = CKR_ATTRIBUTE_SENSITIVE; + pTemplate[i].ulValueLen = (CK_ULONG) - 1; + continue; + } + + flag = template_attribute_find(obj_tmpl, pTemplate[i].type, &attr); + if (flag == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID)); + rc = CKR_ATTRIBUTE_TYPE_INVALID; + pTemplate[i].ulValueLen = (CK_ULONG) - 1; + continue; + } + + if (pTemplate[i].pValue == NULL) { + pTemplate[i].ulValueLen = attr->ulValueLen; + } else if (pTemplate[i].ulValueLen >= attr->ulValueLen) { + memcpy(pTemplate[i].pValue, attr->pValue, attr->ulValueLen); + pTemplate[i].ulValueLen = attr->ulValueLen; + } else { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + pTemplate[i].ulValueLen = (CK_ULONG) - 1; + } + } + + return rc; +} + +// object_set_attribute_values() +// +CK_RV object_set_attribute_values(STDLL_TokData_t * tokdata, + OBJECT * obj, + CK_ATTRIBUTE * pTemplate, CK_ULONG ulCount) +{ + TEMPLATE *new_tmpl = NULL; + CK_BBOOL found; + CK_ULONG class, subclass; + CK_RV rc; + + + if (!obj || !pTemplate) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + + found = template_get_class(obj->template, &class, &subclass); + if (found == FALSE) { + TRACE_ERROR("Failed to find CKA_CLASS in object template.\n"); + rc = CKR_FUNCTION_FAILED; + goto error; + } + + new_tmpl = (TEMPLATE *) malloc(sizeof(TEMPLATE)); + if (!new_tmpl) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + memset(new_tmpl, 0x0, sizeof(TEMPLATE)); + + rc = template_add_attributes(new_tmpl, pTemplate, ulCount); + if (rc != CKR_OK) { + TRACE_DEVEL("template_add_attributes failed.\n"); + goto error; + } + // the user cannot change object classes so we assume the existing + // object attributes are valid. we still need to check the new attributes. + // we cannot merge the new attributes in with the old ones and then check + // for validity because some attributes are added internally and are not + // allowed to be specified by the user (ie. CKA_LOCAL for key types) but + // may still be part of the old template. + // + rc = template_validate_attributes(tokdata, new_tmpl, class, subclass, + MODE_MODIFY); + if (rc != CKR_OK) { + TRACE_DEVEL("template_validate_attributes failed.\n"); + goto error; + } + // merge in the new attributes + // + rc = template_merge(obj->template, &new_tmpl); + if (rc != CKR_OK) { + TRACE_DEVEL("template_merge failed.\n"); + return rc; + } + + return CKR_OK; + +error: + // we only free the template if there was an error...otherwise the + // object "owns" the template + // + if (new_tmpl) + template_free(new_tmpl); + + return rc; +} + + +// +// +CK_RV object_restore(CK_BYTE * data, OBJECT ** new_obj, CK_BBOOL replace) +{ + return object_restore_withSize(data, new_obj, replace, -1); +} + +// +//Modified object_restore to prevent buffer overflow +//If data_size=-1, won't do bounds checking +CK_RV object_restore_withSize(CK_BYTE * data, OBJECT ** new_obj, + CK_BBOOL replace, int data_size) +{ + TEMPLATE *tmpl = NULL; + OBJECT *obj = NULL; + CK_ULONG offset = 0; + CK_ULONG_32 count = 0; + CK_RV rc; + CK_OBJECT_CLASS_32 class32; + + if (!data || !new_obj) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + obj = (OBJECT *) malloc(sizeof(OBJECT)); + if (!obj) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto error; + } + + + memset(obj, 0x0, sizeof(OBJECT)); + + memcpy(&class32, data + offset, sizeof(CK_OBJECT_CLASS_32)); + obj->class = class32; + offset += sizeof(CK_OBJECT_CLASS_32); + + memcpy(&count, data + offset, sizeof(CK_ULONG_32)); + offset += sizeof(CK_ULONG_32); + + + memcpy(&obj->name, data + offset, 8); + offset += 8; + + rc = template_unflatten_withSize(&tmpl, data + offset, count, data_size); + if (rc != CKR_OK) { + TRACE_DEVEL("template_unflatten_withSize failed.\n"); + goto error; + } + obj->template = tmpl; + tmpl = NULL; + + if (replace == FALSE) { + rc = object_init_lock(obj); + if (rc != CKR_OK) + goto error; + + *new_obj = obj; + } else { + /* Reload of existing object only changes the template */ + template_free((*new_obj)->template); + (*new_obj)->template = obj->template; + free(obj); // don't want to do object_free() here! + } + + return CKR_OK; + +error: + if (obj) + object_free(obj); + if (tmpl) + template_free(tmpl); + + return rc; +} + + +// +// +CK_RV object_create_skel(STDLL_TokData_t * tokdata, + CK_ATTRIBUTE * pTemplate, + CK_ULONG ulCount, + CK_ULONG mode, + CK_ULONG class, CK_ULONG subclass, OBJECT ** obj) +{ + TEMPLATE *tmpl = NULL; + TEMPLATE *tmpl2 = NULL; + OBJECT *o = NULL; + CK_RV rc; + + + if (!obj) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (!pTemplate && (ulCount != 0)) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + o = (OBJECT *) calloc(1, sizeof(OBJECT)); + tmpl = (TEMPLATE *) calloc(1, sizeof(TEMPLATE)); + tmpl2 = (TEMPLATE *) calloc(1, sizeof(TEMPLATE)); + + if (!o || !tmpl || !tmpl2) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + + rc = template_add_attributes(tmpl2, pTemplate, ulCount); + if (rc != CKR_OK) + goto done; + + + // at this point, the new template has the list of attributes. we need + // to do some more checking now: + // 1) invalid attribute values + // 2) missing required attributes + // 3) attributes inappropriate for the object class + // 4) conflicting attributes/values + // + + rc = template_validate_attributes(tokdata, tmpl2, class, subclass, mode); + if (rc != CKR_OK) { + TRACE_DEVEL("template_validate_attributes failed.\n"); + goto done; + } + + rc = template_check_required_attributes(tmpl2, class, subclass, mode); + if (rc != CKR_OK) { + TRACE_DEVEL("template_check_required_attributes failed.\n"); + goto done; + } + + rc = template_add_default_attributes(tmpl, tmpl2, class, subclass, mode); + if (rc != CKR_OK) + goto done; + + + rc = template_merge(tmpl, &tmpl2); + if (rc != CKR_OK) { + TRACE_DEVEL("template_merge failed.\n"); + goto done; + } + // at this point, we should have a valid object with correct attributes + // + o->template = tmpl; + tmpl = NULL; + + rc = object_init_lock(o); + if (rc != CKR_OK) + goto done; + + *obj = o; + + return CKR_OK; + +done: + if (o) + free(o); + if (tmpl) + template_free(tmpl); + if (tmpl2) + template_free(tmpl2); + + return rc; +} + +CK_RV object_init_lock(OBJECT *obj) +{ + if (pthread_rwlock_init(&obj->template_rwlock, NULL) != 0) { + TRACE_DEVEL("Object Lock init failed.\n"); + return CKR_CANT_LOCK; + } + + return CKR_OK; +} + +CK_RV object_destroy_lock(OBJECT *obj) +{ + if (pthread_rwlock_destroy(&obj->template_rwlock) != 0) { + TRACE_DEVEL("Object Lock destroy failed.\n"); + return CKR_CANT_LOCK; + } + + return CKR_OK; +} + +/* + * Do NOT try to get an object lock, if the current thread holds the + * XProcLock! This might case a deadlock ! + * Always first acquire the Object lock, and then the XProcLock. + */ +CK_RV object_lock(OBJECT *obj, OBJ_LOCK_TYPE type) +{ + switch (type) { + case NO_LOCK: + break; + case READ_LOCK: + if (pthread_rwlock_rdlock(&obj->template_rwlock) != 0) { + TRACE_DEVEL("Object Read-Lock failed.\n"); + return CKR_CANT_LOCK; + } + break; + case WRITE_LOCK: + if (pthread_rwlock_wrlock(&obj->template_rwlock) != 0) { + TRACE_DEVEL("Object Write-Lock failed.\n"); + return CKR_CANT_LOCK; + } + break; + } + + return CKR_OK; +} + +CK_RV object_unlock(OBJECT *obj) +{ + if (pthread_rwlock_unlock(&obj->template_rwlock) != 0) { + TRACE_DEVEL("Object Unlock failed.\n"); + return CKR_CANT_LOCK; + } + + return CKR_OK; +} diff --git a/usr/lib/common/ock_syslog.h b/usr/lib/common/ock_syslog.h new file mode 100644 index 0000000..1e349ca --- /dev/null +++ b/usr/lib/common/ock_syslog.h @@ -0,0 +1,40 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2018 + * + * 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 OCK_SYSLOG_H +#define OCK_SYSLOG_H + +#include +#include +#include + +#define OCK_SYSLOG_MAX 512 + +#define OCK_SYSLOG(priority, ...) \ + _ock_syslog(priority, __FILE__, __VA_ARGS__) + + +static inline void _ock_syslog(int priority, const char *file, + const char *fmt, ...) { + char buf[OCK_SYSLOG_MAX]; + size_t off; + va_list ap; + + snprintf(buf, sizeof(buf), "%s ", file); + off = strlen(buf); + + va_start(ap, fmt); + vsnprintf(buf + off, sizeof(buf) - off, fmt, ap); + va_end(ap); + + syslog(priority, "%s", buf); +} + +#endif diff --git a/usr/lib/common/p11util.c b/usr/lib/common/p11util.c new file mode 100644 index 0000000..84b63ce --- /dev/null +++ b/usr/lib/common/p11util.c @@ -0,0 +1,501 @@ +/* + * 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 + */ + +#include +#include +#include +#include "pkcs11types.h" + +#define _sym2str(X) case X: return #X + +// +// p11_get_ckr - return textual interpretation of a CKR_ error code +// @rc is the CKR_.. error +// +char *p11_get_ckr(CK_RV rc) +{ + switch (rc) { + _sym2str(CKR_OK); + _sym2str(CKR_CANCEL); + _sym2str(CKR_HOST_MEMORY); + _sym2str(CKR_SLOT_ID_INVALID); + _sym2str(CKR_GENERAL_ERROR); + _sym2str(CKR_FUNCTION_FAILED); + _sym2str(CKR_ARGUMENTS_BAD); + _sym2str(CKR_NO_EVENT); + _sym2str(CKR_NEED_TO_CREATE_THREADS); + _sym2str(CKR_CANT_LOCK); + _sym2str(CKR_ATTRIBUTE_READ_ONLY); + _sym2str(CKR_ATTRIBUTE_SENSITIVE); + _sym2str(CKR_ATTRIBUTE_TYPE_INVALID); + _sym2str(CKR_ATTRIBUTE_VALUE_INVALID); + _sym2str(CKR_DATA_INVALID); + _sym2str(CKR_DATA_LEN_RANGE); + _sym2str(CKR_DEVICE_ERROR); + _sym2str(CKR_DEVICE_MEMORY); + _sym2str(CKR_DEVICE_REMOVED); + _sym2str(CKR_ENCRYPTED_DATA_INVALID); + _sym2str(CKR_ENCRYPTED_DATA_LEN_RANGE); + _sym2str(CKR_FUNCTION_CANCELED); + _sym2str(CKR_FUNCTION_NOT_PARALLEL); + _sym2str(CKR_FUNCTION_NOT_SUPPORTED); + _sym2str(CKR_KEY_HANDLE_INVALID); + _sym2str(CKR_KEY_SIZE_RANGE); + _sym2str(CKR_KEY_TYPE_INCONSISTENT); + _sym2str(CKR_KEY_NOT_NEEDED); + _sym2str(CKR_KEY_CHANGED); + _sym2str(CKR_KEY_NEEDED); + _sym2str(CKR_KEY_INDIGESTIBLE); + _sym2str(CKR_KEY_FUNCTION_NOT_PERMITTED); + _sym2str(CKR_KEY_NOT_WRAPPABLE); + _sym2str(CKR_KEY_UNEXTRACTABLE); + _sym2str(CKR_MECHANISM_INVALID); + _sym2str(CKR_MECHANISM_PARAM_INVALID); + _sym2str(CKR_OBJECT_HANDLE_INVALID); + _sym2str(CKR_OPERATION_ACTIVE); + _sym2str(CKR_OPERATION_NOT_INITIALIZED); + _sym2str(CKR_PIN_INCORRECT); + _sym2str(CKR_PIN_INVALID); + _sym2str(CKR_PIN_LEN_RANGE); + _sym2str(CKR_PIN_EXPIRED); + _sym2str(CKR_PIN_LOCKED); + _sym2str(CKR_SESSION_CLOSED); + _sym2str(CKR_SESSION_COUNT); + _sym2str(CKR_SESSION_HANDLE_INVALID); + _sym2str(CKR_SESSION_PARALLEL_NOT_SUPPORTED); + _sym2str(CKR_SESSION_READ_ONLY); + _sym2str(CKR_SESSION_EXISTS); + _sym2str(CKR_SESSION_READ_ONLY_EXISTS); + _sym2str(CKR_SESSION_READ_WRITE_SO_EXISTS); + _sym2str(CKR_SIGNATURE_INVALID); + _sym2str(CKR_SIGNATURE_LEN_RANGE); + _sym2str(CKR_TEMPLATE_INCOMPLETE); + _sym2str(CKR_TEMPLATE_INCONSISTENT); + _sym2str(CKR_TOKEN_NOT_PRESENT); + _sym2str(CKR_TOKEN_NOT_RECOGNIZED); + _sym2str(CKR_TOKEN_WRITE_PROTECTED); + _sym2str(CKR_UNWRAPPING_KEY_HANDLE_INVALID); + _sym2str(CKR_UNWRAPPING_KEY_SIZE_RANGE); + _sym2str(CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT); + _sym2str(CKR_USER_ALREADY_LOGGED_IN); + _sym2str(CKR_USER_NOT_LOGGED_IN); + _sym2str(CKR_USER_PIN_NOT_INITIALIZED); + _sym2str(CKR_USER_TYPE_INVALID); + _sym2str(CKR_USER_ANOTHER_ALREADY_LOGGED_IN); + _sym2str(CKR_USER_TOO_MANY_TYPES); + _sym2str(CKR_WRAPPED_KEY_INVALID); + _sym2str(CKR_WRAPPED_KEY_LEN_RANGE); + _sym2str(CKR_WRAPPING_KEY_HANDLE_INVALID); + _sym2str(CKR_WRAPPING_KEY_SIZE_RANGE); + _sym2str(CKR_WRAPPING_KEY_TYPE_INCONSISTENT); + _sym2str(CKR_RANDOM_SEED_NOT_SUPPORTED); + _sym2str(CKR_RANDOM_NO_RNG); + _sym2str(CKR_DOMAIN_PARAMS_INVALID); + _sym2str(CKR_CURVE_NOT_SUPPORTED); + _sym2str(CKR_BUFFER_TOO_SMALL); + _sym2str(CKR_SAVED_STATE_INVALID); + _sym2str(CKR_INFORMATION_SENSITIVE); + _sym2str(CKR_STATE_UNSAVEABLE); + _sym2str(CKR_CRYPTOKI_NOT_INITIALIZED); + _sym2str(CKR_CRYPTOKI_ALREADY_INITIALIZED); + _sym2str(CKR_MUTEX_BAD); + _sym2str(CKR_MUTEX_NOT_LOCKED); + _sym2str(CKR_FUNCTION_REJECTED); + default: + return "UNKNOWN"; + } +} + +// is_attribute_defined() +// +// determine whether the specified attribute is defined by Cryptoki +// +CK_BBOOL is_attribute_defined(CK_ATTRIBUTE_TYPE type) +{ + if (type >= CKA_VENDOR_DEFINED) + return TRUE; + + switch (type) { + case CKA_CLASS: + case CKA_TOKEN: + case CKA_PRIVATE: + case CKA_LABEL: + case CKA_APPLICATION: + case CKA_VALUE: + case CKA_CERTIFICATE_TYPE: + case CKA_ISSUER: + case CKA_SERIAL_NUMBER: + case CKA_KEY_TYPE: + case CKA_SUBJECT: + case CKA_ID: + case CKA_SENSITIVE: + case CKA_ENCRYPT: + case CKA_DECRYPT: + case CKA_WRAP: + case CKA_UNWRAP: + case CKA_SIGN: + case CKA_SIGN_RECOVER: + case CKA_VERIFY: + case CKA_VERIFY_RECOVER: + case CKA_DERIVE: + case CKA_START_DATE: + case CKA_END_DATE: + case CKA_MODULUS: + case CKA_MODULUS_BITS: + case CKA_PUBLIC_EXPONENT: + case CKA_PRIVATE_EXPONENT: + case CKA_PRIME_1: + case CKA_PRIME_2: + case CKA_EXPONENT_1: + case CKA_EXPONENT_2: + case CKA_COEFFICIENT: + case CKA_PRIME: + case CKA_SUBPRIME: + case CKA_BASE: + case CKA_VALUE_BITS: + case CKA_VALUE_LEN: + case CKA_EXTRACTABLE: + case CKA_LOCAL: + case CKA_NEVER_EXTRACTABLE: + case CKA_ALWAYS_SENSITIVE: + case CKA_ALWAYS_AUTHENTICATE: + case CKA_MODIFIABLE: + case CKA_ECDSA_PARAMS: + case CKA_EC_POINT: + case CKA_HW_FEATURE_TYPE: + case CKA_HAS_RESET: + case CKA_RESET_ON_INIT: + case CKA_KEY_GEN_MECHANISM: + case CKA_PRIME_BITS: + case CKA_SUBPRIME_BITS: + case CKA_OBJECT_ID: + case CKA_AC_ISSUER: + case CKA_OWNER: + case CKA_ATTR_TYPES: + case CKA_TRUSTED: + case CKA_IBM_RESTRICTABLE: + case CKA_IBM_NEVER_MODIFIABLE: + case CKA_IBM_RETAINKEY: + case CKA_IBM_ATTRBOUND: + case CKA_IBM_KEYTYPE: + case CKA_IBM_CV: + case CKA_IBM_MACKEY: + case CKA_IBM_USE_AS_DATA: + case CKA_IBM_STRUCT_PARAMS: + case CKA_IBM_STD_COMPLIANCE1: + case CKA_NSS_MOZILLA_CA_POLICY: + case CKA_IBM_DILITHIUM_KEYFORM: + case CKA_IBM_DILITHIUM_RHO: + case CKA_IBM_DILITHIUM_SEED: + case CKA_IBM_DILITHIUM_TR: + case CKA_IBM_DILITHIUM_S1: + case CKA_IBM_DILITHIUM_S2: + case CKA_IBM_DILITHIUM_T0: + case CKA_IBM_DILITHIUM_T1: + return TRUE; + } + + return FALSE; +} + + +char *p11_get_ckm(CK_ULONG mechanism) +{ + switch (mechanism) { + _sym2str(CKM_RSA_PKCS_KEY_PAIR_GEN); + _sym2str(CKM_RSA_PKCS); + _sym2str(CKM_RSA_9796); + _sym2str(CKM_RSA_X_509); + _sym2str(CKM_MD2_RSA_PKCS); + _sym2str(CKM_MD5_RSA_PKCS); + _sym2str(CKM_SHA1_RSA_PKCS); + _sym2str(CKM_RIPEMD128_RSA_PKCS); + _sym2str(CKM_RIPEMD160_RSA_PKCS); + _sym2str(CKM_RSA_PKCS_OAEP); + _sym2str(CKM_RSA_X9_31_KEY_PAIR_GEN); + _sym2str(CKM_RSA_X9_31); + _sym2str(CKM_SHA1_RSA_X9_31); + _sym2str(CKM_RSA_PKCS_PSS); + _sym2str(CKM_SHA1_RSA_PKCS_PSS); + _sym2str(CKM_DSA_KEY_PAIR_GEN); + _sym2str(CKM_DSA); + _sym2str(CKM_DSA_SHA1); + _sym2str(CKM_DH_PKCS_KEY_PAIR_GEN); + _sym2str(CKM_DH_PKCS_DERIVE); + _sym2str(CKM_X9_42_DH_KEY_PAIR_GEN); + _sym2str(CKM_X9_42_DH_DERIVE); + _sym2str(CKM_X9_42_DH_HYBRID_DERIVE); + _sym2str(CKM_X9_42_MQV_DERIVE); + _sym2str(CKM_SHA224_RSA_PKCS); + _sym2str(CKM_SHA256_RSA_PKCS); + _sym2str(CKM_SHA384_RSA_PKCS); + _sym2str(CKM_SHA512_RSA_PKCS); + _sym2str(CKM_RC2_KEY_GEN); + _sym2str(CKM_RC2_ECB); + _sym2str(CKM_RC2_CBC); + _sym2str(CKM_RC2_MAC); + _sym2str(CKM_RC2_MAC_GENERAL); + _sym2str(CKM_RC2_CBC_PAD); + _sym2str(CKM_RC4_KEY_GEN); + _sym2str(CKM_RC4); + _sym2str(CKM_DES_KEY_GEN); + _sym2str(CKM_DES_ECB); + _sym2str(CKM_DES_CBC); + _sym2str(CKM_DES_MAC); + _sym2str(CKM_DES_MAC_GENERAL); + _sym2str(CKM_DES_CBC_PAD); + _sym2str(CKM_DES2_KEY_GEN); + _sym2str(CKM_DES3_KEY_GEN); + _sym2str(CKM_DES3_ECB); + _sym2str(CKM_DES3_CBC); + _sym2str(CKM_DES3_MAC); + _sym2str(CKM_DES3_MAC_GENERAL); + _sym2str(CKM_DES3_CBC_PAD); + _sym2str(CKM_CDMF_KEY_GEN); + _sym2str(CKM_CDMF_ECB); + _sym2str(CKM_CDMF_CBC); + _sym2str(CKM_CDMF_MAC); + _sym2str(CKM_CDMF_MAC_GENERAL); + _sym2str(CKM_CDMF_CBC_PAD); + _sym2str(CKM_MD2); + _sym2str(CKM_MD2_HMAC); + _sym2str(CKM_MD2_HMAC_GENERAL); + _sym2str(CKM_MD5); + _sym2str(CKM_MD5_HMAC); + _sym2str(CKM_MD5_HMAC_GENERAL); + _sym2str(CKM_SHA_1); + _sym2str(CKM_SHA_1_HMAC); + _sym2str(CKM_SHA_1_HMAC_GENERAL); + _sym2str(CKM_RIPEMD128); + _sym2str(CKM_RIPEMD128_HMAC); + _sym2str(CKM_RIPEMD128_HMAC_GENERAL); + _sym2str(CKM_RIPEMD160); + _sym2str(CKM_RIPEMD160_HMAC); + _sym2str(CKM_RIPEMD160_HMAC_GENERAL); + _sym2str(CKM_SHA224); + _sym2str(CKM_SHA224_HMAC); + _sym2str(CKM_SHA224_HMAC_GENERAL); + _sym2str(CKM_SHA256); + _sym2str(CKM_SHA256_HMAC); + _sym2str(CKM_SHA256_HMAC_GENERAL); + _sym2str(CKM_SHA384); + _sym2str(CKM_SHA384_HMAC); + _sym2str(CKM_SHA384_HMAC_GENERAL); + _sym2str(CKM_SHA512); + _sym2str(CKM_SHA512_HMAC); + _sym2str(CKM_SHA512_HMAC_GENERAL); + _sym2str(CKM_SHA512_224); + _sym2str(CKM_SHA512_224_HMAC); + _sym2str(CKM_SHA512_224_HMAC_GENERAL); + _sym2str(CKM_SHA512_256); + _sym2str(CKM_SHA512_256_HMAC); + _sym2str(CKM_SHA512_256_HMAC_GENERAL); + _sym2str(CKM_CAST_KEY_GEN); + _sym2str(CKM_CAST_ECB); + _sym2str(CKM_CAST_CBC); + _sym2str(CKM_CAST_MAC); + _sym2str(CKM_CAST_MAC_GENERAL); + _sym2str(CKM_CAST_CBC_PAD); + _sym2str(CKM_CAST3_KEY_GEN); + _sym2str(CKM_CAST3_ECB); + _sym2str(CKM_CAST3_CBC); + _sym2str(CKM_CAST3_MAC); + _sym2str(CKM_CAST3_MAC_GENERAL); + _sym2str(CKM_CAST3_CBC_PAD); + _sym2str(CKM_CAST5_KEY_GEN); + _sym2str(CKM_CAST5_ECB); + _sym2str(CKM_CAST5_CBC); + _sym2str(CKM_CAST5_MAC); + _sym2str(CKM_CAST5_MAC_GENERAL); + _sym2str(CKM_CAST5_CBC_PAD); + _sym2str(CKM_RC5_KEY_GEN); + _sym2str(CKM_RC5_ECB); + _sym2str(CKM_RC5_CBC); + _sym2str(CKM_RC5_MAC); + _sym2str(CKM_RC5_MAC_GENERAL); + _sym2str(CKM_RC5_CBC_PAD); + _sym2str(CKM_IDEA_KEY_GEN); + _sym2str(CKM_IDEA_ECB); + _sym2str(CKM_IDEA_CBC); + _sym2str(CKM_IDEA_MAC); + _sym2str(CKM_IDEA_MAC_GENERAL); + _sym2str(CKM_IDEA_CBC_PAD); + _sym2str(CKM_GENERIC_SECRET_KEY_GEN); + _sym2str(CKM_CONCATENATE_BASE_AND_KEY); + _sym2str(CKM_CONCATENATE_BASE_AND_DATA); + _sym2str(CKM_CONCATENATE_DATA_AND_BASE); + _sym2str(CKM_XOR_BASE_AND_DATA); + _sym2str(CKM_EXTRACT_KEY_FROM_KEY); + _sym2str(CKM_SSL3_PRE_MASTER_KEY_GEN); + _sym2str(CKM_SSL3_MASTER_KEY_DERIVE); + _sym2str(CKM_SSL3_KEY_AND_MAC_DERIVE); + _sym2str(CKM_SSL3_MASTER_KEY_DERIVE_DH); + _sym2str(CKM_TLS_PRE_MASTER_KEY_GEN); + _sym2str(CKM_TLS_MASTER_KEY_DERIVE); + _sym2str(CKM_TLS_KEY_AND_MAC_DERIVE); + _sym2str(CKM_TLS_MASTER_KEY_DERIVE_DH); + _sym2str(CKM_SSL3_MD5_MAC); + _sym2str(CKM_SSL3_SHA1_MAC); + _sym2str(CKM_MD5_KEY_DERIVATION); + _sym2str(CKM_MD2_KEY_DERIVATION); + _sym2str(CKM_SHA1_KEY_DERIVATION); + _sym2str(CKM_SHA224_KEY_DERIVATION); + _sym2str(CKM_SHA256_KEY_DERIVATION); + _sym2str(CKM_SHA384_KEY_DERIVATION); + _sym2str(CKM_SHA512_KEY_DERIVATION); + _sym2str(CKM_PBE_MD2_DES_CBC); + _sym2str(CKM_PBE_MD5_DES_CBC); + _sym2str(CKM_PBE_MD5_CAST_CBC); + _sym2str(CKM_PBE_MD5_CAST3_CBC); + _sym2str(CKM_PBE_MD5_CAST5_CBC); + _sym2str(CKM_PBE_SHA1_CAST5_CBC); + _sym2str(CKM_PBE_SHA1_RC4_128); + _sym2str(CKM_PBE_SHA1_RC4_40); + _sym2str(CKM_PBE_SHA1_DES3_EDE_CBC); + _sym2str(CKM_PBE_SHA1_DES2_EDE_CBC); + _sym2str(CKM_PBE_SHA1_RC2_128_CBC); + _sym2str(CKM_PBE_SHA1_RC2_40_CBC); + _sym2str(CKM_PKCS5_PBKD2); + _sym2str(CKM_PBA_SHA1_WITH_SHA1_HMAC); + _sym2str(CKM_KEY_WRAP_LYNKS); + _sym2str(CKM_KEY_WRAP_SET_OAEP); + _sym2str(CKM_SKIPJACK_KEY_GEN); + _sym2str(CKM_SKIPJACK_ECB64); + _sym2str(CKM_SKIPJACK_CBC64); + _sym2str(CKM_SKIPJACK_OFB64); + _sym2str(CKM_SKIPJACK_CFB64); + _sym2str(CKM_SKIPJACK_CFB32); + _sym2str(CKM_SKIPJACK_CFB16); + _sym2str(CKM_SKIPJACK_CFB8); + _sym2str(CKM_SKIPJACK_WRAP); + _sym2str(CKM_SKIPJACK_PRIVATE_WRAP); + _sym2str(CKM_SKIPJACK_RELAYX); + _sym2str(CKM_KEA_KEY_PAIR_GEN); + _sym2str(CKM_KEA_KEY_DERIVE); + _sym2str(CKM_FORTEZZA_TIMESTAMP); + _sym2str(CKM_BATON_KEY_GEN); + _sym2str(CKM_BATON_ECB128); + _sym2str(CKM_BATON_ECB96); + _sym2str(CKM_BATON_CBC128); + _sym2str(CKM_BATON_COUNTER); + _sym2str(CKM_BATON_SHUFFLE); + _sym2str(CKM_BATON_WRAP); + _sym2str(CKM_EC_KEY_PAIR_GEN); + _sym2str(CKM_ECDSA); + _sym2str(CKM_ECDSA_SHA1); + _sym2str(CKM_ECDSA_SHA224); + _sym2str(CKM_ECDSA_SHA256); + _sym2str(CKM_ECDSA_SHA384); + _sym2str(CKM_ECDSA_SHA512); + _sym2str(CKM_ECDH1_DERIVE); + _sym2str(CKM_ECDH1_COFACTOR_DERIVE); + _sym2str(CKM_ECMQV_DERIVE); + _sym2str(CKM_JUNIPER_KEY_GEN); + _sym2str(CKM_JUNIPER_ECB128); + _sym2str(CKM_JUNIPER_CBC128); + _sym2str(CKM_JUNIPER_COUNTER); + _sym2str(CKM_JUNIPER_SHUFFLE); + _sym2str(CKM_JUNIPER_WRAP); + _sym2str(CKM_FASTHASH); + _sym2str(CKM_AES_KEY_GEN); + _sym2str(CKM_AES_ECB); + _sym2str(CKM_AES_CBC); + _sym2str(CKM_AES_MAC); + _sym2str(CKM_AES_MAC_GENERAL); + _sym2str(CKM_AES_CBC_PAD); + _sym2str(CKM_AES_CTR); + _sym2str(CKM_DSA_PARAMETER_GEN); + _sym2str(CKM_DH_PKCS_PARAMETER_GEN); + _sym2str(CKM_X9_42_DH_PARAMETER_GEN); + _sym2str(CKM_VENDOR_DEFINED); + _sym2str(CKM_IBM_SHA3_224); + _sym2str(CKM_IBM_SHA3_256); + _sym2str(CKM_IBM_SHA3_384); + _sym2str(CKM_IBM_SHA3_512); + _sym2str(CKM_IBM_CMAC); + _sym2str(CKM_IBM_SHA3_224_HMAC); + _sym2str(CKM_IBM_SHA3_256_HMAC); + _sym2str(CKM_IBM_SHA3_384_HMAC); + _sym2str(CKM_IBM_SHA3_512_HMAC); + _sym2str(CKM_IBM_EC_C25519); + _sym2str(CKM_IBM_EDDSA_SHA512); + _sym2str(CKM_IBM_EC_C448); + _sym2str(CKM_IBM_ED448_SHA3); + _sym2str(CKM_IBM_DILITHIUM); + default: + return "UNKNOWN"; + } +} + +// Allocates memory on *dst and puts hex dump from ptr +// with len bytes. +// *dst must be freed by the caller +char *p11_ahex_dump(char **dst, CK_BYTE_PTR ptr, CK_ULONG len) +{ + CK_ULONG i; + + if (dst == NULL) { + return NULL; + } + + *dst = (char *) calloc(2 * len + 1, sizeof(char)); + if (*dst == NULL) { + return NULL; + } + + for (i = 0; i < len; i++) { + sprintf(*dst + 2 * i, "%02hhX", ptr[i]); + } + *(*dst + 2 * len) = '\0'; // null-terminate + + return *dst; +} + + +/* p11_bigint_trim() - trim a big integer. Returns pointer that is + * contained within 'in' + '*size' that represents + * the same number, but without leading zeros. + * @in points to a sequence of bytes forming a big integer, + * unsigned, right-aligned and big-endian + * @size points to the size of @in on input, and the minimum + * size that can represent it on output + */ +CK_BYTE_PTR p11_bigint_trim(CK_BYTE_PTR in, CK_ULONG_PTR size) +{ + CK_ULONG i; + + for (i = 0; (i < *size) && in[i] == 0x00; i++); + *size -= i; + + return in + i; +} + +/* p11_attribute_trim() - trim a PKCS#11 CK_ATTRIBUTE in place, + * using memmove() to move the data and adjusting + * ulValueLen. The resulting "pValue" pointer stays the + * same so that the caller can free() it normally + * @attr is the pointer to the CK_ATTRIBUTE to be trimmed + */ +void p11_attribute_trim(CK_ATTRIBUTE *attr) +{ + + CK_BYTE_PTR ptr; + CK_ULONG size; + + if (attr != NULL) { + size = attr->ulValueLen; + ptr = p11_bigint_trim(attr->pValue, &size); + + if (ptr != attr->pValue) { + attr->ulValueLen = size; + memmove(attr->pValue, ptr, size); + } + } +} diff --git a/usr/lib/common/p11util.h b/usr/lib/common/p11util.h new file mode 100644 index 0000000..30b7f81 --- /dev/null +++ b/usr/lib/common/p11util.h @@ -0,0 +1,57 @@ +/* + * 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 + */ + +#ifndef _P11UTIL_H_ +#define _P11UTIL_H_ + + +#include "pkcs11types.h" + +// +// p11_get_ckr - return textual interpretation of a CKR_ error code +// @rc is the CKR_.. error +// +char *p11_get_ckr(CK_RV rc); +// +// p11_get_ckm - return textual interpretation of a CKM_ mechanism code +// @rc is the CKM_.. as a string +// +char *p11_get_ckm(CK_ULONG); + +// is_attribute_defined() +// +// determine whether the specified attribute is defined by Cryptoki +// +CK_BBOOL is_attribute_defined(CK_ATTRIBUTE_TYPE type); + +// Allocates memory on *dst and puts hex dump from ptr +// with len bytes. +// *dst must be freed by the caller +char *p11_ahex_dump(char **dst, CK_BYTE_PTR ptr, CK_ULONG len); + +/* p11_bigint_trim() - trim a big integer. Returns pointer that is + * contained within 'in' + '*size' that represents + * the same number, but without leading zeros. + * @in points to a sequence of bytes forming a big integer, + * unsigned, right-aligned and big-endian + * @size points to the size of @in on input, and the minimum + * size that can represent it on output + */ +CK_BYTE_PTR p11_bigint_trim(CK_BYTE_PTR in, CK_ULONG_PTR size); + +/* p11_attribute_trim() - trim a PKCS#11 CK_ATTRIBUTE in place, + * using memmove() to move the data and adjusting + * ulValueLen. The resulting "pValue" pointer stays the + * same so that the caller can free() it normally + * @attr is the pointer to the CK_ATTRIBUTE to be trimmed + */ +void p11_attribute_trim(CK_ATTRIBUTE *attr); + +#endif // #ifndef _P11UTIL_H_ diff --git a/usr/lib/common/sess_mgr.c b/usr/lib/common/sess_mgr.c new file mode 100644 index 0000000..a1b5095 --- /dev/null +++ b/usr/lib/common/sess_mgr.c @@ -0,0 +1,975 @@ +/* + * 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 "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; +} + +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); + + // 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; + } 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++; + } + } + } + + *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) +{ + __transaction_atomic { /* start transaction */ + CK_BBOOL result; + + result = (tokdata->global_login_state == CKS_RW_SO_FUNCTIONS); + + return result; + } /* end transaction */ +} + + +// 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) +{ + __transaction_atomic { /* start transaction */ + CK_BBOOL result; + + result = ((tokdata->global_login_state == CKS_RO_USER_FUNCTIONS) || + (tokdata->global_login_state == CKS_RW_USER_FUNCTIONS)); + + return result; + } /* end transaction */ +} + + +// 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) +{ + __transaction_atomic { /* start transaction */ + CK_BBOOL result; + + result = ((tokdata->global_login_state == CKS_RO_PUBLIC_SESSION) || + (tokdata->global_login_state == CKS_RW_PUBLIC_SESSION)); + + return result; + } /* end transaction */ +} + + +// 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) +{ + __transaction_atomic { /* start transaction */ + CK_BBOOL result; + + result = (tokdata->ro_session_count > 0); + + return result; + } /* end transaction */ +} + + +// 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)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + 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 */ + + // 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) + free(sess->encr_ctx.context); + + if (sess->encr_ctx.mech.pParameter) + free(sess->encr_ctx.mech.pParameter); + + if (sess->decr_ctx.context) + free(sess->decr_ctx.context); + + if (sess->decr_ctx.mech.pParameter) + free(sess->decr_ctx.mech.pParameter); + + if (sess->digest_ctx.context) + free(sess->digest_ctx.context); + + if (sess->digest_ctx.mech.pParameter) + free(sess->digest_ctx.mech.pParameter); + + if (sess->sign_ctx.context) + free(sess->sign_ctx.context); + + if (sess->sign_ctx.mech.pParameter) + free(sess->sign_ctx.mech.pParameter); + + if (sess->verify_ctx.context) + 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); + + __transaction_atomic { /* start transaction */ + tokdata->global_login_state = CKS_RO_PUBLIC_SESSION; + } /* end transaction */ + // 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: + 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) + free(sess->encr_ctx.context); + + if (sess->encr_ctx.mech.pParameter) + free(sess->encr_ctx.mech.pParameter); + + if (sess->decr_ctx.context) + free(sess->decr_ctx.context); + + if (sess->decr_ctx.mech.pParameter) + free(sess->decr_ctx.mech.pParameter); + + if (sess->digest_ctx.context) + free(sess->digest_ctx.context); + + if (sess->digest_ctx.mech.pParameter) + free(sess->digest_ctx.mech.pParameter); + + if (sess->sign_ctx.context) + free(sess->sign_ctx.context); + + if (sess->sign_ctx.mech.pParameter) + free(sess->sign_ctx.mech.pParameter); + + if (sess->verify_ctx.context) + 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 +// +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 */ + + 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; + } + + __transaction_atomic { /* start transaction */ + tokdata->global_login_state = s->session_info.state; // SAB + } /* end transaction */ +} + +// 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) +{ + bt_for_each_node(tokdata, &tokdata->sess_btree, session_login, + (void *)&user_type); + + 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; + + __transaction_atomic { /* start transaction */ + tokdata->global_login_state = s->session_info.state; // SAB + } /* end transaction */ +} + +// session_mgr_logout_all() +// +// changes the login status of all sessions in the token +// +CK_RV session_mgr_logout_all(STDLL_TokData_t *tokdata) +{ + bt_for_each_node(tokdata, &tokdata->sess_btree, session_logout, NULL); + + return CKR_OK; +} + + +// +// +CK_RV session_mgr_get_op_state(SESSION *sess, + CK_BBOOL length_only, + CK_BYTE *data, CK_ULONG *data_len) +{ + OP_STATE_DATA *op_data = NULL; + CK_ULONG op_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) { + active_ops++; + if (op_data != NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); + return CKR_STATE_UNSAVEABLE; + } + op_data_len = sizeof(OP_STATE_DATA) + + sizeof(ENCR_DECR_CONTEXT) + + sess->encr_ctx.context_len + sess->encr_ctx.mech.ulParameterLen; + + if (length_only == FALSE) { + op_data = (OP_STATE_DATA *) data; + + 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); + } + } + } + + if (sess->decr_ctx.active == TRUE) { + active_ops++; + if (op_data != NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); + return CKR_STATE_UNSAVEABLE; + } + op_data_len = sizeof(OP_STATE_DATA) + + sizeof(ENCR_DECR_CONTEXT) + + sess->decr_ctx.context_len + sess->decr_ctx.mech.ulParameterLen; + + if (length_only == FALSE) { + op_data = (OP_STATE_DATA *) data; + + 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); + } + } + } + + if (sess->digest_ctx.active == TRUE) { + active_ops++; + if (op_data != NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); + return CKR_STATE_UNSAVEABLE; + } + op_data_len = sizeof(OP_STATE_DATA) + + sizeof(DIGEST_CONTEXT) + + sess->digest_ctx.context_len + sess->digest_ctx.mech.ulParameterLen; + + if (length_only == FALSE) { + op_data = (OP_STATE_DATA *) data; + + 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); + } + } + } + + if (sess->sign_ctx.active == TRUE) { + active_ops++; + if (op_data != NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); + return CKR_STATE_UNSAVEABLE; + } + op_data_len = sizeof(OP_STATE_DATA) + + sizeof(SIGN_VERIFY_CONTEXT) + + sess->sign_ctx.context_len + sess->sign_ctx.mech.ulParameterLen; + + if (length_only == FALSE) { + op_data = (OP_STATE_DATA *) data; + + 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); + } + } + } + + if (sess->verify_ctx.active == TRUE) { + active_ops++; + if (op_data != NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); + return CKR_STATE_UNSAVEABLE; + } + op_data_len = sizeof(OP_STATE_DATA) + + sizeof(SIGN_VERIFY_CONTEXT) + + sess->verify_ctx.context_len + sess->verify_ctx.mech.ulParameterLen; + + if (length_only == FALSE) { + op_data = (OP_STATE_DATA *) data; + + 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->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); + } + } + } + + if (!active_ops) { + TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE)); + return CKR_OPERATION_NOT_INITIALIZED; + } + + *data_len = op_data_len; + return CKR_OK; +} + + +// +// +CK_RV session_mgr_set_op_state(SESSION *sess, + CK_OBJECT_HANDLE encr_key, + CK_OBJECT_HANDLE auth_key, + CK_BYTE *data, CK_ULONG 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; + + UNUSED(data_len); + + if (!sess || !data) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + op_data = (OP_STATE_DATA *) data; + + // make sure the session states are compatible + // + if (sess->session_info.state != op_data->session_state) { + TRACE_ERROR("%s\n", ock_err(ERR_SAVED_STATE_INVALID)); + return CKR_SAVED_STATE_INVALID; + } + // validate the new state information. don't touch the session + // until the new state is valid. + // + switch (op_data->active_operation) { + case STATE_ENCR: + case STATE_DECR: + { + ENCR_DECR_CONTEXT *ctx = + (ENCR_DECR_CONTEXT *) (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 (auth_key != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_NOT_NEEDED)); + return CKR_KEY_NOT_NEEDED; + } + if (encr_key == 0) { + 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 *) (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 == 0) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_NEEDED)); + return CKR_KEY_NEEDED; + } + if (encr_key != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_NOT_NEEDED)); + return CKR_KEY_NOT_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 *) (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; + } + if (auth_key != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_NOT_NEEDED)); + return CKR_KEY_NOT_NEEDED; + } + if (encr_key != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_NOT_NEEDED)); + return CKR_KEY_NOT_NEEDED; + } + 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; + } + + + // state information looks okay. cleanup the current session state, first + // + if (sess->encr_ctx.active) + encr_mgr_cleanup(&sess->encr_ctx); + + if (sess->decr_ctx.active) + decr_mgr_cleanup(&sess->decr_ctx); + + if (sess->digest_ctx.active) + digest_mgr_cleanup(&sess->digest_ctx); + + if (sess->sign_ctx.active) + sign_mgr_cleanup(&sess->sign_ctx); + + if (sess->verify_ctx.active) + verify_mgr_cleanup(&sess->verify_ctx); + + + // 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; + } + + 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 --git a/usr/lib/common/shared_memory.c b/usr/lib/common/shared_memory.c new file mode 100644 index 0000000..d5a65fc --- /dev/null +++ b/usr/lib/common/shared_memory.c @@ -0,0 +1,433 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2012-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 + */ + +/* + * OpenCryptoki ICSF token - Shared memory abstraction for OpenCryptoki + * + * Author: Marcelo Cerri (mhcerri@br.ibm.com) + * + * Note: the functions in this files are implemented as an abstraction layer for + * POSIX shared memory functions but they can be extended to support other + * APIs of shared memory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* For logging functions: */ +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "trace.h" + +#include "shared_memory.h" + +/* + * Helper macros for logging. + */ +#define SYS_ERROR(_errno, _msg, ...) \ + do { \ + char _sys_error[1024]; \ + if (strerror_r(_errno, _sys_error, sizeof(_sys_error))) \ + strcpy(_sys_error, "Unknown error"); \ + syslog(LOG_ERR, "Error: " _msg " %s (errno=%d)", \ + __VA_ARGS__, _sys_error, _errno); \ + TRACE_ERROR("Error: " _msg " %s (errno=%d)", \ + __VA_ARGS__, _sys_error, _errno); \ + } while (0) + +/* + * Shared context used to keep meta data into the shared memory. + * + * The address to data field is the address visible outside this file. + * + * See shm_open for more details. + */ +struct shm_context { + /* + * `ref` is a counter that is used to detect mismatching between + * sm_open and sm_close calls. + */ + int ref; + + /* + * `name` is the shared memory identifier and it is used to destroy + * an allocated shared memory region. + */ + char name[SM_NAME_LEN + 1]; + + /* + * `data_len` is the length of the variable length filed `data`. + */ + int data_len; + + /* + * `data` points to the region that will actually be used by + * `sm_open`s caller. + */ + char data[]; +}; + +/* + * Obtain the context pointer based on a data address. + */ +static inline struct shm_context *get_shm_context(void *addr) +{ + struct shm_context *ctx; + + ctx = (struct shm_context *)((unsigned char *)addr + - offsetof(struct shm_context, data)); + return ctx; +} + +/* + * If a complete path is informed, convert it to a shared memory name. + */ +static char *convert_path_to_shm_name(const char *file_path) +{ + char *name = NULL; + size_t len = strlen(file_path) + 1; + int i; + char *it; + + /* Need a starting '/' */ + if (file_path[0] != '/') + len++; + + if (len > SM_NAME_LEN) { + TRACE_ERROR("Error: path \"%s\" too long.\n", file_path); + return NULL; + } + + it = name = malloc(len + 1); + if (name == NULL) { + TRACE_ERROR("Error: failed to allocate memory for " + "path \"%s\".\n", file_path); + return NULL; + } + + i = 0; + *it++ = '/'; + if (file_path[0] == '/') + i++; + + for (; file_path[i]; i++, it++) { + if (file_path[i] == '/') + *it = '.'; + else + *it = file_path[i]; + } + *it = '\0'; + + TRACE_DEVEL("File path \"%s\" converted to \"%s\".\n", file_path, name); + + return name; +} + +/* + * Open a shared memory region identified by `sm_name` using permissions defined + * by `mode` with length `len`. + * + * If the shared memory already exists and doesn't match the given length an + * error is returned (if `force` is zero) or the shared memory is reinitialized + * (if `force` is non zero). + */ +int sm_open(const char *sm_name, int mode, void **p_addr, size_t len, int force) +{ + int rc; + int fd = -1; + void *addr = NULL; + struct stat stat_buf; + char *name = NULL; + struct shm_context *ctx = NULL; + size_t real_len = sizeof(*ctx) + len; + int created = 0; + + /* + * This is used for portability purpose. Please check `shm_open` + * man page for more details. + */ + if ((name = convert_path_to_shm_name(sm_name)) == NULL) { + rc = -EINVAL; + goto done; + } + + /* try and open first... */ + fd = shm_open(name, O_RDWR, mode); + if (fd < 0) { + /* maybe it needs to be created ... */ + fd = shm_open(name, O_RDWR | O_CREAT, mode); + if (fd < 0) { + rc = -errno; + SYS_ERROR(errno, "Failed to open shared memory \"%s\".\n", name); + goto done; + } else { + /* umask may have altered permissions if we created + * the shared memory in above call, so set proper + * permissions just in case. + */ + if (fchmod(fd, mode) == -1) { + rc = -errno; + SYS_ERROR(errno, "fchmod(%s): %s\n", name, strerror(errno)); + goto done; + } + } + } + + /* + * fstat is used here to check if the shared memory region already + * exists. When a shared memory region is first created, its size is + * always zero. + */ + if (fstat(fd, &stat_buf)) { + rc = -errno; + SYS_ERROR(errno, "Cannot stat \"%s\".\n", name); + goto done; + } + + /* + * The shared memory needs to be extended when created (when its length + * is zero). When its length is not zero and is not equal to the + * expected size, an error is returned if `force` is not set. If `force` + * is set, the existing shared memory is truncated and any data on it is + * lost. + */ + if (stat_buf.st_size == 0 + || (force && (size_t)stat_buf.st_size != real_len)) { + /* + * If the shared memory region was just created, it's necessary + * to extend it to the expected size using ftruncate. + * + * It's important to notice that it is resized to a length + * greater than the value requested (`len`). The extra space is + * used to store additional information related to the shared + * memory, such as its size and identifier. + */ + created = 1; + TRACE_DEVEL("Truncating \"%s\".\n", name); + if (ftruncate(fd, real_len) < 0) { + rc = -errno; + SYS_ERROR(errno, "Cannot truncate \"%s\".\n", name); + goto done; + } + } else if ((size_t)stat_buf.st_size != real_len) { + int ref; + + /* get ref count */ + addr = mmap(NULL, sizeof(*ctx), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (addr == NULL) { + rc = -errno; + SYS_ERROR(errno, "Failed to map \"%s\" to memory.\n", name); + goto done; + } + ctx = addr; + ref = ctx->ref; + if (munmap(addr, sizeof(*ctx))) { + rc = -errno; + SYS_ERROR(errno, "Failed to unmap \"%s\" (%p).\n", name, (void *)ctx); + goto done;; + } + + /* + * Too big real_len indicates the new token data format is used. + * If no application is attached to the shm (ref==1) it can be + * safely expanded/recreated. Otherwise, fail. + */ + if (ref <= 1 && real_len > (size_t)stat_buf.st_size) { + created = 1; + TRACE_DEVEL("Truncating \"%s\".\n", name); + if (ftruncate(fd, real_len) < 0) { + rc = -errno; + SYS_ERROR(errno, "Cannot truncate \"%s\".\n", name); + goto done; + } + } else { + rc = -1; + TRACE_ERROR("Error: shared memory \"%s\" exists and does not " + "match the expected size.\n", name); + goto done; + } + } + + addr = mmap(NULL, real_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (addr == NULL) { + rc = -errno; + SYS_ERROR(errno, "Failed to map \"%s\" to memory.\n", name); + goto done; + } + + /* + * `addr` points to the start of the shared memory region. The first + * bytes of it are used to store the additional information about the + * shared memory allocated. This info can be accessed using an pointer + * to a `shm_context` structure. + */ + ctx = addr; + if (created) { + strcpy(ctx->name, name); + ctx->data_len = len; + memset(ctx->data, 0, ctx->data_len); + ctx->ref = 0; + } + ctx->ref += 1; + + /* + * The portion of the shared memory that will actually be used by the + * called is pointed by `data`. + * + * The address returned (in this case `ctx->data`) is equal to + * `addr + sizeof(struct shm_context)`, which means that the additional + * data is skipped off. + */ + *p_addr = ctx->data; + rc = created ? 0 : 1; + if (sm_sync(ctx->data)) { + rc = -errno; + SYS_ERROR(errno, "Failed to sync shared memory \"%s\".\n", name); + if (created) + sm_close(addr, 1, 0); + goto done; + } + TRACE_DEVEL("open: ref = %d\n", ctx->ref); + +done: + if (fd >= 0) + close(fd); + if (name) + free(name); + + return rc; +} + +/* + * Close (unmap) a shared memory region. `destroy` indicates if the shared + * memory should be destroyed if no other processes are using it. + * 'ignore_ref_count' indicates that the reference count in the shared memory + * should not be decremented (used during termination after a fork). + */ +int sm_close(void *addr, int destroy, int ignore_ref_count) +{ + int rc; + int ref; + char name[SM_NAME_LEN + 1] = { 0, }; + struct shm_context *ctx = get_shm_context(addr); + + if (ctx->ref <= 0) { + TRACE_ERROR("Error: invalid shared memory address %p (ref=%d).\n", + addr, ctx->ref); + return -EINVAL; + } + + if (!ignore_ref_count) + ctx->ref--; + ref = ctx->ref; + + TRACE_DEVEL("close: ref = %d\n", ref); + if (ref == 0 && destroy) { + strncpy(name, ctx->name, SM_NAME_LEN + 1); + name[SM_NAME_LEN] = '\0'; + } + + if (munmap(ctx, sizeof(*ctx) + ctx->data_len)) { + rc = -errno; + SYS_ERROR(errno, "Failed to unmap \"%s\" (%p).\n", name, (void *)ctx); + return rc; + } + + if (ref == 0 && destroy) { + TRACE_DEVEL("Deleting shared memory \"%s\".\n", name); + if ((rc = sm_destroy(name)) != 0) + return rc; + } + + return 0; +} + +/* + * Destroy a shared memory region. + */ +int sm_destroy(const char *name) +{ + int rc; + + if (shm_unlink(name)) { + rc = -errno; + SYS_ERROR(errno, "Failed to delete shared memory \"%s\".\n", name); + return rc; + } + + return 0; +} + +/* + * Force sync for a shared memory region. + */ +int sm_sync(void *addr) +{ + struct shm_context *ctx = get_shm_context(addr); + + if (ctx->ref <= 0) { + TRACE_ERROR("Error: invalid shared memory address %p (ref=%d).\n", + addr, ctx->ref); + return -EINVAL; + } + + return msync(ctx, ctx->data_len, MS_SYNC); +} + +/* + * Get the name of the shared memory indicated by `addr` and copy it to the + * given `buffer`. + */ +int sm_copy_name(void *addr, char *buffer, size_t len) +{ + size_t name_len; + struct shm_context *ctx = get_shm_context(addr); + + if (ctx->ref <= 0) { + TRACE_ERROR("Error: invalid shared memory address %p (ref=%d).\n", + addr, ctx->ref); + return -EINVAL; + } + + name_len = strlen(ctx->name); + if (len <= name_len) + return -ENOSPC; + + strcpy(buffer, ctx->name); + + return 0; +} + +/* + * Return the reference count for the given shared memory. + */ +int sm_get_count(void *addr) +{ + struct shm_context *ctx = get_shm_context(addr); + + if (ctx->ref <= 0) { + TRACE_ERROR("Error: invalid shared memory address %p (ref=%d).\n", + addr, ctx->ref); + return -EINVAL; + } + + return ctx->ref; +} diff --git a/usr/lib/common/shared_memory.h b/usr/lib/common/shared_memory.h new file mode 100644 index 0000000..1eaf88e --- /dev/null +++ b/usr/lib/common/shared_memory.h @@ -0,0 +1,42 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2012-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 + */ + +/* + * OpenCryptoki ICSF token - Shared memory abstraction for OpenCryptoki + * + * Author: Marcelo Cerri (mhcerri@br.ibm.com) + * + * Note: the functions in this files are implemented as an abstraction layer for + * POSIX shared memory functions but they can be extended to support other + * APIs of shared memory. + */ + +#ifndef OCK_SHARED_MEMORY_H +#define OCK_SHARED_MEMORY_H + +#include + +#define SM_NAME_LEN (NAME_MAX) + + +int sm_open(const char *sm_name, int mode, void **p_addr, size_t len, + int force); + +int sm_close(void *addr, int destroy, int ignore_ref_count); + +int sm_destroy(const char *name); + +int sm_sync(void *addr); + +int sm_copy_name(void *addr, char *buffer, size_t len); + +int sm_get_count(void *addr); + +#endif diff --git a/usr/lib/common/sign_mgr.c b/usr/lib/common/sign_mgr.c new file mode 100644 index 0000000..d537cea --- /dev/null +++ b/usr/lib/common/sign_mgr.c @@ -0,0 +1,1227 @@ +/* + * 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: sign_mgr.c +// +// Signature manager routines +// + +#include + +#include // for memcmp() et al +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "trace.h" + +// +// +CK_RV sign_mgr_init(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_MECHANISM *mech, + CK_BBOOL recover_mode, CK_OBJECT_HANDLE key) +{ + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *ptr = NULL; + CK_KEY_TYPE keytype; + CK_OBJECT_CLASS class; + CK_BBOOL flag; + CK_RV rc; + + + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (ctx->active != FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + return CKR_OPERATION_ACTIVE; + } + // key usage restrictions + // + rc = object_mgr_find_in_map1(tokdata, key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle.\n"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + if (recover_mode) { + // is key allowed to generate signatures where the data can be + // recovered from the signature? + rc = template_attribute_find(key_obj->template, CKA_SIGN_RECOVER, + &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_SIGN_RECOVER for the key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + } else { + // is key allowed to generate signatures where the signature is an + // appendix to the data? + rc = template_attribute_find(key_obj->template, CKA_SIGN, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_SIGN for the key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + } + flag = *(CK_BBOOL *) attr->pValue; + if (flag != TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_FUNCTION_NOT_PERMITTED)); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + + // is the mechanism supported? is the key type correct? is a + // parameter present if required? is the key size allowed? + // is the key allowed to generate signatures? + // + switch (mech->mechanism) { + case CKM_RSA_X_509: + case CKM_RSA_PKCS: + case CKM_RSA_PKCS_PSS: + if (mech->mechanism == CKM_RSA_PKCS_PSS) { + rc = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + rc = check_pss_params(mech, attr->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("check_pss_params() failed.\n"); + goto done; + } + } else { + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } + + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_RSA) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // must be a PRIVATE key + // + flag = template_attribute_find(key_obj->template, CKA_CLASS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + class = *(CK_OBJECT_CLASS *) attr->pValue; + } + + // if it's not a private RSA key then we have an internal failure... + // means that somehow a public key got assigned a CKA_SIGN attribute + // + if (class != CKO_PRIVATE_KEY) { + TRACE_ERROR("This operation requires a private key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + // PKCS #11 doesn't allow multi-part RSA operations + // + ctx->context_len = 0; + ctx->context = NULL; + break; + case CKM_ECDSA: + case CKM_ECDSA_SHA1: + case CKM_ECDSA_SHA224: + case CKM_ECDSA_SHA256: + case CKM_ECDSA_SHA384: + case CKM_ECDSA_SHA512: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_EC) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // must be a PRIVATE key + // + flag = template_attribute_find(key_obj->template, CKA_CLASS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + class = *(CK_OBJECT_CLASS *) attr->pValue; + } + + if (class != CKO_PRIVATE_KEY) { + TRACE_ERROR("This operation requires a private key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + + if (mech->mechanism == CKM_ECDSA) { + ctx->context_len = 0; + ctx->context = NULL; + } else { + ctx->context_len = sizeof(RSA_DIGEST_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(RSA_DIGEST_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(RSA_DIGEST_CONTEXT)); + } + break; +#if !(NOMD2) + case CKM_MD2_RSA_PKCS: +#endif + 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: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_RSA) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // must be a PRIVATE key operation + // + flag = template_attribute_find(key_obj->template, CKA_CLASS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + class = *(CK_OBJECT_CLASS *) attr->pValue; + } + + if (class != CKO_PRIVATE_KEY) { + TRACE_ERROR("This operation requires a private key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + ctx->context_len = sizeof(RSA_DIGEST_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(RSA_DIGEST_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(RSA_DIGEST_CONTEXT)); + break; + 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: + rc = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + rc = check_pss_params(mech, attr->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("check_pss_params failed.\n"); + goto done; + } + + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_RSA) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // must be a PRIVATE key operation + // + flag = template_attribute_find(key_obj->template, CKA_CLASS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + class = *(CK_OBJECT_CLASS *) attr->pValue; + } + + if (class != CKO_PRIVATE_KEY) { + TRACE_ERROR("This operation requires a private key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + ctx->context_len = sizeof(DIGEST_CONTEXT); + ctx->context = (CK_BYTE *) malloc(ctx->context_len); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, ctx->context_len); + break; +#if !(NODSA) + case CKM_DSA: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_DSA) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // must be a PRIVATE key + // + flag = template_attribute_find(key_obj->template, CKA_CLASS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + class = *(CK_OBJECT_CLASS *) attr->pValue; + } + + // if it's not a private RSA key then we have an internal failure... + // means that somehow a public key got assigned a CKA_SIGN attribute + // + if (class != CKO_PRIVATE_KEY) { + TRACE_ERROR("This operation requires a private key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + // PKCS #11 doesn't allow multi-part DSA operations + // + ctx->context_len = 0; + ctx->context = NULL; + break; +#endif +#if !(NOMD2) + case CKM_MD2_HMAC: +#endif + case CKM_MD5_HMAC: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_GENERIC_SECRET) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + /* Note: It was previously believed that pkcs#11 did not + * support hmac multipart. As a result, those tokens using the + * locally implemented hmac helper functions do not support + * multipart hmac. + */ + ctx->context_len = 0; + ctx->context = NULL; + break; + case CKM_SHA_1_HMAC: + case CKM_SHA224_HMAC: + case CKM_SHA256_HMAC: + case CKM_SHA384_HMAC: + case CKM_SHA512_HMAC: + case CKM_SHA512_224_HMAC: + case CKM_SHA512_256_HMAC: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_GENERIC_SECRET) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // PKCS #11 doesn't allow multi-part HMAC operations + // + ctx->context_len = 0; + ctx->context = NULL; + + rc = hmac_sign_init(tokdata, sess, mech, key); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to initialize hmac.\n"); + goto done; + } + break; +#if !(NOMD2) + case CKM_MD2_HMAC_GENERAL: +#endif + case CKM_MD5_HMAC_GENERAL: + { + CK_MAC_GENERAL_PARAMS *param = + (CK_MAC_GENERAL_PARAMS *) mech->pParameter; + + if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } +#if !(NOMD2) + if ((mech->mechanism == CKM_MD2_HMAC_GENERAL) && (*param > 16)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } +#endif + + if ((mech->mechanism == CKM_MD5_HMAC_GENERAL) && (*param > 16)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, + &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_GENERIC_SECRET) { + TRACE_ERROR("A generic secret key is required.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + } + + // PKCS #11 doesn't allow multi-part HMAC operations + // + ctx->context_len = 0; + ctx->context = NULL; + } + break; + case CKM_SHA_1_HMAC_GENERAL: + case CKM_SHA224_HMAC_GENERAL: + case CKM_SHA256_HMAC_GENERAL: + case CKM_SHA384_HMAC_GENERAL: + case CKM_SHA512_HMAC_GENERAL: + case CKM_SHA512_224_HMAC_GENERAL: + case CKM_SHA512_256_HMAC_GENERAL: + { + CK_MAC_GENERAL_PARAMS *param = + (CK_MAC_GENERAL_PARAMS *) mech->pParameter; + + if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + if ((mech->mechanism == CKM_SHA_1_HMAC_GENERAL) && (*param > 20)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + if ((mech->mechanism == CKM_SHA224_HMAC_GENERAL) && (*param > 28)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + if ((mech->mechanism == CKM_SHA256_HMAC_GENERAL) && (*param > 32)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + if ((mech->mechanism == CKM_SHA384_HMAC_GENERAL) && (*param > 48)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + if ((mech->mechanism == CKM_SHA512_HMAC_GENERAL) && (*param > 64)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + if ((mech->mechanism == CKM_SHA512_224_HMAC_GENERAL) + && (*param > 28)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + if ((mech->mechanism == CKM_SHA512_256_HMAC_GENERAL) + && (*param > 32)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, + &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_GENERIC_SECRET) { + TRACE_ERROR("A generic secret key is required.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + } + + /* Note: It was previously believed that pkcs#11 did not + * support hmac multipart. As a result, those tokens using the + * locally implemented hmac helper functions do not support + * multipart hmac. + */ + ctx->context_len = 0; + ctx->context = NULL; + + rc = hmac_sign_init(tokdata, sess, mech, key); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to initialize hmac.\n"); + goto done; + } + } + break; + case CKM_SSL3_MD5_MAC: + case CKM_SSL3_SHA1_MAC: + { + CK_MAC_GENERAL_PARAMS *param = + (CK_MAC_GENERAL_PARAMS *) mech->pParameter; + + if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // FIXME - Netscape sets the parameter == 16. PKCS #11 limit is 8 + // + if (mech->mechanism == CKM_SSL3_MD5_MAC) { + if (*param < 4 || *param > 16) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } + + if (mech->mechanism == CKM_SSL3_SHA1_MAC) { + if (*param < 4 || *param > 20) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } + + rc = template_attribute_find(key_obj->template, CKA_CLASS, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + class = *(CK_OBJECT_CLASS *) attr->pValue; + if (class != CKO_SECRET_KEY) { + TRACE_ERROR("This operation requires a secret key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + } + + ctx->context_len = sizeof(SSL3_MAC_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(SSL3_MAC_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(SSL3_MAC_CONTEXT)); + } + break; + case CKM_DES3_MAC: + case CKM_DES3_MAC_GENERAL: + if (mech->pParameter) { + + if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + CK_MAC_GENERAL_PARAMS *param = + (CK_MAC_GENERAL_PARAMS *) mech->pParameter; + + if (mech->mechanism == CKM_DES3_MAC_GENERAL) { + if (*param < 1 || *param > DES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } else { + /* CKM_DES3_MAC should not have params */ + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } + + ctx->context = (CK_BYTE *) malloc(sizeof(DES_DATA_CONTEXT)); + ctx->context_len = sizeof(DES_DATA_CONTEXT); + + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(DES_DATA_CONTEXT)); + break; + case CKM_DES3_CMAC: + case CKM_DES3_CMAC_GENERAL: + if (mech->pParameter) { + + if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + CK_MAC_GENERAL_PARAMS *param = + (CK_MAC_GENERAL_PARAMS *) mech->pParameter; + + if (mech->mechanism == CKM_DES3_CMAC_GENERAL) { + if (*param < 1 || *param > DES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } else { + /* CKM_DES3_CMAC should not have params */ + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } + + ctx->context = (CK_BYTE *) malloc(sizeof(DES_CMAC_CONTEXT)); + ctx->context_len = sizeof(DES_CMAC_CONTEXT); + + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(DES_CMAC_CONTEXT)); + break; + case CKM_AES_MAC: + case CKM_AES_MAC_GENERAL: + if (mech->pParameter) { + + if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + CK_MAC_GENERAL_PARAMS *param = + (CK_MAC_GENERAL_PARAMS *) mech->pParameter; + + if (mech->mechanism == CKM_AES_MAC_GENERAL) { + if (*param < 1 || *param > AES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } else { + /* CKM_AES_MAC should not have params */ + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } + + ctx->context = (CK_BYTE *) malloc(sizeof(AES_DATA_CONTEXT)); + ctx->context_len = sizeof(AES_DATA_CONTEXT); + + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(AES_DATA_CONTEXT)); + break; + case CKM_AES_CMAC: + case CKM_AES_CMAC_GENERAL: + if (mech->pParameter) { + + if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + CK_MAC_GENERAL_PARAMS *param = + (CK_MAC_GENERAL_PARAMS *) mech->pParameter; + + if (mech->mechanism == CKM_AES_CMAC_GENERAL) { + if (*param < 1 || *param > AES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } else { + /* CKM_AES_CMAC should not have params */ + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } + + ctx->context = (CK_BYTE *) malloc(sizeof(AES_CMAC_CONTEXT)); + ctx->context_len = sizeof(AES_CMAC_CONTEXT); + + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(AES_CMAC_CONTEXT)); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + + if (mech->ulParameterLen > 0 && mech->pParameter != NULL) { + ptr = (CK_BYTE *) malloc(mech->ulParameterLen); + if (!ptr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memcpy(ptr, mech->pParameter, mech->ulParameterLen); + } + + ctx->key = key; + ctx->mech.ulParameterLen = mech->ulParameterLen; + ctx->mech.mechanism = mech->mechanism; + ctx->mech.pParameter = ptr; + ctx->multi_init = FALSE; + ctx->multi = FALSE; + ctx->active = TRUE; + ctx->recover = recover_mode; + + rc = CKR_OK; + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +// +// +CK_RV sign_mgr_cleanup(SIGN_VERIFY_CONTEXT *ctx) +{ + if (!ctx) { + TRACE_ERROR("Invalid function argument.\n"); + return CKR_FUNCTION_FAILED; + } + ctx->key = 0; + ctx->mech.ulParameterLen = 0; + ctx->mech.mechanism = 0; + ctx->multi_init = FALSE; + ctx->multi = FALSE; + ctx->active = FALSE; + ctx->init_pending = FALSE; + ctx->recover = FALSE; + ctx->context_len = 0; + + if (ctx->mech.pParameter) { + free(ctx->mech.pParameter); + ctx->mech.pParameter = NULL; + } + + if (ctx->context) { + free(ctx->context); + ctx->context = NULL; + } + + return CKR_OK; +} + + +// +// +CK_RV sign_mgr_sign(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (ctx->active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->recover == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->multi_init == FALSE) { + ctx->multi = FALSE; + ctx->multi_init = TRUE; + } + + // if the caller just wants the signature length, there is no reason to + // specify the input data. I just need the input data length + // + if ((length_only == FALSE) && (!in_data || !out_data)) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + if (ctx->multi == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + return CKR_OPERATION_ACTIVE; + } + + switch (ctx->mech.mechanism) { + case CKM_RSA_PKCS: + return rsa_pkcs_sign(tokdata, sess, length_only, ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_RSA_X_509: + return rsa_x509_sign(tokdata, sess, length_only, ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_RSA_PKCS_PSS: + return rsa_pss_sign(tokdata, sess, length_only, ctx, in_data, + in_data_len, out_data, out_data_len); +#if !(NOMD2) + case CKM_MD2_RSA_PKCS: +#endif + 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: + return rsa_hash_pkcs_sign(tokdata, sess, length_only, ctx, + in_data, in_data_len, out_data, out_data_len); + 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: + return rsa_hash_pss_sign(tokdata, sess, length_only, ctx, in_data, + in_data_len, out_data, out_data_len); +#if !(NODSA) + case CKM_DSA: + return dsa_sign(tokdata, sess, length_only, ctx, + in_data, in_data_len, out_data, out_data_len); +#endif +#if !(NOMD2) + case CKM_MD2_HMAC: + case CKM_MD2_HMAC_GENERAL: + return md2_hmac_sign(tokdata, sess, length_only, ctx, + in_data, in_data_len, out_data, out_data_len); +#endif + case CKM_MD5_HMAC: + case CKM_MD5_HMAC_GENERAL: + return md5_hmac_sign(tokdata, sess, length_only, ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_SHA_1_HMAC: + case CKM_SHA_1_HMAC_GENERAL: + return sha1_hmac_sign(tokdata, sess, length_only, ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_SHA224_HMAC: + case CKM_SHA224_HMAC_GENERAL: + return sha224_hmac_sign(tokdata, sess, length_only, ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_SHA256_HMAC: + case CKM_SHA256_HMAC_GENERAL: + return sha256_hmac_sign(tokdata, sess, length_only, ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_SHA384_HMAC: + case CKM_SHA384_HMAC_GENERAL: + return sha384_hmac_sign(tokdata, sess, length_only, ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_SHA512_HMAC: + case CKM_SHA512_HMAC_GENERAL: + case CKM_SHA512_224_HMAC: + case CKM_SHA512_224_HMAC_GENERAL: + case CKM_SHA512_256_HMAC: + case CKM_SHA512_256_HMAC_GENERAL: + return sha512_hmac_sign(tokdata, sess, length_only, ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_SSL3_MD5_MAC: + case CKM_SSL3_SHA1_MAC: + return ssl3_mac_sign(tokdata, sess, length_only, ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_ECDSA_SHA1: + case CKM_ECDSA_SHA224: + case CKM_ECDSA_SHA256: + case CKM_ECDSA_SHA384: + case CKM_ECDSA_SHA512: + return ec_hash_sign(tokdata, sess, length_only, ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_ECDSA: + return ec_sign(tokdata, sess, length_only, ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_DES3_MAC: + case CKM_DES3_MAC_GENERAL: + return des3_mac_sign(tokdata, sess, length_only, ctx, in_data, + in_data_len, out_data, out_data_len); + case CKM_DES3_CMAC: + case CKM_DES3_CMAC_GENERAL: + return des3_cmac_sign(tokdata, sess, length_only, ctx, in_data, + in_data_len, out_data, out_data_len); + case CKM_AES_MAC: + case CKM_AES_MAC_GENERAL: + return aes_mac_sign(tokdata, sess, length_only, ctx, in_data, + in_data_len, out_data, out_data_len); + case CKM_AES_CMAC: + case CKM_AES_CMAC_GENERAL: + return aes_cmac_sign(tokdata, sess, length_only, ctx, in_data, + in_data_len, out_data, out_data_len); + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + TRACE_DEVEL("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + + +// +// +CK_RV sign_mgr_sign_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + + if (ctx->active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->recover == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->multi_init == FALSE) { + ctx->multi = TRUE; + ctx->multi_init = TRUE; + } + if (ctx->multi == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + return CKR_OPERATION_ACTIVE; + } + + switch (ctx->mech.mechanism) { +#if !(NOMD2) + case CKM_MD2_RSA_PKCS: +#endif + 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: + return rsa_hash_pkcs_sign_update(tokdata, sess, ctx, in_data, + in_data_len); + 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: + return rsa_hash_pss_update(tokdata, sess, ctx, in_data, in_data_len); + case CKM_SSL3_MD5_MAC: + case CKM_SSL3_SHA1_MAC: + return ssl3_mac_sign_update(tokdata, sess, ctx, in_data, in_data_len); + case CKM_DES3_MAC: + case CKM_DES3_MAC_GENERAL: + return des3_mac_sign_update(tokdata, sess, ctx, in_data, in_data_len); + case CKM_DES3_CMAC: + case CKM_DES3_CMAC_GENERAL: + return des3_cmac_sign_update(tokdata, sess, ctx, in_data, in_data_len); + case CKM_AES_MAC: + case CKM_AES_MAC_GENERAL: + return aes_mac_sign_update(tokdata, sess, ctx, in_data, in_data_len); + case CKM_AES_CMAC: + case CKM_AES_CMAC_GENERAL: + return aes_cmac_sign_update(tokdata, sess, ctx, in_data, in_data_len); + case CKM_ECDSA_SHA1: + case CKM_ECDSA_SHA224: + case CKM_ECDSA_SHA256: + case CKM_ECDSA_SHA384: + case CKM_ECDSA_SHA512: + return ec_hash_sign_update(tokdata, sess, ctx, in_data, in_data_len); + case CKM_SHA_1_HMAC: + case CKM_SHA224_HMAC: + case CKM_SHA256_HMAC: + case CKM_SHA384_HMAC: + case CKM_SHA512_HMAC: + case CKM_SHA512_224_HMAC: + case CKM_SHA512_256_HMAC: + case CKM_SHA_1_HMAC_GENERAL: + case CKM_SHA224_HMAC_GENERAL: + case CKM_SHA256_HMAC_GENERAL: + case CKM_SHA384_HMAC_GENERAL: + case CKM_SHA512_HMAC_GENERAL: + case CKM_SHA512_224_HMAC_GENERAL: + case CKM_SHA512_256_HMAC_GENERAL: + return hmac_sign_update(tokdata, sess, in_data, in_data_len); + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + TRACE_DEVEL("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + + +// +// +CK_RV sign_mgr_sign_final(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG *sig_len) +{ + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (ctx->active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->recover == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->multi_init == FALSE) { + ctx->multi = TRUE; + ctx->multi_init = TRUE; + } + if (ctx->multi == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + return CKR_OPERATION_ACTIVE; + } + + switch (ctx->mech.mechanism) { +#if !(NOMD2) + case CKM_MD2_RSA_PKCS: +#endif + 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: + return rsa_hash_pkcs_sign_final(tokdata, sess, length_only, ctx, + signature, sig_len); + 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: + return rsa_hash_pss_sign_final(tokdata, sess, length_only, ctx, + signature, sig_len); + case CKM_SSL3_MD5_MAC: + case CKM_SSL3_SHA1_MAC: + return ssl3_mac_sign_final(tokdata, sess, length_only, ctx, signature, + sig_len); + case CKM_DES3_MAC: + case CKM_DES3_MAC_GENERAL: + return des3_mac_sign_final(tokdata, sess, length_only, ctx, + signature, sig_len); + case CKM_DES3_CMAC: + case CKM_DES3_CMAC_GENERAL: + return des3_cmac_sign_final(tokdata, sess, length_only, ctx, + signature, sig_len); + case CKM_AES_MAC: + case CKM_AES_MAC_GENERAL: + return aes_mac_sign_final(tokdata, sess, length_only, ctx, signature, + sig_len); + case CKM_AES_CMAC: + case CKM_AES_CMAC_GENERAL: + return aes_cmac_sign_final(tokdata, sess, length_only, ctx, signature, + sig_len); + case CKM_ECDSA_SHA1: + case CKM_ECDSA_SHA224: + case CKM_ECDSA_SHA256: + case CKM_ECDSA_SHA384: + case CKM_ECDSA_SHA512: + return ec_hash_sign_final(tokdata, sess, length_only, ctx, signature, + sig_len); + case CKM_SHA_1_HMAC: + case CKM_SHA224_HMAC: + case CKM_SHA256_HMAC: + case CKM_SHA384_HMAC: + case CKM_SHA512_HMAC: + case CKM_SHA512_224_HMAC: + case CKM_SHA512_256_HMAC: + case CKM_SHA_1_HMAC_GENERAL: + case CKM_SHA224_HMAC_GENERAL: + case CKM_SHA256_HMAC_GENERAL: + case CKM_SHA384_HMAC_GENERAL: + case CKM_SHA512_HMAC_GENERAL: + case CKM_SHA512_224_HMAC_GENERAL: + case CKM_SHA512_256_HMAC_GENERAL: + return hmac_sign_final(tokdata, sess, signature, sig_len); + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + TRACE_DEVEL("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + + +// +// +CK_RV sign_mgr_sign_recover(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (ctx->active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->recover == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + // if the caller just wants the signature length, there is no reason to + // specify the input data. I just need the input data length + // + if ((length_only == FALSE) && (!in_data || !out_data)) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + if (ctx->multi == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + return CKR_OPERATION_ACTIVE; + } + + switch (ctx->mech.mechanism) { + case CKM_RSA_PKCS: + // we can use the same sign mechanism to do sign-recover + // + return rsa_pkcs_sign(tokdata, sess, length_only, ctx, + in_data, in_data_len, out_data, out_data_len); + case CKM_RSA_X_509: + return rsa_x509_sign(tokdata, sess, length_only, ctx, + in_data, in_data_len, out_data, out_data_len); + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + TRACE_DEVEL("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} diff --git a/usr/lib/common/sw_crypt.c b/usr/lib/common/sw_crypt.c new file mode 100644 index 0000000..2de14be --- /dev/null +++ b/usr/lib/common/sw_crypt.c @@ -0,0 +1,111 @@ +/* + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pkcs11types.h" +#include "p11util.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "trace.h" +#include "sw_crypt.h" + +CK_RV sw_des3_cbc(CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, + CK_BYTE *init_v, CK_BYTE *key_value, CK_BYTE encrypt) +{ + DES_key_schedule des_key1; + DES_key_schedule des_key2; + DES_key_schedule des_key3; + + const_DES_cblock key_SSL1, key_SSL2, key_SSL3; + DES_cblock ivec; + + // the des decrypt will only fail if the data length is not evenly divisible + // by DES_BLOCK_SIZE + if (in_data_len % DES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + // The key as passed in is a 24 byte string containing 3 keys + // pick it apart and create the key schedules + memcpy(&key_SSL1, key_value, (size_t) 8); + memcpy(&key_SSL2, key_value + 8, (size_t) 8); + memcpy(&key_SSL3, key_value + 16, (size_t) 8); + DES_set_key_unchecked(&key_SSL1, &des_key1); + DES_set_key_unchecked(&key_SSL2, &des_key2); + DES_set_key_unchecked(&key_SSL3, &des_key3); + + memcpy(ivec, init_v, sizeof(ivec)); + + // Encrypt or decrypt the data + if (encrypt) { + DES_ede3_cbc_encrypt(in_data, + out_data, + in_data_len, + &des_key1, + &des_key2, &des_key3, &ivec, DES_ENCRYPT); + *out_data_len = in_data_len; + } else { + DES_ede3_cbc_encrypt(in_data, + out_data, + in_data_len, + &des_key1, + &des_key2, &des_key3, &ivec, DES_DECRYPT); + + *out_data_len = in_data_len; + } + + return CKR_OK; +} + +CK_RV sw_aes_cbc(CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, + CK_BYTE *init_v, CK_BYTE *key_value, CK_ULONG keylen, + CK_BYTE encrypt) +{ + AES_KEY aes_key; + + UNUSED(out_data_len); //XXX can this parameter be removed ? + + memset(&aes_key, 0, sizeof(aes_key)); + + // the aes decrypt will only fail if the data length is not evenly divisible + // by AES_BLOCK_SIZE + if (in_data_len % AES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + + // Encrypt or decrypt the data + if (encrypt) { + AES_set_encrypt_key(key_value, keylen * 8, &aes_key); + AES_cbc_encrypt(in_data, out_data, in_data_len, &aes_key, + init_v, AES_ENCRYPT); + } else { + AES_set_decrypt_key(key_value, keylen * 8, &aes_key); + AES_cbc_encrypt(in_data, out_data, in_data_len, &aes_key, + init_v, AES_DECRYPT); + } + + return CKR_OK; +} diff --git a/usr/lib/common/sw_crypt.h b/usr/lib/common/sw_crypt.h new file mode 100644 index 0000000..af79f4b --- /dev/null +++ b/usr/lib/common/sw_crypt.h @@ -0,0 +1,39 @@ +/* + * 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 + */ + +#ifndef __SW_CRYPT_H__ +#define __SW_CRYPT_H__ + +#define sw_des3_cbc_encrypt(clear, len, cipher, len2, iv, key) \ + sw_des3_cbc(clear, len, cipher, len2, iv, key, 1) + +#define sw_des3_cbc_decrypt(clear, len, cipher, len2, iv, key) \ + sw_des3_cbc(clear, len, cipher, len2, iv, key, 0) + +CK_RV sw_des3_cbc(CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, + CK_BYTE *init_v, CK_BYTE *key_value, CK_BYTE encrypt); + +#define sw_aes_cbc_encrypt(clear, len, cipher, len2, iv, key, keylen) \ + sw_aes_cbc(clear, len, cipher, len2, iv, key, keylen, 1) + +#define sw_aes_cbc_decrypt(clear, len, cipher, len2, iv, key, keylen) \ + sw_aes_cbc(clear, len, cipher, len2, iv, key, keylen, 0) + +CK_RV sw_aes_cbc(CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, + CK_BYTE *init_v, CK_BYTE *key_value, CK_ULONG keylen, + CK_BYTE encrypt); + +#endif diff --git a/usr/lib/common/template.c b/usr/lib/common/template.c new file mode 100644 index 0000000..2e7dd5e --- /dev/null +++ b/usr/lib/common/template.c @@ -0,0 +1,1261 @@ +/* + * 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: template.c + * + * Attribute template management routines + * + * Functions contained in this file: + * + * template_add_attributes + * template_add_default_attributes + * template_attribute_find + * template_check_required_attributes + * template_check_required_base_attributes + * template_free + * template_set_default_common_attributes + * template_update_attribute + * template_validate_attribute + * template_validate_attributes + * template_validate_base_attribute + */ + +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "pkcs32.h" +#include "p11util.h" +#include "trace.h" + +/* template_add_attributes() + * + * blindly add the given attributes to the template. do no sanity checking + * at this point. sanity checking will occur later. + */ +CK_RV template_add_attributes(TEMPLATE *tmpl, CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount) +{ + CK_ATTRIBUTE *attr = NULL; + CK_RV rc; + unsigned int i; + + for (i = 0; i < ulCount; i++) { + if (!is_attribute_defined(pTemplate[i].type)) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID)); + return CKR_ATTRIBUTE_TYPE_INVALID; + } + attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + + pTemplate[i].ulValueLen); + if (!attr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + attr->type = pTemplate[i].type; + attr->ulValueLen = pTemplate[i].ulValueLen; + + if (attr->ulValueLen != 0) { + attr->pValue = (CK_BYTE *) attr + sizeof(CK_ATTRIBUTE); + memcpy(attr->pValue, pTemplate[i].pValue, attr->ulValueLen); + } else { + attr->pValue = NULL; + } + + rc = template_update_attribute(tmpl, attr); + if (rc != CKR_OK) { + free(attr); + TRACE_DEVEL("template_update_attribute failed.\n"); + return rc; + } + } + + return CKR_OK; +} + + +/* template_add_default_attributes() + * Add default attributes to '*tmpl'. + * '*basetmpl' may be used to derive values to the default attributes + */ +CK_RV template_add_default_attributes(TEMPLATE *tmpl, TEMPLATE *basetmpl, + CK_ULONG class, CK_ULONG subclass, + CK_ULONG mode) +{ + CK_RV rc; + + /* first add the default common attributes */ + rc = template_set_default_common_attributes(tmpl); + if (rc != CKR_OK) { + TRACE_DEVEL("template_set_default_common_attributes failed.\n"); + return rc; + } + + /* set the template class-specific default attributes */ + switch (class) { + case CKO_DATA: + return data_object_set_default_attributes(tmpl, mode); + case CKO_CERTIFICATE: + if (subclass == CKC_X_509) + return cert_x509_set_default_attributes(tmpl, mode); + else + return CKR_OK; + case CKO_PUBLIC_KEY: + switch (subclass) { + case CKK_RSA: + return rsa_publ_set_default_attributes(tmpl, basetmpl, mode); + case CKK_DSA: + return dsa_publ_set_default_attributes(tmpl, mode); + case CKK_ECDSA: + return ecdsa_publ_set_default_attributes(tmpl, mode); + case CKK_DH: + return dh_publ_set_default_attributes(tmpl, mode); + case CKK_KEA: + return kea_publ_set_default_attributes(tmpl, mode); + case CKK_IBM_PQC_DILITHIUM: + return ibm_dilithium_publ_set_default_attributes(tmpl, mode); + default: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; // unknown key type + } + case CKO_PRIVATE_KEY: + switch (subclass) { + case CKK_RSA: + return rsa_priv_set_default_attributes(tmpl, mode); + case CKK_DSA: + return dsa_priv_set_default_attributes(tmpl, mode); + case CKK_ECDSA: + return ecdsa_priv_set_default_attributes(tmpl, mode); + case CKK_DH: + return dh_priv_set_default_attributes(tmpl, mode); + case CKK_KEA: + return kea_priv_set_default_attributes(tmpl, mode); + case CKK_IBM_PQC_DILITHIUM: + return ibm_dilithium_priv_set_default_attributes(tmpl, mode); + default: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; // unknown key type + } + case CKO_SECRET_KEY: + switch (subclass) { + case CKK_GENERIC_SECRET: + return generic_secret_set_default_attributes(tmpl, mode); + case CKK_RC2: + return rc2_set_default_attributes(tmpl, mode); + case CKK_RC4: + return rc4_set_default_attributes(tmpl, mode); + case CKK_RC5: + return rc5_set_default_attributes(tmpl, mode); + case CKK_DES: + return des_set_default_attributes(tmpl, mode); + case CKK_DES2: + return des2_set_default_attributes(tmpl, mode); + case CKK_DES3: + return des3_set_default_attributes(tmpl, mode); + case CKK_CAST: + return cast_set_default_attributes(tmpl, mode); + case CKK_CAST3: + return cast3_set_default_attributes(tmpl, mode); + case CKK_CAST5: + return cast5_set_default_attributes(tmpl, mode); + case CKK_IDEA: + return idea_set_default_attributes(tmpl, mode); +#if !(NOCDMF) + case CKK_CDMF: + return cdmf_set_default_attributes(tmpl, mode); +#endif + case CKK_SKIPJACK: + return skipjack_set_default_attributes(tmpl, mode); + case CKK_BATON: + return baton_set_default_attributes(tmpl, mode); + case CKK_JUNIPER: + return juniper_set_default_attributes(tmpl, mode); + case CKK_AES: + return aes_set_default_attributes(tmpl, mode); + default: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; // unknown key type + } + case CKO_HW_FEATURE: + if (subclass >= CKH_VENDOR_DEFINED) + return CKR_OK; + switch (subclass) { + case CKH_CLOCK: + return clock_set_default_attributes(tmpl, mode); + case CKH_MONOTONIC_COUNTER: + return counter_set_default_attributes(tmpl, mode); + default: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + case CKO_DOMAIN_PARAMETERS: + switch (subclass) { + case CKK_DSA: + return dp_dsa_set_default_attributes(tmpl, mode); + case CKK_DH: + return dp_dh_set_default_attributes(tmpl, mode); + case CKK_X9_42_DH: + return dp_x9dh_set_default_attributes(tmpl, mode); + default: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + default: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } +} + + +/* template_attribute_find() + * + * find the attribute in the list and return its value + */ +CK_BBOOL template_attribute_find(TEMPLATE *tmpl, CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE **attr) +{ + DL_NODE *node = NULL; + CK_ATTRIBUTE *a = NULL; + + if (!tmpl || !attr) + return FALSE; + + node = tmpl->attribute_list; + + while (node != NULL) { + a = (CK_ATTRIBUTE *) node->data; + + if (type == a->type) { + *attr = a; + return TRUE; + } + + node = node->next; + } + + *attr = NULL; + + return FALSE; +} + +/* template_attribute_find_multiple() + * + * find the attributes in the list and return their values + */ +void template_attribute_find_multiple(TEMPLATE *tmpl, + ATTRIBUTE_PARSE_LIST *parselist, + CK_ULONG plcount) +{ + CK_ATTRIBUTE *attr = NULL; + CK_ULONG i; + + for (i = 0; i < plcount; i++) { + parselist[i].found = template_attribute_find(tmpl, + parselist[i].type, &attr); + + if (parselist[i].found && parselist[i].ptr != NULL) + memcpy(parselist[i].ptr, attr->pValue, parselist[i].len); + } +} + + +/* template_check_required_attributes() */ +CK_RV template_check_required_attributes(TEMPLATE *tmpl, CK_ULONG class, + CK_ULONG subclass, CK_ULONG mode) +{ + if (class == CKO_DATA) { + return data_object_check_required_attributes(tmpl, mode); + } else if (class == CKO_CERTIFICATE) { + if (subclass == CKC_X_509) + return cert_x509_check_required_attributes(tmpl, mode); + else + return cert_vendor_check_required_attributes(tmpl, mode); + } else if (class == CKO_PUBLIC_KEY) { + switch (subclass) { + case CKK_RSA: + return rsa_publ_check_required_attributes(tmpl, mode); + case CKK_DSA: + return dsa_publ_check_required_attributes(tmpl, mode); + case CKK_ECDSA: + return ecdsa_publ_check_required_attributes(tmpl, mode); + case CKK_DH: + return dh_publ_check_required_attributes(tmpl, mode); + case CKK_KEA: + return kea_publ_check_required_attributes(tmpl, mode); + case CKK_IBM_PQC_DILITHIUM: + return ibm_dilithium_publ_check_required_attributes(tmpl, mode); + default: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; // unknown keytype + } + } else if (class == CKO_PRIVATE_KEY) { + switch (subclass) { + case CKK_RSA: + return rsa_priv_check_required_attributes(tmpl, mode); + case CKK_DSA: + return dsa_priv_check_required_attributes(tmpl, mode); + case CKK_ECDSA: + return ecdsa_priv_check_required_attributes(tmpl, mode); + case CKK_DH: + return dh_priv_check_required_attributes(tmpl, mode); + case CKK_KEA: + return kea_priv_check_required_attributes(tmpl, mode); + case CKK_IBM_PQC_DILITHIUM: + return ibm_dilithium_priv_check_required_attributes(tmpl, mode); + default: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; // unknown key type + } + } else if (class == CKO_SECRET_KEY) { + switch (subclass) { + case CKK_GENERIC_SECRET: + return generic_secret_check_required_attributes(tmpl, mode); + case CKK_RC2: + return rc2_check_required_attributes(tmpl, mode); + case CKK_RC4: + return rc4_check_required_attributes(tmpl, mode); + case CKK_RC5: + return rc5_check_required_attributes(tmpl, mode); + case CKK_DES: + return des_check_required_attributes(tmpl, mode); + case CKK_DES2: + return des2_check_required_attributes(tmpl, mode); + case CKK_DES3: + return des3_check_required_attributes(tmpl, mode); + case CKK_CAST: + return cast_check_required_attributes(tmpl, mode); + case CKK_CAST3: + return cast3_check_required_attributes(tmpl, mode); + case CKK_CAST5: + return cast5_check_required_attributes(tmpl, mode); + case CKK_IDEA: + return idea_check_required_attributes(tmpl, mode); +#if !(NOCDMF) + case CKK_CDMF: + return cdmf_check_required_attributes(tmpl, mode); +#endif + case CKK_SKIPJACK: + return skipjack_check_required_attributes(tmpl, mode); + case CKK_BATON: + return baton_check_required_attributes(tmpl, mode); + case CKK_JUNIPER: + return juniper_check_required_attributes(tmpl, mode); + case CKK_AES: + return aes_check_required_attributes(tmpl, mode); + default: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; // unknown key type + } + } else if (class == CKO_HW_FEATURE) { + if (subclass >= CKH_VENDOR_DEFINED) + return CKR_OK; + switch (subclass) { + case CKH_CLOCK: + return clock_check_required_attributes(tmpl, mode); + case CKH_MONOTONIC_COUNTER: + return counter_check_required_attributes(tmpl, mode); + default: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + } else if (class == CKO_DOMAIN_PARAMETERS) { + switch (subclass) { + case CKK_DSA: + return dp_dsa_check_required_attributes(tmpl, mode); + case CKK_DH: + return dp_dh_check_required_attributes(tmpl, mode); + case CKK_X9_42_DH: + return dp_x9dh_check_required_attributes(tmpl, mode); + default: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + } + + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + + return CKR_ATTRIBUTE_VALUE_INVALID; // default fallthru +} + + +/* template_check_required_base_attributes() + * + * check to make sure that attributes required by Cryptoki are + * present. does not check to see if the attribute makes sense + * for the particular object (that is done in the 'validate' routines) + */ +CK_RV template_check_required_base_attributes(TEMPLATE *tmpl, CK_ULONG mode) +{ + CK_ATTRIBUTE *attr; + CK_BBOOL found; + + found = template_attribute_find(tmpl, CKA_CLASS, &attr); + if (mode == MODE_CREATE && found == FALSE) + return CKR_TEMPLATE_INCOMPLETE; + + return CKR_OK; +} + +/* template_compare() */ +CK_BBOOL template_compare(CK_ATTRIBUTE *t1, CK_ULONG ulCount, TEMPLATE *t2) +{ + CK_ATTRIBUTE *attr1 = NULL; + CK_ATTRIBUTE *attr2 = NULL; + CK_ULONG i; + CK_RV rc; + + if (!t1 || !t2) + return FALSE; + + attr1 = t1; + + for (i = 0; i < ulCount; i++) { + rc = template_attribute_find(t2, attr1->type, &attr2); + if (rc == FALSE) + return FALSE; + + if (attr1->ulValueLen != attr2->ulValueLen) + return FALSE; + + if (memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen) != 0) + return FALSE; + + attr1++; + } + + return TRUE; +} + + +/* template_copy() + * + * This doesn't copy the template items verbatim. The new template is in + * the reverse order of the old one. This should not have any effect. + * + * This is very similar to template_merge(). template_merge() can also + * be used to copy a list (of unique attributes) but is slower because for + * each attribute, it must search through the list. + */ +CK_RV template_copy(TEMPLATE *dest, TEMPLATE *src) +{ + DL_NODE *node; + + if (!dest || !src) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + node = src->attribute_list; + + while (node) { + CK_ATTRIBUTE *attr = (CK_ATTRIBUTE *) node->data; + CK_ATTRIBUTE *new_attr = NULL; + CK_ULONG len; + + len = sizeof(CK_ATTRIBUTE) + attr->ulValueLen; + + new_attr = (CK_ATTRIBUTE *) malloc(len); + if (!new_attr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + memcpy(new_attr, attr, len); + + new_attr->pValue = (CK_BYTE *) new_attr + sizeof(CK_ATTRIBUTE); + + dest->attribute_list = dlist_add_as_first(dest->attribute_list, + new_attr); + node = node->next; + } + + return CKR_OK; +} + + +/* template_flatten() + * this still gets used when saving token objects to disk + */ +CK_RV template_flatten(TEMPLATE *tmpl, CK_BYTE *dest) +{ + DL_NODE *node = NULL; + CK_BYTE *ptr = NULL; + CK_ULONG_32 long_len; + CK_ATTRIBUTE_32 *attr_32 = NULL; + CK_ULONG Val; + CK_ULONG_32 Val_32; + CK_ULONG *pVal; + + long_len = sizeof(CK_ULONG); + + if (!tmpl || !dest) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + ptr = dest; + node = tmpl->attribute_list; + while (node) { + CK_ATTRIBUTE *attr = (CK_ATTRIBUTE *) node->data; + + if (long_len == 4) { + memcpy(ptr, attr, sizeof(CK_ATTRIBUTE) + attr->ulValueLen); + ptr += sizeof(CK_ATTRIBUTE) + attr->ulValueLen; + } else { + attr_32 = malloc(sizeof(CK_ATTRIBUTE_32)); + if (!attr_32) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + attr_32->type = attr->type; + attr_32->pValue = 0x00; + if ((attr->type == CKA_CLASS || + attr->type == CKA_KEY_TYPE || + attr->type == CKA_MODULUS_BITS || + attr->type == CKA_VALUE_BITS || + attr->type == CKA_CERTIFICATE_TYPE || + attr->type == CKA_VALUE_LEN) && attr->ulValueLen != 0) { + + attr_32->ulValueLen = sizeof(CK_ULONG_32); + + memcpy(ptr, attr_32, sizeof(CK_ATTRIBUTE_32)); + ptr += sizeof(CK_ATTRIBUTE_32); + + pVal = (CK_ULONG *) attr->pValue; + Val = *pVal; + Val_32 = (CK_ULONG_32) Val; + memcpy(ptr, &Val_32, sizeof(CK_ULONG_32)); + ptr += sizeof(CK_ULONG_32); + } else { + attr_32->ulValueLen = attr->ulValueLen; + memcpy(ptr, attr_32, sizeof(CK_ATTRIBUTE_32)); + ptr += sizeof(CK_ATTRIBUTE_32); + if (attr->ulValueLen != 0) { + memcpy(ptr, attr->pValue, attr->ulValueLen); + ptr += attr->ulValueLen; + } + } + free(attr_32); + } + + node = node->next; + } + + return CKR_OK; +} + +CK_RV template_unflatten(TEMPLATE **new_tmpl, CK_BYTE *buf, CK_ULONG count) +{ + return template_unflatten_withSize(new_tmpl, buf, count, -1); +} + +/* Modified version of template_unflatten that checks + * that buf isn't overread. buf_size=-1 turns off checking + * (for backwards compatability) + */ +CK_RV template_unflatten_withSize(TEMPLATE **new_tmpl, CK_BYTE *buf, + CK_ULONG count, int buf_size) +{ + TEMPLATE *tmpl = NULL; + CK_ATTRIBUTE *a2 = NULL; + CK_BYTE *ptr = NULL; + CK_ULONG i, len; + CK_RV rc; + CK_ULONG_32 long_len = sizeof(CK_ULONG); + CK_ULONG_32 attr_ulong_32; + CK_ULONG attr_ulong; + CK_ATTRIBUTE *a1_64 = NULL; + CK_ATTRIBUTE_32 *a1 = NULL; + + + if (!new_tmpl || !buf) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + tmpl = (TEMPLATE *) malloc(sizeof(TEMPLATE)); + if (!tmpl) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + memset(tmpl, 0x0, sizeof(TEMPLATE)); + + ptr = buf; + for (i = 0; i < count; i++) { + if (buf_size >= 0 && + ((ptr + sizeof(CK_ATTRIBUTE)) > (buf + buf_size))) { + template_free(tmpl); + return CKR_FUNCTION_FAILED; + } + + if (long_len == 4) { + a1_64 = (CK_ATTRIBUTE *) ptr; + + len = sizeof(CK_ATTRIBUTE) + a1_64->ulValueLen; + a2 = (CK_ATTRIBUTE *) malloc(len); + if (!a2) { + template_free(tmpl); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + /* if a buffer size is given, make sure it + * doesn't get overrun + */ + if (buf_size >= 0 && + (((unsigned char *) a1_64 + len) + > ((unsigned char *) buf + buf_size))) { + free(a2); + template_free(tmpl); + return CKR_FUNCTION_FAILED; + } + memcpy(a2, a1_64, len); + } else { + a1 = (CK_ATTRIBUTE_32 *) ptr; + + if ((a1->type == CKA_CLASS || a1->type == CKA_KEY_TYPE + || a1->type == CKA_MODULUS_BITS + || a1->type == CKA_VALUE_BITS + || a1->type == CKA_CERTIFICATE_TYPE + || a1->type == CKA_VALUE_LEN) + && a1->ulValueLen != 0) { + len = sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG); + } else { + len = sizeof(CK_ATTRIBUTE) + a1->ulValueLen; + } + + a2 = (CK_ATTRIBUTE *) malloc(len); + if (!a2) { + template_free(tmpl); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + a2->type = a1->type; + + if ((a1->type == CKA_CLASS || a1->type == CKA_KEY_TYPE + || a1->type == CKA_MODULUS_BITS + || a1->type == CKA_VALUE_BITS + || a1->type == CKA_CERTIFICATE_TYPE + || a1->type == CKA_VALUE_LEN) + && a1->ulValueLen != 0) { + + a2->ulValueLen = sizeof(CK_ULONG); + + { + CK_ULONG_32 *p32; + CK_BYTE *pb2; + + pb2 = (CK_BYTE *) a1; + pb2 += sizeof(CK_ATTRIBUTE_32); + p32 = (CK_ULONG_32 *) pb2; + attr_ulong_32 = *p32; + } + + attr_ulong = attr_ulong_32; + + { + CK_BYTE *pb2; + pb2 = (CK_BYTE *) a2; + pb2 += sizeof(CK_ATTRIBUTE); + memcpy(pb2, (CK_BYTE *) & attr_ulong, sizeof(CK_ULONG)); + } + } else { + CK_BYTE *pb2, *pb; + + a2->ulValueLen = a1->ulValueLen; + pb2 = (CK_BYTE *) a2; + pb2 += sizeof(CK_ATTRIBUTE); + pb = (CK_BYTE *) a1; + pb += sizeof(CK_ATTRIBUTE_32); + /* if a buffer size is given, make sure it + * doesn't get overrun + */ + if (buf_size >= 0 && (pb + a1->ulValueLen) > (buf + buf_size)) { + free(a2); + template_free(tmpl); + return CKR_FUNCTION_FAILED; + } + memcpy(pb2, pb, a1->ulValueLen); + } + } + + if (a2->ulValueLen != 0) + a2->pValue = (CK_BYTE *) a2 + sizeof(CK_ATTRIBUTE); + else + a2->pValue = NULL; + + rc = template_update_attribute(tmpl, a2); + if (rc != CKR_OK) { + free(a2); + template_free(tmpl); + return rc; + } + if (long_len == 4) + ptr += len; + else + ptr += sizeof(CK_ATTRIBUTE_32) + a1->ulValueLen; + } + + *new_tmpl = tmpl; + + return CKR_OK; +} + + +/* template_free() */ +CK_RV template_free(TEMPLATE *tmpl) +{ + if (!tmpl) + return CKR_OK; + + while (tmpl->attribute_list) { + CK_ATTRIBUTE *attr = (CK_ATTRIBUTE *) tmpl->attribute_list->data; + + if (attr) + free(attr); + + tmpl->attribute_list = dlist_remove_node(tmpl->attribute_list, + tmpl->attribute_list); + } + + free(tmpl); + + return CKR_OK; +} + +/* template_get_class */ +CK_BBOOL template_get_class(TEMPLATE *tmpl, CK_ULONG *class, + CK_ULONG *subclass) +{ + DL_NODE *node; + CK_BBOOL found = FALSE; + + if (!tmpl || !class || !subclass) + return FALSE; + + node = tmpl->attribute_list; + + /* have to iterate through all attributes. no early exits */ + while (node) { + CK_ATTRIBUTE *attr = (CK_ATTRIBUTE *) node->data; + + if (attr->type == CKA_CLASS) { + *class = *(CK_OBJECT_CLASS *) attr->pValue; + found = TRUE; + } + + /* underneath, these guys are both CK_ULONG so we + * could combine this + */ + if (attr->type == CKA_CERTIFICATE_TYPE) + *subclass = *(CK_CERTIFICATE_TYPE *) attr->pValue; + + if (attr->type == CKA_KEY_TYPE) + *subclass = *(CK_KEY_TYPE *) attr->pValue; + + node = node->next; + } + + return found; +} + +CK_ULONG template_get_count(TEMPLATE *tmpl) +{ + if (tmpl == NULL) + return 0; + + return dlist_length(tmpl->attribute_list); +} + +CK_ULONG template_get_size(TEMPLATE *tmpl) +{ + DL_NODE *node; + CK_ULONG size = 0; + + if (tmpl == NULL) + return 0; + + node = tmpl->attribute_list; + while (node) { + CK_ATTRIBUTE *attr = (CK_ATTRIBUTE *) node->data; + + size += sizeof(CK_ATTRIBUTE) + attr->ulValueLen; + + node = node->next; + } + + return size; +} + +CK_ULONG template_get_compressed_size(TEMPLATE *tmpl) +{ + DL_NODE *node; + CK_ULONG size = 0; + + if (tmpl == NULL) + return 0; + node = tmpl->attribute_list; + while (node) { + CK_ATTRIBUTE *attr = (CK_ATTRIBUTE *) node->data; + + size += sizeof(CK_ATTRIBUTE_32); + if ((attr->type == CKA_CLASS || attr->type == CKA_KEY_TYPE + || attr->type == CKA_MODULUS_BITS + || attr->type == CKA_VALUE_BITS + || attr->type == CKA_CERTIFICATE_TYPE + || attr->type == CKA_VALUE_LEN) + && attr->ulValueLen != 0) { + size += sizeof(CK_ULONG_32); + } else { + size += attr->ulValueLen; + } + + node = node->next; + } + + return size; +} + +/* template_is_okay_to_reveal_attribute() + * + * determines whether the specified CK_ATTRIBUTE_TYPE is allowed to + * be leave the card in the clear. note: the specified template doesn't need + * to actually posess an attribute of type 'type'. The template is + * provided mainly to determine the object class and subclass + * + * this routine is called by C_GetAttributeValue which exports the attributes + * in the clear. this routine is NOT called when wrapping a key. + */ +CK_BBOOL template_check_exportability(TEMPLATE *tmpl, CK_ATTRIBUTE_TYPE type) +{ + CK_ATTRIBUTE *sensitive = NULL; + CK_ATTRIBUTE *extractable = NULL; + CK_ULONG class; + CK_ULONG subclass; + CK_BBOOL sensitive_val; + CK_BBOOL extractable_val; + + if (!tmpl) + return FALSE; + + /* since 'tmpl' belongs to a validated object, it's safe + * to assume that the following routine works + */ + template_get_class(tmpl, &class, &subclass); + + /* Early exits: + * 1) CKA_SENSITIVE and CKA_EXTRACTABLE only apply to private key + * and secret key objects. If object type is any other, then + * by default the attribute is exportable. + * + * 2) If CKA_SENSITIVE = FALSE and CKA_EXTRACTABLE = TRUE then + * all attributes are exportable + */ + if (class != CKO_PRIVATE_KEY && class != CKO_SECRET_KEY) + return TRUE; + + sensitive_val = template_attribute_find(tmpl, CKA_SENSITIVE, &sensitive); + extractable_val = template_attribute_find(tmpl, CKA_EXTRACTABLE, + &extractable); + if (sensitive_val && extractable_val) { + sensitive_val = *(CK_BBOOL *) sensitive->pValue; + extractable_val = *(CK_BBOOL *) extractable->pValue; + if (sensitive_val == FALSE && extractable_val == TRUE) + return TRUE; + } else { + /* technically, we should throw an error here... */ + return FALSE; + } + + /* at this point, we know the object must have CKA_SENSITIVE = TRUE + * or CKA_EXTRACTABLE = FALSE (or both). + * need to determine whether the particular attribute in question is + * a "sensitive" attribute. + */ + + if (class == CKO_PRIVATE_KEY) { + switch (subclass) { + case CKK_RSA: + return rsa_priv_check_exportability(type); + case CKK_DSA: + return dsa_priv_check_exportability(type); + case CKK_ECDSA: + return ecdsa_priv_check_exportability(type); + case CKK_X9_42_DH: + case CKK_DH: + return dh_priv_check_exportability(type); + case CKK_KEA: + return kea_priv_check_exportability(type); + default: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return TRUE; + } + } else if (class == CKO_SECRET_KEY) { + return secret_key_check_exportability(type); + } + + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + + return TRUE; +} + +/* template_merge() + * + * Merge two templates together: dest = dest U src + * + * src is destroyed in the process + */ +CK_RV template_merge(TEMPLATE *dest, TEMPLATE **src) +{ + DL_NODE *node; + CK_RV rc; + + if (!dest || !src) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + node = (*src)->attribute_list; + + while (node) { + CK_ATTRIBUTE *attr = (CK_ATTRIBUTE *) node->data; + + rc = template_update_attribute(dest, attr); + if (rc != CKR_OK) { + TRACE_DEVEL("template_update_attribute failed.\n"); + return rc; + } + /* we've assigned the node's data to a node in 'dest' */ + node->data = NULL; + node = node->next; + } + + template_free(*src); + *src = NULL; + + return CKR_OK; +} + +/* template_set_default_common_attributes() + * + * Set the default attributes common to all objects: + * + * CKA_TOKEN: FALSE + * CKA_PRIVATE: TRUE -- Cryptoki leaves this up to the token to decide + * CKA_MODIFIABLE: TRUE + * CKA_LABEL: empty string + */ +CK_RV template_set_default_common_attributes(TEMPLATE *tmpl) +{ + CK_ATTRIBUTE *token_attr; + CK_ATTRIBUTE *priv_attr; + CK_ATTRIBUTE *mod_attr; + CK_ATTRIBUTE *label_attr; + + /* add the default common attributes */ + token_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + + sizeof(CK_BBOOL)); + priv_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + + sizeof(CK_BBOOL)); + mod_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + + sizeof(CK_BBOOL)); + label_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + 0); + + if (!token_attr || !priv_attr || !mod_attr || !label_attr) { + if (token_attr) + free(token_attr); + if (priv_attr) + free(priv_attr); + if (mod_attr) + free(mod_attr); + if (label_attr) + free(label_attr); + + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + token_attr->type = CKA_TOKEN; + token_attr->ulValueLen = sizeof(CK_BBOOL); + token_attr->pValue = (CK_BYTE *) token_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) token_attr->pValue = FALSE; + + priv_attr->type = CKA_PRIVATE; + priv_attr->ulValueLen = sizeof(CK_BBOOL); + priv_attr->pValue = (CK_BYTE *) priv_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) priv_attr->pValue = FALSE; + + mod_attr->type = CKA_MODIFIABLE; + mod_attr->ulValueLen = sizeof(CK_BBOOL); + mod_attr->pValue = (CK_BYTE *) mod_attr + sizeof(CK_ATTRIBUTE); + *(CK_BBOOL *) mod_attr->pValue = TRUE; + + label_attr->type = CKA_LABEL; + label_attr->ulValueLen = 0; // empty string + label_attr->pValue = NULL; + + template_update_attribute(tmpl, token_attr); + template_update_attribute(tmpl, priv_attr); + template_update_attribute(tmpl, mod_attr); + template_update_attribute(tmpl, label_attr); + + /* the TEMPLATE 'owns' the attributes now. + * it is responsible for freeing them upon deletion... + */ + return CKR_OK; +} + + +/* template_update_attribute() + * + * modifies an existing attribute or adds a new attribute to the template + * + * Returns: TRUE on success, FALSE on failure + */ +CK_RV template_update_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *new_attr) +{ + DL_NODE *node = NULL; + CK_ATTRIBUTE *attr = NULL; + + if (!tmpl || !new_attr) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + 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) { + free(attr); + tmpl->attribute_list = + dlist_remove_node(tmpl->attribute_list, node); + break; + } + + node = node->next; + } + + /* add the new attribute */ + tmpl->attribute_list = dlist_add_as_first(tmpl->attribute_list, new_attr); + + return CKR_OK; +} + + +/* template_validate_attribute() + * + * essentially a group of if-then-else-switch clauses. separated from + * template_validate_attributes() to make that routine more readable + */ +CK_RV template_validate_attribute(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ATTRIBUTE *attr, CK_ULONG class, + CK_ULONG subclass, CK_ULONG mode) +{ + if (class == CKO_DATA) { + return data_object_validate_attribute(tmpl, attr, mode); + } else if (class == CKO_CERTIFICATE) { + if (subclass == CKC_X_509) + return cert_x509_validate_attribute(tmpl, attr, mode); + else + return cert_vendor_validate_attribute(tmpl, attr, mode); + } else if (class == CKO_PUBLIC_KEY) { + switch (subclass) { + case CKK_RSA: + return rsa_publ_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_DSA: + return dsa_publ_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_ECDSA: + return ecdsa_publ_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_DH: + return dh_publ_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_KEA: + return kea_publ_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_IBM_PQC_DILITHIUM: + return ibm_dilithium_publ_validate_attribute(tokdata, tmpl, attr, mode); + default: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; // unknown key type + } + } else if (class == CKO_PRIVATE_KEY) { + switch (subclass) { + case CKK_RSA: + return rsa_priv_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_DSA: + return dsa_priv_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_ECDSA: + return ecdsa_priv_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_DH: + return dh_priv_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_KEA: + return kea_priv_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_IBM_PQC_DILITHIUM: + return ibm_dilithium_priv_validate_attribute(tokdata, tmpl, attr, mode); + default: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; // unknown key type + } + } else if (class == CKO_SECRET_KEY) { + switch (subclass) { + case CKK_GENERIC_SECRET: + return generic_secret_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_RC2: + return rc2_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_RC4: + return rc4_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_RC5: + return rc5_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_DES: + return des_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_DES2: + return des2_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_DES3: + return des3_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_CAST: + return cast_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_CAST3: + return cast3_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_CAST5: + return cast5_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_IDEA: + return idea_validate_attribute(tokdata, tmpl, attr, mode); +#if !(NOCDMF) + case CKK_CDMF: + return cdmf_validate_attribute(tokdata, tmpl, attr, mode); +#endif + case CKK_SKIPJACK: + return skipjack_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_BATON: + return baton_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_JUNIPER: + return juniper_validate_attribute(tokdata, tmpl, attr, mode); + case CKK_AES: + return aes_validate_attribute(tokdata, tmpl, attr, mode); + default: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; // unknown key type + } + } else if (class == CKO_HW_FEATURE) { + if (subclass >= CKH_VENDOR_DEFINED) + return CKR_OK; + switch (subclass) { + case CKH_CLOCK: + return clock_validate_attribute(tmpl, attr, mode); + case CKH_MONOTONIC_COUNTER: + return counter_validate_attribute(tmpl, attr, mode); + default: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + } else if (class == CKO_DOMAIN_PARAMETERS) { + switch (subclass) { + case CKK_DSA: + return dp_dsa_validate_attribute(tmpl, attr, mode); + case CKK_DH: + return dp_dh_validate_attribute(tmpl, attr, mode); + case CKK_X9_42_DH: + return dp_x9dh_validate_attribute(tmpl, attr, mode); + default: + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + } + + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + + return CKR_ATTRIBUTE_VALUE_INVALID; // default fallthru +} + + +/* template_validate_attributes() + * + * walk through the list of attributes in the template validating each one + */ +CK_RV template_validate_attributes(STDLL_TokData_t *tokdata, TEMPLATE *tmpl, + CK_ULONG class, CK_ULONG subclass, + CK_ULONG mode) +{ + DL_NODE *node; + CK_RV rc = CKR_OK; + + node = tmpl->attribute_list; + + while (node) { + CK_ATTRIBUTE *attr = (CK_ATTRIBUTE *) node->data; + + rc = template_validate_attribute(tokdata, tmpl, attr, class, + subclass, mode); + if (rc != CKR_OK) { + TRACE_DEVEL("template_validate_attribute failed.\n"); + return rc; + } + node = node->next; + } + + return CKR_OK; +} + + +/* template_validate_base_attribute() */ +CK_RV template_validate_base_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *attr, + CK_ULONG mode) +{ + if (!tmpl || !attr) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + switch (attr->type) { + case CKA_CLASS: + if ((mode & (MODE_CREATE | MODE_DERIVE | MODE_KEYGEN | MODE_UNWRAP)) != + 0) + return CKR_OK; + break; + case CKA_TOKEN: + if ((mode & (MODE_CREATE | MODE_COPY | MODE_DERIVE | MODE_KEYGEN | + MODE_UNWRAP)) != 0) + return CKR_OK; + break; + case CKA_PRIVATE: + if ((mode & (MODE_CREATE | MODE_COPY | MODE_DERIVE | MODE_KEYGEN | + MODE_UNWRAP)) != 0) + return CKR_OK; + break; + case CKA_ALWAYS_AUTHENTICATE: + if ((mode & (MODE_CREATE | MODE_COPY | MODE_DERIVE | MODE_KEYGEN | + MODE_UNWRAP)) != 0) + return CKR_OK; + break; + case CKA_LABEL: + return CKR_OK; + case CKA_IBM_OPAQUE: + /* Allow this attribute to be modified in order to support + * migratable keys on secure key tokens. + */ + if ((mode & (MODE_COPY | MODE_MODIFY)) != 0) + return CKR_OK; + break; + case CKA_MODIFIABLE: + if ((mode & (MODE_CREATE | MODE_COPY | MODE_DERIVE | MODE_KEYGEN | + MODE_UNWRAP)) != 0) + return CKR_OK; + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + } + + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_READ_ONLY)); + + return CKR_ATTRIBUTE_READ_ONLY; +} diff --git a/usr/lib/common/tok_spec_struct.h b/usr/lib/common/tok_spec_struct.h new file mode 100644 index 0000000..8765c87 --- /dev/null +++ b/usr/lib/common/tok_spec_struct.h @@ -0,0 +1,268 @@ +/* + * 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 + */ + +/*************************************************************************** + Change Log + ========== + 4/25/03 Kapil Sood (kapil@corrent.com) + Added DH key pair generation and DH shared key derivation + functions. + + + +****************************************************************************/ + +#ifndef _TOK_SPECIFIC_STRUCT +#define _TOK_SPECIFIC_STRUCT + + +struct token_specific_struct { + // Used to be in the token_local.h as a #def + char token_directory[PATH_MAX]; + + // Subdirectory + char token_subdir[PATH_MAX]; + + // Set to keysize for secure key tokens + int token_keysize; + + // Information about how token's data should be stored. + struct { + // Use a separate directory for each user + CK_BBOOL per_user; + + // Use data store? + CK_BBOOL use_master_key; + + // Algorithm used to store private data (should be one of the + // CKM_* macros). + CK_MECHANISM_TYPE encryption_algorithm; + + // Default Initialization vectors used for each token. Its size + // depends on the used algorithm. + CK_BYTE *pin_initial_vector; + CK_BYTE *obj_initial_vector; + } data_store; + + // Create lockfile if different from standard way. + int (*t_creatlock) (void); + + // Create or attach to token's shared memory + CK_RV(*t_attach_shm) (STDLL_TokData_t *, CK_SLOT_ID slot_id); + + // Initialization function + CK_RV(*t_init) (STDLL_TokData_t *, CK_SLOT_ID, char *); + + // Token data functions + CK_RV(*t_init_token_data) (STDLL_TokData_t *tokdata, CK_SLOT_ID slot_id); + CK_RV(*t_load_token_data) (STDLL_TokData_t *tokdata, + CK_SLOT_ID slot_id, FILE *fh); + CK_RV(*t_save_token_data) (STDLL_TokData_t *tokdata, + CK_SLOT_ID slot_id, FILE *fh); + + // Random Number Gen + CK_RV(*t_rng) (STDLL_TokData_t *, CK_BYTE *, CK_ULONG); + + // any specific final code + CK_RV(*t_final) (STDLL_TokData_t *, CK_BBOOL); + + CK_RV(*t_init_token) (STDLL_TokData_t *, CK_SLOT_ID, CK_CHAR_PTR, + CK_ULONG, CK_CHAR_PTR); + CK_RV(*t_login) (STDLL_TokData_t *, SESSION *, CK_USER_TYPE, + CK_CHAR_PTR, CK_ULONG); + CK_RV(*t_logout) (STDLL_TokData_t *); + CK_RV(*t_init_pin) (STDLL_TokData_t *, SESSION *, CK_CHAR_PTR, CK_ULONG); + 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_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, + CK_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE *, CK_BYTE); + + CK_RV(*t_tdes_ecb) (STDLL_TokData_t *, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE); + CK_RV(*t_tdes_cbc) (STDLL_TokData_t *, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE *, CK_BYTE); + + CK_RV(*t_tdes_ofb) (STDLL_TokData_t *, CK_BYTE *, CK_BYTE *, CK_ULONG, + OBJECT *, CK_BYTE *, uint_32); + + CK_RV(*t_tdes_cfb) (STDLL_TokData_t *, CK_BYTE *, CK_BYTE *, CK_ULONG, + OBJECT *, CK_BYTE *, uint_32, uint_32); + + CK_RV(*t_tdes_mac) (STDLL_TokData_t *, CK_BYTE *, CK_ULONG, OBJECT *, + CK_BYTE *); + + CK_RV(*t_tdes_cmac) (STDLL_TokData_t *, CK_BYTE *, CK_ULONG, OBJECT *, + CK_BYTE *,CK_BBOOL, CK_BBOOL, CK_VOID_PTR *); + + CK_RV(*t_rsa_decrypt) (STDLL_TokData_t *, CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *); + + CK_RV(*t_rsa_encrypt) (STDLL_TokData_t *, CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *); + + CK_RV(*t_rsa_sign) (STDLL_TokData_t *, SESSION *, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG *, OBJECT *); + CK_RV(*t_rsa_verify) (STDLL_TokData_t *, SESSION *, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG, OBJECT *); + + CK_RV(*t_rsa_verify_recover) (STDLL_TokData_t *, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG *, OBJECT *); + + CK_RV(*t_rsa_x509_decrypt) (STDLL_TokData_t *, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG *, OBJECT *); + + CK_RV(*t_rsa_x509_encrypt) (STDLL_TokData_t *, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG *, OBJECT *); + + CK_RV(*t_rsa_x509_sign) (STDLL_TokData_t *, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG *, OBJECT *); + + CK_RV(*t_rsa_x509_verify) (STDLL_TokData_t *, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG, OBJECT *); + + CK_RV(*t_rsa_x509_verify_recover) (STDLL_TokData_t *, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG *, OBJECT *); + + CK_RV(*t_rsa_oaep_decrypt) (STDLL_TokData_t *, ENCR_DECR_CONTEXT *, + CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, + CK_BYTE *, CK_ULONG); + + CK_RV(*t_rsa_oaep_encrypt) (STDLL_TokData_t *, ENCR_DECR_CONTEXT *, + CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, + CK_BYTE *, CK_ULONG); + + CK_RV(*t_rsa_pss_sign) (STDLL_TokData_t *, SESSION *, + SIGN_VERIFY_CONTEXT *, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG *); + + CK_RV(*t_rsa_pss_verify) (STDLL_TokData_t *, SESSION *, + SIGN_VERIFY_CONTEXT *, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG); + + CK_RV(*t_rsa_generate_keypair) (STDLL_TokData_t *tokdata, TEMPLATE *, + TEMPLATE *); + + CK_RV(*t_ec_sign) (STDLL_TokData_t *tokdata, SESSION *, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG *, OBJECT *); + CK_RV(*t_ec_verify) (STDLL_TokData_t *tokdata, SESSION *, CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG, OBJECT *); + CK_RV(*t_ec_generate_keypair) (STDLL_TokData_t *tokdata, TEMPLATE *, + TEMPLATE *); + + + CK_RV(*t_ecdh_pkcs_derive) (STDLL_TokData_t *tokdata, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, + CK_BYTE *, CK_ULONG); + + /* Begin code contributed by Corrent corp. */ + + // Token Specific DH functions + CK_RV(*t_dh_pkcs_derive) (STDLL_TokData_t *tokdata, CK_BYTE *, + CK_ULONG *, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG); + + CK_RV(*t_dh_pkcs_key_pair_gen) (STDLL_TokData_t *tokdata, TEMPLATE *, + TEMPLATE *); + + /* End code contributed by Corrent corp. */ + + // Token Specific SHA1 functions + CK_RV(*t_sha_init) (STDLL_TokData_t *, DIGEST_CONTEXT *, CK_MECHANISM *); + CK_RV(*t_sha) (STDLL_TokData_t *, DIGEST_CONTEXT *, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG *); + CK_RV(*t_sha_update) (STDLL_TokData_t *, DIGEST_CONTEXT *, CK_BYTE *, + CK_ULONG); + CK_RV(*t_sha_final) (STDLL_TokData_t *, DIGEST_CONTEXT *, CK_BYTE *, + CK_ULONG *); + + // Token Specific HMAC + CK_RV(*t_hmac_sign_init) (STDLL_TokData_t *, SESSION *, CK_MECHANISM *, + CK_OBJECT_HANDLE); + CK_RV(*t_hmac_sign) (STDLL_TokData_t *, SESSION *, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG *); + CK_RV(*t_hmac_sign_update) (STDLL_TokData_t *, SESSION *, CK_BYTE *, + CK_ULONG); + CK_RV(*t_hmac_sign_final) (STDLL_TokData_t *, SESSION *, CK_BYTE *, + CK_ULONG *); + + CK_RV(*t_hmac_verify_init) (STDLL_TokData_t *, SESSION *, + CK_MECHANISM *, CK_OBJECT_HANDLE); + CK_RV(*t_hmac_verify) (STDLL_TokData_t *, SESSION *, CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG); + CK_RV(*t_hmac_verify_update) (STDLL_TokData_t *, SESSION *, CK_BYTE *, + CK_ULONG); + CK_RV(*t_hmac_verify_final) (STDLL_TokData_t *, SESSION *, CK_BYTE *, + CK_ULONG); + + 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_RV(*t_aes_ecb) (STDLL_TokData_t *tokdata, 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_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE *, CK_BYTE); + + CK_RV(*t_aes_ctr) (STDLL_TokData_t *tokdata, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE *, CK_ULONG, + CK_BYTE); + + CK_RV(*t_aes_gcm_init) (STDLL_TokData_t *, SESSION *, + ENCR_DECR_CONTEXT *, CK_MECHANISM *, + CK_OBJECT_HANDLE, CK_BYTE); + + CK_RV(*t_aes_gcm) (STDLL_TokData_t *, SESSION *, ENCR_DECR_CONTEXT *, + CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, CK_BYTE); + + CK_RV(*t_aes_gcm_update) (STDLL_TokData_t *, SESSION *, + ENCR_DECR_CONTEXT *, CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG *, CK_BYTE); + + CK_RV(*t_aes_gcm_final) (STDLL_TokData_t *, SESSION *, + ENCR_DECR_CONTEXT *, CK_BYTE *, + CK_ULONG *, CK_BYTE); + + CK_RV(*t_aes_ofb) (STDLL_TokData_t *, CK_BYTE *, CK_ULONG, CK_BYTE *, + OBJECT *, CK_BYTE *, uint_32); + + CK_RV(*t_aes_cfb) (STDLL_TokData_t *, CK_BYTE *, CK_ULONG, CK_BYTE *, + OBJECT *, CK_BYTE *, uint_32, uint_32); + + CK_RV(*t_aes_mac) (STDLL_TokData_t *, CK_BYTE *, CK_ULONG, OBJECT *, + CK_BYTE *); + + CK_RV(*t_aes_cmac) (STDLL_TokData_t *, CK_BYTE *, CK_ULONG, OBJECT *, + CK_BYTE *, CK_BBOOL, CK_BBOOL, CK_VOID_PTR *); + + // Token Specific DSA functions + CK_RV(*t_dsa_generate_keypair) (STDLL_TokData_t *, TEMPLATE *, TEMPLATE *); + + CK_RV(*t_dsa_sign) (STDLL_TokData_t *, CK_BYTE *, CK_BYTE *, OBJECT *); + + CK_RV(*t_dsa_verify) (STDLL_TokData_t *, CK_BYTE *, CK_BYTE *, OBJECT *); + + CK_RV(*t_get_mechanism_list) (STDLL_TokData_t *, CK_MECHANISM_TYPE_PTR, + CK_ULONG_PTR); + CK_RV(*t_get_mechanism_info) (STDLL_TokData_t *, CK_MECHANISM_TYPE, + CK_MECHANISM_INFO_PTR); + + CK_RV(*t_object_add) (STDLL_TokData_t *, SESSION *, OBJECT *); + +}; + +typedef struct token_specific_struct token_spec_t; + +#endif diff --git a/usr/lib/common/tok_specific.h b/usr/lib/common/tok_specific.h new file mode 100644 index 0000000..19f6b47 --- /dev/null +++ b/usr/lib/common/tok_specific.h @@ -0,0 +1,308 @@ +/* + * 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 + */ + +/*************************************************************************** + Change Log + ========== + 4/25/03 Kapil Sood (kapil@corrent.com) + Added DH key pair generation and DH shared key derivation + functions. + + + +****************************************************************************/ + +// Token specific functions that tokens must implement..... +// +// Prototypes + + +#ifndef _TOK_SPECIFIC +#define _TOK_SPECIFIC + +int token_specific_creatlock(void); +CK_RV token_specific_attach_shm(STDLL_TokData_t *, CK_ULONG); +CK_RV token_specific_rng(STDLL_TokData_t *, CK_BYTE *, CK_ULONG); +CK_RV token_specific_init(STDLL_TokData_t *, CK_SLOT_ID, char *); + +CK_RV token_specific_init_token_data(STDLL_TokData_t *, CK_SLOT_ID slot_id); +CK_RV token_specific_load_token_data(STDLL_TokData_t *, CK_SLOT_ID slot_id, + FILE *fh); +CK_RV token_specific_save_token_data(STDLL_TokData_t *, CK_SLOT_ID slot_id, + FILE *fh); + +CK_RV token_specific_final(STDLL_TokData_t *, CK_BBOOL); +CK_RV token_specific_init_token(STDLL_TokData_t *, CK_SLOT_ID, CK_CHAR_PTR, + CK_ULONG, CK_CHAR_PTR); +CK_RV token_specific_login(STDLL_TokData_t *, SESSION *, CK_USER_TYPE, + CK_CHAR_PTR, CK_ULONG); +CK_RV token_specific_logout(STDLL_TokData_t *); +CK_RV token_specific_init_pin(STDLL_TokData_t *, SESSION *, CK_CHAR_PTR, + CK_ULONG); +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_RV token_specific_des_ecb(STDLL_TokData_t *, + CK_BYTE *, + CK_ULONG, + CK_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE); + +CK_RV token_specific_des_cbc(STDLL_TokData_t *, + CK_BYTE *, + CK_ULONG, + CK_BYTE *, + CK_ULONG *, OBJECT *, CK_BYTE *, CK_BYTE); + +CK_RV token_specific_tdes_ecb(STDLL_TokData_t *, + CK_BYTE *, + CK_ULONG, + CK_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE); + +CK_RV token_specific_tdes_cbc(STDLL_TokData_t *, + CK_BYTE *, + CK_ULONG, + CK_BYTE *, + CK_ULONG *, OBJECT *, CK_BYTE *, CK_BYTE); + +CK_RV token_specific_tdes_mac(STDLL_TokData_t *, + CK_BYTE *, CK_ULONG, OBJECT *, CK_BYTE *); + +CK_RV token_specific_tdes_cmac(STDLL_TokData_t *, + CK_BYTE *, CK_ULONG, OBJECT *, CK_BYTE *, + CK_BBOOL, CK_BBOOL, CK_VOID_PTR *); + +CK_RV token_specific_tdes_ofb(STDLL_TokData_t *, + CK_BYTE *, + CK_BYTE *, + CK_ULONG, OBJECT *, CK_BYTE *, uint_32); + +CK_RV token_specific_tdes_cfb(STDLL_TokData_t *, + CK_BYTE *, + CK_BYTE *, + CK_ULONG, OBJECT *, CK_BYTE *, uint_32, uint_32); + +CK_RV token_specific_rsa_decrypt(STDLL_TokData_t *, + CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *); + +CK_RV token_specific_rsa_encrypt(STDLL_TokData_t *, + CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *); + +CK_RV token_specific_rsa_generate_keypair(STDLL_TokData_t *tokdata, TEMPLATE *, + TEMPLATE *); + +CK_RV token_specific_rsa_sign(STDLL_TokData_t *, SESSION *, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG *, OBJECT *); + +CK_RV token_specific_rsa_verify(STDLL_TokData_t *tokdata, SESSION *, CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG, OBJECT *); + +CK_RV token_specific_rsa_verify_recover(STDLL_TokData_t *tokdata, CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG *, + OBJECT *); + +CK_RV token_specific_rsa_x509_encrypt(STDLL_TokData_t *tokdata, CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG *, + OBJECT *); + +CK_RV token_specific_rsa_x509_decrypt(STDLL_TokData_t *tokdata, CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG *, + OBJECT *); + +CK_RV token_specific_rsa_x509_sign(STDLL_TokData_t *tokdata, CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *); + +CK_RV token_specific_rsa_x509_verify(STDLL_TokData_t *tokdata, CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG, OBJECT *); + +CK_RV token_specific_rsa_x509_verify_recover(STDLL_TokData_t *tokdata, + CK_BYTE *, CK_ULONG, CK_BYTE *, + CK_ULONG *, OBJECT *); + +CK_RV token_specific_rsa_oaep_encrypt(STDLL_TokData_t *, ENCR_DECR_CONTEXT *, + CK_BYTE *, CK_ULONG, CK_BYTE *, + CK_ULONG *, CK_BYTE *, CK_ULONG); + +CK_RV token_specific_rsa_oaep_decrypt(STDLL_TokData_t *, ENCR_DECR_CONTEXT *, + CK_BYTE *, CK_ULONG, CK_BYTE *, + CK_ULONG *, CK_BYTE *, CK_ULONG); + +CK_RV token_specific_rsa_pss_sign(STDLL_TokData_t *, SESSION *, + SIGN_VERIFY_CONTEXT *, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG *); + +CK_RV token_specific_rsa_pss_verify(STDLL_TokData_t *, SESSION *, + SIGN_VERIFY_CONTEXT *, CK_BYTE *, CK_ULONG, + CK_BYTE *, CK_ULONG); + +CK_RV token_specific_ec_sign(STDLL_TokData_t *, + SESSION *, + CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG *, OBJECT *); + +CK_RV token_specific_ec_verify(STDLL_TokData_t *, + SESSION *, + CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG, OBJECT *); + +CK_RV token_specific_ecdh_pkcs_derive(STDLL_TokData_t *tokdata, CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, + CK_ULONG *, CK_BYTE *, CK_ULONG); + +CK_RV token_specific_copy_object(SESSION *, CK_ATTRIBUTE_PTR, CK_ULONG, + CK_OBJECT_HANDLE, CK_OBJECT_HANDLE_PTR); + +CK_RV token_specific_ec_generate_keypair(STDLL_TokData_t *, TEMPLATE *, + TEMPLATE *); + +CK_RV token_specific_create_object(SESSION *, CK_ATTRIBUTE_PTR, CK_ULONG, + CK_OBJECT_HANDLE_PTR); + +CK_RV token_specific_generate_key(SESSION *, CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, + CK_ULONG, CK_OBJECT_HANDLE_PTR); + +CK_RV token_specific_generate_key_pair(SESSION *, CK_MECHANISM_PTR, + CK_ATTRIBUTE_PTR, CK_ULONG, + CK_ATTRIBUTE_PTR, CK_ULONG, + CK_OBJECT_HANDLE_PTR, + CK_OBJECT_HANDLE_PTR); + + +/* Begin code contributed by Corrent corp. */ +#ifndef NODH +CK_RV token_specific_dh_pkcs_derive(STDLL_TokData_t *tokdata, CK_BYTE *, + CK_ULONG *, CK_BYTE *, CK_ULONG, CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG); + +CK_RV token_specific_dh_pkcs_key_pair_gen(STDLL_TokData_t *tokdata, + TEMPLATE *publ_tmpl, + TEMPLATE *priv_tmpl); +#endif +/* End code contributed by Corrent corp. */ +CK_RV tok_cdmv_transform(CK_VOID_PTR, CK_ULONG); + + +CK_RV token_specific_sha_init(STDLL_TokData_t *, DIGEST_CONTEXT *, + CK_MECHANISM *); + +CK_RV token_specific_sha(STDLL_TokData_t *, DIGEST_CONTEXT *, CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG *); + +CK_RV token_specific_sha_update(STDLL_TokData_t *, DIGEST_CONTEXT *, CK_BYTE *, + CK_ULONG); + +CK_RV token_specific_sha_final(STDLL_TokData_t *, DIGEST_CONTEXT *, CK_BYTE *, + CK_ULONG *); + +CK_RV token_specific_hmac_sign_init(STDLL_TokData_t *, SESSION *, + CK_MECHANISM *, CK_OBJECT_HANDLE); + +CK_RV token_specific_hmac_sign(STDLL_TokData_t *, SESSION *, CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG *); + +CK_RV token_specific_hmac_sign_update(STDLL_TokData_t *, SESSION *, CK_BYTE *, + CK_ULONG); + +CK_RV token_specific_hmac_sign_final(STDLL_TokData_t *, SESSION *, CK_BYTE *, + CK_ULONG *); + +CK_RV token_specific_hmac_verify_init(STDLL_TokData_t *, SESSION *, + CK_MECHANISM *, CK_OBJECT_HANDLE); + +CK_RV token_specific_hmac_verify(STDLL_TokData_t *, SESSION *, CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG); + +CK_RV token_specific_hmac_verify_update(STDLL_TokData_t *, SESSION *, + CK_BYTE *, CK_ULONG); + +CK_RV token_specific_hmac_verify_final(STDLL_TokData_t *, SESSION *, + CK_BYTE *, CK_ULONG); + +CK_RV token_specific_generic_secret_key_gen(STDLL_TokData_t *, + TEMPLATE *template); + +#ifndef NOAES +CK_RV token_specific_aes_key_gen(STDLL_TokData_t *, + CK_BYTE *, CK_ULONG, CK_ULONG); + +CK_RV token_specific_aes_ecb(STDLL_TokData_t *, + CK_BYTE *, + CK_ULONG, + CK_BYTE *, CK_ULONG *, OBJECT *, CK_BYTE); + +CK_RV token_specific_aes_cbc(STDLL_TokData_t *, + CK_BYTE *, + CK_ULONG, + CK_BYTE *, + CK_ULONG *, OBJECT *, CK_BYTE *, CK_BYTE); + +CK_RV token_specific_aes_ctr(STDLL_TokData_t *, + CK_BYTE *, + CK_ULONG, + CK_BYTE *, + CK_ULONG *, + OBJECT *, CK_BYTE *, CK_ULONG, CK_BYTE); + +CK_RV token_specific_aes_gcm_init(STDLL_TokData_t *, SESSION *, + ENCR_DECR_CONTEXT *, CK_MECHANISM *, + CK_OBJECT_HANDLE, CK_BYTE); + +CK_RV token_specific_aes_gcm(STDLL_TokData_t *, SESSION *, ENCR_DECR_CONTEXT *, + CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, + CK_BYTE); + +CK_RV token_specific_aes_gcm_update(STDLL_TokData_t *, SESSION *, + ENCR_DECR_CONTEXT *, CK_BYTE *, + CK_ULONG, CK_BYTE *, CK_ULONG *, CK_BYTE); + +CK_RV token_specific_aes_gcm_final(STDLL_TokData_t *, SESSION *, + ENCR_DECR_CONTEXT *, CK_BYTE *, + CK_ULONG *, CK_BYTE); + +CK_RV token_specific_aes_ofb(STDLL_TokData_t *, + CK_BYTE *, + CK_ULONG, CK_BYTE *, OBJECT *, CK_BYTE *, uint_32); + +CK_RV token_specific_aes_cfb(STDLL_TokData_t *, + CK_BYTE *, + CK_ULONG, + CK_BYTE *, OBJECT *, CK_BYTE *, uint_32, uint_32); + +CK_RV token_specific_aes_mac(STDLL_TokData_t *, + CK_BYTE *, CK_ULONG, OBJECT *, CK_BYTE *); + +CK_RV token_specific_aes_cmac(STDLL_TokData_t *, + CK_BYTE *, CK_ULONG, OBJECT *, CK_BYTE *, + CK_BBOOL, CK_BBOOL, CK_VOID_PTR *); + +#endif + +CK_RV token_specific_dsa_generate_keypair(STDLL_TokData_t *, + TEMPLATE *, TEMPLATE *); +CK_RV token_specific_dsa_sign(STDLL_TokData_t *, CK_BYTE *, CK_ULONG, CK_ULONG); + +CK_RV token_specific_dsa_verify(STDLL_TokData_t *, + CK_BYTE *, CK_BYTE *, OBJECT *); + +CK_RV token_specific_get_mechanism_list(STDLL_TokData_t *, + CK_MECHANISM_TYPE_PTR pMechanismList, + CK_ULONG_PTR pulCount); + +CK_RV token_specific_get_mechanism_info(STDLL_TokData_t *, + CK_MECHANISM_TYPE type, + CK_MECHANISM_INFO_PTR pInfo); + +CK_RV token_specific_object_add(STDLL_TokData_t *, SESSION *, OBJECT *); + +#endif diff --git a/usr/lib/common/trace.c b/usr/lib/common/trace.c new file mode 100644 index 0000000..f470548 --- /dev/null +++ b/usr/lib/common/trace.c @@ -0,0 +1,297 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2015-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 + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "trace.h" +#include "ock_syslog.h" + +#ifdef SYS_gettid +#define __gettid() syscall(SYS_gettid) +#endif + +pthread_mutex_t tlmtx = PTHREAD_MUTEX_INITIALIZER; +struct trace_handle_t trace; + +static const char *ock_err_msg[] = { + "Malloc Failed", /*ERR_HOST_MEMORY */ + "Slot Invalid", /*ERR_SLOT_ID_INVALID */ + "General Error", /*ERR_GENERAL_ERROR */ + "Function Failed", /*ERR_FUNCTION_FAILED */ + "Bad Arguments", /*ERR_ARGUMENTS_BAD */ + "No Event", /*ERR_NO_EVENT */ + "Attribute Read Only", /*ERR_ATTRIBUTE_READ_ONLY */ + "Attribute Sensitive", /*ERR_ATTRIBUTE_SENSITIVE */ + "Attribute Type Invalid", /*ERR_ATTRIBUTE_TYPE_INVALID */ + "Attribute Value Invalid", /*ERR_ATTRIBUTE_VALUE_INVALID */ + "Data Invalid", /*ERR_DATA_INVALID */ + "Data Length out of Range", /*ERR_DATA_LEN_RANGE */ + "Device Error", /*ERR_DEVICE_ERROR */ + "Device does not have Sufficient Memory", /*ERR_DEVICE_MEMORY */ + "Device Removed", /*ERR_DEVICE_REMOVED */ + "Encrypted Data Invalid", /*ERR_ENCRYPTED_DATA_INVALID */ + "Encrypted Data Length out of Range", /*ERR_ENCRYPTED_DATA_LEN_RANGE */ + "Function Cancelled", /*ERR_FUNCTION_CANCELED */ + "Function Not Parallel", /*ERR_FUNCTION_NOT_PARALLEL */ + "Function Not Supported", /*ERR_FUNCTION_NOT_SUPPORTED */ + "Key Changed", /*ERR_KEY_CHANGED */ + "Key Function Not Permitted", /*ERR_KEY_FUNCTION_NOT_PERMITTED */ + "Key Handle Invalid", /*ERR_KEY_HANDLE_INVALID */ + "Key Indigestible", /*ERR_KEY_INDIGESTIBLE */ + "Key Needed", /*ERR_KEY_NEEDED */ + "Key Not Needed", /*ERR_KEY_NOT_NEEDED */ + "Key Not Wrappable", /*ERR_KEY_NOT_WRAPPABLE */ + "Key Size out of Range", /*ERR_KEY_SIZE_RANGE */ + "Key Type Inconsistent", /*ERR_KEY_TYPE_INCONSISTENT */ + "Key Unextractable", /*ERR_KEY_UNEXTRACTABLE */ + "Mechanism Invalid", /*ERR_MECHANISM_INVALID */ + "Mechanism Param Invalid", /*ERR_MECHANISM_PARAM_INVALID */ + "Object Handle Invalid", /*ERR_OBJECT_HANDLE_INVALID */ + "Operation Active", /*ERR_OPERATION_ACTIVE */ + "Operation Not Initialized", /*ERR_OPERATION_NOT_INITIALIZED */ + "Pin Incorrect", /*ERR_PIN_INCORRECT */ + "Pin Invalid", /*ERR_PIN_INVALID */ + "Pin Length out of Range", /*ERR_PIN_LEN_RANGE */ + "Pin Expired", /*ERR_PIN_EXPIRED */ + "Pin Locked", /*ERR_PIN_LOCKED */ + "Session Closed", /*ERR_SESSION_CLOSED */ + "Session Count", /*ERR_SESSION_COUNT */ + "Session Handle Invalid", /*ERR_SESSION_HANDLE_INVALID */ + "Parallel Session Not Supported", /*ERR_SESSION_PARALLEL_NOT_SUPPORTED */ + "Session Read Only", /*ERR_SESSION_READ_ONLY */ + "Session Exists", /*ERR_SESSION_EXISTS */ + "Session Read only Exists", /*ERR_SESSION_READ_ONLY_EXISTS */ + "Session Read Write Exists", /*ERR_SESSION_READ_WRITE_SO_EXISTS */ + "Signature Invalid", /*ERR_SIGNATURE_INVALID */ + "Signature Length out of Range", /*ERR_SIGNATURE_LEN_RANGE */ + "Template Incomplete", /*ERR_TEMPLATE_INCOMPLETE */ + "Template Inconsistent", /*ERR_TEMPLATE_INCONSISTENT */ + "Token Not Present", /*ERR_TOKEN_NOT_PRESENT */ + "Token Not Recognized", /*ERR_TOKEN_NOT_RECOGNIZED */ + "Token Write Protected", /*ERR_TOKEN_WRITE_PROTECTED */ + "Unwrapping Key Handle Invalid", /*ERR_UNWRAPPING_KEY_HANDLE_INVALID */ + "Unwrapping Key Size Range Invalid", /*ERR_UNWRAPPING_KEY_SIZE_RANGE */ + "Unwrapping Key Type Inconsistent", /*ERR_UNWRAPPING_KEY_TYPE_INCONSISTENT */ + "User Already Logged In", /*ERR_USER_ALREADY_LOGGED_IN */ + "User Not Logged In", /*ERR_USER_NOT_LOGGED_IN */ + "User PIN Not Initialized", /*ERR_USER_PIN_NOT_INITIALIZED */ + "User Type Invalid", /*ERR_USER_TYPE_INVALID */ + "Another User Already Logged In", /*ERR_USER_ANOTHER_ALREADY_LOGGED_IN */ + "Too Many User Types", /*ERR_USER_TOO_MANY_TYPES */ + "Wrapped Key Invalid", /*ERR_WRAPPED_KEY_INVALID */ + "Wrapped Key Length Invalid", /*ERR_WRAPPED_KEY_LEN_RANGE */ + "Wrapping Key Handle Invalid", /*ERR_WRAPPING_KEY_HANDLE_INVALID */ + "Wrapping Key Size out of Range", /*ERR_WRAPPING_KEY_SIZE_RANGE */ + "Wrapping Key Type Inconsistent", /*ERR_WRAPPING_KEY_TYPE_INCONSISTENT */ + "Random Seed Not Supported", /*ERR_RANDOM_SEED_NOT_SUPPORTED */ + "Domain Parameter Invalid", /*ERR_DOMAIN_PARAMS_INVALID */ + "Buffer Too Small", /*ERR_BUFFER_TOO_SMALL */ + "Saved State Invalid", /*ERR_SAVED_STATE_INVALID */ + "Information Sensitive", /*ERR_INFORMATION_SENSITIVE */ + "State Unsaveable", /*ERR_STATE_UNSAVEABLE */ + "API not initialized", /*ERR_CRYPTOKI_NOT_INITIALIZED */ + "API already Initialized", /*ERR_CRYPTOKI_ALREADY_INITIALIZED */ + "Mutex Invalid", /*ERR_MUTEX_BAD */ + "Mutex was not locked", /*ERR_MUTEX_NOT_LOCKED */ + "Unknown error", /*ERR_MAX */ +}; + +void set_trace(struct trace_handle_t t_handle) +{ + trace.fd = t_handle.fd; + trace.level = t_handle.level; +} + +void trace_finalize(void) +{ + if (trace.fd) + close(trace.fd); + trace.fd = -1; + trace.level = TRACE_LEVEL_NONE; +} + +CK_RV trace_initialize(void) +{ + char *opt = NULL; + char *end; + long int num; + struct group *grp; + char tracefile[PATH_MAX]; + + /* initialize the trace values */ + trace.level = TRACE_LEVEL_NONE; + trace.fd = -1; + + opt = getenv("OPENCRYPTOKI_TRACE_LEVEL"); + if (!opt) + return (CKR_FUNCTION_FAILED); + + num = strtol(opt, &end, 10); + if (*end) { + OCK_SYSLOG(LOG_WARNING, "OPENCRYPTOKI_TRACE_LEVEL '%s' is " + "invalid. Tracing disabled.", opt); + return (CKR_FUNCTION_FAILED); + } + + switch (num) { + case TRACE_LEVEL_NONE: + return CKR_OK; + case TRACE_LEVEL_ERROR: + case TRACE_LEVEL_WARNING: + case TRACE_LEVEL_INFO: + case TRACE_LEVEL_DEVEL: +#ifdef DEBUG + case TRACE_LEVEL_DEBUG: +#endif + trace.level = num; + break; + default: + OCK_SYSLOG(LOG_WARNING, "Trace level %ld is out of range. " + "Tracing disabled.", num); + return (CKR_FUNCTION_FAILED); + } + + grp = getgrnam("pkcs11"); + if (grp == NULL) { + OCK_SYSLOG(LOG_ERR, "getgrnam(pkcs11) failed: %s." + "Tracing is disabled.\n", strerror(errno)); + goto error; + } + + /* open trace file */ + snprintf(tracefile, sizeof(tracefile), "/%s/%s.%d", OCK_LOGDIR, + "trace", getpid()); + + trace.fd = open(tracefile, O_RDWR | O_APPEND | O_CREAT, + S_IRUSR | S_IWUSR | S_IRGRP); + + if (trace.fd < 0) { + OCK_SYSLOG(LOG_WARNING, + "open(%s) failed: %s. Tracing disabled.\n", + tracefile, strerror(errno)); + goto error; + } + + /* 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)); + goto error; + } + + return (CKR_OK); + +error: + trace.level = TRACE_LEVEL_NONE; + trace.fd = -1; + + return (CKR_FUNCTION_FAILED); +} + +void ock_traceit(trace_level_t level, const char *file, int line, + const char *stdll_name, const char *fmt, ...) +{ + va_list ap; + time_t t; + struct tm *tm; + const char *fmt_pre; + char buf[1024]; + char *pbuf; + int buflen, len; +#ifdef __gettid + pid_t tid; +#endif + + if (trace.fd < 0) + return; + + if (level > trace.level) + return; + + pbuf = buf; + buflen = sizeof(buf); + + /* add the current time */ + t = time(0); + tm = localtime(&t); + len = strftime(pbuf, buflen, "%m/%d/%Y %H:%M:%S ", tm); + pbuf += len; + buflen -= len; + +#ifdef __gettid + /* add thread id */ + tid = __gettid(); + len = snprintf(pbuf, buflen, "%u ", (unsigned int) tid); + pbuf += len; + buflen -= len; +#endif + + /* add file line and stdll name */ + switch (level) { + case TRACE_LEVEL_ERROR: + fmt_pre = "[%s:%d %s] ERROR: "; + break; + case TRACE_LEVEL_WARNING: + fmt_pre = "[%s:%d %s] WARN: "; + break; + case TRACE_LEVEL_INFO: + fmt_pre = "[%s:%d %s] INFO: "; + break; + case TRACE_LEVEL_DEVEL: + fmt_pre = "[%s:%d %s] DEVEL: "; + break; + case TRACE_LEVEL_DEBUG: + fmt_pre = "[%s:%d %s] DEBUG: "; + break; + default: /* cannot happen */ + fmt_pre = "[%s:%d %s] ERROR: "; + break; + } + snprintf(pbuf, buflen, fmt_pre, file, line, stdll_name); + + /* add the format */ + len = strlen(buf); + pbuf = buf + len; + buflen = sizeof(buf) - len; + va_start(ap, fmt); + vsnprintf(pbuf, buflen, fmt, ap); + va_end(ap); + + /* serialize appends to the file */ + pthread_mutex_lock(&tlmtx); + if (write(trace.fd, buf, strlen(buf)) == -1) + fprintf(stderr, "cannot write to trace file\n"); + pthread_mutex_unlock(&tlmtx); +} + +const char *ock_err(int num) +{ + if (num < 0 || num > ERR_MAX) + num = ERR_MAX; + + return ock_err_msg[num]; +} diff --git a/usr/lib/common/trace.h b/usr/lib/common/trace.h new file mode 100644 index 0000000..ec3a549 --- /dev/null +++ b/usr/lib/common/trace.h @@ -0,0 +1,154 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2015-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 + */ + +#ifndef _TRACE_H +#define _TRACE_H + +#include "defs.h" +#include "host_defs.h" + +/* pkcs11 error messages */ + +enum errmsg { + ERR_HOST_MEMORY = 0, + ERR_SLOT_ID_INVALID, + ERR_GENERAL_ERROR, + ERR_FUNCTION_FAILED, + ERR_ARGUMENTS_BAD, + ERR_NO_EVENT, + ERR_ATTRIBUTE_READ_ONLY, + ERR_ATTRIBUTE_SENSITIVE, + ERR_ATTRIBUTE_TYPE_INVALID, + ERR_ATTRIBUTE_VALUE_INVALID, + ERR_DATA_INVALID, + ERR_DATA_LEN_RANGE, + ERR_DEVICE_ERROR, + ERR_DEVICE_MEMORY, + ERR_DEVICE_REMOVED, + ERR_ENCRYPTED_DATA_INVALID, + ERR_ENCRYPTED_DATA_LEN_RANGE, + ERR_FUNCTION_CANCELED, + ERR_FUNCTION_NOT_PARALLEL, + ERR_FUNCTION_NOT_SUPPORTED, + ERR_KEY_CHANGED, + ERR_KEY_FUNCTION_NOT_PERMITTED, + ERR_KEY_HANDLE_INVALID, + ERR_KEY_INDIGESTIBLE, + ERR_KEY_NEEDED, + ERR_KEY_NOT_NEEDED, + ERR_KEY_NOT_WRAPPABLE, + ERR_KEY_SIZE_RANGE, + ERR_KEY_TYPE_INCONSISTENT, + ERR_KEY_UNEXTRACTABLE, + ERR_MECHANISM_INVALID, + ERR_MECHANISM_PARAM_INVALID, + ERR_OBJECT_HANDLE_INVALID, + ERR_OPERATION_ACTIVE, + ERR_OPERATION_NOT_INITIALIZED, + ERR_PIN_INCORRECT, + ERR_PIN_INVALID, + ERR_PIN_LEN_RANGE, + ERR_PIN_EXPIRED, + ERR_PIN_LOCKED, + ERR_SESSION_CLOSED, + ERR_SESSION_COUNT, + ERR_SESSION_HANDLE_INVALID, + ERR_SESSION_PARALLEL_NOT_SUPPORTED, + ERR_SESSION_READ_ONLY, + ERR_SESSION_EXISTS, + ERR_SESSION_READ_ONLY_EXISTS, + ERR_SESSION_READ_WRITE_SO_EXISTS, + ERR_SIGNATURE_INVALID, + ERR_SIGNATURE_LEN_RANGE, + ERR_TEMPLATE_INCOMPLETE, + ERR_TEMPLATE_INCONSISTENT, + ERR_TOKEN_NOT_PRESENT, + ERR_TOKEN_NOT_RECOGNIZED, + ERR_TOKEN_WRITE_PROTECTED, + ERR_UNWRAPPING_KEY_HANDLE_INVALID, + ERR_UNWRAPPING_KEY_SIZE_RANGE, + ERR_UNWRAPPING_KEY_TYPE_INCONSISTENT, + ERR_USER_ALREADY_LOGGED_IN, + ERR_USER_NOT_LOGGED_IN, + ERR_USER_PIN_NOT_INITIALIZED, + ERR_USER_TYPE_INVALID, + ERR_USER_ANOTHER_ALREADY_LOGGED_IN, + ERR_USER_TOO_MANY_TYPES, + ERR_WRAPPED_KEY_INVALID, + ERR_WRAPPED_KEY_LEN_RANGE, + ERR_WRAPPING_KEY_HANDLE_INVALID, + ERR_WRAPPING_KEY_SIZE_RANGE, + ERR_WRAPPING_KEY_TYPE_INCONSISTENT, + ERR_RANDOM_SEED_NOT_SUPPORTED, + ERR_DOMAIN_PARAMS_INVALID, + ERR_BUFFER_TOO_SMALL, + ERR_SAVED_STATE_INVALID, + ERR_INFORMATION_SENSITIVE, + ERR_STATE_UNSAVEABLE, + ERR_CRYPTOKI_NOT_INITIALIZED, + ERR_CRYPTOKI_ALREADY_INITIALIZED, + ERR_MUTEX_BAD, + ERR_MUTEX_NOT_LOCKED, + ERR_MAX, +}; + +/* Log levels */ +typedef enum { + TRACE_LEVEL_NONE = 0, + TRACE_LEVEL_ERROR, + TRACE_LEVEL_WARNING, + TRACE_LEVEL_INFO, + TRACE_LEVEL_DEVEL, + TRACE_LEVEL_DEBUG +} trace_level_t; + + +/* Encapsulate all trace variables */ +struct trace_handle_t { + int fd; /* file descriptor for filename */ + trace_level_t level; /* trace level */ +}; + +extern struct trace_handle_t trace; + +void set_trace(struct trace_handle_t t); +CK_RV trace_initialize(); +void trace_finalize(); +void ock_traceit(trace_level_t level, const char *file, int line, + const char *stdll_name, const char *fmt, ...) + __attribute__ ((format(printf, 5, 6))); +const char *ock_err(int num); + + +#define TRACE_ERROR(...) \ + ock_traceit(TRACE_LEVEL_ERROR, __FILE__, __LINE__, STDLL_NAME, __VA_ARGS__) + +#define TRACE_WARNING(...) \ + ock_traceit(TRACE_LEVEL_WARNING, __FILE__, __LINE__, STDLL_NAME, \ + __VA_ARGS__) + +#define TRACE_INFO(...) \ + ock_traceit(TRACE_LEVEL_INFO, __FILE__, __LINE__, STDLL_NAME, __VA_ARGS__) + +#define TRACE_DEVEL(...) \ + ock_traceit(TRACE_LEVEL_DEVEL, __FILE__, __LINE__, STDLL_NAME, __VA_ARGS__) + +#ifdef DEBUG +#define TRACE_DEBUG(...) \ + ock_traceit(TRACE_LEVEL_DEBUG, __FILE__, __LINE__, STDLL_NAME, __VA_ARGS__) + +void dump_shm(LW_SHM_TYPE *, const char *); +#define DUMP_SHM(x,y) dump_shm(x,y) +#else +#define TRACE_DEBUG(...) +#define DUMP_SHM(x,y) +#endif + +#endif diff --git a/usr/lib/common/utility.c b/usr/lib/common/utility.c new file mode 100644 index 0000000..cbc0023 --- /dev/null +++ b/usr/lib/common/utility.c @@ -0,0 +1,1137 @@ +/* + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "pkcs32.h" +#include "shared_memory.h" +#include "trace.h" +#include "ock_syslog.h" + +#include +#include + +// Function: dlist_add_as_first() +// +// Adds the specified node to the start of the list +// +// Returns: pointer to the start of the list +// +DL_NODE *dlist_add_as_first(DL_NODE *list, void *data) +{ + DL_NODE *node = NULL; + + if (!data) + return list; + + node = (DL_NODE *) malloc(sizeof(DL_NODE)); + if (!node) + return NULL; + + node->data = data; + node->prev = NULL; + node->next = list; + if (list) + list->prev = node; + + return node; +} + +// Function: dlist_add_as_last() +// +// Adds the specified node to the end of the list +// +// Returns: pointer to the start of the list +// +DL_NODE *dlist_add_as_last(DL_NODE *list, void *data) +{ + DL_NODE *node = NULL; + + if (!data) + return list; + + node = (DL_NODE *) malloc(sizeof(DL_NODE)); + if (!node) + return NULL; + + node->data = data; + node->next = NULL; + + if (!list) { + node->prev = NULL; + return node; + } else { + DL_NODE *temp = dlist_get_last(list); + temp->next = node; + node->prev = temp; + + return list; + } +} + +// Function: dlist_find() +// +DL_NODE *dlist_find(DL_NODE *list, void *data) +{ + DL_NODE *node = list; + + while (node && node->data != data) + node = node->next; + + return node; +} + +// Function: dlist_get_first() +// +// Returns the last node in the list or NULL if list is empty +// +DL_NODE *dlist_get_first(DL_NODE *list) +{ + DL_NODE *temp = list; + + if (!list) + return NULL; + + while (temp->prev != NULL) + temp = temp->prev; + + return temp; +} + +// Function: dlist_get_last() +// +// Returns the last node in the list or NULL if list is empty +// +DL_NODE *dlist_get_last(DL_NODE *list) +{ + DL_NODE *temp = list; + + if (!list) + return NULL; + + while (temp->next != NULL) + temp = temp->next; + + return temp; +} + +// +// +CK_ULONG dlist_length(DL_NODE *list) +{ + DL_NODE *temp = list; + CK_ULONG len = 0; + + while (temp) { + len++; + temp = temp->next; + } + + return len; +} + +// +// +DL_NODE *dlist_next(DL_NODE *node) +{ + if (!node) + return NULL; + + return node->next; +} + +// +// +DL_NODE *dlist_prev(DL_NODE *node) +{ + if (!node) + return NULL; + + return node->prev; +} + +// +// +void dlist_purge(DL_NODE *list) +{ + DL_NODE *node; + + if (!list) + return; + + do { + node = list->next; + free(list); + list = node; + } while (list); +} + +// Function: dlist_remove_node() +// +// Attempts to remove the specified node from the list. The caller is +// responsible for freeing the data associated with the node prior to +// calling this routine +// +DL_NODE *dlist_remove_node(DL_NODE *list, DL_NODE *node) +{ + DL_NODE *temp = list; + + if (!list || !node) + return NULL; + + // special case: removing head of the list + // + if (list == node) { + temp = list->next; + if (temp) + temp->prev = NULL; + + free(list); + return temp; + } + // we have no guarantee that the node is in the list + // so search through the list to find it + // + while ((temp != NULL) && (temp->next != node)) + temp = temp->next; + + if (temp != NULL) { + DL_NODE *next = node->next; + + temp->next = next; + if (next) + next->prev = temp; + + free(node); + } + + return list; +} + +CK_RV CreateXProcLock(char *tokname, STDLL_TokData_t *tokdata) +{ + char lockfile[2 * PATH_MAX + sizeof(LOCKDIR_PATH) + 6]; + char lockdir[PATH_MAX + sizeof(LOCKDIR_PATH)]; + struct group *grp; + struct stat statbuf; + mode_t mode = (S_IRUSR | S_IRGRP); + int ret = -1; + + if (tokdata->spinxplfd == -1) { + + if (token_specific.t_creatlock != NULL) { + tokdata->spinxplfd = token_specific.t_creatlock(); + if (tokdata->spinxplfd != -1) + return CKR_OK; + else + return CKR_FUNCTION_FAILED; + } + + /** create lock subdir for each token if it doesn't exist. + * The root directory should be created in slotmgr daemon **/ + if (strlen(tokname) > 0) + sprintf(lockdir, "%s/%s", LOCKDIR_PATH, tokname); + else + sprintf(lockdir, "%s/%s", LOCKDIR_PATH, SUB_DIR); + + ret = stat(lockdir, &statbuf); + if (ret != 0 && errno == ENOENT) { + /* dir does not exist, try to create it */ + ret = mkdir(lockdir, S_IRWXU | S_IRWXG); + if (ret != 0) { + OCK_SYSLOG(LOG_ERR, + "Directory(%s) missing: %s\n", + lockdir, strerror(errno)); + goto err; + } + grp = getgrnam("pkcs11"); + if (grp == NULL) { + fprintf(stderr, "getgrname(pkcs11): %s", strerror(errno)); + goto err; + } + /* set ownership to euid, and pkcs11 group */ + if (chown(lockdir, geteuid(), grp->gr_gid) != 0) { + fprintf(stderr, "Failed to set owner:group \ + ownership on %s directory", lockdir); + goto err; + } + /* mkdir does not set group permission right, so + ** trying explictly here again */ + if (chmod(lockdir, S_IRWXU | S_IRWXG) != 0) { + fprintf(stderr, "Failed to change \ + permissions on %s directory", lockdir); + goto err; + } + } + + /* create user lock file */ + if (strlen(tokname) > 0) + sprintf(lockfile, "%s/%s/LCK..%s", LOCKDIR_PATH, tokname, tokname); + else + sprintf(lockfile, "%s/%s/LCK..%s", LOCKDIR_PATH, SUB_DIR, SUB_DIR); + + if (stat(lockfile, &statbuf) == 0) { + tokdata->spinxplfd = open(lockfile, O_RDONLY, mode); + } else { + tokdata->spinxplfd = open(lockfile, O_CREAT | O_RDONLY, mode); + if (tokdata->spinxplfd != -1) { + /* umask may prevent correct mode,so set it. */ + if (fchmod(tokdata->spinxplfd, mode) == -1) { + OCK_SYSLOG(LOG_ERR, "fchmod(%s): %s\n", + lockfile, strerror(errno)); + goto err; + } + + grp = getgrnam("pkcs11"); + if (grp != NULL) { + if (fchown(tokdata->spinxplfd, -1, grp->gr_gid) == -1) { + OCK_SYSLOG(LOG_ERR, + "fchown(%s): %s\n", + lockfile, strerror(errno)); + goto err; + } + } else { + OCK_SYSLOG(LOG_ERR, "getgrnam(): %s\n", strerror(errno)); + goto err; + } + } + } + if (tokdata->spinxplfd == -1) { + OCK_SYSLOG(LOG_ERR, "open(%s): %s\n", lockfile, strerror(errno)); + return CKR_FUNCTION_FAILED; + } + } + + return CKR_OK; + +err: + if (tokdata->spinxplfd != -1) + close(tokdata->spinxplfd); + + return CKR_FUNCTION_FAILED; +} + +void CloseXProcLock(STDLL_TokData_t *tokdata) +{ + if (tokdata->spinxplfd != -1) + close(tokdata->spinxplfd); + pthread_mutex_destroy(&tokdata->spinxplfd_mutex); +} + +CK_RV XThreadLock(STDLL_TokData_t *tokdata) +{ + if (pthread_mutex_lock(&tokdata->spinxplfd_mutex)) { + TRACE_ERROR("Lock failed.\n"); + return CKR_CANT_LOCK; + } + + return CKR_OK; +} + +CK_RV XThreadUnLock(STDLL_TokData_t *tokdata) +{ + if (pthread_mutex_unlock(&tokdata->spinxplfd_mutex)) { + TRACE_ERROR("Unlock failed.\n"); + return CKR_CANT_LOCK; + } + + return CKR_OK; +} + +CK_RV XProcLock(STDLL_TokData_t *tokdata) +{ + if (XThreadLock(tokdata) != CKR_OK) + return CKR_CANT_LOCK; + + if (tokdata->spinxplfd < 0) { + TRACE_DEVEL("No file descriptor to lock with.\n"); + return CKR_CANT_LOCK; + } + + if (tokdata->spinxplfd_count == 0) { + if (flock(tokdata->spinxplfd, LOCK_EX) != 0) { + TRACE_DEVEL("flock has failed.\n"); + return CKR_CANT_LOCK; + } + } + tokdata->spinxplfd_count++; + + return CKR_OK; +} + +CK_RV XProcUnLock(STDLL_TokData_t *tokdata) +{ + if (tokdata->spinxplfd < 0) { + TRACE_DEVEL("No file descriptor to unlock with.\n"); + return CKR_CANT_LOCK; + } + + if (tokdata->spinxplfd_count == 0) { + TRACE_DEVEL("No file lock is held.\n"); + return CKR_CANT_LOCK; + } + if (tokdata->spinxplfd_count == 1) { + if (flock(tokdata->spinxplfd, LOCK_UN) != 0) { + TRACE_DEVEL("flock has failed.\n"); + return CKR_CANT_LOCK; + } + } + tokdata->spinxplfd_count--; + + if (XThreadUnLock(tokdata) != CKR_OK) + return CKR_CANT_LOCK; + + return CKR_OK; +} + +CK_RV XProcLock_Init(STDLL_TokData_t *tokdata) +{ + pthread_mutexattr_t attr; + + tokdata->spinxplfd = -1; + tokdata->spinxplfd_count = 0; + + if (pthread_mutexattr_init(&attr)) { + TRACE_ERROR("Mutex attribute init failed.\n"); + return CKR_CANT_LOCK; + } + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) { + TRACE_ERROR("Mutex attribute set failed.\n"); + return CKR_CANT_LOCK; + } + if (pthread_mutex_init(&tokdata->spinxplfd_mutex, &attr)) { + TRACE_ERROR("Mutex init failed.\n"); + return CKR_CANT_LOCK; + } + + return CKR_OK; +} + +// +// + +extern const char manuf[]; +extern const char model[]; +extern const char descr[]; +extern const char label[]; + +// +// +void init_slotInfo(CK_SLOT_INFO *slot_info) +{ + memset(slot_info->slotDescription, ' ', sizeof(slot_info->slotDescription)); + memset(slot_info->manufacturerID, ' ', sizeof(slot_info->manufacturerID)); + + memcpy(slot_info->slotDescription, descr, strlen(descr)); + memcpy(slot_info->manufacturerID, manuf, strlen(manuf)); + + slot_info->hardwareVersion.major = 1; + slot_info->hardwareVersion.minor = 0; + slot_info->firmwareVersion.major = 1; + slot_info->firmwareVersion.minor = 0; + slot_info->flags = CKF_TOKEN_PRESENT | CKF_HW_SLOT; +} + +// +// +void init_tokenInfo(TOKEN_DATA *nv_token_data) +{ + CK_TOKEN_INFO_32 *token_info = &nv_token_data->token_info; + + memset(token_info->label, ' ', sizeof(token_info->label)); + memset(token_info->manufacturerID, ' ', sizeof(token_info->manufacturerID)); + memset(token_info->model, ' ', sizeof(token_info->model)); + memset(token_info->serialNumber, ' ', sizeof(token_info->serialNumber)); + memset(token_info->utcTime, ' ', sizeof(token_info->utcTime)); + + memcpy(token_info->label, label, strlen(label)); + memcpy(token_info->manufacturerID, manuf, strlen(manuf)); + memcpy(token_info->model, model, strlen(model)); + + // Unused + // memcpy(token_info->serialNumber, "123", 3); + + // I don't see any API support for changing the clock so + // we will use the system clock for the token's clock. + // + + token_info->flags = CKF_RNG | CKF_LOGIN_REQUIRED | CKF_CLOCK_ON_TOKEN | + CKF_SO_PIN_TO_BE_CHANGED; + // XXX New in v2.11 - KEY + + if (memcmp(nv_token_data->user_pin_sha, "00000000000000000000", + SHA1_HASH_SIZE) != 0) + token_info->flags |= CKF_USER_PIN_INITIALIZED; + else + token_info->flags |= CKF_USER_PIN_TO_BE_CHANGED; + // XXX New in v2.11 - KEY + + // For the release, we made these + // values as CK_UNAVAILABLE_INFORMATION or CK_EFFECTIVELY_INFINITE + // + token_info->ulMaxSessionCount = (CK_ULONG_32) CK_EFFECTIVELY_INFINITE; + token_info->ulSessionCount = (CK_ULONG_32) CK_UNAVAILABLE_INFORMATION; + token_info->ulMaxRwSessionCount = (CK_ULONG_32) CK_EFFECTIVELY_INFINITE; + token_info->ulRwSessionCount = (CK_ULONG_32) CK_UNAVAILABLE_INFORMATION; + token_info->ulMaxPinLen = MAX_PIN_LEN; + token_info->ulMinPinLen = MIN_PIN_LEN; + token_info->ulTotalPublicMemory = (CK_ULONG_32) CK_UNAVAILABLE_INFORMATION; + token_info->ulFreePublicMemory = (CK_ULONG_32) CK_UNAVAILABLE_INFORMATION; + token_info->ulTotalPrivateMemory = (CK_ULONG_32) CK_UNAVAILABLE_INFORMATION; + token_info->ulFreePrivateMemory = (CK_ULONG_32) CK_UNAVAILABLE_INFORMATION; + + token_info->hardwareVersion.major = 0; + token_info->hardwareVersion.minor = 0; + token_info->firmwareVersion.major = 0; + token_info->firmwareVersion.minor = 0; +} + +// +// +CK_RV init_token_data(STDLL_TokData_t *tokdata, CK_SLOT_ID slot_id) +{ + CK_RV rc; + TOKEN_DATA_VERSION *dat = &tokdata->nv_token_data->dat; + + memset((char *) tokdata->nv_token_data, 0, sizeof(TOKEN_DATA)); + + // the normal USER pin is not set when the token is initialized + // + if (tokdata->version < TOK_NEW_DATA_STORE) { + memcpy(tokdata->nv_token_data->user_pin_sha, "00000000000000000000", + SHA1_HASH_SIZE); + memcpy(tokdata->nv_token_data->so_pin_sha, default_so_pin_sha, + SHA1_HASH_SIZE); + + memset(tokdata->user_pin_md5, 0x0, MD5_HASH_SIZE); + memcpy(tokdata->so_pin_md5, default_so_pin_md5, MD5_HASH_SIZE); + } else { + int rv; + + dat->version = tokdata->version; + + /* SO login key */ + dat->so_login_it = SO_KDF_LOGIN_IT; + memcpy(dat->so_login_salt, SO_KDF_LOGIN_PURPOSE, 32); + rng_generate(tokdata, dat->so_login_salt + 32, 32); + + rv = PKCS5_PBKDF2_HMAC(SO_PIN_DEFAULT, strlen(SO_PIN_DEFAULT), + dat->so_login_salt, 64, + dat->so_login_it, EVP_sha512(), + 256 / 8, dat->so_login_key); + if (rv != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + return CKR_FUNCTION_FAILED; + } + + /* SO wrap key */ + dat->so_wrap_it = SO_KDF_WRAP_IT; + memcpy(dat->so_wrap_salt, SO_KDF_WRAP_PURPOSE, 32); + rng_generate(tokdata, dat->so_wrap_salt + 32, 32); + + rv = PKCS5_PBKDF2_HMAC(SO_PIN_DEFAULT, strlen(SO_PIN_DEFAULT), + dat->so_wrap_salt, 64, + dat->so_wrap_it, EVP_sha512(), + 256 / 8, tokdata->so_wrap_key); + if (rv != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + return CKR_FUNCTION_FAILED; + } + + /* User login key */ + dat->user_login_it = USER_KDF_LOGIN_IT; + memcpy(dat->user_login_salt, USER_KDF_LOGIN_PURPOSE, 32); + rng_generate(tokdata, dat->user_login_salt + 32, 32); + + rv = PKCS5_PBKDF2_HMAC(USER_PIN_DEFAULT, strlen(USER_PIN_DEFAULT), + dat->user_login_salt, 64, + dat->user_login_it, EVP_sha512(), + 256 / 8, dat->user_login_key); + if (rv != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + return CKR_FUNCTION_FAILED; + } + + /* User wrap key */ + dat->user_wrap_it = USER_KDF_WRAP_IT; + memcpy(dat->user_wrap_salt, USER_KDF_WRAP_PURPOSE, 32); + rng_generate(tokdata, dat->user_wrap_salt + 32, 32); + + rv = PKCS5_PBKDF2_HMAC(USER_PIN_DEFAULT, strlen(USER_PIN_DEFAULT), + dat->user_wrap_salt, 64, + dat->user_wrap_it, EVP_sha512(), + 256 / 8, tokdata->user_wrap_key); + if (rv != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + return CKR_FUNCTION_FAILED; + } + } + + memcpy(tokdata->nv_token_data->next_token_object_name, "00000000", 8); + + // generate the master key used for signing the Operation State information + // ` + memset(tokdata->nv_token_data->token_info.label, ' ', + sizeof(tokdata->nv_token_data->token_info.label)); + memcpy(tokdata->nv_token_data->token_info.label, label, + strlen(label)); + + tokdata->nv_token_data->tweak_vector.allow_weak_des = TRUE; + tokdata->nv_token_data->tweak_vector.check_des_parity = FALSE; + tokdata->nv_token_data->tweak_vector.allow_key_mods = TRUE; + tokdata->nv_token_data->tweak_vector.netscape_mods = TRUE; + + init_tokenInfo(tokdata->nv_token_data); + + if (token_specific.t_init_token_data) { + rc = token_specific.t_init_token_data(tokdata, slot_id); + if (rc != CKR_OK) + return rc; + } else { + // + // FIXME: erase the token object index file (and all token objects) + // + rc = generate_master_key(tokdata, tokdata->master_key); + if (rc != CKR_OK) { + TRACE_DEVEL("generate_master_key failed.\n"); + return CKR_FUNCTION_FAILED; + } + + rc = save_masterkey_so(tokdata); + if (rc != CKR_OK) { + TRACE_DEVEL("save_masterkey_so failed.\n"); + return rc; + } + } + + rc = save_token_data(tokdata, slot_id); + + return rc; +} + +// Function: compute_next_token_obj_name() +// +// Given a token object name (8 bytes in the range [0-9A-Z]) increment by one +// adjusting as necessary +// +// This gives us a namespace of 36^8 = 2,821,109,907,456 objects before wrapping +// around +// +// Note: If the current name contains an invalid character (i.e. not within +// [0-9A-Z]), then this character is set to '0' in the next name and +// the following characters are incremented by 1 adjusting as necessary. +// +CK_RV compute_next_token_obj_name(CK_BYTE *current, CK_BYTE *next) +{ + int val[8]; + int i; + + if (!current || !next) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + // Convert to integral base 36 + // + for (i = 0; i < 8; i++) { + if (current[i] >= '0' && current[i] <= '9') + val[i] = current[i] - '0'; + else if (current[i] >= 'A' && current[i] <= 'Z') + val[i] = current[i] - 'A' + 10; + else + val[i] = 36; + } + + val[0]++; + + i = 0; + + while (val[i] > 35) { + val[i] = 0; + + if (i + 1 < 8) { + val[i + 1]++; + i++; + } else { + val[0]++; + i = 0; // start pass 2 + } + } + + // now, convert back to [0-9A-Z] + // + for (i = 0; i < 8; i++) { + if (val[i] < 10) + next[i] = '0' + val[i]; + else + next[i] = 'A' + val[i] - 10; + } + + return CKR_OK; +} + +// +// +CK_RV build_attribute(CK_ATTRIBUTE_TYPE type, + CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **attrib) +{ + CK_ATTRIBUTE *attr = NULL; + + attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + data_len); + if (!attr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + attr->type = type; + attr->ulValueLen = data_len; + + if (data_len > 0) { + attr->pValue = (CK_BYTE *) attr + sizeof(CK_ATTRIBUTE); + memcpy(attr->pValue, data, data_len); + } else { + attr->pValue = NULL; + } + + *attrib = attr; + + return CKR_OK; +} + +/* + * Find an attribute in an attribute array. + * + * Returns CKR_FUNCTION_FAILED when attribute is not found, + * CKR_ATTRIBUTE_TYPE_INVALID when length doesn't match the expected and + * CKR_OK when values is returned in the `value` argument. + */ +CK_RV find_bbool_attribute(CK_ATTRIBUTE *attrs, CK_ULONG attrs_len, + CK_ATTRIBUTE_TYPE type, CK_BBOOL *value) +{ + CK_ULONG i; + + for (i = 0; i < attrs_len; i++) { + if (attrs[i].type == type) { + /* Check size */ + if (attrs[i].ulValueLen != sizeof(*value)) + return CKR_ATTRIBUTE_TYPE_INVALID; + + /* Get value */ + *value = *((CK_BBOOL *) attrs[i].pValue); + } + } + + return CKR_FUNCTION_FAILED; +} + +// +// +CK_RV add_pkcs_padding(CK_BYTE *ptr, + CK_ULONG block_size, CK_ULONG data_len, + CK_ULONG total_len) +{ + CK_ULONG i, pad_len; + CK_BYTE pad_value; + + pad_len = block_size - (data_len % block_size); + pad_value = (CK_BYTE) pad_len; + + if (data_len + pad_len > total_len) { + TRACE_ERROR("The total length is too small to add padding.\n"); + return CKR_FUNCTION_FAILED; + } + for (i = 0; i < pad_len; i++) + ptr[i] = pad_value; + + return CKR_OK; +} + +// +// +CK_RV strip_pkcs_padding(CK_BYTE *ptr, CK_ULONG total_len, CK_ULONG *data_len) +{ + CK_BYTE pad_value; + + pad_value = ptr[total_len - 1]; + if (pad_value > total_len) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID)); + return CKR_ENCRYPTED_DATA_INVALID; + } + // thus, we have 'pad_value' bytes of 'pad_value' appended to the end + // + *data_len = total_len - pad_value; + + return CKR_OK; +} + +// +// +CK_BYTE parity_adjust(CK_BYTE b) +{ + if (parity_is_odd(b) == FALSE) + b = (b & 0xFE) | ((~b) & 0x1); + + return b; +} + +// +// +CK_RV parity_is_odd(CK_BYTE b) +{ + b = ((b >> 4) ^ b) & 0x0f; + b = ((b >> 2) ^ b) & 0x03; + b = ((b >> 1) ^ b) & 0x01; + + if (b == 1) + return TRUE; + else + return FALSE; +} + +CK_RV attach_shm(STDLL_TokData_t *tokdata, CK_SLOT_ID slot_id) +{ + CK_RV rc; + int ret; + char buf[PATH_MAX]; + LW_SHM_TYPE **shm = &tokdata->global_shm; + + if (token_specific.t_attach_shm != NULL) + return token_specific.t_attach_shm(tokdata, slot_id); + + rc = XProcLock(tokdata); + if (rc != CKR_OK) + goto err; + + /* + * Attach to an existing shared memory region or create it if it doesn't + * exists. When it's created (ret=0) the region is initialized with + * zeros. + */ + ret = sm_open(get_pk_dir(tokdata, buf), 0666, (void **) shm, sizeof(**shm), 0); + if (ret < 0) { + TRACE_DEVEL("sm_open failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto err; + } + + return XProcUnLock(tokdata); + +err: + XProcUnLock(tokdata); + return rc; +} + +CK_RV detach_shm(STDLL_TokData_t *tokdata, CK_BBOOL ignore_ref_count) +{ + CK_RV rc; + + rc = XProcLock(tokdata); + if (rc != CKR_OK) + goto err; + + if (sm_close((void *) tokdata->global_shm, 0, ignore_ref_count)) { + TRACE_DEVEL("sm_close failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto err; + } + + return XProcUnLock(tokdata); + +err: + XProcUnLock(tokdata); + return rc; +} + +CK_RV get_sha_size(CK_ULONG mech, CK_ULONG *hsize) +{ + switch (mech) { + case CKM_SHA_1: + *hsize = SHA1_HASH_SIZE; + break; + case CKM_SHA224: + case CKM_SHA512_224: + *hsize = SHA224_HASH_SIZE; + break; + case CKM_SHA256: + case CKM_SHA512_256: + *hsize = SHA256_HASH_SIZE; + break; + case CKM_SHA384: + *hsize = SHA384_HASH_SIZE; + break; + case CKM_SHA512: + *hsize = SHA512_HASH_SIZE; + break; + case CKM_IBM_SHA3_224: + *hsize = SHA3_224_HASH_SIZE; + break; + case CKM_IBM_SHA3_256: + *hsize = SHA3_256_HASH_SIZE; + break; + case CKM_IBM_SHA3_384: + *hsize = SHA3_384_HASH_SIZE; + break; + case CKM_IBM_SHA3_512: + *hsize = SHA3_512_HASH_SIZE; + break; + default: + return CKR_MECHANISM_INVALID; + } + return CKR_OK; +} + +CK_RV get_sha_block_size(CK_ULONG mech, CK_ULONG *bsize) +{ + switch (mech) { + case CKM_SHA_1: + *bsize = SHA1_BLOCK_SIZE; + break; + case CKM_SHA224: + *bsize = SHA224_BLOCK_SIZE; + break; + case CKM_SHA256: + *bsize = SHA256_BLOCK_SIZE; + break; + case CKM_SHA384: + *bsize = SHA384_BLOCK_SIZE; + break; + case CKM_SHA512: + case CKM_SHA512_224: + case CKM_SHA512_256: + *bsize = SHA512_BLOCK_SIZE; + break; + case CKM_IBM_SHA3_224: + *bsize = SHA3_224_BLOCK_SIZE; + break; + case CKM_IBM_SHA3_256: + *bsize = SHA3_256_BLOCK_SIZE; + break; + case CKM_IBM_SHA3_384: + *bsize = SHA3_384_BLOCK_SIZE; + break; + case CKM_IBM_SHA3_512: + *bsize = SHA3_512_BLOCK_SIZE; + break; + default: + return CKR_MECHANISM_INVALID; + } + return CKR_OK; +} + +/* Compute specified SHA using either software or token implementation */ +CK_RV compute_sha(STDLL_TokData_t *tokdata, CK_BYTE *data, CK_ULONG len, + CK_BYTE *hash, CK_ULONG mech) +{ + DIGEST_CONTEXT ctx; + CK_ULONG hash_len; + CK_RV rv; + + memset(&ctx, 0x0, sizeof(ctx)); + ctx.mech.mechanism = mech; + + rv = get_sha_size(mech, &hash_len); + if (rv != CKR_OK) + return rv; + + rv = sha_init(tokdata, NULL, &ctx, &ctx.mech); + if (rv != CKR_OK) { + TRACE_DEBUG("failed to create digest.\n"); + return rv; + } + rv = sha_hash(tokdata, NULL, FALSE, &ctx, data, len, hash, &hash_len); + + digest_mgr_cleanup(&ctx); + return rv; +} + +/* Compute SHA1 using software implementation */ +CK_RV compute_sha1(STDLL_TokData_t *tokdata, CK_BYTE *data, CK_ULONG len, + CK_BYTE *hash) +{ + // XXX KEY + DIGEST_CONTEXT ctx; + CK_ULONG hash_len = SHA1_HASH_SIZE; + + UNUSED(tokdata); + + memset(&ctx, 0x0, sizeof(ctx)); + + sw_sha1_init(&ctx); + if (ctx.context == NULL) + return CKR_HOST_MEMORY; + + return sw_sha1_hash(&ctx, data, len, hash, &hash_len); +} + +CK_RV compute_md5(STDLL_TokData_t *tokdata, CK_BYTE *data, CK_ULONG len, + CK_BYTE *hash) +{ + DIGEST_CONTEXT ctx; + CK_ULONG hash_len = MD5_HASH_SIZE; + + UNUSED(tokdata); + + memset(&ctx, 0x0, sizeof(ctx)); + + sw_md5_init(&ctx); + if (ctx.context == NULL) + return CKR_HOST_MEMORY; + + return sw_md5_hash(&ctx, data, len, hash, &hash_len); +} + +CK_RV get_keytype(STDLL_TokData_t *tokdata, CK_OBJECT_HANDLE hkey, + CK_KEY_TYPE *keytype) +{ + CK_RV rc; + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + + rc = object_mgr_find_in_map1(tokdata, hkey, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_find_in_map1 failed.\n"); + return rc; + } + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + } else { + *keytype = *(CK_KEY_TYPE *) attr->pValue; + rc = CKR_OK; + } + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV check_user_and_group() +{ + int i; + uid_t uid, euid; + struct passwd *pw, *epw; + struct group *grp; + + /* + * Check for root user or Group PKCS#11 Membershp. + * Only these are allowed. + */ + uid = getuid(); + euid = geteuid(); + + /* Root or effective Root is ok */ + if (uid == 0 || euid == 0) + return CKR_OK; + + /* + * Check for member of group. SAB get login seems to not work + * with some instances of application invocations (particularly + * 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"); + if (grp == NULL) { + OCK_SYSLOG(LOG_ERR, "getgrnam() failed: %s\n", strerror(errno)); + goto error; + } + + if (getgid() == grp->gr_gid || getegid() == grp->gr_gid) + return CKR_OK; + /* Check if user or effective user is member of pkcs11 group */ + pw = getpwuid(uid); + epw = getpwuid(euid); + for (i = 0; grp->gr_mem[i]; i++) { + if ((pw && (strncmp(pw->pw_name, grp->gr_mem[i], + strlen(pw->pw_name)) == 0)) || + (epw && (strncmp(epw->pw_name, grp->gr_mem[i], + strlen(epw->pw_name)) == 0))) + return CKR_OK; + } + +error: + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + +void copy_token_contents_sensibly(CK_TOKEN_INFO_PTR pInfo, + TOKEN_DATA *nv_token_data) +{ + memcpy(pInfo, &nv_token_data->token_info, sizeof(CK_TOKEN_INFO_32)); + pInfo->flags = nv_token_data->token_info.flags; + pInfo->ulMaxPinLen = nv_token_data->token_info.ulMaxPinLen; + pInfo->ulMinPinLen = nv_token_data->token_info.ulMinPinLen; + + if (nv_token_data->token_info.ulTotalPublicMemory == + (CK_ULONG_32) CK_UNAVAILABLE_INFORMATION) { + pInfo->ulTotalPublicMemory = (CK_ULONG) CK_UNAVAILABLE_INFORMATION; + } else { + pInfo->ulTotalPublicMemory = + nv_token_data->token_info.ulTotalPublicMemory; + } + + if (nv_token_data->token_info.ulFreePublicMemory == + (CK_ULONG_32) CK_UNAVAILABLE_INFORMATION) { + pInfo->ulFreePublicMemory = (CK_ULONG) CK_UNAVAILABLE_INFORMATION; + } else { + pInfo->ulFreePublicMemory = + nv_token_data->token_info.ulFreePublicMemory; + } + + if (nv_token_data->token_info.ulTotalPrivateMemory == + (CK_ULONG_32) CK_UNAVAILABLE_INFORMATION) { + pInfo->ulTotalPrivateMemory = (CK_ULONG) CK_UNAVAILABLE_INFORMATION; + } else { + pInfo->ulTotalPrivateMemory = + nv_token_data->token_info.ulTotalPrivateMemory; + } + + if (nv_token_data->token_info.ulFreePrivateMemory == + (CK_ULONG_32) CK_UNAVAILABLE_INFORMATION) { + pInfo->ulFreePrivateMemory = (CK_ULONG) CK_UNAVAILABLE_INFORMATION; + } else { + pInfo->ulFreePrivateMemory = + nv_token_data->token_info.ulFreePrivateMemory; + } + + pInfo->hardwareVersion = nv_token_data->token_info.hardwareVersion; + pInfo->firmwareVersion = nv_token_data->token_info.firmwareVersion; + pInfo->ulMaxSessionCount = CK_EFFECTIVELY_INFINITE; + /* pInfo->ulSessionCount is set at the API level */ + pInfo->ulMaxRwSessionCount = CK_EFFECTIVELY_INFINITE; + pInfo->ulRwSessionCount = CK_UNAVAILABLE_INFORMATION; +} + +CK_BBOOL is_secure_key_token() +{ + /* + * If token has a specific key size that means that it uses secure keys. + */ + return token_specific.token_keysize > 0 ? TRUE : FALSE; +} diff --git a/usr/lib/common/verify_mgr.c b/usr/lib/common/verify_mgr.c new file mode 100644 index 0000000..646d673 --- /dev/null +++ b/usr/lib/common/verify_mgr.c @@ -0,0 +1,1210 @@ +/* + * 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: verify_mgr.c +// +// Verify manager routines +// + +#include +#include // for memcmp() et al +#include + + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "trace.h" + + +// +// +CK_RV verify_mgr_init(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_MECHANISM *mech, + CK_BBOOL recover_mode, CK_OBJECT_HANDLE key) +{ + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *ptr = NULL; + CK_KEY_TYPE keytype; + CK_OBJECT_CLASS class; + CK_BBOOL flag; + CK_RV rc; + + + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (ctx->active != FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + return CKR_OPERATION_ACTIVE; + } + // key usage restrictions + // + rc = object_mgr_find_in_map1(tokdata, key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to acquire key from specified handle.\n"); + if (rc == CKR_OBJECT_HANDLE_INVALID) + return CKR_KEY_HANDLE_INVALID; + else + return rc; + } + + if (recover_mode) { + // is key allowed to verify signatures where the data can be + // recovered from the signature? + rc = template_attribute_find(key_obj->template, CKA_VERIFY_RECOVER, + &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_VERIFY_RECOVER for the key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + } else { + // is key allowed to verify signatures where the signature is an + // appendix to the data? + rc = template_attribute_find(key_obj->template, CKA_VERIFY, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_VERIFY for the key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + } + flag = *(CK_BBOOL *) attr->pValue; + if (flag != TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_FUNCTION_NOT_PERMITTED)); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + + // is the mechanism supported? is the key type correct? is a + // parameter present if required? is the key size allowed? + // is the key allowed to generate signatures? + // + switch (mech->mechanism) { + case CKM_RSA_X_509: + case CKM_RSA_PKCS: + case CKM_RSA_PKCS_PSS: + if (mech->mechanism == CKM_RSA_PKCS_PSS) { + rc = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_VERIFY for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + rc = check_pss_params(mech, attr->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("check_pss_params failed.\n"); + goto done; + } + } else { + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } + + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_RSA) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // must be a PUBLIC key operation + // + flag = template_attribute_find(key_obj->template, CKA_CLASS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + class = *(CK_OBJECT_CLASS *) attr->pValue; + } + + if (class != CKO_PUBLIC_KEY) { + TRACE_ERROR("This operation requires a private key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + // PKCS #11 doesn't allow multi-part RSA operations + // + ctx->context_len = 0; + ctx->context = NULL; + break; + case CKM_ECDSA: + case CKM_ECDSA_SHA1: + case CKM_ECDSA_SHA224: + case CKM_ECDSA_SHA256: + case CKM_ECDSA_SHA384: + case CKM_ECDSA_SHA512: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_EC) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // must be a PUBLIC key operation + // + flag = template_attribute_find(key_obj->template, CKA_CLASS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + class = *(CK_OBJECT_CLASS *) attr->pValue; + } + + if (class != CKO_PUBLIC_KEY) { + TRACE_ERROR("This operation requires a public key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + + if (mech->mechanism == CKM_ECDSA) { + ctx->context_len = 0; + ctx->context = NULL; + } else { + ctx->context_len = sizeof(RSA_DIGEST_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(RSA_DIGEST_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(RSA_DIGEST_CONTEXT)); + } + break; + 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: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_RSA) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // must be a PUBLIC key operation + // + flag = template_attribute_find(key_obj->template, CKA_CLASS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + class = *(CK_OBJECT_CLASS *) attr->pValue; + } + + if (class != CKO_PUBLIC_KEY) { + TRACE_ERROR("This operation requires a public key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + ctx->context_len = sizeof(RSA_DIGEST_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(RSA_DIGEST_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(RSA_DIGEST_CONTEXT)); + break; + 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: + rc = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + rc = check_pss_params(mech, attr->ulValueLen); + if (rc != CKR_OK) { + TRACE_DEVEL("check_pss_params failed.\n"); + goto done; + } + + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_RSA) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // must be a PUBLIC key operation + // + flag = template_attribute_find(key_obj->template, CKA_CLASS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + class = *(CK_OBJECT_CLASS *) attr->pValue; + } + + if (class != CKO_PUBLIC_KEY) { + TRACE_ERROR("This operation requires a public key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + ctx->context_len = sizeof(DIGEST_CONTEXT); + ctx->context = (CK_BYTE *) malloc(ctx->context_len); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, ctx->context_len); + break; +#if !(NODSA) + case CKM_DSA: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_DSA) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // must be a PUBLIC key operation + // + flag = template_attribute_find(key_obj->template, CKA_CLASS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + class = *(CK_OBJECT_CLASS *) attr->pValue; + } + + if (class != CKO_PUBLIC_KEY) { + TRACE_ERROR("This operation requires a public key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + // PKCS #11 doesn't allow multi-part DSA operations + // + ctx->context_len = 0; + ctx->context = NULL; + break; +#endif + case CKM_MD2_HMAC: + case CKM_MD5_HMAC: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_GENERIC_SECRET) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // PKCS #11 doesn't allow multi-part HMAC operations + // + ctx->context_len = 0; + ctx->context = NULL; + break; + case CKM_SHA_1_HMAC: + case CKM_SHA224_HMAC: + case CKM_SHA256_HMAC: + case CKM_SHA384_HMAC: + case CKM_SHA512_HMAC: + case CKM_SHA512_224_HMAC: + case CKM_SHA512_256_HMAC: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_GENERIC_SECRET) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + /* Note: It was previously believed that pkcs#11 did not + * support hmac multipart. As a result, those tokens using the + * locally implemented hmac helper functions do not support + * multipart hmac. + */ + ctx->context_len = 0; + ctx->context = NULL; + + rc = hmac_verify_init(tokdata, sess, mech, key); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to initialize hmac.\n"); + goto done; + } + break; + case CKM_MD2_HMAC_GENERAL: + case CKM_MD5_HMAC_GENERAL: + { + CK_MAC_GENERAL_PARAMS *param = + (CK_MAC_GENERAL_PARAMS *) mech->pParameter; + + if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + if ((mech->mechanism == CKM_MD2_HMAC_GENERAL) && (*param > 16)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + if ((mech->mechanism == CKM_MD5_HMAC_GENERAL) && (*param > 16)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, + &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_GENERIC_SECRET) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + // PKCS #11 doesn't allow multi-part HMAC operations + // + ctx->context_len = 0; + ctx->context = NULL; + } + break; + case CKM_SHA_1_HMAC_GENERAL: + case CKM_SHA224_HMAC_GENERAL: + case CKM_SHA256_HMAC_GENERAL: + case CKM_SHA384_HMAC_GENERAL: + case CKM_SHA512_HMAC_GENERAL: + case CKM_SHA512_224_HMAC_GENERAL: + case CKM_SHA512_256_HMAC_GENERAL: + { + CK_MAC_GENERAL_PARAMS *param = + (CK_MAC_GENERAL_PARAMS *) mech->pParameter; + + if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc= CKR_MECHANISM_PARAM_INVALID; + goto done; + } + if ((mech->mechanism == CKM_MD2_HMAC_GENERAL) && (*param > 16)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + if ((mech->mechanism == CKM_MD5_HMAC_GENERAL) && (*param > 16)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + if ((mech->mechanism == CKM_SHA_1_HMAC_GENERAL) && (*param > 20)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + if ((mech->mechanism == CKM_SHA224_HMAC_GENERAL) && (*param > 28)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + if ((mech->mechanism == CKM_SHA256_HMAC_GENERAL) && (*param > 32)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + if ((mech->mechanism == CKM_SHA384_HMAC_GENERAL) && (*param > 48)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + if ((mech->mechanism == CKM_SHA512_HMAC_GENERAL) && (*param > 64)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + if ((mech->mechanism == CKM_SHA512_224_HMAC_GENERAL) + && (*param > 28)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + if ((mech->mechanism == CKM_SHA512_256_HMAC_GENERAL) + && (*param > 32)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + rc = template_attribute_find(key_obj->template, CKA_KEY_TYPE, + &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + keytype = *(CK_KEY_TYPE *) attr->pValue; + if (keytype != CKK_GENERIC_SECRET) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); + rc = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + } + + /* Note: It was previously believed that pkcs#11 did not + * support hmac multipart. As a result, those tokens using the + * locally implemented hmac helper functions do not support + * multipart hmac. + */ + ctx->context_len = 0; + ctx->context = NULL; + + rc = hmac_verify_init(tokdata, sess, mech, key); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to initialize hmac.\n"); + goto done; + } + } + break; + case CKM_SSL3_MD5_MAC: + case CKM_SSL3_SHA1_MAC: + { + CK_MAC_GENERAL_PARAMS *param = + (CK_MAC_GENERAL_PARAMS *) mech->pParameter; + + if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + // Netscape sets the parameter == 16. PKCS #11 limit is 8 + // + if (mech->mechanism == CKM_SSL3_MD5_MAC) { + if (*param < 4 || *param > 16) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } + + if (mech->mechanism == CKM_SSL3_SHA1_MAC) { + if (*param < 4 || *param > 20) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } + + rc = template_attribute_find(key_obj->template, CKA_CLASS, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_CLASS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + class = *(CK_OBJECT_CLASS *) attr->pValue; + if (class != CKO_SECRET_KEY) { + TRACE_ERROR("This operation requires a secret key.\n"); + rc = CKR_KEY_FUNCTION_NOT_PERMITTED; + goto done; + } + } + + ctx->context_len = sizeof(SSL3_MAC_CONTEXT); + ctx->context = (CK_BYTE *) malloc(sizeof(SSL3_MAC_CONTEXT)); + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(SSL3_MAC_CONTEXT)); + } + break; + case CKM_DES3_MAC: + case CKM_DES3_MAC_GENERAL: + { + if (mech->pParameter) { + if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + CK_MAC_GENERAL_PARAMS *param = + (CK_MAC_GENERAL_PARAMS *) mech->pParameter; + if (mech->mechanism == CKM_DES3_MAC_GENERAL) { + if (*param < 1 || *param > DES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", + ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } else { + /* CKM_DES_MAC or CKM_DES3_MAC should not have params */ + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } + + ctx->context = (CK_BYTE *) malloc(sizeof(DES_DATA_CONTEXT)); + ctx->context_len = sizeof(DES_DATA_CONTEXT); + + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(DES_DATA_CONTEXT)); + } + break; + case CKM_DES3_CMAC: + case CKM_DES3_CMAC_GENERAL: + if (mech->pParameter) { + if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + CK_MAC_GENERAL_PARAMS *param = + (CK_MAC_GENERAL_PARAMS *) mech->pParameter; + if (mech->mechanism == CKM_DES3_CMAC_GENERAL) { + if (*param < 1 || *param > DES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", + ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } else { + /* CKM_DES3_CMAC should not have params */ + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } + + ctx->context = (CK_BYTE *) malloc(sizeof(DES_CMAC_CONTEXT)); + ctx->context_len = sizeof(DES_CMAC_CONTEXT); + + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(DES_CMAC_CONTEXT)); + break; + case CKM_AES_MAC: + case CKM_AES_MAC_GENERAL: + { + if (mech->pParameter) { + if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + CK_MAC_GENERAL_PARAMS *param = + (CK_MAC_GENERAL_PARAMS *) mech->pParameter; + + if (mech->mechanism == CKM_AES_MAC_GENERAL) { + if (*param < 1 || *param > AES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", + ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } else { + /* CKM_AES_MAC should not have params */ + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } + + ctx->context = (CK_BYTE *) malloc(sizeof(AES_DATA_CONTEXT)); + ctx->context_len = sizeof(AES_DATA_CONTEXT); + + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(AES_DATA_CONTEXT)); + } + break; + case CKM_AES_CMAC: + case CKM_AES_CMAC_GENERAL: + if (mech->pParameter) { + if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + CK_MAC_GENERAL_PARAMS *param = + (CK_MAC_GENERAL_PARAMS *) mech->pParameter; + + if (mech->mechanism == CKM_AES_CMAC_GENERAL) { + if (*param < 1 || *param > AES_BLOCK_SIZE) { + TRACE_ERROR("%s\n", + ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } else { + /* CKM_AES_CMAC should not have params */ + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + } + + ctx->context = (CK_BYTE *) malloc(sizeof(AES_CMAC_CONTEXT)); + ctx->context_len = sizeof(AES_CMAC_CONTEXT); + + if (!ctx->context) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(ctx->context, 0x0, sizeof(AES_CMAC_CONTEXT)); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + + if (mech->ulParameterLen > 0 && mech->pParameter != NULL) { + ptr = (CK_BYTE *) malloc(mech->ulParameterLen); + if (!ptr) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memcpy(ptr, mech->pParameter, mech->ulParameterLen); + } + + ctx->key = key; + ctx->mech.ulParameterLen = mech->ulParameterLen; + ctx->mech.mechanism = mech->mechanism; + ctx->mech.pParameter = ptr; + ctx->multi_init = FALSE; + ctx->multi = FALSE; + ctx->active = TRUE; + ctx->recover = recover_mode; + + rc = CKR_OK; + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +// +// +CK_RV verify_mgr_cleanup(SIGN_VERIFY_CONTEXT *ctx) +{ + if (!ctx) { + TRACE_ERROR("Invalid function argument.\n"); + return CKR_FUNCTION_FAILED; + } + ctx->key = 0; + ctx->mech.ulParameterLen = 0; + ctx->mech.mechanism = 0; + ctx->multi_init = FALSE; + ctx->multi = FALSE; + ctx->active = FALSE; + ctx->init_pending = FALSE; + ctx->recover = FALSE; + ctx->context_len = 0; + + if (ctx->mech.pParameter) { + free(ctx->mech.pParameter); + ctx->mech.pParameter = NULL; + } + + if (ctx->context) { + free(ctx->context); + ctx->context = NULL; + } + + return CKR_OK; +} + + +// +// +CK_RV verify_mgr_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) +{ + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (ctx->active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->recover == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->multi_init == FALSE) { + ctx->multi = FALSE; + ctx->multi_init = TRUE; + } + + // if the caller just wants the signature length, there is no reason to + // specify the input data. I just need the input data length + // + if (!in_data || !signature) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + if (ctx->multi == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + return CKR_OPERATION_ACTIVE; + } + + switch (ctx->mech.mechanism) { + case CKM_RSA_PKCS: + return rsa_pkcs_verify(tokdata, sess, ctx, + in_data, in_data_len, signature, sig_len); + case CKM_RSA_X_509: + return rsa_x509_verify(tokdata, sess, ctx, + in_data, in_data_len, signature, sig_len); + case CKM_RSA_PKCS_PSS: + return rsa_pss_verify(tokdata, sess, ctx, in_data, in_data_len, + signature, sig_len); + 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: + return rsa_hash_pkcs_verify(tokdata, sess, ctx, + in_data, in_data_len, signature, sig_len); + 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: + return rsa_hash_pss_verify(tokdata, sess, ctx, in_data, in_data_len, + signature, sig_len); +#if !(NODSA) + case CKM_DSA: + return dsa_verify(tokdata, sess, ctx, + in_data, in_data_len, signature, sig_len); +#endif +#if !(NOMD2) + case CKM_MD2_HMAC: + case CKM_MD2_HMAC_GENERAL: + return md2_hmac_verify(tokdata, sess, ctx, + in_data, in_data_len, signature, sig_len); +#endif + case CKM_MD5_HMAC: + case CKM_MD5_HMAC_GENERAL: + return md5_hmac_verify(tokdata, sess, ctx, + in_data, in_data_len, signature, sig_len); + case CKM_SHA_1_HMAC: + case CKM_SHA_1_HMAC_GENERAL: + return sha1_hmac_verify(tokdata, sess, ctx, + in_data, in_data_len, signature, sig_len); + case CKM_SHA224_HMAC: + case CKM_SHA224_HMAC_GENERAL: + return sha224_hmac_verify(tokdata, sess, ctx, + in_data, in_data_len, signature, sig_len); + case CKM_SHA256_HMAC: + case CKM_SHA256_HMAC_GENERAL: + return sha256_hmac_verify(tokdata, sess, ctx, + in_data, in_data_len, signature, sig_len); + case CKM_SHA384_HMAC: + case CKM_SHA384_HMAC_GENERAL: + return sha384_hmac_verify(tokdata, sess, ctx, + in_data, in_data_len, signature, sig_len); + case CKM_SHA512_HMAC: + case CKM_SHA512_HMAC_GENERAL: + case CKM_SHA512_224_HMAC: + case CKM_SHA512_224_HMAC_GENERAL: + case CKM_SHA512_256_HMAC: + case CKM_SHA512_256_HMAC_GENERAL: + return sha512_hmac_verify(tokdata, sess, ctx, + in_data, in_data_len, signature, sig_len); + case CKM_SSL3_MD5_MAC: + case CKM_SSL3_SHA1_MAC: + return ssl3_mac_verify(tokdata, sess, ctx, + in_data, in_data_len, signature, sig_len); + case CKM_DES3_MAC: + case CKM_DES3_MAC_GENERAL: + return des3_mac_verify(tokdata, sess, ctx, in_data, in_data_len, + signature, sig_len); + case CKM_DES3_CMAC: + case CKM_DES3_CMAC_GENERAL: + return des3_cmac_verify(tokdata, sess, ctx, in_data, in_data_len, + signature, sig_len); + case CKM_AES_MAC: + case CKM_AES_MAC_GENERAL: + return aes_mac_verify(tokdata, sess, ctx, + in_data, in_data_len, signature, sig_len); + case CKM_AES_CMAC: + case CKM_AES_CMAC_GENERAL: + return aes_cmac_verify(tokdata, sess, ctx, + in_data, in_data_len, signature, sig_len); + case CKM_ECDSA_SHA1: + case CKM_ECDSA_SHA224: + case CKM_ECDSA_SHA256: + case CKM_ECDSA_SHA384: + case CKM_ECDSA_SHA512: + return ec_hash_verify(tokdata, sess, ctx, + in_data, in_data_len, signature, sig_len); + case CKM_ECDSA: + return ec_verify(tokdata, sess, ctx, + in_data, in_data_len, signature, sig_len); + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + + +// +// +CK_RV verify_mgr_verify_update(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (ctx->active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->recover == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->multi_init == FALSE) { + ctx->multi = TRUE; + ctx->multi_init = TRUE; + } + if (ctx->multi == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + return CKR_OPERATION_ACTIVE; + } + + switch (ctx->mech.mechanism) { + 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: + return rsa_hash_pkcs_verify_update(tokdata, sess, ctx, in_data, + in_data_len); + 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: + return rsa_hash_pss_update(tokdata, sess, ctx, in_data, in_data_len); + case CKM_SSL3_MD5_MAC: + case CKM_SSL3_SHA1_MAC: + return ssl3_mac_verify_update(tokdata, sess, ctx, in_data, in_data_len); + case CKM_DES3_MAC: + case CKM_DES3_MAC_GENERAL: + return des3_mac_verify_update(tokdata, sess, ctx, in_data, in_data_len); + case CKM_DES3_CMAC: + case CKM_DES3_CMAC_GENERAL: + return des3_cmac_verify_update(tokdata, sess, ctx, in_data, + in_data_len); + case CKM_AES_MAC: + case CKM_AES_MAC_GENERAL: + return aes_mac_verify_update(tokdata, sess, ctx, in_data, in_data_len); + case CKM_AES_CMAC: + case CKM_AES_CMAC_GENERAL: + return aes_cmac_verify_update(tokdata, sess, ctx, in_data, in_data_len); + case CKM_ECDSA_SHA1: + case CKM_ECDSA_SHA224: + case CKM_ECDSA_SHA256: + case CKM_ECDSA_SHA384: + case CKM_ECDSA_SHA512: + return ec_hash_verify_update(tokdata, sess, ctx, in_data, in_data_len); + case CKM_SHA_1_HMAC: + case CKM_SHA224_HMAC: + case CKM_SHA256_HMAC: + case CKM_SHA384_HMAC: + case CKM_SHA512_HMAC: + case CKM_SHA512_224_HMAC: + case CKM_SHA512_256_HMAC: + case CKM_SHA_1_HMAC_GENERAL: + case CKM_SHA224_HMAC_GENERAL: + case CKM_SHA256_HMAC_GENERAL: + case CKM_SHA384_HMAC_GENERAL: + case CKM_SHA512_HMAC_GENERAL: + case CKM_SHA512_224_HMAC_GENERAL: + case CKM_SHA512_256_HMAC_GENERAL: + return hmac_verify_update(tokdata, sess, in_data, in_data_len); + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + + +// +// +CK_RV verify_mgr_verify_final(STDLL_TokData_t *tokdata, + SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, CK_ULONG sig_len) +{ + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (ctx->active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->recover == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->multi_init == FALSE) { + ctx->multi = TRUE; + ctx->multi_init = TRUE; + } + if (ctx->multi == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + return CKR_OPERATION_ACTIVE; + } + + switch (ctx->mech.mechanism) { + 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: + return rsa_hash_pkcs_verify_final(tokdata, sess, ctx, signature, + sig_len); + 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: + return rsa_hash_pss_verify_final(tokdata, sess, ctx, signature, + sig_len); + case CKM_SSL3_MD5_MAC: + case CKM_SSL3_SHA1_MAC: + return ssl3_mac_verify_final(tokdata, sess, ctx, signature, sig_len); + case CKM_DES3_MAC: + case CKM_DES3_MAC_GENERAL: + return des3_mac_verify_final(tokdata, sess, ctx, signature, sig_len); + case CKM_DES3_CMAC: + case CKM_DES3_CMAC_GENERAL: + return des3_cmac_verify_final(tokdata, sess, ctx, signature, sig_len); + case CKM_AES_MAC: + case CKM_AES_MAC_GENERAL: + return aes_mac_verify_final(tokdata, sess, ctx, signature, sig_len); + case CKM_AES_CMAC: + case CKM_AES_CMAC_GENERAL: + return aes_cmac_verify_final(tokdata, sess, ctx, signature, sig_len); + case CKM_ECDSA_SHA1: + case CKM_ECDSA_SHA224: + case CKM_ECDSA_SHA256: + case CKM_ECDSA_SHA384: + case CKM_ECDSA_SHA512: + return ec_hash_verify_final(tokdata, sess, ctx, signature, sig_len); + case CKM_SHA_1_HMAC: + case CKM_SHA224_HMAC: + case CKM_SHA256_HMAC: + case CKM_SHA384_HMAC: + case CKM_SHA512_HMAC: + case CKM_SHA512_224_HMAC: + case CKM_SHA512_256_HMAC: + case CKM_SHA_1_HMAC_GENERAL: + case CKM_SHA224_HMAC_GENERAL: + case CKM_SHA256_HMAC_GENERAL: + case CKM_SHA384_HMAC_GENERAL: + case CKM_SHA512_HMAC_GENERAL: + case CKM_SHA512_224_HMAC_GENERAL: + case CKM_SHA512_256_HMAC_GENERAL: + return hmac_verify_final(tokdata, sess, signature, sig_len); + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} + + +// +// +CK_RV verify_mgr_verify_recover(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BBOOL length_only, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *signature, + CK_ULONG sig_len, + CK_BYTE *out_data, CK_ULONG *out_len) +{ + if (!sess || !ctx) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + if (ctx->active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + if (ctx->recover == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + return CKR_OPERATION_NOT_INITIALIZED; + } + // if the caller just wants the signature length, there is no reason to + // specify the input data. I just need the input data length + // + if (!signature || !out_len) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + if (ctx->multi == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + return CKR_OPERATION_ACTIVE; + } + + switch (ctx->mech.mechanism) { + case CKM_RSA_PKCS: + return rsa_pkcs_verify_recover(tokdata, sess, length_only, + ctx, + signature, sig_len, out_data, out_len); + case CKM_RSA_X_509: + return rsa_x509_verify_recover(tokdata, sess, length_only, + ctx, + signature, sig_len, out_data, out_len); + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + + return CKR_FUNCTION_FAILED; +} diff --git a/usr/lib/ep11_stdll/ep11.h b/usr/lib/ep11_stdll/ep11.h new file mode 100644 index 0000000..bedb5c1 --- /dev/null +++ b/usr/lib/ep11_stdll/ep11.h @@ -0,0 +1,281 @@ +/* + * 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 + */ + +/*---------------------------------------------------------------------- + * IBM Research & Development + * Author: Urban, Volker (volker.urban@de.ibm.com) + *----------------------------------------------------------------------*/ + +#if ! defined(__EP11_H__) +#define __EP11_H__ + +#if !defined(CKR_OK) /* don't assume include guards */ +#include "pkcs11.h" +#endif + +#if !defined(INT64_MIN) +#error "We need 64-bit types, please include before this file." +#endif + +// SHA224 etc. are additions to PKCS#11 2.20 +// remove these when host migrates beyond 2.20 +// +#if !defined(CKM_SHA224) +#define CKM_SHA224 0x00000255 +#define CKM_SHA224_HMAC 0x00000256 +#define CKM_SHA224_HMAC_GENERAL 0x00000257 +#define CKM_SHA224_RSA_PKCS 0x00000046 +#define CKM_SHA224_RSA_PKCS_PSS 0x00000047 +#define CKM_SHA224_KEY_DERIVATION 0x00000396 +#define CKM_AES_CTR 0x00001086 +#define CKG_MGF1_SHA224 0x00000005 +#endif + +#if !defined(CKM_AES_CMAC) +#define CKM_AES_CMAC 0x0000108a +#endif + +#if !defined(CKM_ALG_DES3_CMAC) +#define CKM_DES3_CMAC 0x00000138 +#endif + +typedef uint64_t target_t; + +/*---------------------------------------------------------------------- + * CK_... type arguments correspond to the original PKCS#11 call's + * arguments. Standard types mean PKCS#11 objects (session, token etc.) + * are mapped to a native type (key blob, mechanism) etc. + * + * As an example, for _Encrypt and _Decrypt, a session is passed to + * the PKCS#11 function. This session needs to be matched to a key blob, + * so our _Encrypt interface takes a key/keylen buffer instead of the + * session. All other parameters should be passed through unchanged. + * + * For certain operations, such as _GenerateKey, there are no real + * PKCS#11 type parameters at this level. + */ + +CK_RV m_GenerateRandom(CK_BYTE_PTR rnd, CK_ULONG len, target_t target); + +/* note: external seeding not supported */ +CK_RV m_SeedRandom(CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen, target_t target); +CK_RV m_DigestInit(unsigned char *state, size_t * len, + const CK_MECHANISM_PTR pmech, target_t target); + +CK_RV m_Digest(const unsigned char *state, size_t slen, + CK_BYTE_PTR data, CK_ULONG len, + CK_BYTE_PTR digest, CK_ULONG_PTR dglen, target_t target); +CK_RV m_DigestUpdate(unsigned char *state, size_t slen, + CK_BYTE_PTR data, CK_ULONG dlen, target_t target); +CK_RV m_DigestKey(unsigned char *state, size_t slen, + const unsigned char *key, size_t klen, target_t target); +CK_RV m_DigestFinal(const unsigned char *state, size_t slen, + CK_BYTE_PTR digest, CK_ULONG_PTR dlen, target_t target); +CK_RV m_DigestSingle(CK_MECHANISM_PTR pmech, + CK_BYTE_PTR data, CK_ULONG len, + CK_BYTE_PTR digest, CK_ULONG_PTR dlen, target_t target); + +CK_RV m_EncryptInit(unsigned char *state, size_t * slen, + CK_MECHANISM_PTR pmech, + const unsigned char *key, size_t klen, target_t target); +CK_RV m_DecryptInit(unsigned char *state, size_t * slen, + CK_MECHANISM_PTR pmech, + const unsigned char *key, size_t klen, target_t target); + +CK_RV m_EncryptUpdate(unsigned char *state, size_t slen, + CK_BYTE_PTR plain, CK_ULONG plen, + CK_BYTE_PTR cipher, CK_ULONG_PTR clen, target_t target); +CK_RV m_DecryptUpdate(unsigned char *state, size_t slen, + CK_BYTE_PTR cipher, CK_ULONG clen, + CK_BYTE_PTR plain, CK_ULONG_PTR plen, target_t target); + +/* one-pass en/decrypt with key blob */ +CK_RV m_Encrypt(const unsigned char *state, size_t slen, + CK_BYTE_PTR plain, CK_ULONG plen, + CK_BYTE_PTR cipher, CK_ULONG_PTR clen, target_t target); +CK_RV m_Decrypt(const unsigned char *state, size_t slen, + CK_BYTE_PTR cipher, CK_ULONG clen, + CK_BYTE_PTR plain, CK_ULONG_PTR plen, target_t target); + +CK_RV m_EncryptFinal(const unsigned char *state, size_t slen, + CK_BYTE_PTR output, CK_ULONG_PTR len, target_t target); +CK_RV m_DecryptFinal(const unsigned char *state, size_t slen, + CK_BYTE_PTR output, CK_ULONG_PTR len, target_t target); + +/* en/decrypt directly with key blob */ +CK_RV m_EncryptSingle(const unsigned char *key, size_t klen, + CK_MECHANISM_PTR mech, + CK_BYTE_PTR plain, CK_ULONG plen, + CK_BYTE_PTR cipher, CK_ULONG_PTR clen, target_t target); +CK_RV m_DecryptSingle(const unsigned char *key, size_t klen, + CK_MECHANISM_PTR mech, + CK_BYTE_PTR cipher, CK_ULONG clen, + CK_BYTE_PTR plain, CK_ULONG_PTR plen, target_t target); + +/* de+encrypt in one pass, without exposing cleartext */ +CK_RV m_ReencryptSingle(const unsigned char *dkey, size_t dklen, + const unsigned char *ekey, size_t eklen, + CK_MECHANISM_PTR pdecrmech, + CK_MECHANISM_PTR pencrmech, + CK_BYTE_PTR in, CK_ULONG ilen, + CK_BYTE_PTR out, CK_ULONG_PTR olen, target_t target); + +CK_RV m_GenerateKey(CK_MECHANISM_PTR pmech, + CK_ATTRIBUTE_PTR ptempl, CK_ULONG templcount, + const unsigned char *pin, size_t pinlen, + unsigned char *key, size_t * klen, + unsigned char *csum, size_t * clen, target_t target); + +CK_RV m_GenerateKeyPair(CK_MECHANISM_PTR pmech, + CK_ATTRIBUTE_PTR ppublic, CK_ULONG pubattrs, + CK_ATTRIBUTE_PTR pprivate, CK_ULONG prvattrs, + const unsigned char *pin, size_t pinlen, + unsigned char *key, size_t * klen, + unsigned char *pubkey, size_t * pklen, target_t target); + +CK_RV m_SignInit(unsigned char *state, size_t * slen, + CK_MECHANISM_PTR alg, + const unsigned char *key, size_t klen, target_t target); +CK_RV m_VerifyInit(unsigned char *state, size_t * slen, + CK_MECHANISM_PTR alg, + const unsigned char *key, size_t klen, target_t target); + +CK_RV m_SignUpdate(unsigned char *state, size_t slen, + CK_BYTE_PTR data, CK_ULONG dlen, target_t target); +CK_RV m_VerifyUpdate(unsigned char *state, size_t slen, + CK_BYTE_PTR data, CK_ULONG dlen, target_t target); + +CK_RV m_SignFinal(const unsigned char *state, size_t stlen, + CK_BYTE_PTR sig, CK_ULONG_PTR siglen, target_t target); +CK_RV m_VerifyFinal(const unsigned char *state, size_t stlen, + CK_BYTE_PTR sig, CK_ULONG siglen, target_t target); + +CK_RV m_Sign(const unsigned char *state, size_t stlen, + CK_BYTE_PTR data, CK_ULONG dlen, + CK_BYTE_PTR sig, CK_ULONG_PTR siglen, target_t target); +CK_RV m_Verify(const unsigned char *state, size_t stlen, + CK_BYTE_PTR data, CK_ULONG dlen, + CK_BYTE_PTR sig, CK_ULONG siglen, target_t target); + +CK_RV m_SignSingle(const unsigned char *key, size_t klen, + CK_MECHANISM_PTR pmech, + CK_BYTE_PTR data, CK_ULONG dlen, + CK_BYTE_PTR sig, CK_ULONG_PTR slen, target_t target); +CK_RV m_VerifySingle(const unsigned char *key, size_t klen, + CK_MECHANISM_PTR pmech, + CK_BYTE_PTR data, CK_ULONG dlen, + CK_BYTE_PTR sig, CK_ULONG slen, target_t target); + +/* mackey is NULL for PKCS#11 formats, not for authenticated ones */ +CK_RV m_WrapKey(const unsigned char *key, size_t keylen, + const unsigned char *kek, size_t keklen, + const unsigned char *mackey, size_t mklen, + const CK_MECHANISM_PTR pmech, + CK_BYTE_PTR wrapped, CK_ULONG_PTR wlen, target_t target); + +/* mackey is NULL for PKCS#11 formats, not for authenticated ones */ +CK_RV m_UnwrapKey(const CK_BYTE_PTR wrapped, CK_ULONG wlen, + const unsigned char *kek, size_t keklen, + const unsigned char *mackey, size_t mklen, + const unsigned char *pin, size_t pinlen, + const CK_MECHANISM_PTR uwmech, + const CK_ATTRIBUTE_PTR ptempl, CK_ULONG pcount, + unsigned char *unwrapped, size_t * uwlen, + CK_BYTE_PTR csum, CK_ULONG * cslen, target_t target); + +CK_RV m_DeriveKey(CK_MECHANISM_PTR pderivemech, + CK_ATTRIBUTE_PTR ptempl, CK_ULONG templcount, + const unsigned char *basekey, size_t bklen, + const unsigned char *data, size_t dlen, + const unsigned char *pin, size_t pinlen, + unsigned char *newkey, size_t * nklen, + unsigned char *csum, size_t * cslen, target_t target); + + +CK_RV m_GetMechanismList(CK_SLOT_ID slot, + CK_MECHANISM_TYPE_PTR mechs, + CK_ULONG_PTR count, target_t target); +CK_RV m_GetMechanismInfo(CK_SLOT_ID slot, + CK_MECHANISM_TYPE mech, + CK_MECHANISM_INFO_PTR pmechinfo, target_t target); + +CK_RV m_GetAttributeValue(const unsigned char *obj, size_t olen, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, + target_t target); +CK_RV m_SetAttributeValue(unsigned char *obj, size_t olen, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, + target_t target); + + +CK_RV m_Login(CK_UTF8CHAR_PTR pin, CK_ULONG pinlen, + const unsigned char *nonce, size_t nlen, + unsigned char *pinblob, size_t * pinbloblen, target_t target); +CK_RV m_Logout(const unsigned char *pin, size_t len, target_t target); + +CK_RV m_admin(unsigned char *response1, size_t * r1len, + unsigned char *response2, size_t * r2len, + const unsigned char *cmd, size_t clen, + const unsigned char *sigs, size_t slen, target_t target); + + +/*-------------------------------------------------------------------------- + * Module management. + */ + +typedef struct XCP_ModuleSocket { + char host[256 + 1]; + uint32_t port; +} *XCP_ModuleSocket_t; + +typedef struct XCP_DomainPerf { + unsigned int lastperf[256]; +} *XCP_DomainPerf_t; + +typedef struct XCP_Module { + uint32_t version; + uint64_t flags; + uint32_t domains; + unsigned char domainmask[256 /8]; + struct XCP_ModuleSocket socket; + uint32_t module_nr; + void *mhandle; + struct XCP_DomainPerf perf; + /* ----- end of v1 fields ----- */ + uint32_t api; + /* ----- end of v2 fields ----- */ +} *XCP_Module_t ; + +typedef enum { + XCP_MFL_SOCKET = 1, + XCP_MFL_MODULE = 2, + XCP_MFL_MHANDLE = 4, + XCP_MFL_PERF = 8, + XCP_MFL_VIRTUAL = 0x10, + XCP_MFL_STRICT = 0x20, + XCP_MFL_PROBE = 0x40, + XCP_MFL_ALW_TGT_ADD = 0x80, + XCP_MFL_MAX = 0xff +} XCP_Module_Flags; + +#define XCP_MOD_VERSION_1 1 +#define XCP_MOD_VERSION_2 2 +#define XCP_TGT_INIT ~0UL + +#define XCPTGTMASK_SET_DOM(mask, domain) \ + mask[((domain)/8)] |= (1 << (7-(domain)%8)) + +int m_add_backend(const char *name, unsigned int port); +int m_init(void); +int m_shutdown(void); +int m_add_module(XCP_Module_t module, target_t *target); +int m_rm_module(XCP_Module_t module, target_t target); + + +#endif /* n defined(__EP11_H__) */ diff --git a/usr/lib/ep11_stdll/ep11_func.h b/usr/lib/ep11_stdll/ep11_func.h new file mode 100644 index 0000000..11f3df2 --- /dev/null +++ b/usr/lib/ep11_stdll/ep11_func.h @@ -0,0 +1,447 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2016-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 + */ + +typedef CK_RV (*m_GenerateRandom_t) (CK_BYTE_PTR rnd, CK_ULONG len, + target_t target); +typedef CK_RV (*m_SeedRandom_t) (CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen, + target_t target); +typedef CK_RV (*m_Digest_t) (const unsigned char *state, size_t slen, + CK_BYTE_PTR data, CK_ULONG len, + CK_BYTE_PTR digest, CK_ULONG_PTR dglen, + target_t target); +typedef CK_RV (*m_DigestInit_t) (unsigned char *state, size_t * len, + const CK_MECHANISM_PTR pmech, + target_t target); +typedef CK_RV (*m_DigestUpdate_t) (unsigned char *state, size_t slen, + CK_BYTE_PTR data, CK_ULONG dlen, + target_t target); +typedef CK_RV (*m_DigestKey_t) (unsigned char *state, size_t slen, + const unsigned char *key, size_t klen, + target_t target); +typedef CK_RV (*m_DigestFinal_t) (const unsigned char *state, + size_t slen, CK_BYTE_PTR digest, + CK_ULONG_PTR dlen, target_t target); +typedef CK_RV (*m_DigestSingle_t) (CK_MECHANISM_PTR pmech, + CK_BYTE_PTR data, CK_ULONG len, + CK_BYTE_PTR digest, CK_ULONG_PTR dlen, + target_t target); +typedef CK_RV (*m_EncryptInit_t) (unsigned char *state, size_t * slen, + CK_MECHANISM_PTR pmech, + const unsigned char *key, size_t klen, + target_t target); +typedef CK_RV (*m_DecryptInit_t) (unsigned char *state, size_t * slen, + CK_MECHANISM_PTR pmech, + const unsigned char *key, size_t klen, + target_t target); +typedef CK_RV (*m_EncryptUpdate_t) (unsigned char *state, size_t slen, + CK_BYTE_PTR plain, CK_ULONG plen, + CK_BYTE_PTR cipher, + CK_ULONG_PTR clen, target_t target); +typedef CK_RV (*m_DecryptUpdate_t) (unsigned char *state, size_t slen, + CK_BYTE_PTR cipher, CK_ULONG clen, + CK_BYTE_PTR plain, CK_ULONG_PTR plen, + target_t target); +typedef CK_RV (*m_Encrypt_t) (const unsigned char *state, size_t slen, + CK_BYTE_PTR plain, CK_ULONG plen, + CK_BYTE_PTR cipher, CK_ULONG_PTR clen, + target_t target); +typedef CK_RV (*m_Decrypt_t) (const unsigned char *state, size_t slen, + CK_BYTE_PTR cipher, CK_ULONG clen, + CK_BYTE_PTR plain, CK_ULONG_PTR plen, + target_t target); +typedef CK_RV (*m_EncryptFinal_t) (const unsigned char *state, + size_t slen, CK_BYTE_PTR output, + CK_ULONG_PTR len, target_t target); +typedef CK_RV (*m_DecryptFinal_t) (const unsigned char *state, + size_t slen, CK_BYTE_PTR output, + CK_ULONG_PTR len, target_t target); +typedef CK_RV (*m_EncryptSingle_t) (const unsigned char *key, + size_t klen, CK_MECHANISM_PTR mech, + CK_BYTE_PTR plain, CK_ULONG plen, + CK_BYTE_PTR cipher, + CK_ULONG_PTR clen, target_t target); +typedef CK_RV (*m_DecryptSingle_t) (const unsigned char *key, + size_t klen, CK_MECHANISM_PTR mech, + CK_BYTE_PTR cipher, CK_ULONG clen, + CK_BYTE_PTR plain, CK_ULONG_PTR plen, + target_t target); +typedef CK_RV (*m_ReencryptSingle_t) (const unsigned char *dkey, + size_t dklen, + const unsigned char *ekey, + size_t eklen, + CK_MECHANISM_PTR pdecrmech, + CK_MECHANISM_PTR pencrmech, + CK_BYTE_PTR in, CK_ULONG ilen, + CK_BYTE_PTR out, CK_ULONG_PTR olen, + target_t target); +typedef CK_RV (*m_GenerateKey_t) (CK_MECHANISM_PTR pmech, + CK_ATTRIBUTE_PTR ptempl, + CK_ULONG templcount, + const unsigned char *pin, + size_t pinlen, unsigned char *key, + size_t * klen, unsigned char *csum, + size_t * clen, target_t target); +typedef CK_RV (*m_GenerateKeyPair_t) (CK_MECHANISM_PTR pmech, + CK_ATTRIBUTE_PTR ppublic, + CK_ULONG pubattrs, + CK_ATTRIBUTE_PTR pprivate, + CK_ULONG prvattrs, + const unsigned char *pin, + size_t pinlen, unsigned char *key, + size_t * klen, + unsigned char *pubkey, + size_t * pklen, target_t target); +typedef CK_RV (*m_SignInit_t) (unsigned char *state, size_t * slen, + CK_MECHANISM_PTR alg, + const unsigned char *key, size_t klen, + target_t target); +typedef CK_RV (*m_VerifyInit_t) (unsigned char *state, size_t * slen, + CK_MECHANISM_PTR alg, + const unsigned char *key, size_t klen, + target_t target); +typedef CK_RV (*m_SignUpdate_t) (unsigned char *state, size_t slen, + CK_BYTE_PTR data, CK_ULONG dlen, + target_t target); +typedef CK_RV (*m_VerifyUpdate_t) (unsigned char *state, size_t slen, + CK_BYTE_PTR data, CK_ULONG dlen, + target_t target); +typedef CK_RV (*m_SignFinal_t) (const unsigned char *state, size_t stlen, + CK_BYTE_PTR sig, CK_ULONG_PTR siglen, + target_t target); +typedef CK_RV (*m_VerifyFinal_t) (const unsigned char *state, + size_t stlen, CK_BYTE_PTR sig, + CK_ULONG siglen, target_t target); +typedef CK_RV (*m_Sign_t) (const unsigned char *state, size_t stlen, + CK_BYTE_PTR data, CK_ULONG dlen, + CK_BYTE_PTR sig, CK_ULONG_PTR siglen, + target_t target); +typedef CK_RV (*m_Verify_t) (const unsigned char *state, size_t stlen, + CK_BYTE_PTR data, CK_ULONG dlen, + CK_BYTE_PTR sig, CK_ULONG siglen, + target_t target); +typedef CK_RV (*m_SignSingle_t) (const unsigned char *key, size_t klen, + CK_MECHANISM_PTR pmech, + CK_BYTE_PTR data, CK_ULONG dlen, + CK_BYTE_PTR sig, CK_ULONG_PTR slen, + target_t target); +typedef CK_RV (*m_VerifySingle_t) (const unsigned char *key, size_t klen, + CK_MECHANISM_PTR pmech, + CK_BYTE_PTR data, CK_ULONG dlen, + CK_BYTE_PTR sig, CK_ULONG slen, + target_t target); + +/* mackey is NULL for PKCS#11 formats, not for authenticated ones */ +typedef CK_RV (*m_WrapKey_t) (const unsigned char *key, size_t keylen, + const unsigned char *kek, size_t keklen, + const unsigned char *mackey, size_t mklen, + const CK_MECHANISM_PTR pmech, + CK_BYTE_PTR wrapped, CK_ULONG_PTR wlen, + target_t target); + /**/ +/* mackey is NULL for PKCS#11 formats, not for authenticated ones */ +typedef CK_RV (*m_UnwrapKey_t) (const CK_BYTE_PTR wrapped, CK_ULONG wlen, + const unsigned char *kek, size_t keklen, + const unsigned char *mackey, + size_t mklen, const unsigned char *pin, + size_t pinlen, + const CK_MECHANISM_PTR uwmech, + const CK_ATTRIBUTE_PTR ptempl, + CK_ULONG pcount, + unsigned char *unwrapped, size_t * uwlen, + CK_BYTE_PTR csum, CK_ULONG * cslen, + target_t target); + +typedef CK_RV (*m_DeriveKey_t) (CK_MECHANISM_PTR pderivemech, + CK_ATTRIBUTE_PTR ptempl, + CK_ULONG templcount, + const unsigned char *basekey, + size_t bklen, + const unsigned char *data, size_t dlen, + const unsigned char *pin, size_t pinlen, + unsigned char *newkey, size_t * nklen, + unsigned char *csum, size_t * cslen, + target_t target); + +typedef CK_RV (*m_GetMechanismList_t) (CK_SLOT_ID slot, + CK_MECHANISM_TYPE_PTR mechs, + CK_ULONG_PTR count, + target_t target); +typedef CK_RV (*m_GetMechanismInfo_t) (CK_SLOT_ID slot, + CK_MECHANISM_TYPE mech, + CK_MECHANISM_INFO_PTR pmechinfo, + target_t target); +typedef CK_RV (*m_GetAttributeValue_t) (const unsigned char *obj, + size_t olen, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount, + target_t target); +typedef CK_RV (*m_SetAttributeValue_t) (unsigned char *obj, size_t olen, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount, + target_t target); +typedef CK_RV (*m_Login_t) (CK_UTF8CHAR_PTR pin, CK_ULONG pinlen, + const unsigned char *nonce, size_t nlen, + unsigned char *pinblob, size_t * pinbloblen, + target_t target); +typedef CK_RV (*m_Logout_t) (const unsigned char *pin, size_t len, + target_t target); +typedef CK_RV (*m_admin_t) (unsigned char *response1, size_t * r1len, + unsigned char *response2, size_t * r2len, + const unsigned char *cmd, size_t clen, + const unsigned char *sigs, size_t slen, + target_t target); +typedef int (*m_add_backend_t) (const char *name, unsigned int port); +typedef int (*m_init_t) (void); +typedef int (*m_shutdown_t) (void); +typedef int (*m_add_module_t) (XCP_Module_t module, target_t *target); +typedef int (*m_rm_module_t) (XCP_Module_t module, target_t target); + +#ifndef XCP_SERIALNR_CHARS +#define XCP_SERIALNR_CHARS 8 +#endif +#ifndef XCP_ADMCTR_BYTES +#define XCP_ADMCTR_BYTES ((size_t) (128/8)) +#endif +#ifndef XCP_ADM_QUERY +#define XCP_ADM_QUERY 0x10000 +#endif +#ifndef XCP_ADMQ_DOM_CTRLPOINTS +#define XCP_ADMQ_DOM_CTRLPOINTS 6 | XCP_ADM_QUERY // domain CP +#endif + +#ifndef __xcpadm_h__ +typedef struct XCPadmresp { + uint32_t fn; + uint32_t domain; + uint32_t domainInst; + + /* module ID || module instance */ + unsigned char module[XCP_SERIALNR_CHARS + XCP_SERIALNR_CHARS]; + unsigned char modNr[XCP_SERIALNR_CHARS]; + unsigned char modInst[XCP_SERIALNR_CHARS]; + + unsigned char tctr[XCP_ADMCTR_BYTES]; /* transaction counter */ + + CK_RV rv; + uint32_t reason; + + // points to original response; NULL if no payload + // make sure it's copied if used after releasing response block + // + const unsigned char *payload; + size_t pllen; +} *XCPadmresp_t; +#endif + +#ifndef XCP_CPB_ADD_CPBS +#define XCP_CPB_ADD_CPBS 0 // allow addition (activation) of CP bits +#define XCP_CPB_DELETE_CPBS 1 // allow removal (deactivation) of CP bits + // remove both ADD_CPBs and DELETE_CPBs + // to make unit read-only +#define XCP_CPB_SIGN_ASYMM 2 // sign with private keys +#define XCP_CPB_SIGN_SYMM 3 // sign with HMAC or CMAC +#define XCP_CPB_SIGVERIFY_SYMM 4 // verify with HMAC or CMAC +#define XCP_CPB_ENCRYPT_SYMM 5 // encrypt with symmetric keys + // No asymmetric counterpart: one + // may not restrict use of public keys +#define XCP_CPB_DECRYPT_ASYMM 6 // decrypt with private keys +#define XCP_CPB_DECRYPT_SYMM 7 // decrypt with symmetric keys +#define XCP_CPB_WRAP_ASYMM 8 // key export with public keys +#define XCP_CPB_WRAP_SYMM 9 // key export with symmetric keys +#define XCP_CPB_UNWRAP_ASYMM 10 // key import with private keys +#define XCP_CPB_UNWRAP_SYMM 11 // key import with symmetric keys +#define XCP_CPB_KEYGEN_ASYMM 12 // generate asymmetric keypairs +#define XCP_CPB_KEYGEN_SYMM 13 // generate or derive symmetric keys + // including DSA parameters +#define XCP_CPB_RETAINKEYS 14 // allow backend to save semi/retained + // keys +#define XCP_CPB_SKIP_KEYTESTS 15 // disable selftests on new asymmetric + // keys +#define XCP_CPB_NON_ATTRBOUND 16 // allow keywrap without attribute-binding +#define XCP_CPB_MODIFY_OBJECTS 17 // allow changes to objects + // (Booleans only) +#define XCP_CPB_RNG_SEED 18 // allow mixing external seed to RNG +#define XCP_CPB_ALG_RAW_RSA 19 // allow RSA private-key use without + // padding (highly discouraged) +#define XCP_CPB_ALG_NFIPS2009 20 // allow non-FIPS-approved algs + // (as of 2009) + // including non-FIPS keysizes +#define XCP_CPB_ALG_NBSI2009 21 // allow non-BSI algorithms (as of 2009) + // including non-FIPS keysizes +#define XCP_CPB_KEYSZ_HMAC_ANY 22 // don't enforce minimum keysize on HMAC +#define XCP_CPB_KEYSZ_BELOW80BIT 23 // allow algorithms below 80-bit strength + // public-key operations are still allowed +#define XCP_CPB_KEYSZ_80BIT 24 // allow 80 to 111-bit algorithms +#define XCP_CPB_KEYSZ_112BIT 25 // allow 112 to 127-bit algorithms +#define XCP_CPB_KEYSZ_128BIT 26 // allow 128 to 191-bit algorithms +#define XCP_CPB_KEYSZ_192BIT 27 // allow 192 to 255-bit algorithms +#define XCP_CPB_KEYSZ_256BIT 28 // allow 256-bit algorithms +#define XCP_CPB_KEYSZ_RSA65536 29 // allow RSA public exponents below + // 0x10001 +#define XCP_CPB_ALG_RSA 30 // RSA private-key or key-encrypt use +#define XCP_CPB_ALG_DSA 31 // DSA private-key use +#define XCP_CPB_ALG_EC 32 // EC private-key use, see also + // curve restrictions +#define XCP_CPB_ALG_EC_BPOOLCRV 33 // Brainpool (E.U.) EC curves +#define XCP_CPB_ALG_EC_NISTCRV 34 // NIST/SECG EC curves +#define XCP_CPB_ALG_NFIPS2011 35 // allow non-FIPS-approved algs + // (as of 2011) + // including non-FIPS keysizes +#define XCP_CPB_ALG_NBSI2011 36 // allow non-BSI algorithms (as of 2011) + // including non-BSI keysizes +#define XCP_CPB_USER_SET_TRUSTED 37 // allow non-admins to set TRUSTED on a + // blob/SPKI +#define XCP_CPB_ALG_SKIP_CROSSCHK 38 // do not double-check sign/decrypt ops +#define XCP_CPB_WRAP_CRYPT_KEYS 39 // allow keys which can en/decrypt data + // and also un/wrap other keys +#define XCP_CPB_SIGN_CRYPT_KEYS 40 // allow keys which can en/decrypt data + // and also sign/verify +#define XCP_CPB_WRAP_SIGN_KEYS 41 // allow keys which can un/wrap data + // and also sign/verify +#define XCP_CPB_USER_SET_ATTRBOUND 42 // allow non-administrators to + // Wire format 69/82 + // mark public key objects ATTRBOUND +#define XCP_CPB_ALLOW_PASSPHRASE 43 // allow host to pass passprases, such as + // PKCS12 data, in the clear +#define XCP_CPB_WRAP_STRONGER_KEY 44 // allow wrapping of stronger keys + // by weaker keys +#define XCP_CPB_WRAP_WITH_RAW_SPKI 45 // allow wrapping with SPKIs without + // MAC and attributes +#define XCP_CPB_ALG_DH 46 // Diffie-Hellman use (private keys) +#define XCP_CPB_DERIVE 47 // allow key derivation (symmetric+EC/DH) +#define XCP_CPB_ALG_EC_25519 55 // enable support of curve25519, c41417, + // c448 and related algorithms incl. EdDSA +#define XCP_CPB_ALG_NBSI2017 61 // allow non-BSI algorithms (as of 2017) + // including non-BSI keysizes +#define XCP_CPB_CPACF_PK 64 // support data key generation and import + // for protected key +#define XCP_CPB_ALG_PQC_DILITHIUM 65 // enable support for Dilithium algorithm + +#define XCP_CPBITS_MAX XCP_CPB_ALG_PQC_DILITHIUM // marks last used CPB + +#define XCP_CPBLOCK_BITS 128 // handle CPs in this granularity +#define XCP_CPCOUNT \ + (((XCP_CPBITS_MAX + XCP_CPBLOCK_BITS-1) / XCP_CPBLOCK_BITS) * \ + XCP_CPBLOCK_BITS) +#define XCP_CP_BYTES (XCP_CPCOUNT / 8) // full blocks, incl. unused bits + +#endif + +typedef long (*xcpa_queryblock_t) (unsigned char *blk, size_t blen, + unsigned int fn, uint64_t domain, + const unsigned char *payload, size_t plen); +typedef long (*xcpa_internal_rv_t) (const unsigned char *rsp, size_t rlen, + struct XCPadmresp * rspblk, CK_RV * rv); + +typedef CK_RV (*m_get_xcp_info_t)(CK_VOID_PTR pinfo, CK_ULONG_PTR infbytes, + unsigned int query, unsigned int subquery, + target_t target); + +#ifndef CK_IBM_XCP_HOSTQ_IDX + +typedef enum { + CK_IBM_XCPQ_API = 0, /* API and build identifier */ + CK_IBM_XCPQ_MODULE = 1, /* module-level information */ + CK_IBM_XCPQ_DOMAINS = 2, /* list active domains & WK IDs */ + CK_IBM_XCPQ_DOMAIN = 3, + CK_IBM_XCPQ_SELFTEST = 4, /* integrity & algorithm tests */ + CK_IBM_XCPQ_EXT_CAPS = 5, /* extended capabilities, count */ + CK_IBM_XCPQ_EXT_CAPLIST = 6, /* extended capabilities, list */ + CK_IBM_XCPQ_AUDITLOG = 8, /* audit record or records */ + CK_IBM_XCPQ_DESCRTEXT = 9, /* human-readable text/tokens */ + CK_IBM_XCPQ_EC_CURVES = 10, /* supported elliptic curves */ + CK_IBM_XCPQ_COMPAT = 11, /* domains' compatibility modes */ + CK_IBM_XCPQ_MAX = CK_IBM_XCPQ_COMPAT +} CK_IBM_XCPQUERY_t; + +#define CK_IBM_XCP_HOSTQ_IDX 0xff000000 /* host-only queries index, min. */ +typedef enum { + CK_IBM_XCPHQ_COUNT = (int)0xff000000, /* number of host-query indexes */ + /* including this type itself */ + CK_IBM_XCPHQ_VERSION = (int)0xff000001, /* host-specific package version*/ + /* such as packaging library ID */ + CK_IBM_XCPHQ_VERSION_HASH + = (int)0xff000002, /* Assumed-unique identifier of */ + /* host code, such as version- */ + /* identifying cryptographic */ + /* hash (library signature */ + /* field...) */ + CK_IBM_XCPHQ_DIAGS = (int)0xff000003, /* Host code diagnostic level. */ + /* 0 if non-diagnostics host */ + /* code. */ + CK_IBM_XCPHQ_HVERSION = (int)0xff000004, /* Human-readable host version */ + /* identification (recommended: */ + /* UTF-8 string) */ + CK_IBM_XCPHQ_TGT_MODE = (int)0xff000005, /* Host targeting modes */ + /* returns supported target */ + /* modes as bitmask. */ + /* If not available only */ + /* compat target mode is in */ + /* use. See */ + /* CK_IBM_XCPHQ_TGT_MODES_t. */ + CK_IBM_XCPHQ_MAX = CK_IBM_XCPHQ_TGT_MODE +} CK_IBM_XCPHQUERY_t; + +typedef struct CK_IBM_XCPAPI_INFO { + CK_ULONG firmwareApi; + CK_ULONG firmwareConfig; /* truncated firmware hash */ +} CK_IBM_XCPAPI_INFO; + +typedef CK_IBM_XCPAPI_INFO CK_PTR CK_IBM_XCPAPI_INFO_PTR; + +typedef struct CK_IBM_XCP_INFO { + CK_ULONG firmwareApi; /* API ordinal number */ + /* major+minor pairs */ + CK_ULONG firmwareId; /* truncated firmwareConfig */ + + CK_VERSION firmwareVersion; /* xcp only, matches xcpConfig below */ + CK_VERSION cspVersion; + + /* hashes, possibly truncated */ + CK_BYTE firmwareConfig[ 32 ]; + CK_BYTE xcpConfig [ 32 ]; + CK_BYTE cspConfig [ 32 ]; + + CK_CHAR serialNumber[ 16 ]; /* device || instance */ + CK_CHAR utcTime [ 16 ]; + + CK_ULONG opMode2; /* currently, reserved 0 */ + CK_ULONG opMode1; /* operational mode, card-level */ + + CK_FLAGS flags; /* PKCS#11 capabilities */ + CK_FLAGS extflags; /* non-PKCS#11 capabilities */ + + CK_ULONG domains; + CK_ULONG symmStateBytes; + CK_ULONG digestStateBytes; + CK_ULONG pinBlockBytes; + CK_ULONG symmKeyBytes; + CK_ULONG spkiBytes; + CK_ULONG prvkeyBytes; + + CK_ULONG maxPayloadBytes; + CK_ULONG cpProfileBytes; + CK_ULONG controlPoints; +} CK_IBM_XCP_INFO; + +typedef CK_IBM_XCP_INFO CK_PTR CK_IBM_XCP_INFO_PTR; + +#endif + +#ifndef XCP_PINBLOB_BYTES +#define XCP_HMAC_BYTES ((size_t) (256 /8)) /* SHA-256 */ +#define XCP_WK_BYTES ((size_t) (256 /8)) /* keypart and session sizes */ +#define MOD_WRAP_BLOCKSIZE ((size_t) (128 /8)) /* blob crypt block bytecount */ +#define XCP_PIN_SALT_BYTES MOD_WRAP_BLOCKSIZE +#define XCP_PINBLOB_BYTES \ + (XCP_WK_BYTES + XCP_PIN_SALT_BYTES + XCP_HMAC_BYTES) +#define XCP_MIN_PINBYTES 8 +#define XCP_MAX_PINBYTES 16 +#endif diff --git a/usr/lib/ep11_stdll/ep11_specific.c b/usr/lib/ep11_stdll/ep11_specific.c new file mode 100644 index 0000000..b641aad --- /dev/null +++ b/usr/lib/ep11_stdll/ep11_specific.c @@ -0,0 +1,9190 @@ +/* + * 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 + */ + +/*************************************************************************** + Change Log + ========== +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "errno.h" +#include "tok_specific.h" +#include "tok_struct.h" +#include "stdll.h" +#include "attributes.h" +#include "trace.h" +#include "ock_syslog.h" +#include "ec_defs.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +#include +#endif + +#include +#include + +#include "ep11.h" +#include "ep11_func.h" +#include "ep11_specific.h" + +#define EP11SHAREDLIB_NAME "OCK_EP11_LIBRARY" +#define EP11SHAREDLIB_V3 "libep11.so.3" +#define EP11SHAREDLIB_V2 "libep11.so.2" +#define EP11SHAREDLIB_V1 "libep11.so.1" +#define EP11SHAREDLIB "libep11.so" +#define ICASHAREDLIB "libica.so.3" + +CK_RV ep11tok_get_mechanism_list(STDLL_TokData_t * tokdata, + CK_MECHANISM_TYPE_PTR mlist, + CK_ULONG_PTR count); +CK_RV ep11tok_get_mechanism_info(STDLL_TokData_t * tokdata, + CK_MECHANISM_TYPE type, + CK_MECHANISM_INFO_PTR pInfo); +CK_RV ep11tok_is_mechanism_supported(STDLL_TokData_t *tokdata, + CK_MECHANISM_TYPE type); +CK_RV ep11tok_is_mechanism_supported_ex(STDLL_TokData_t *tokdata, + CK_MECHANISM_PTR mech); + +static m_GenerateRandom_t dll_m_GenerateRandom; +static m_SeedRandom_t dll_m_SeedRandom; + +static m_Digest_t dll_m_Digest; +static m_DigestInit_t dll_m_DigestInit; +static m_DigestUpdate_t dll_m_DigestUpdate; +static m_DigestKey_t dll_m_DigestKey; +static m_DigestFinal_t dll_m_DigestFinal; +static m_DigestSingle_t dll_m_DigestSingle; + +static m_Encrypt_t dll_m_Encrypt; +static m_EncryptInit_t dll_m_EncryptInit; +static m_EncryptUpdate_t dll_m_EncryptUpdate; +static m_EncryptFinal_t dll_m_EncryptFinal; +static m_EncryptSingle_t dll_m_EncryptSingle; + +static m_Decrypt_t dll_m_Decrypt; +static m_DecryptInit_t dll_m_DecryptInit; +static m_DecryptUpdate_t dll_m_DecryptUpdate; +static m_DecryptFinal_t dll_m_DecryptFinal; +static m_DecryptSingle_t dll_m_DecryptSingle; + +static m_ReencryptSingle_t dll_m_ReencryptSingle; +static m_GenerateKey_t dll_m_GenerateKey; +static m_GenerateKeyPair_t dll_m_GenerateKeyPair; + +static m_Sign_t dll_m_Sign; +static m_SignInit_t dll_m_SignInit; +static m_SignUpdate_t dll_m_SignUpdate; +static m_SignFinal_t dll_m_SignFinal; +static m_SignSingle_t dll_m_SignSingle; + +static m_Verify_t dll_m_Verify; +static m_VerifyInit_t dll_m_VerifyInit; +static m_VerifyUpdate_t dll_m_VerifyUpdate; +static m_VerifyFinal_t dll_m_VerifyFinal; +static m_VerifySingle_t dll_m_VerifySingle; + +static m_WrapKey_t dll_m_WrapKey; +static m_UnwrapKey_t dll_m_UnwrapKey; +static m_DeriveKey_t dll_m_DeriveKey; + +static m_GetMechanismList_t dll_m_GetMechanismList; +static m_GetMechanismInfo_t dll_m_GetMechanismInfo; +static m_GetAttributeValue_t dll_m_GetAttributeValue; +static m_SetAttributeValue_t dll_m_SetAttributeValue; + +static m_Login_t dll_m_Login; +static m_Logout_t dll_m_Logout; +static m_admin_t dll_m_admin; +static m_add_backend_t dll_m_add_backend; +static m_init_t dll_m_init; +static m_shutdown_t dll_m_shutdown; +static m_add_module_t dll_m_add_module; +static m_rm_module_t dll_m_rm_module; + +static xcpa_queryblock_t dll_xcpa_queryblock; +static xcpa_internal_rv_t dll_xcpa_internal_rv; + +static m_get_xcp_info_t dll_m_get_xcp_info; + +#ifdef DEBUG + +/* a simple function for dumping out a memory area */ +static inline void hexdump(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'; + TRACE_DEBUG("%s\n", line); + } +} + +#define TRACE_DEBUG_DUMP(_buf, _buflen) hexdump(_buf, _buflen) + +#endif /* DEBUG */ + +const char manuf[] = "IBM"; +const char model[] = "EP11"; +const char descr[] = "IBM EP11 token"; +const char label[] = "ep11tok"; + +/* largest blobsize ever seen is about 5k (for 4096 mod bits RSA keys) */ +#define MAX_BLOBSIZE 8192 +#define MAX_CSUMSIZE 64 +#define MAX_DIGEST_STATE_BYTES 1024 +#define MAX_CRYPT_STATE_BYTES 8192 +#define MAX_SIGN_STATE_BYTES 8192 +#define MAX_APQN 256 + +/* wrap_key is used for importing keys */ +static const char wrap_key_name[] = "EP11_wrapkey"; + +typedef struct cp_mech_config { + CK_MECHANISM_TYPE mech; // the mechanism ID + struct cp_mech_config *next; // next mechanism, or NULL +} cp_mech_config_t; + + +typedef struct cp_config { + unsigned long int cp; // control point number + cp_mech_config_t *mech; // list of mechanisms affected by this CP + struct cp_config *next; // next control point, or NULL +} cp_config_t; + +typedef struct { + SESSION *session; + CK_BYTE session_id[SHA256_HASH_SIZE]; + CK_BYTE vhsm_pin[XCP_MAX_PINBYTES]; + CK_BYTE flags; + CK_BYTE session_pin_blob[XCP_PINBLOB_BYTES]; + CK_OBJECT_HANDLE session_object; + CK_BYTE vhsm_pin_blob[XCP_PINBLOB_BYTES]; + CK_OBJECT_HANDLE vhsm_object; +} ep11_session_t; + +#define EP11_SESS_PINBLOB_VALID 0x01 +#define EP11_VHSM_PINBLOB_VALID 0x02 +#define EP11_VHSMPIN_VALID 0x10 +#define EP11_STRICT_MODE 0x40 +#define EP11_VHSM_MODE 0x80 + +#define DEFAULT_EP11_PIN " " + +#define CKH_IBM_EP11_SESSION CKH_VENDOR_DEFINED + 1 +#define CKH_IBM_EP11_VHSMPIN CKH_VENDOR_DEFINED + 2 + +#define PUBLIC_SESSION_ID_LENGTH 16 + +#define MAX_RETRY_COUNT 100 + +#define RETRY_START do { \ + int retry_count; \ + for(retry_count = 0; \ + retry_count < MAX_RETRY_COUNT; \ + retry_count ++) { + +#define RETRY_END(rc, tokdata, session) if ((rc) != CKR_SESSION_CLOSED) \ + break; \ + (rc) = ep11tok_relogin_session( \ + tokdata, session); \ + if ((rc) != CKR_OK) \ + break; \ + } \ + } while (0); + +#define CKF_EP11_HELPER_SESSION 0x80000000 + +static CK_BOOL ep11_is_session_object(CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len); +static CK_RV ep11tok_relogin_session(STDLL_TokData_t * tokdata, SESSION * session); +static void ep11_get_pin_blob(ep11_session_t * ep11_session, CK_BOOL is_session_obj, + CK_BYTE ** pin_blob, CK_ULONG * pin_blob_len); +static CK_RV ep11_open_helper_session(STDLL_TokData_t * tokdata, SESSION * sess, + CK_SESSION_HANDLE_PTR phSession); +static CK_RV ep11_close_helper_session(STDLL_TokData_t * tokdata, + ST_SESSION_HANDLE * sSession); + +static void free_cp_config(cp_config_t * cp); +#ifdef DEBUG +static const char *ep11_get_cp(unsigned int cp); +#endif +static CK_ULONG ep11_get_cp_by_name(const char *name); +static CK_RV check_cps_for_mechanism(cp_config_t * cp_config, + CK_MECHANISM_TYPE mech, + unsigned char *cp, size_t cp_len, + size_t max_cp_index); +static CK_RV get_control_points(STDLL_TokData_t * tokdata, + unsigned char *cp, size_t * cp_len, + size_t *max_cp_index); + +typedef struct ep11_card_version { + struct ep11_card_version *next; + CK_ULONG card_type; + CK_VERSION firmware_version; + CK_ULONG firmware_API_version; +} ep11_card_version_t; + +static CK_RV ep11tok_get_ep11_library_version(CK_VERSION *lib_version); +static CK_RV ep11tok_get_ep11_version(STDLL_TokData_t *tokdata); +static void free_card_versions(ep11_card_version_t *card_version); +static int check_card_version(STDLL_TokData_t *tokdata, CK_ULONG card_type, + const CK_VERSION *ep11_lib_version, + const CK_VERSION *firmware_version, + const CK_ULONG *firmware_API_version); +static int compare_ck_version(const CK_VERSION *v1, const CK_VERSION *v2); + +typedef struct { + const CK_VERSION *min_lib_version; + const CK_VERSION *min_firmware_version; + const CK_ULONG *min_firmware_API_version; + CK_ULONG card_type; +} version_req_t; + +static int check_required_versions(STDLL_TokData_t *tokdata, + const version_req_t req[], + CK_ULONG num_req); + +/* EP11 Firmware levels that contain the HMAC min/max keysize fix */ +static const CK_VERSION cex4p_hmac_fix = { .major = 4, .minor = 20 }; +static const CK_VERSION cex5p_hmac_fix = { .major = 6, .minor = 3 }; +static const CK_VERSION cex6p_hmac_fix = { .major = 6, .minor = 9 }; + +static const version_req_t hmac_req_versions[] = { + { .card_type = 4, .min_firmware_version = &cex4p_hmac_fix }, + { .card_type = 5, .min_firmware_version = &cex5p_hmac_fix }, + { .card_type = 6, .min_firmware_version = &cex6p_hmac_fix } +}; +#define NUM_HMAC_REQ (sizeof(hmac_req_versions) / sizeof(version_req_t)) + +static const CK_VERSION cex7p_ibm_sha3_support = { .major = 7, .minor = 11 }; + +static const version_req_t ibm_sha3_req_versions[] = { + { .card_type = 7, .min_firmware_version = &cex7p_ibm_sha3_support } +}; +#define NUM_IBM_SHA3_REQ (sizeof(ibm_sha3_req_versions) / sizeof(version_req_t)) + +static const CK_VERSION cex7p_cmac_support = { .major = 7, .minor = 11 }; + +static const version_req_t cmac_req_versions[] = { + { .card_type = 7, .min_firmware_version = &cex7p_cmac_support } +}; +#define NUM_CMAC_REQ (sizeof(cmac_req_versions) / sizeof(version_req_t)) + +static const CK_VERSION cex7p_oaep_sha2_support = { .major = 7, .minor = 13 }; + +static const version_req_t oaep_sha2_req_versions[] = { + { .card_type = 7, .min_firmware_version = &cex7p_oaep_sha2_support } +}; +#define NUM_OAEP_SHA2_REQ (sizeof(oaep_sha2_req_versions) / sizeof(version_req_t)) + +static const CK_VERSION cex7p_edwards_support = { .major = 7, .minor = 15 }; + +static const version_req_t edwards_req_versions[] = { + { .card_type = 7, .min_firmware_version = &cex7p_edwards_support } +}; +#define NUM_EDWARDS_REQ (sizeof(edwards_req_versions) / sizeof(version_req_t)) + +static const CK_VERSION ibm_cex7p_dilithium_support = { .major = 7, .minor = 15 }; + +static const version_req_t ibm_dilithium_req_versions[] = { + { .card_type = 7, .min_firmware_version = &ibm_cex7p_dilithium_support } +}; +#define NUM_DILITHIUM_REQ (sizeof(ibm_dilithium_req_versions) / sizeof(version_req_t)) + +/* Definitions for loading libica dynamically */ + +typedef unsigned int (*ica_sha1_t)(unsigned int message_part, + unsigned int input_length, + unsigned char *input_data, + sha_context_t *sha_context, + unsigned char *output_data); + +typedef unsigned int (*ica_sha224_t)(unsigned int message_part, + unsigned int input_length, + unsigned char *input_data, + sha256_context_t *sha_context, + unsigned char *output_data); + +typedef unsigned int (*ica_sha256_t)(unsigned int message_part, + unsigned int input_length, + unsigned char *input_data, + sha256_context_t *sha_context, + unsigned char *output_data); + +typedef unsigned int (*ica_sha384_t)(unsigned int message_part, + unsigned int input_length, + unsigned char *input_data, + sha512_context_t *sha_context, + unsigned char *output_data); + +typedef unsigned int (*ica_sha512_t)(unsigned int message_part, + unsigned int input_length, + unsigned char *input_data, + sha512_context_t *sha_context, + unsigned char *output_data); + +typedef unsigned int (*ica_sha512_224_t)(unsigned int message_part, + unsigned int input_length, + unsigned char *input_data, + sha512_context_t *sha_context, + unsigned char *output_data); + +typedef unsigned int (*ica_sha512_256_t)(unsigned int message_part, + unsigned int input_length, + unsigned char *input_data, + sha512_context_t *sha_context, + unsigned char *output_data); + +#ifdef SHA3_224 +typedef unsigned int (*ica_sha3_224_t)(unsigned int message_part, + unsigned int input_length, + unsigned char *input_data, + sha3_224_context_t *sha3_224_context, + unsigned char *output_data); + +typedef unsigned int (*ica_sha3_256_t)(unsigned int message_part, + unsigned int input_length, + unsigned char *input_data, + sha3_256_context_t *sha3_256_context, + unsigned char *output_data); + +typedef unsigned int (*ica_sha3_384_t)(unsigned int message_part, + uint64_t input_length, + unsigned char *input_data, + sha3_384_context_t *sha3_384_context, + unsigned char *output_data); + +typedef unsigned int (*ica_sha3_512_t)(unsigned int message_part, + uint64_t input_length, + unsigned char *input_data, + sha3_512_context_t *sha3_512_context, + unsigned char *output_data); +#endif + +typedef struct { + CK_BYTE buffer[MAX_SHA_BLOCK_SIZE]; + CK_ULONG block_size; + CK_ULONG offset; + CK_BBOOL first; + union { + sha_context_t sha1; + sha256_context_t sha256; + sha512_context_t sha512; +#ifdef SHA3_224 + sha3_224_context_t sha3_224; + sha3_256_context_t sha3_256; + sha3_384_context_t sha3_384; + sha3_512_context_t sha3_512; +#endif + } ctx; +} libica_sha_context_t; + +typedef struct { + void *library; + ica_sha1_t ica_sha1; + ica_sha224_t ica_sha224; + ica_sha256_t ica_sha256; + ica_sha384_t ica_sha384; + ica_sha512_t ica_sha512; + ica_sha512_224_t ica_sha512_224; + ica_sha512_256_t ica_sha512_256; +#ifdef SHA3_224 + ica_sha3_224_t ica_sha3_224; + ica_sha3_256_t ica_sha3_256; + ica_sha3_384_t ica_sha3_384; + ica_sha3_512_t ica_sha3_512; +#endif +} libica_t; + +/* target list of adapters/domains, specified in a config file by user, + tells the device driver which adapter/domain pairs should be used, + they must have the same master key */ +typedef struct { + short format; + short length; + short apqns[2 * MAX_APQN]; +} __attribute__ ((packed)) ep11_target_t; + +/* EP11 token private data */ +typedef struct { + target_t target; + ep11_target_t target_list; + CK_BYTE raw2key_wrap_blob[MAX_BLOBSIZE]; + size_t raw2key_wrap_blob_l; + int cka_sensitive_default_true; + char cp_filter_config_filename[PATH_MAX]; + cp_config_t *cp_config; + unsigned char control_points[XCP_CP_BYTES]; + size_t control_points_len; + size_t max_control_point_index; + int strict_mode; + int vhsm_mode; + int optimize_single_ops; + int digest_libica; + char digest_libica_path[PATH_MAX]; + libica_t libica; + CK_VERSION ep11_lib_version; + ep11_card_version_t *card_versions; + CK_ULONG used_firmware_API_version; + CK_CHAR serialNumber[16]; +} ep11_private_data_t; + +static CK_RV ep11tok_setup_target(STDLL_TokData_t *tokdata); + +static CK_RV get_ep11_target_for_apqn(uint_32 adapter, uint_32 domain, + target_t *target); +static void free_ep11_target_for_apqn(target_t target); + + +/* defined in the makefile, ep11 library can run standalone (without HW card), + crypto algorithms are implemented in software then (no secure key) */ + + +typedef struct const_info { + unsigned const int code; + const char *name; +} const_info_t; + +#define CONSTINFO(_X) { (_X), (#_X) } + +/* mechanisms defined by EP11 with an invalid (outdated) ID */ +#define CKM_EP11_SHA512_224 0x000002B0 // 0x00000048 in PKCS#11 +#define CKM_EP11_SHA512_224_HMAC 0x000002B1 // 0x00000049 in PKCS#11 +#define CKM_EP11_SHA512_224_HMAC_GENERAL 0x000002B2 // 0x0000004A in PKCS#11 +#define CKM_EP11_SHA512_256 0x000002C0 // 0x0000004C in PKCS#11 +#define CKM_EP11_SHA512_256_HMAC 0x000002C1 // 0x0000004D in PKCS#11 +#define CKM_EP11_SHA512_256_HMAC_GENERAL 0x000002C2 // 0x0000004E in PKCS#11 + +/* Vendor specific mechanisms unknown by ock, but known by EP11 */ +#define CKM_IBM_ECDSA_SHA224 CKM_VENDOR_DEFINED + 0x00010008 +#define CKM_IBM_ECDSA_SHA256 CKM_VENDOR_DEFINED + 0x00010009 +#define CKM_IBM_ECDSA_SHA384 CKM_VENDOR_DEFINED + 0x0001000A +#define CKM_IBM_ECDSA_SHA512 CKM_VENDOR_DEFINED + 0x0001000B +#define CKM_IBM_EC_MULTIPLY CKM_VENDOR_DEFINED + 0x0001000C +#define CKM_IBM_EAC CKM_VENDOR_DEFINED + 0x0001000D +#define CKM_IBM_TESTCODE CKM_VENDOR_DEFINED + 0x0001000E +#define CKM_IBM_SHA512_256 CKM_VENDOR_DEFINED + 0x00010012 +#define CKM_IBM_SHA512_224 CKM_VENDOR_DEFINED + 0x00010013 +#define CKM_IBM_SHA512_256_HMAC CKM_VENDOR_DEFINED + 0x00010014 +#define CKM_IBM_SHA512_224_HMAC CKM_VENDOR_DEFINED + 0x00010015 +#define CKM_IBM_SHA512_256_KEY_DERIVATION CKM_VENDOR_DEFINED + 0x00010016 +#define CKM_IBM_SHA512_224_KEY_DERIVATION CKM_VENDOR_DEFINED + 0x00010017 +#define CKM_IBM_EDDSA_PH_SHA512 CKM_VENDOR_DEFINED + 0x0001001D +#define CKM_IBM_SIPHASH CKM_VENDOR_DEFINED + 0x00010021 +#define CKM_IBM_DILITHIUM CKM_VENDOR_DEFINED + 0x00010023 +#define CKM_IBM_CLEARKEY_TRANSPORT CKM_VENDOR_DEFINED + 0x00020001 +#define CKM_IBM_ATTRIBUTEBOUND_WRAP CKM_VENDOR_DEFINED + 0x00020004 +#define CKM_IBM_TRANSPORTKEY CKM_VENDOR_DEFINED + 0x00020005 +#define CKM_IBM_DH_PKCS_DERIVE_RAW CKM_VENDOR_DEFINED + 0x00020006 +#define CKM_IBM_ECDH1_DERIVE_RAW CKM_VENDOR_DEFINED + 0x00020007 +#define CKM_IBM_WIRETEST CKM_VENDOR_DEFINED + 0x00030004 +#define CKM_IBM_RETAINKEY CKM_VENDOR_DEFINED + 0x00040001 +#define CKM_IBM_SM3 CKM_VENDOR_DEFINED + 0x0005000e +#define CKM_IBM_CPACF_WRAP CKM_VENDOR_DEFINED + 0x00060001 + +static CK_RV cleanse_attribute(TEMPLATE *template, + CK_ATTRIBUTE_TYPE attr_type) +{ + CK_ATTRIBUTE *attr; + + if (!template_attribute_find(template, attr_type, &attr)) + return CKR_FUNCTION_FAILED; + + OPENSSL_cleanse(attr->pValue, attr->ulValueLen); + + return CKR_OK; +} + +static CK_RV check_key_attributes(STDLL_TokData_t * tokdata, + CK_KEY_TYPE kt, CK_OBJECT_CLASS kc, + CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, + CK_ATTRIBUTE_PTR * p_attrs, + CK_ULONG * p_attrs_len) +{ + + CK_RV rc; + CK_ULONG i; + CK_BBOOL cktrue = TRUE; + CK_ULONG check_types_pub[] = { CKA_VERIFY, CKA_ENCRYPT, CKA_WRAP }; + CK_ULONG check_types_priv[] = { CKA_SIGN, CKA_DECRYPT, CKA_UNWRAP }; + CK_ULONG check_types_sec[] = + { CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP }; + CK_ULONG check_types_sec_sensitive[] = + { CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SENSITIVE }; + CK_ULONG check_types_gen_sec[] = + { CKA_SIGN, CKA_VERIFY, CKA_ENCRYPT, CKA_DECRYPT }; + CK_ULONG check_types_gen_sec_sensitive[] = + { CKA_SIGN, CKA_VERIFY, CKA_ENCRYPT, CKA_DECRYPT, CKA_SENSITIVE }; + CK_ULONG check_types_derive[] = { CKA_DERIVE }; + CK_ULONG *check_types = NULL; + CK_BBOOL *check_values[] = { &cktrue, &cktrue, &cktrue, &cktrue, &cktrue }; + CK_ULONG attr_cnt = 0; + ep11_private_data_t *ep11_data = tokdata->private_data; + + /* check/add attributes for public key template */ + if ((rc = dup_attribute_array(attrs, attrs_len, p_attrs, p_attrs_len))) + return rc; + + switch (kc) { + case CKO_SECRET_KEY: + if (kt == CKK_GENERIC_SECRET) { + if (ep11_data->cka_sensitive_default_true) { + check_types = &check_types_gen_sec_sensitive[0]; + attr_cnt = + sizeof(check_types_gen_sec_sensitive) / sizeof(CK_ULONG); + + } else { + check_types = &check_types_gen_sec[0]; + attr_cnt = sizeof(check_types_gen_sec) / sizeof(CK_ULONG); + } + } else { + if (ep11_data->cka_sensitive_default_true) { + check_types = &check_types_sec_sensitive[0]; + attr_cnt = sizeof(check_types_sec_sensitive) / sizeof(CK_ULONG); + } else { + check_types = &check_types_sec[0]; + attr_cnt = sizeof(check_types_sec) / sizeof(CK_ULONG); + } + } + break; + case CKO_PUBLIC_KEY: + if ((kt == CKK_EC) || (kt == CKK_ECDSA) || (kt == CKK_DSA)) { + check_types = &check_types_pub[0]; + attr_cnt = 1; /* only CKA_VERIFY */ + } else if (kt == CKK_RSA) { + check_types = &check_types_pub[0]; + attr_cnt = sizeof(check_types_pub) / sizeof(CK_ULONG); + } + /* do nothing for CKM_DH_PKCS_KEY_PAIR_GEN + and CKM_DH_PKCS_PARAMETER_GEN and CKK_IBM_PQC_DILITHIUM */ + break; + case CKO_PRIVATE_KEY: + if ((kt == CKK_EC) || (kt == CKK_ECDSA) || (kt == CKK_DSA)) { + check_types = &check_types_priv[0]; + attr_cnt = 1; /* only CKA_SIGN */ + } else if (kt == CKK_RSA) { + check_types = &check_types_priv[0]; + attr_cnt = sizeof(check_types_priv) / sizeof(CK_ULONG); + } else if (kt == CKK_DH) { + check_types = &check_types_derive[0]; + attr_cnt = sizeof(check_types_derive) / sizeof(CK_ULONG); + } + /* Do nothing for CKK_IBM_PQC_DILITHIUM */ + break; + default: + return CKR_OK; + } + + for (i = 0; i < attr_cnt; i++, check_types++) { + CK_ATTRIBUTE_PTR attr = get_attribute_by_type(*p_attrs, + *p_attrs_len, + *check_types); + if (!attr) { + rc = add_to_attribute_array(p_attrs, p_attrs_len, + *check_types, + (CK_BYTE *) check_values[i], + sizeof(*check_values[i])); + if (rc) + goto cleanup; + } + } + return CKR_OK; +cleanup: + if (rc) { + free_attribute_array(*p_attrs, *p_attrs_len); + *p_attrs = NULL; + *p_attrs_len = 0; + } + return rc; +} + +static CK_RV override_key_attributes(STDLL_TokData_t *tokdata, + CK_KEY_TYPE kt, CK_OBJECT_CLASS kc, + CK_ATTRIBUTE_PTR attrs, + CK_ULONG attrs_len) +{ + CK_ULONG i; + CK_BBOOL cktrue = TRUE; + CK_ULONG override_types_public_key[] = + { CKA_VERIFY, CKA_ENCRYPT }; + CK_ULONG *override_types = NULL; + CK_BBOOL *override_values[] = { &cktrue, &cktrue }; + CK_ULONG attr_cnt = 0; + + UNUSED(tokdata); + + switch (kc) { + case CKO_PUBLIC_KEY: + /* + * EP11 does not allow to restrict public RSA/DSA/EC keys with + * CKA_VERIFY=FALSE and/or CKA_ENCRYPT=FALSE since it can not + * technically enforce the restrictions. Therefore override these + * attributes for the EP11 library, but keep the original attribute + * values in the object. + */ + if (kt != CKK_EC && kt != CKK_RSA && kt != CKK_DSA) + return CKR_OK; + + override_types = &override_types_public_key[0]; + attr_cnt = sizeof(override_types_public_key) / + sizeof(override_types_public_key[0]); + break; + + default: + return CKR_OK; + } + + for (i = 0; i < attr_cnt; i++, override_types++) { + CK_ATTRIBUTE_PTR attr = get_attribute_by_type(attrs, + attrs_len, + *override_types); + if (attr != NULL) + *(CK_BBOOL *)(attr->pValue) = *override_values[i]; + } + + return CKR_OK; +} + +static CK_RV check_key_restriction(OBJECT *key_obj, CK_ATTRIBUTE_TYPE type) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + CK_BBOOL flag; + + rc = template_attribute_find(key_obj->template, type, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find attribute 0x%lx for the key.\n", type); + return CKR_KEY_FUNCTION_NOT_PERMITTED; + } + + flag = *(CK_BBOOL *) attr->pValue; + if (flag != TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_FUNCTION_NOT_PERMITTED)); + return CKR_KEY_FUNCTION_NOT_PERMITTED; + } + + return CKR_OK; +} + +static CK_RV ep11_get_keytype(CK_ATTRIBUTE * attrs, CK_ULONG attrs_len, + CK_MECHANISM_PTR mech, CK_ULONG * type, CK_ULONG * class) +{ + CK_ULONG i; + CK_RV rc = CKR_TEMPLATE_INCONSISTENT; + + *type = 0; + *class = 0; + + for (i = 0; i < attrs_len; i++) { + if (attrs[i].type == CKA_CLASS) + *class = *(CK_ULONG *) attrs[i].pValue; + } + + for (i = 0; i < attrs_len; i++) { + if (attrs[i].type == CKA_KEY_TYPE) { + *type = *(CK_ULONG *) attrs[i].pValue; + 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_DES3_KEY_GEN: + *type = CKK_DES3; + break; + case CKM_CDMF_KEY_GEN: + *type = CKK_CDMF; + break; + case CKM_AES_KEY_GEN: + *type = CKK_AES; + 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; + default: + return CKR_MECHANISM_INVALID; + } + + rc = CKR_OK; + + return rc; +} + +static const_info_t ep11_mechanisms[] = { + CONSTINFO(CKM_RSA_PKCS_KEY_PAIR_GEN), + CONSTINFO(CKM_RSA_PKCS), + CONSTINFO(CKM_RSA_9796), + CONSTINFO(CKM_RSA_X_509), + CONSTINFO(CKM_MD2_RSA_PKCS), + CONSTINFO(CKM_MD5_RSA_PKCS), + CONSTINFO(CKM_SHA1_RSA_PKCS), + CONSTINFO(CKM_RIPEMD128_RSA_PKCS), + CONSTINFO(CKM_RIPEMD160_RSA_PKCS), + CONSTINFO(CKM_RSA_PKCS_OAEP), + CONSTINFO(CKM_RSA_X9_31_KEY_PAIR_GEN), + CONSTINFO(CKM_RSA_X9_31), + CONSTINFO(CKM_SHA1_RSA_X9_31), + CONSTINFO(CKM_RSA_PKCS_PSS), + CONSTINFO(CKM_SHA1_RSA_PKCS_PSS), + CONSTINFO(CKM_DSA_KEY_PAIR_GEN), + CONSTINFO(CKM_DSA), + CONSTINFO(CKM_DSA_SHA1), + CONSTINFO(CKM_DH_PKCS_KEY_PAIR_GEN), + CONSTINFO(CKM_DH_PKCS_DERIVE), + CONSTINFO(CKM_X9_42_DH_KEY_PAIR_GEN), + CONSTINFO(CKM_X9_42_DH_DERIVE), + CONSTINFO(CKM_X9_42_DH_HYBRID_DERIVE), + CONSTINFO(CKM_X9_42_MQV_DERIVE), + CONSTINFO(CKM_SHA256_RSA_PKCS), + CONSTINFO(CKM_SHA384_RSA_PKCS), + CONSTINFO(CKM_SHA512_RSA_PKCS), + CONSTINFO(CKM_RC2_KEY_GEN), + CONSTINFO(CKM_RC2_ECB), + CONSTINFO(CKM_RC2_CBC), + CONSTINFO(CKM_RC2_MAC), + CONSTINFO(CKM_RC2_MAC_GENERAL), + CONSTINFO(CKM_RC2_CBC_PAD), + CONSTINFO(CKM_RC4_KEY_GEN), + CONSTINFO(CKM_RC4), + CONSTINFO(CKM_DES_KEY_GEN), + CONSTINFO(CKM_DES_ECB), + CONSTINFO(CKM_DES_CBC), + CONSTINFO(CKM_DES_MAC), + CONSTINFO(CKM_DES_MAC_GENERAL), + CONSTINFO(CKM_DES_CBC_PAD), + CONSTINFO(CKM_DES2_KEY_GEN), + CONSTINFO(CKM_DES3_KEY_GEN), + CONSTINFO(CKM_DES3_ECB), + CONSTINFO(CKM_DES3_CBC), + CONSTINFO(CKM_DES3_MAC), + CONSTINFO(CKM_DES3_MAC_GENERAL), + CONSTINFO(CKM_DES3_CMAC), + CONSTINFO(CKM_DES3_CMAC_GENERAL), + CONSTINFO(CKM_DES3_CBC_PAD), + CONSTINFO(CKM_CDMF_KEY_GEN), + CONSTINFO(CKM_CDMF_ECB), + CONSTINFO(CKM_CDMF_CBC), + CONSTINFO(CKM_CDMF_MAC), + CONSTINFO(CKM_CDMF_MAC_GENERAL), + CONSTINFO(CKM_CDMF_CBC_PAD), + CONSTINFO(CKM_MD2), + CONSTINFO(CKM_MD2_HMAC), + CONSTINFO(CKM_MD2_HMAC_GENERAL), + CONSTINFO(CKM_MD5), + CONSTINFO(CKM_MD5_HMAC), + CONSTINFO(CKM_MD5_HMAC_GENERAL), + CONSTINFO(CKM_SHA_1), + CONSTINFO(CKM_SHA_1_HMAC), + CONSTINFO(CKM_SHA_1_HMAC_GENERAL), + CONSTINFO(CKM_RIPEMD128), + CONSTINFO(CKM_RIPEMD128_HMAC), + CONSTINFO(CKM_RIPEMD128_HMAC_GENERAL), + CONSTINFO(CKM_RIPEMD160), + CONSTINFO(CKM_RIPEMD160_HMAC), + CONSTINFO(CKM_RIPEMD160_HMAC_GENERAL), + CONSTINFO(CKM_SHA224), + CONSTINFO(CKM_SHA224_HMAC), + CONSTINFO(CKM_SHA224_HMAC_GENERAL), + CONSTINFO(CKM_SHA256), + CONSTINFO(CKM_SHA256_HMAC), + CONSTINFO(CKM_SHA256_HMAC_GENERAL), + CONSTINFO(CKM_SHA384), + CONSTINFO(CKM_SHA384_HMAC), + CONSTINFO(CKM_SHA384_HMAC_GENERAL), + CONSTINFO(CKM_SHA512), + CONSTINFO(CKM_SHA512_HMAC), + CONSTINFO(CKM_SHA512_HMAC_GENERAL), + CONSTINFO(CKM_CAST_KEY_GEN), + CONSTINFO(CKM_CAST_ECB), + CONSTINFO(CKM_CAST_CBC), + CONSTINFO(CKM_CAST_MAC), + CONSTINFO(CKM_CAST_MAC_GENERAL), + CONSTINFO(CKM_CAST_CBC_PAD), + CONSTINFO(CKM_CAST3_KEY_GEN), + CONSTINFO(CKM_CAST3_ECB), + CONSTINFO(CKM_CAST3_CBC), + CONSTINFO(CKM_CAST3_MAC), + CONSTINFO(CKM_CAST3_MAC_GENERAL), + CONSTINFO(CKM_CAST3_CBC_PAD), + CONSTINFO(CKM_CAST5_KEY_GEN), + CONSTINFO(CKM_CAST5_ECB), + CONSTINFO(CKM_CAST5_CBC), + CONSTINFO(CKM_CAST5_MAC), + CONSTINFO(CKM_CAST5_MAC_GENERAL), + CONSTINFO(CKM_CAST5_CBC_PAD), + CONSTINFO(CKM_RC5_KEY_GEN), + CONSTINFO(CKM_RC5_ECB), + CONSTINFO(CKM_RC5_CBC), + CONSTINFO(CKM_RC5_MAC), + CONSTINFO(CKM_RC5_MAC_GENERAL), + CONSTINFO(CKM_RC5_CBC_PAD), + CONSTINFO(CKM_IDEA_KEY_GEN), + CONSTINFO(CKM_IDEA_ECB), + CONSTINFO(CKM_IDEA_CBC), + CONSTINFO(CKM_IDEA_MAC), + CONSTINFO(CKM_IDEA_MAC_GENERAL), + CONSTINFO(CKM_IDEA_CBC_PAD), + CONSTINFO(CKM_GENERIC_SECRET_KEY_GEN), + CONSTINFO(CKM_CONCATENATE_BASE_AND_KEY), + CONSTINFO(CKM_CONCATENATE_BASE_AND_DATA), + CONSTINFO(CKM_CONCATENATE_DATA_AND_BASE), + CONSTINFO(CKM_XOR_BASE_AND_DATA), + CONSTINFO(CKM_EXTRACT_KEY_FROM_KEY), + CONSTINFO(CKM_SSL3_PRE_MASTER_KEY_GEN), + CONSTINFO(CKM_SSL3_MASTER_KEY_DERIVE), + CONSTINFO(CKM_SSL3_KEY_AND_MAC_DERIVE), + CONSTINFO(CKM_SSL3_MASTER_KEY_DERIVE_DH), + CONSTINFO(CKM_TLS_PRE_MASTER_KEY_GEN), + CONSTINFO(CKM_TLS_MASTER_KEY_DERIVE), + CONSTINFO(CKM_TLS_KEY_AND_MAC_DERIVE), + CONSTINFO(CKM_TLS_MASTER_KEY_DERIVE_DH), + CONSTINFO(CKM_SSL3_MD5_MAC), + CONSTINFO(CKM_SSL3_SHA1_MAC), + CONSTINFO(CKM_MD5_KEY_DERIVATION), + CONSTINFO(CKM_MD2_KEY_DERIVATION), + CONSTINFO(CKM_SHA1_KEY_DERIVATION), + CONSTINFO(CKM_SHA256_KEY_DERIVATION), + CONSTINFO(CKM_PBE_MD2_DES_CBC), + CONSTINFO(CKM_PBE_MD5_DES_CBC), + CONSTINFO(CKM_PBE_MD5_CAST_CBC), + CONSTINFO(CKM_PBE_MD5_CAST3_CBC), + CONSTINFO(CKM_PBE_MD5_CAST5_CBC), + CONSTINFO(CKM_PBE_SHA1_CAST5_CBC), + CONSTINFO(CKM_PBE_SHA1_RC4_128), + CONSTINFO(CKM_PBE_SHA1_RC4_40), + CONSTINFO(CKM_PBE_SHA1_DES3_EDE_CBC), + CONSTINFO(CKM_PBE_SHA1_DES2_EDE_CBC), + CONSTINFO(CKM_PBE_SHA1_RC2_128_CBC), + CONSTINFO(CKM_PBE_SHA1_RC2_40_CBC), + CONSTINFO(CKM_PKCS5_PBKD2), + CONSTINFO(CKM_PBA_SHA1_WITH_SHA1_HMAC), + CONSTINFO(CKM_KEY_WRAP_LYNKS), + CONSTINFO(CKM_KEY_WRAP_SET_OAEP), + CONSTINFO(CKM_SKIPJACK_KEY_GEN), + CONSTINFO(CKM_SKIPJACK_ECB64), + CONSTINFO(CKM_SKIPJACK_CBC64), + CONSTINFO(CKM_SKIPJACK_OFB64), + CONSTINFO(CKM_SKIPJACK_CFB64), + CONSTINFO(CKM_SKIPJACK_CFB32), + CONSTINFO(CKM_SKIPJACK_CFB16), + CONSTINFO(CKM_SKIPJACK_CFB8), + CONSTINFO(CKM_SKIPJACK_WRAP), + CONSTINFO(CKM_SKIPJACK_PRIVATE_WRAP), + CONSTINFO(CKM_SKIPJACK_RELAYX), + CONSTINFO(CKM_KEA_KEY_PAIR_GEN), + CONSTINFO(CKM_KEA_KEY_DERIVE), + CONSTINFO(CKM_FORTEZZA_TIMESTAMP), + CONSTINFO(CKM_BATON_KEY_GEN), + CONSTINFO(CKM_BATON_ECB128), + CONSTINFO(CKM_BATON_ECB96), + CONSTINFO(CKM_BATON_CBC128), + CONSTINFO(CKM_BATON_COUNTER), + CONSTINFO(CKM_BATON_SHUFFLE), + CONSTINFO(CKM_BATON_WRAP), + CONSTINFO(CKM_EC_KEY_PAIR_GEN), + CONSTINFO(CKM_ECDSA), + CONSTINFO(CKM_ECDSA_SHA1), + CONSTINFO(CKM_ECDSA_SHA224), + CONSTINFO(CKM_ECDSA_SHA256), + CONSTINFO(CKM_ECDSA_SHA384), + CONSTINFO(CKM_ECDSA_SHA512), + CONSTINFO(CKM_ECDH1_DERIVE), + CONSTINFO(CKM_ECDH1_COFACTOR_DERIVE), + CONSTINFO(CKM_ECMQV_DERIVE), + CONSTINFO(CKM_JUNIPER_KEY_GEN), + CONSTINFO(CKM_JUNIPER_ECB128), + CONSTINFO(CKM_JUNIPER_CBC128), + CONSTINFO(CKM_JUNIPER_COUNTER), + CONSTINFO(CKM_JUNIPER_SHUFFLE), + CONSTINFO(CKM_JUNIPER_WRAP), + CONSTINFO(CKM_FASTHASH), + CONSTINFO(CKM_AES_KEY_GEN), + CONSTINFO(CKM_AES_ECB), + CONSTINFO(CKM_AES_CBC), + CONSTINFO(CKM_AES_MAC), + CONSTINFO(CKM_AES_MAC_GENERAL), + CONSTINFO(CKM_AES_CBC_PAD), + CONSTINFO(CKM_AES_CTR), + CONSTINFO(CKM_AES_CMAC), + CONSTINFO(CKM_AES_CMAC_GENERAL), + CONSTINFO(CKM_DSA_PARAMETER_GEN), + CONSTINFO(CKM_DH_PKCS_PARAMETER_GEN), + CONSTINFO(CKM_X9_42_DH_PARAMETER_GEN), + CONSTINFO(CKM_VENDOR_DEFINED), + CONSTINFO(CKM_SHA256_RSA_PKCS_PSS), + CONSTINFO(CKM_SHA224_RSA_PKCS), + CONSTINFO(CKM_SHA224_RSA_PKCS_PSS), + CONSTINFO(CKM_SHA384_RSA_PKCS_PSS), + CONSTINFO(CKM_SHA512_RSA_PKCS_PSS), + CONSTINFO(CKM_SHA224_KEY_DERIVATION), + CONSTINFO(CKM_SHA384_KEY_DERIVATION), + CONSTINFO(CKM_SHA512_KEY_DERIVATION), + CONSTINFO(CKM_SHA512_224), + CONSTINFO(CKM_SHA512_224_HMAC), + CONSTINFO(CKM_SHA512_224_HMAC_GENERAL), + CONSTINFO(CKM_SHA512_256), + CONSTINFO(CKM_SHA512_256_HMAC), + CONSTINFO(CKM_SHA512_256_HMAC_GENERAL), + CONSTINFO(CKM_EP11_SHA512_224), + CONSTINFO(CKM_EP11_SHA512_224_HMAC), + CONSTINFO(CKM_EP11_SHA512_224_HMAC_GENERAL), + CONSTINFO(CKM_EP11_SHA512_256), + CONSTINFO(CKM_EP11_SHA512_256_HMAC), + CONSTINFO(CKM_EP11_SHA512_256_HMAC_GENERAL), + CONSTINFO(CKM_IBM_CMAC), + CONSTINFO(CKM_IBM_ECDSA_SHA224), + CONSTINFO(CKM_IBM_ECDSA_SHA256), + CONSTINFO(CKM_IBM_ECDSA_SHA384), + CONSTINFO(CKM_IBM_ECDSA_SHA512), + CONSTINFO(CKM_IBM_EC_MULTIPLY), + CONSTINFO(CKM_IBM_EAC), + CONSTINFO(CKM_IBM_TESTCODE), + CONSTINFO(CKM_IBM_SHA512_256), + CONSTINFO(CKM_IBM_SHA512_224), + CONSTINFO(CKM_IBM_SHA512_256_HMAC), + CONSTINFO(CKM_IBM_SHA512_224_HMAC), + CONSTINFO(CKM_IBM_SHA512_256_KEY_DERIVATION), + CONSTINFO(CKM_IBM_SHA512_224_KEY_DERIVATION), + CONSTINFO(CKM_IBM_EC_C25519), + CONSTINFO(CKM_IBM_EDDSA_SHA512), + CONSTINFO(CKM_IBM_EDDSA_PH_SHA512), + CONSTINFO(CKM_IBM_EC_C448), + CONSTINFO(CKM_IBM_ED448_SHA3), + CONSTINFO(CKM_IBM_SIPHASH), + CONSTINFO(CKM_IBM_CLEARKEY_TRANSPORT), + CONSTINFO(CKM_IBM_ATTRIBUTEBOUND_WRAP), + CONSTINFO(CKM_IBM_TRANSPORTKEY), + CONSTINFO(CKM_IBM_DH_PKCS_DERIVE_RAW), + CONSTINFO(CKM_IBM_ECDH1_DERIVE_RAW), + CONSTINFO(CKM_IBM_WIRETEST), + CONSTINFO(CKM_IBM_RETAINKEY), + CONSTINFO(CKM_IBM_CPACF_WRAP), + CONSTINFO(CKM_IBM_SM3), + CONSTINFO(CKM_IBM_DILITHIUM), + CONSTINFO(CKM_IBM_SHA3_224), + CONSTINFO(CKM_IBM_SHA3_256), + CONSTINFO(CKM_IBM_SHA3_384), + CONSTINFO(CKM_IBM_SHA3_512), + CONSTINFO(CKM_IBM_SHA3_224_HMAC), + CONSTINFO(CKM_IBM_SHA3_256_HMAC), + CONSTINFO(CKM_IBM_SHA3_384_HMAC), + CONSTINFO(CKM_IBM_SHA3_512_HMAC), +}; + +#define UNKNOWN_MECHANISM 0xFFFFFFFF + +/* for logging, debugging */ +static const char *ep11_get_ckm(CK_ULONG mechanism) +{ + unsigned int i; + + for (i = 0; + i < (sizeof(ep11_mechanisms) / sizeof(ep11_mechanisms[0])); + i++) { + if (ep11_mechanisms[i].code == mechanism) + return ep11_mechanisms[i].name; + } + + TRACE_WARNING("%s unknown mechanism %lx\n", __func__, mechanism); + return "UNKNOWN"; +} + +static CK_ULONG ep11_get_mechanisms_by_name(const char *name) +{ + unsigned int i; + + for (i = 0; + i < (sizeof(ep11_mechanisms) / sizeof(ep11_mechanisms[0])); + i++) { + if (strcmp(ep11_mechanisms[i].name, name) == 0) + return ep11_mechanisms[i].code; + } + + TRACE_WARNING("%s unknown mechanism name '%s'\n", __func__, name); + return UNKNOWN_MECHANISM; +} + +static CK_RV h_opaque_2_blob(STDLL_TokData_t * tokdata, CK_OBJECT_HANDLE handle, + CK_BYTE ** blob, size_t * blob_len, + OBJECT ** kobj, OBJ_LOCK_TYPE lock_type); +static CK_RV obj_opaque_2_blob(STDLL_TokData_t *tokdata, OBJECT *key_obj, + CK_BYTE **blob, size_t *blobsize); + +#define EP11_DEFAULT_CFG_FILE "ep11tok.conf" +#define EP11_CFG_FILE_SIZE 4096 + +#define EP11_DEFAULT_CPFILTER_FILE "ep11cpfilter.conf" + +/* error rc for reading the adapter config file */ +static const int APQN_FILE_INV = 3; +static const int APQN_FILE_INV_FILE_SIZE = 5; +static const int APQN_FILE_SYNTAX_ERROR_0 = 7; +static const int APQN_FILE_SYNTAX_ERROR_1 = 8; +static const int APQN_FILE_SYNTAX_ERROR_2 = 9; +static const int APQN_FILE_SYNTAX_ERROR_3 = 10; +static const int APQN_FILE_SYNTAX_ERROR_4 = 11; +static const int APQN_FILE_SYNTAX_ERROR_5 = 12; +static const int APQN_FILE_NO_APQN_GIVEN = 13; +static const int APQN_FILE_NO_APQN_MODE = 14; +static const int APQN_FILE_UNEXPECTED_END_OF_FILE = 15; +static const int APQN_FILE_SYNTAX_ERROR_6 = 16; +static const int APQN_FILE_SYNTAX_ERROR_7 = 17; +static const int APQN_FILE_SYNTAX_ERROR_8 = 18; +static const int APQN_OUT_OF_MEMORY = 19; + +static int read_adapter_config_file(STDLL_TokData_t * tokdata, + const char *conf_name); +static int read_cp_filter_config_file(const char *conf_name, + cp_config_t ** cp_config); + +/* + * EP11 specific return codes + */ +#define CKR_IBM_WKID_MISMATCH CKR_VENDOR_DEFINED + 0x00010001 +#define CKR_IBM_INTERNAL_ERROR CKR_VENDOR_DEFINED + 0x00010002 +#define CKR_IBM_TRANSPORT_ERROR CKR_VENDOR_DEFINED + 0x00010003 +#define CKR_IBM_BLOB_ERROR CKR_VENDOR_DEFINED + 0x00010004 +#define CKR_IBM_BLOBKEY_CONFLICT CKR_VENDOR_DEFINED + 0x00010005 +#define CKR_IBM_MODE_CONFLICT CKR_VENDOR_DEFINED + 0x00010006 +#define CKR_IBM_NONCRT_KEY_SIZE CKR_VENDOR_DEFINED + 0x00010008 +#define CKR_IBM_WK_NOT_INITIALIZED CKR_VENDOR_DEFINED + 0x00010009 +#define CKR_IBM_OA_API_ERROR CKR_VENDOR_DEFINED + 0x0001000a +#define CKR_IBM_REQ_TIMEOUT CKR_VENDOR_DEFINED + 0x0001000b +#define CKR_IBM_READONLY CKR_VENDOR_DEFINED + 0x0001000c +#define CKR_IBM_STATIC_POLICY CKR_VENDOR_DEFINED + 0x0001000d +#define CKR_IBM_TRANSPORT_LIMIT CKR_VENDOR_DEFINED + 0x00010010 + +static CK_RV ep11_error_to_pkcs11_error(CK_RV rc, SESSION *session) +{ + if (rc < CKR_VENDOR_DEFINED) + return rc; + + TRACE_ERROR("%s ep11 specific error: rc=0x%lx\n", __func__, rc); + + if (session != NULL) + session->session_info.ulDeviceError = rc; + + switch (rc) { + case CKR_IBM_INTERNAL_ERROR: + case CKR_IBM_TRANSPORT_ERROR: + case CKR_IBM_OA_API_ERROR: + case CKR_IBM_TRANSPORT_LIMIT: + case CKR_IBM_REQ_TIMEOUT: + return CKR_FUNCTION_FAILED; + case CKR_IBM_WKID_MISMATCH: + case CKR_IBM_WK_NOT_INITIALIZED: + return CKR_DEVICE_ERROR; + case CKR_IBM_STATIC_POLICY: + return CKR_KEY_SIZE_RANGE; + case CKR_IBM_READONLY: + return CKR_ARGUMENTS_BAD; + case CKR_IBM_BLOB_ERROR: + case CKR_IBM_BLOBKEY_CONFLICT: + return CKR_ENCRYPTED_DATA_INVALID; + case CKR_IBM_MODE_CONFLICT: + case CKR_IBM_NONCRT_KEY_SIZE: + return CKR_ARGUMENTS_BAD; + default: + return CKR_FUNCTION_FAILED; + } +} + +/* import a DES/AES key, that is, make a blob for a DES/AES key + * that was not created by EP11 hardware, encrypt the key by the wrap key, + * unwrap it by the wrap key + */ +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) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_BYTE cipher[MAX_BLOBSIZE]; + CK_ULONG clen = sizeof(cipher); + CK_BYTE csum[MAX_CSUMSIZE]; + size_t cslen = sizeof(csum); + CK_BYTE iv[AES_BLOCK_SIZE]; + CK_MECHANISM mech = { CKM_AES_CBC_PAD, iv, AES_BLOCK_SIZE }; + DL_NODE *node = key_obj->template->attribute_list; + CK_RV rc; + CK_ATTRIBUTE_PTR p_attrs = NULL; + CK_ULONG attrs_len = 0; + CK_ATTRIBUTE_PTR new_p_attrs = NULL; + CK_ULONG new_attrs_len = 0; + unsigned char *ep11_pin_blob = NULL; + CK_ULONG ep11_pin_blob_len = 0; + ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data; + + /* tell ep11 the attributes the user specified */ + node = key_obj->template->attribute_list; + while (node != NULL) { + CK_ATTRIBUTE_PTR a = node->data; + + /* ep11 handles this as 'read only' and reports + * an error if specified + */ + if (CKA_NEVER_EXTRACTABLE == a->type || CKA_MODIFIABLE == a->type + || CKA_LOCAL == a->type) { + ; + } else { + rc = add_to_attribute_array(&p_attrs, &attrs_len, + a->type, a->pValue, a->ulValueLen); + if (rc != CKR_OK) { + TRACE_ERROR("%s adding attribute failed type=0x%lx rc=0x%lx\n", + __func__, a->type, rc); + goto rawkey_2_blob_end; + } + } + + node = node->next; + } + + memset(cipher, 0, sizeof(cipher)); + memcpy(iv, "1234567812345678", AES_BLOCK_SIZE); + + /* + * calls the ep11 lib (which in turns sends the request to the card), + * all m_ function are ep11 functions + */ + RETRY_START + rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_l, &mech, key, + ksize, cipher, &clen, ep11_data->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, sess); + TRACE_ERROR("%s encrypt ksize=0x%lx clen=0x%lx rc=0x%lx\n", + __func__, ksize, clen, rc); + goto rawkey_2_blob_end; + } + TRACE_INFO("%s encrypt ksize=0x%lx clen=0x%lx rc=0x%lx\n", + __func__, ksize, clen, rc); + + rc = check_key_attributes(tokdata, ktype, CKO_SECRET_KEY, p_attrs, + attrs_len, &new_p_attrs, &new_attrs_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s RSA/EC check private key attributes failed with " + "rc=0x%lx\n", __func__, rc); + return rc; + } + + ep11_get_pin_blob(ep11_session, object_is_session_object(key_obj), + &ep11_pin_blob, &ep11_pin_blob_len); + + /* the encrypted key is decrypted and a blob is build, + * card accepts only blobs as keys + */ + RETRY_START + rc = dll_m_UnwrapKey(cipher, clen, ep11_data->raw2key_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, ep11_data->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, sess); + TRACE_ERROR("%s unwrap blen=%zd rc=0x%lx\n", __func__, *blen, rc); + } else { + TRACE_INFO("%s unwrap blen=%zd rc=0x%lx\n", __func__, *blen, rc); + } + +rawkey_2_blob_end: + if (p_attrs != NULL) + free_attribute_array(p_attrs, attrs_len); + if (new_p_attrs) + free_attribute_array(new_p_attrs, new_attrs_len); + return rc; +} + +/* random number generator */ +CK_RV token_specific_rng(STDLL_TokData_t * tokdata, CK_BYTE * output, + CK_ULONG bytes) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + + CK_RV rc = dll_m_GenerateRandom(output, bytes, ep11_data->target); + if (rc != CKR_OK) + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s output=%p bytes=%lu rc=0x%lx\n", + __func__, (void *)output, bytes, rc); + return rc; +} + +/* + * 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, + * we use an AES key + */ +static CK_RV make_wrapblob(STDLL_TokData_t * tokdata, CK_ATTRIBUTE * tmpl_in, + CK_ULONG tmpl_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_MECHANISM mech = { CKM_AES_KEY_GEN, NULL_PTR, 0 }; + CK_BYTE csum[MAX_CSUMSIZE]; + size_t csum_l = sizeof(csum); + CK_RV rc; + + if (ep11_data->raw2key_wrap_blob_l != 0) { + TRACE_INFO("%s blob already exists raw2key_wrap_blob_l=0x%zx\n", + __func__, ep11_data->raw2key_wrap_blob_l); + return CKR_OK; + } + + 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, + ep11_data->target); + + + 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); + } else { + TRACE_INFO("%s end raw2key_wrap_blob_l=0x%zx rc=0x%lx\n", + __func__, ep11_data->raw2key_wrap_blob_l, rc); + } + + return rc; +} + +#ifdef EP11_HSMSIM +#define DLOPEN_FLAGS RTLD_GLOBAL | RTLD_NOW | RTLD_DEEPBIND +#else +#define DLOPEN_FLAGS RTLD_GLOBAL | RTLD_NOW +#endif + +static void *ep11_load_host_lib() +{ + void *lib_ep11; + char *ep11_lib_name; + char *errstr; + + ep11_lib_name = getenv(EP11SHAREDLIB_NAME); + if (ep11_lib_name != NULL) { + lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS); + + if (lib_ep11 == NULL) { + errstr = dlerror(); + OCK_SYSLOG(LOG_ERR, + "%s: Error loading shared library '%s' [%s]\n", + __func__, ep11_lib_name, errstr); + TRACE_ERROR("%s Error loading shared library '%s' [%s]\n", + __func__, ep11_lib_name, errstr); + return NULL; + } + return lib_ep11; + } + + ep11_lib_name = EP11SHAREDLIB_V3; + lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS); + + if (lib_ep11 == NULL) { + TRACE_DEVEL("%s Error loading shared library '%s', trying '%s'\n", + __func__, EP11SHAREDLIB_V3, EP11SHAREDLIB_V2); + /* Try version 2 instead */ + ep11_lib_name = EP11SHAREDLIB_V2; + lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS); + } + + if (lib_ep11 == NULL) { + TRACE_DEVEL("%s Error loading shared library '%s', trying '%s'\n", + __func__, EP11SHAREDLIB_V2, EP11SHAREDLIB_V1); + /* Try version 1 instead */ + ep11_lib_name = EP11SHAREDLIB_V1; + lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS); + } + + if (lib_ep11 == NULL) { + TRACE_DEVEL("%s Error loading shared library '%s', trying '%s'\n", + __func__, EP11SHAREDLIB_V1, EP11SHAREDLIB); + /* Try unversioned library instead */ + ep11_lib_name = EP11SHAREDLIB; + lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS); + } + + if (lib_ep11 == NULL) { + errstr = dlerror(); + OCK_SYSLOG(LOG_ERR, + "%s: Error loading shared library '%s[.3|.2|.1]' [%s]\n", + __func__, EP11SHAREDLIB, errstr); + TRACE_ERROR("%s Error loading shared library '%s[.3|.2|.1]' [%s]\n", + __func__, EP11SHAREDLIB, errstr); + return NULL; + } + + return lib_ep11; +} + +static CK_RV ep11_resolve_lib_sym(void *hdl) +{ + char *error = NULL; + + dlerror(); /* Clear existing error */ + + *(void **)(&dll_m_GenerateRandom) = dlsym(hdl, "m_GenerateRandom"); + *(void **)(&dll_m_SeedRandom) = dlsym(hdl, "m_SeedRandom"); + + *(void **)(&dll_m_Digest) = dlsym(hdl, "m_Digest"); + *(void **)(&dll_m_DigestInit) = dlsym(hdl, "m_DigestInit"); + *(void **)(&dll_m_DigestUpdate) = dlsym(hdl, "m_DigestUpdate"); + *(void **)(&dll_m_DigestFinal) = dlsym(hdl, "m_DigestFinal"); + *(void **)(&dll_m_DigestKey) = dlsym(hdl, "m_DigestKey"); + *(void **)(&dll_m_DigestSingle) = dlsym(hdl, "m_DigestSingle"); + + *(void **)(&dll_m_Encrypt) = dlsym(hdl, "m_Encrypt"); + *(void **)(&dll_m_EncryptInit) = dlsym(hdl, "m_EncryptInit"); + *(void **)(&dll_m_EncryptUpdate) = dlsym(hdl, "m_EncryptUpdate"); + *(void **)(&dll_m_EncryptFinal) = dlsym(hdl, "m_EncryptFinal"); + *(void **)(&dll_m_EncryptSingle) = dlsym(hdl, "m_EncryptSingle"); + + *(void **)(&dll_m_Decrypt) = dlsym(hdl, "m_Decrypt"); + *(void **)(&dll_m_DecryptInit) = dlsym(hdl, "m_DecryptInit"); + *(void **)(&dll_m_DecryptUpdate) = dlsym(hdl, "m_DecryptUpdate"); + *(void **)(&dll_m_DecryptFinal) = dlsym(hdl, "m_DecryptFinal"); + *(void **)(&dll_m_DecryptSingle) = dlsym(hdl, "m_DecryptSingle"); + + *(void **)(&dll_m_ReencryptSingle) = dlsym(hdl, "m_ReencryptSingle"); + *(void **)(&dll_m_GenerateKey) = dlsym(hdl, "m_GenerateKey"); + *(void **)(&dll_m_GenerateKeyPair) = dlsym(hdl, "m_GenerateKeyPair"); + + *(void **)(&dll_m_Sign) = dlsym(hdl, "m_Sign"); + *(void **)(&dll_m_SignInit) = dlsym(hdl, "m_SignInit"); + *(void **)(&dll_m_SignUpdate) = dlsym(hdl, "m_SignUpdate"); + *(void **)(&dll_m_SignFinal) = dlsym(hdl, "m_SignFinal"); + *(void **)(&dll_m_SignSingle) = dlsym(hdl, "m_SignSingle"); + + *(void **)(&dll_m_Verify) = dlsym(hdl, "m_Verify"); + *(void **)(&dll_m_VerifyInit) = dlsym(hdl, "m_VerifyInit"); + *(void **)(&dll_m_VerifyUpdate) = dlsym(hdl, "m_VerifyUpdate"); + *(void **)(&dll_m_VerifyFinal) = dlsym(hdl, "m_VerifyFinal"); + *(void **)(&dll_m_VerifySingle) = dlsym(hdl, "m_VerifySingle"); + + *(void **)(&dll_m_WrapKey) = dlsym(hdl, "m_WrapKey"); + *(void **)(&dll_m_UnwrapKey) = dlsym(hdl, "m_UnwrapKey"); + *(void **)(&dll_m_DeriveKey) = dlsym(hdl, "m_DeriveKey"); + + *(void **)(&dll_m_GetMechanismList) = dlsym(hdl, "m_GetMechanismList"); + *(void **)(&dll_m_GetMechanismInfo) = dlsym(hdl, "m_GetMechanismInfo"); + *(void **)(&dll_m_GetAttributeValue) = dlsym(hdl, "m_GetAttributeValue"); + *(void **)(&dll_m_SetAttributeValue) = dlsym(hdl, "m_SetAttributeValue"); + + *(void **)(&dll_m_Login) = dlsym(hdl, "m_Login"); + *(void **)(&dll_m_Logout) = dlsym(hdl, "m_Logout"); + *(void **)(&dll_m_admin) = dlsym(hdl, "m_admin"); + + *(void **)(&dll_m_init) = dlsym(hdl, "m_init"); + *(void **)(&dll_m_add_backend) = dlsym(hdl, "m_add_backend"); + *(void **)(&dll_m_shutdown) = dlsym(hdl, "m_shutdown"); + + *(void **)(&dll_xcpa_queryblock) = dlsym(hdl, "xcpa_queryblock"); + *(void **)(&dll_xcpa_internal_rv) = dlsym(hdl, "xcpa_internal_rv"); + + *(void **)(&dll_m_get_xcp_info) = dlsym(hdl, "m_get_xcp_info"); + + if ((error = dlerror()) != NULL) { + TRACE_ERROR("%s Error: %s\n", __func__, error); + OCK_SYSLOG(LOG_ERR, "%s: Error: %s\n", __func__, error); + return CKR_FUNCTION_FAILED; + } + + /* + * The following are only available since EP11 host library version 2. + * Ignore if they fail to load, the code will fall back to the old target + * handling in this case. + */ + *(void **)(&dll_m_add_module) = dlsym(hdl, "m_add_module"); + *(void **)(&dll_m_rm_module) = dlsym(hdl, "m_rm_module"); + if (dll_m_add_module == NULL || dll_m_rm_module == NULL) { + dll_m_add_module = NULL; + dll_m_rm_module = NULL; + } + + return CKR_OK; +} + +static CK_RV ep11tok_load_libica(STDLL_TokData_t *tokdata) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + libica_t *libica = &ep11_data->libica; + int default_libica = 0; + char *errstr; + + if (ep11_data->digest_libica == 0) + return CKR_OK; + + if (strcmp(ep11_data->digest_libica_path, "") == 0) { + strcpy(ep11_data->digest_libica_path, ICASHAREDLIB); + default_libica = 1; + } + + libica->library = dlopen(ep11_data->digest_libica_path, + RTLD_GLOBAL | RTLD_NOW); + if (libica->library == NULL) { + errstr = dlerror(); + OCK_SYSLOG(default_libica ? LOG_WARNING : LOG_ERR, + "%s: Error loading shared library '%s' [%s]\n", + __func__, ep11_data->digest_libica_path, errstr); + TRACE_ERROR("%s Error loading shared library '%s' [%s]\n", + __func__, ep11_data->digest_libica_path, errstr); + ep11_data->digest_libica = 0; + return default_libica ? CKR_OK : CKR_FUNCTION_FAILED; + } + + *(void **)(&libica->ica_sha1) = dlsym(libica->library, "ica_sha1"); + *(void **)(&libica->ica_sha224) = dlsym(libica->library, "ica_sha224"); + *(void **)(&libica->ica_sha256) = dlsym(libica->library, "ica_sha256"); + *(void **)(&libica->ica_sha384) = dlsym(libica->library, "ica_sha384"); + *(void **)(&libica->ica_sha512) = dlsym(libica->library, "ica_sha512"); + *(void **)(&libica->ica_sha512_224) = + dlsym(libica->library, "ica_sha512_224"); + *(void **)(&libica->ica_sha512_256) = + dlsym(libica->library, "ica_sha512_256"); +#ifdef SHA3_224 + *(void **)(&libica->ica_sha3_224) = dlsym(libica->library, "ica_sha3_224"); + *(void **)(&libica->ica_sha3_256) = dlsym(libica->library, "ica_sha3_256"); + *(void **)(&libica->ica_sha3_384) = dlsym(libica->library, "ica_sha3_384"); + *(void **)(&libica->ica_sha3_512) = dlsym(libica->library, "ica_sha3_512"); +#endif + /* No error checking, each of the libica functions is allowed to be NULL */ + + TRACE_DEVEL("%s: Loaded libica from '%s'\n", __func__, + ep11_data->digest_libica_path); + return CKR_OK; +} + +CK_RV ep11tok_init(STDLL_TokData_t * tokdata, CK_SLOT_ID SlotNumber, + char *conf_name) +{ + CK_RV rc; + void *lib_ep11; + CK_ULONG len = 16; + CK_BBOOL cktrue = 1; + CK_ATTRIBUTE wrap_tmpl[] = { {CKA_VALUE_LEN, &len, sizeof(CK_ULONG)} + , + {CKA_WRAP, (void *) &cktrue, sizeof(cktrue)} + , + {CKA_UNWRAP, (void *) &cktrue, sizeof(cktrue)} + , + {CKA_ENCRYPT, (void *) &cktrue, sizeof(cktrue)} + , + {CKA_DECRYPT, (void *) &cktrue, sizeof(cktrue)} + , + {CKA_EXTRACTABLE, (void *) &cktrue, sizeof(cktrue)} + , + {CKA_LABEL, (void *) wrap_key_name, sizeof(wrap_key_name)} + , + {CKA_TOKEN, (void *) &cktrue, sizeof(cktrue)} + }; + ep11_private_data_t *ep11_data; + + TRACE_INFO("ep11 %s slot=%lu running\n", __func__, SlotNumber); + + ep11_data = calloc(1, sizeof(ep11_private_data_t)); + if (ep11_data == NULL) + return CKR_HOST_MEMORY; + + tokdata->private_data = ep11_data; + + /* read ep11 specific config file with user specified + * adapter/domain pairs */ + rc = read_adapter_config_file(tokdata, conf_name); + if (rc != CKR_OK) { + TRACE_ERROR("%s ep11 config file error rc=0x%lx\n", __func__, rc); + rc = CKR_GENERAL_ERROR; + goto error; + } + + /* dynamically load in the ep11 shared library */ + lib_ep11 = ep11_load_host_lib(); + if (lib_ep11 == NULL) { + rc = CKR_FUNCTION_FAILED; + goto error; + } + + rc = ep11_resolve_lib_sym(lib_ep11); + if (rc != CKR_OK) + goto error; + +#ifndef XCP_STANDALONE + /* call ep11 shared lib init */ + if (dll_m_init() < 0) { + TRACE_ERROR("%s ep11 lib init failed\n", __func__); + OCK_SYSLOG(LOG_ERR, + "%s: Error: EP 11 library initialization failed\n", + __func__); + rc = CKR_DEVICE_ERROR; + goto error; + } +#endif + + rc = ep11tok_get_ep11_version(tokdata); + if (rc != CKR_OK) + goto error; + + rc = ep11tok_setup_target(tokdata); + if (rc != CKR_OK) + goto error; + + if (ep11_data->digest_libica) { + rc = ep11tok_load_libica(tokdata); + if (rc != CKR_OK) + goto error; + } + + ep11_data->control_points_len = sizeof(ep11_data->control_points); + rc = get_control_points(tokdata, ep11_data->control_points, + &ep11_data->control_points_len, + &ep11_data->max_control_point_index); + if (rc != CKR_OK) { + TRACE_ERROR("%s Failed to get the control points (get_control_points " + "rc=0x%lx)\n", __func__, rc); + OCK_SYSLOG(LOG_ERR, "%s: Failed to get the control points rc=0x%lx\n", + __func__, rc); + goto error; + } + + /* create an AES key needed for importing keys + * (encrypt by wrap_key and m_UnwrapKey by wrap key) + */ + rc = make_wrapblob(tokdata, wrap_tmpl, 8); + if (rc != CKR_OK) { + TRACE_ERROR("%s make_wrapblob failed rc=0x%lx\n", __func__, rc); + if (rc == CKR_IBM_WK_NOT_INITIALIZED) { + TRACE_ERROR("%s rc is CKR_IBM_WK_NOT_INITIALIZED, " + "no master key set ?\n", __func__); + OCK_SYSLOG(LOG_ERR, + "%s: Error: CKR_IBM_WK_NOT_INITIALIZED occurred, no " + "master key set ?\n", __func__); + } + if (rc == CKR_FUNCTION_CANCELED) { + TRACE_ERROR("%s rc is CKR_FUNCTION_CANCELED, " + "control point 13 (generate or derive symmetric " + "keys including DSA parameters) disabled ?\n", + __func__); + OCK_SYSLOG(LOG_ERR, + "%s: Error: CKR_FUNCTION_CANCELED occurred, " + "control point 13 (generate or derive symmetric " + "keys including DSA parameters) disabled ?\n", __func__); + } + rc = CKR_GENERAL_ERROR; + goto error; + } + + TRACE_INFO("%s init done successfully\n", __func__); + return CKR_OK; + +error: + ep11tok_final(tokdata); + TRACE_INFO("%s init failed with rc: 0x%lx\n", __func__, rc); + return rc; +} + +CK_RV ep11tok_final(STDLL_TokData_t * tokdata) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + + TRACE_INFO("ep11 %s running\n", __func__); + + if (ep11_data != NULL) { + if (dll_m_rm_module != NULL) + dll_m_rm_module(NULL, ep11_data->target); + free_cp_config(ep11_data->cp_config); + free_card_versions(ep11_data->card_versions); + free(ep11_data); + tokdata->private_data = NULL; + } + + return CKR_OK; +} + +/* + * Makes a public key blob which is a MACed SPKI of the public key. + */ +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) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + 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_MECHANISM mech = { CKM_IBM_TRANSPORTKEY, 0, 0 }; + CK_ATTRIBUTE_PTR p_attrs = NULL; + CK_ULONG attrs_len = 0; + CK_ATTRIBUTE_PTR attr; + CK_BBOOL bool_value; + DL_NODE *node; + CK_BYTE csum[MAX_BLOBSIZE]; + CK_ULONG cslen = sizeof(csum); + CK_KEY_TYPE keytype; + CK_RV rc; + + rc = template_attribute_find(pub_key_obj->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + keytype = *(CK_KEY_TYPE *)attr->pValue; + + /* + * m_UnwrapKey with CKM_IBM_TRANSPORTKEY allows boolean attributes only to + * be added to MACed-SPKIs + */ + node = pub_key_obj->template->attribute_list; + while (node != NULL) { + attr = node->data; + + switch (attr->type) { + case CKA_ENCRYPT: + case CKA_VERIFY: + case CKA_VERIFY_RECOVER: + /* + * EP11 does not allow to restrict public RSA/DSA/EC keys with + * CKA_VERIFY=FALSE and/or CKA_ENCRYPT=FALSE since it can not + * technically enforce the restrictions. Therefore override these + * attributes for the EP11 library, but keep the original attribute + * values in the object. + */ + if (keytype == CKK_EC || keytype == CKK_RSA || keytype == CKK_DSA) + bool_value = CK_TRUE; + else + bool_value = *(CK_BBOOL *)attr->pValue; + rc = add_to_attribute_array(&p_attrs, &attrs_len, attr->type, + &bool_value, sizeof(bool_value)); + if (rc != CKR_OK) { + TRACE_ERROR("%s adding attribute failed type=0x%lx rc=0x%lx\n", + __func__, attr->type, rc); + goto make_maced_spki_end; + } + break; + + case CKA_EXTRACTABLE: + //case CKA_NEVER_EXTRACTABLE: + //case CKA_MODIFIABLE: + case CKA_DERIVE: + case CKA_WRAP: + //case CKA_LOCAL: + case CKA_TRUSTED: + case CKA_IBM_RESTRICTABLE: + case CKA_IBM_NEVER_MODIFIABLE: + case CKA_IBM_ATTRBOUND: + case CKA_IBM_USE_AS_DATA: + rc = add_to_attribute_array(&p_attrs, &attrs_len, attr->type, + attr->pValue, attr->ulValueLen); + if (rc != CKR_OK) { + TRACE_ERROR("%s adding attribute failed type=0x%lx rc=0x%lx\n", + __func__, attr->type, rc); + goto make_maced_spki_end; + } + break; + + default: + break; + } + node = node->next; + } + + ep11_get_pin_blob(ep11_session, object_is_session_object(pub_key_obj), + &ep11_pin_blob, &ep11_pin_blob_len); + + RETRY_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, ep11_data->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, sess); + TRACE_ERROR("%s unwrapping SPKI rc=0x%lx spki_len=0x%zx maced_spki_len=0x%zx\n", + __func__, rc, spki_len, *maced_spki_len); + } else { + TRACE_INFO("%s unwrapping SPKI rc=0x%lx spki_len=0x%zx maced_spki_len=0x%zx\n", + __func__, rc, spki_len, *maced_spki_len); + } + +make_maced_spki_end: + if (p_attrs != NULL) + cleanse_and_free_attribute_array(p_attrs, attrs_len); + + return rc; +} + +/* + * makes blobs for private imported RSA keys and + * SPKIs for public imported RSA keys. + * Similar to rawkey_2_blob, but keys must follow a standard BER encoding. + */ +static CK_RV import_RSA_key(STDLL_TokData_t * tokdata, SESSION * sess, + OBJECT * rsa_key_obj, + CK_BYTE * blob, size_t * blob_size) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE iv[AES_BLOCK_SIZE]; + CK_MECHANISM mech_w = { CKM_AES_CBC_PAD, iv, AES_BLOCK_SIZE }; + CK_BYTE cipher[MAX_BLOBSIZE]; + CK_ULONG cipher_l = sizeof(cipher); + DL_NODE *node; + CK_ATTRIBUTE_PTR p_attrs = NULL; + CK_ULONG attrs_len = 0; + CK_ATTRIBUTE_PTR new_p_attrs = NULL; + CK_ULONG new_attrs_len = 0; + CK_BYTE csum[MAX_BLOBSIZE]; + CK_ULONG cslen = sizeof(csum); + CK_OBJECT_CLASS class; + CK_BYTE *data = NULL; + CK_ULONG data_len; + unsigned char *ep11_pin_blob = NULL; + CK_ULONG ep11_pin_blob_len = 0; + ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data; + + memcpy(iv, "1234567812345678", AES_BLOCK_SIZE); + + /* need class for private/public key info */ + if (!template_attribute_find(rsa_key_obj->template, CKA_CLASS, &attr)) { + TRACE_ERROR("%s no CKA_CLASS\n", __func__); + return CKR_TEMPLATE_INCOMPLETE; + } + + /* m_Unwrap builds key blob in the card, + * tell ep11 the attributes the user specified for that key. + */ + node = rsa_key_obj->template->attribute_list; + while (node != NULL) { + CK_ATTRIBUTE_PTR a = node->data; + + /* ep11 handles this as 'read only' */ + if (CKA_NEVER_EXTRACTABLE == a->type || + CKA_MODIFIABLE == a->type || CKA_LOCAL == a->type) { + ; + } else { + rc = add_to_attribute_array(&p_attrs, &attrs_len, + a->type, a->pValue, a->ulValueLen); + if (rc != CKR_OK) { + TRACE_ERROR("%s adding attribute failed type=0x%lx rc=0x%lx\n", + __func__, a->type, rc); + goto import_RSA_key_end; + } + } + + node = node->next; + } + + class = *(CK_OBJECT_CLASS *) attr->pValue; + + if (class != CKO_PRIVATE_KEY) { + + /* an imported public RSA key, we need a SPKI for it. */ + + CK_ATTRIBUTE *modulus; + CK_ATTRIBUTE *publ_exp; + + if (!template_attribute_find(rsa_key_obj->template, + CKA_MODULUS, &modulus)) { + rc = CKR_TEMPLATE_INCOMPLETE; + goto import_RSA_key_end; + } + if (!template_attribute_find(rsa_key_obj->template, + CKA_PUBLIC_EXPONENT, &publ_exp)) { + rc = CKR_TEMPLATE_INCOMPLETE; + goto import_RSA_key_end; + } + + /* our contribution to asn1.c, + * builds the BER encoding that is a SPKI. + */ + rc = ber_encode_RSAPublicKey(0, &data, &data_len, modulus, publ_exp); + if (rc != CKR_OK) { + TRACE_ERROR("%s public key import class=0x%lx rc=0x%lx " + "data_len=0x%lx\n", __func__, class, rc, data_len); + goto import_RSA_key_end; + } else { + TRACE_INFO("%s public key import class=0x%lx rc=0x%lx " + "data_len=0x%lx\n", __func__, class, rc, data_len); + } + + /* save the SPKI as blob although it is not a blob. + * The card expects MACed-SPKIs as public keys. + */ + rc = make_maced_spki(tokdata, sess, rsa_key_obj, data, data_len, + blob, blob_size); + if (rc != CKR_OK) { + TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n", + __func__, rc); + goto import_RSA_key_end; + } + + } else { + + /* imported private RSA key goes here */ + + /* extract the secret data to be wrapped + * since this is AES_CBC_PAD, padding is done in mechanism. + */ + rc = rsa_priv_wrap_get_data(rsa_key_obj->template, FALSE, + &data, &data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("%s RSA wrap get data failed\n", __func__); + goto import_RSA_key_end; + } + + /* encrypt */ + RETRY_START + rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_l, &mech_w, + data, data_len, cipher, &cipher_l, + ep11_data->target); + RETRY_END(rc, tokdata, sess) + + TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", + __func__, rc, cipher_l); + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, sess); + TRACE_ERROR("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", + __func__, rc, cipher_l); + goto import_RSA_key_end; + } + + rc = check_key_attributes(tokdata, CKK_RSA, CKO_PRIVATE_KEY, p_attrs, + attrs_len, &new_p_attrs, &new_attrs_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s RSA/EC check private key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto import_RSA_key_end; + } + + ep11_get_pin_blob(ep11_session, object_is_session_object(rsa_key_obj), + &ep11_pin_blob, &ep11_pin_blob_len); + + /* calls the card, it decrypts the private RSA key, + * reads its BER format and builds a blob. + */ + RETRY_START + rc = dll_m_UnwrapKey(cipher, cipher_l, ep11_data->raw2key_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, + csum, &cslen, ep11_data->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, sess); + TRACE_ERROR("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n", + __func__, rc, *blob_size); + } else { + TRACE_INFO("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n", + __func__, rc, *blob_size); + } + + cleanse_attribute(rsa_key_obj->template, CKA_PRIVATE_EXPONENT); + cleanse_attribute(rsa_key_obj->template, CKA_PRIME_1); + cleanse_attribute(rsa_key_obj->template, CKA_PRIME_2); + cleanse_attribute(rsa_key_obj->template, CKA_EXPONENT_1); + cleanse_attribute(rsa_key_obj->template, CKA_EXPONENT_2); + cleanse_attribute(rsa_key_obj->template, CKA_COEFFICIENT); + } + +import_RSA_key_end: + if (data) { + OPENSSL_cleanse(data, data_len); + free(data); + } + if (p_attrs != NULL) + cleanse_and_free_attribute_array(p_attrs, attrs_len); + if (new_p_attrs) + cleanse_and_free_attribute_array(new_p_attrs, new_attrs_len); + return rc; +} + +/* + * makes blobs for private imported EC keys and + * SPKIs for public imported EC keys. + * Similar to rawkey_2_blob, but keys must follow a standard BER encoding. + */ +static CK_RV import_EC_key(STDLL_TokData_t * tokdata, SESSION * sess, + OBJECT * ec_key_obj, + CK_BYTE * blob, size_t * blob_size) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE iv[AES_BLOCK_SIZE]; + CK_MECHANISM mech_w = { CKM_AES_CBC_PAD, iv, AES_BLOCK_SIZE }; + CK_BYTE cipher[MAX_BLOBSIZE]; + CK_ULONG cipher_l = sizeof(cipher); + DL_NODE *node; + CK_ATTRIBUTE_PTR p_attrs = NULL; + CK_ULONG attrs_len = 0; + CK_ATTRIBUTE_PTR new_p_attrs = NULL; + CK_ULONG new_attrs_len = 0; + CK_BYTE csum[MAX_BLOBSIZE]; + CK_ULONG cslen = sizeof(csum); + CK_OBJECT_CLASS class; + CK_BYTE *data = NULL; + CK_ULONG data_len; + 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_ULONG privkey_len, pubkey_len; + CK_BYTE *pubkey = NULL; + + memcpy(iv, "1234567812345678", AES_BLOCK_SIZE); + + /* need class for private/public key info */ + if (!template_attribute_find(ec_key_obj->template, CKA_CLASS, &attr)) { + TRACE_ERROR("%s no CKA_CLASS\n", __func__); + return CKR_TEMPLATE_INCOMPLETE; + } + + /* m_Unwrap builds key blob in the card, + * tell ep11 the attributes the user specified for that key. + */ + node = ec_key_obj->template->attribute_list; + while (node != NULL) { + CK_ATTRIBUTE_PTR a = node->data; + + /* ep11 handles this as 'read only' */ + if (CKA_NEVER_EXTRACTABLE == a->type || + CKA_MODIFIABLE == a->type || CKA_LOCAL == a->type) { + ; + } else { + rc = add_to_attribute_array(&p_attrs, &attrs_len, + a->type, a->pValue, a->ulValueLen); + if (rc != CKR_OK) { + TRACE_ERROR("%s adding attribute failed type=0x%lx rc=0x%lx\n", + __func__, a->type, rc); + goto import_EC_key_end; + } + } + + node = node->next; + } + + class = *(CK_OBJECT_CLASS *) attr->pValue; + + if (class != CKO_PRIVATE_KEY) { + + /* an imported public EC key, we need a SPKI for it. */ + + CK_ATTRIBUTE *ec_params; + CK_ATTRIBUTE *ec_point_attr; + CK_ATTRIBUTE ec_point_uncompr; + CK_BYTE *ecpoint; + CK_ULONG ecpoint_len, field_len; + + if (!template_attribute_find(ec_key_obj->template, + CKA_EC_PARAMS, &ec_params)) { + rc = CKR_TEMPLATE_INCOMPLETE; + goto import_EC_key_end; + } + if (!template_attribute_find(ec_key_obj->template, + CKA_EC_POINT, &ec_point_attr)) { + rc = CKR_TEMPLATE_INCOMPLETE; + goto import_EC_key_end; + } + + /* CKA_EC_POINT is an BER encoded OCTET STRING. Extract it. */ + rc = ber_decode_OCTET_STRING((CK_BYTE *)ec_point_attr->pValue, &ecpoint, + &ecpoint_len, &field_len); + if (rc != CKR_OK || ec_point_attr->ulValueLen != field_len) { + TRACE_DEVEL("%s ber_decode_OCTET_STRING failed\n", __func__); + rc = CKR_ATTRIBUTE_VALUE_INVALID; + goto import_EC_key_end; + } + + /* Uncompress the public key (EC_POINT) */ + rc = get_ecsiglen(ec_key_obj, &privkey_len); + if (rc != CKR_OK) + goto import_EC_key_end; + privkey_len /= 2; /* private key is half the size of an EC signature */ + + pubkey_len = 1 + 2 * privkey_len; + pubkey = (CK_BYTE *)malloc(pubkey_len); + if (pubkey == NULL) { + rc = CKR_HOST_MEMORY; + goto import_EC_key_end; + } + + rc = ec_uncompress_public_key(ec_params->pValue, ec_params->ulValueLen, + ecpoint, ecpoint_len, + privkey_len, pubkey, &pubkey_len); + if (rc != CKR_OK) + goto import_EC_key_end; + + /* build ec-point attribute as BER encoded OCTET STRING */ + rc = ber_encode_OCTET_STRING(FALSE, &ecpoint, &ecpoint_len, + pubkey, pubkey_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_OCTET_STRING failed\n"); + goto import_EC_key_end; + } + + ec_point_uncompr.type = ec_point_attr->type; + ec_point_uncompr.pValue = ecpoint; + ec_point_uncompr.ulValueLen = ecpoint_len; + + /* + * Builds the DER encoding (ansi_x962) SPKI. + * (get the length first) + */ + rc = ber_encode_ECPublicKey(TRUE, &data, &data_len, + ec_params, &ec_point_uncompr); + data = malloc(data_len); + + rc = ber_encode_ECPublicKey(FALSE, &data, &data_len, + ec_params, &ec_point_uncompr); + free(ecpoint); + if (rc != CKR_OK) { + TRACE_ERROR("%s public key import class=0x%lx rc=0x%lx " + "data_len=0x%lx\n", __func__, class, rc, data_len); + goto import_EC_key_end; + } else { + TRACE_INFO("%s public key import class=0x%lx rc=0x%lx " + "data_len=0x%lx\n", __func__, class, rc, data_len); + } + + /* save the SPKI as blob although it is not a blob. + * The card expects MACed-SPKIs as public keys. + */ + rc = make_maced_spki(tokdata, sess, ec_key_obj, data, data_len, + blob, blob_size); + if (rc != CKR_OK) { + TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n", + __func__, rc); + goto import_EC_key_end; + } + + } else { + + /* imported private EC key goes here */ + + /* extract the secret data to be wrapped + * since this is AES_CBC_PAD, padding is done in mechanism. + */ + rc = ecdsa_priv_wrap_get_data(ec_key_obj->template, FALSE, + &data, &data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("%s EC wrap get data failed\n", __func__); + goto import_EC_key_end; + } + + /* encrypt */ + RETRY_START + rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_l, + &mech_w, data, data_len, + cipher, &cipher_l, ep11_data->target); + RETRY_END(rc, tokdata, sess) + + TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", + __func__, rc, cipher_l); + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, sess); + TRACE_ERROR("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", + __func__, rc, cipher_l); + goto import_EC_key_end; + } + + rc = check_key_attributes(tokdata, CKK_EC, CKO_PRIVATE_KEY, p_attrs, + attrs_len, &new_p_attrs, &new_attrs_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s EC check private key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto import_EC_key_end; + } + + ep11_get_pin_blob(ep11_session, object_is_session_object(ec_key_obj), + &ep11_pin_blob, &ep11_pin_blob_len); + + /* calls the card, it decrypts the private EC key, + * reads its BER format and builds a blob. + */ + RETRY_START + rc = dll_m_UnwrapKey(cipher, cipher_l, + ep11_data->raw2key_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, csum, &cslen, ep11_data->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, sess); + TRACE_ERROR("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n", + __func__, rc, *blob_size); + } else { + TRACE_INFO("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n", + __func__, rc, *blob_size); + } + + cleanse_attribute(ec_key_obj->template, CKA_VALUE); + } + +import_EC_key_end: + if (pubkey) + free(pubkey); + if (data) { + OPENSSL_cleanse(data, data_len); + free(data); + } + if (p_attrs != NULL) + cleanse_and_free_attribute_array(p_attrs, attrs_len); + if (new_p_attrs) + cleanse_and_free_attribute_array(new_p_attrs, new_attrs_len); + return rc; +} + +/* + * makes blobs for private imported DSA keys and + * SPKIs for public imported DSA keys. + * Similar to rawkey_2_blob, but keys must follow a standard BER encoding. + */ +static CK_RV import_DSA_key(STDLL_TokData_t * tokdata, SESSION * sess, + OBJECT * dsa_key_obj, + CK_BYTE * blob, size_t * blob_size) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE iv[AES_BLOCK_SIZE]; + CK_MECHANISM mech_w = { CKM_AES_CBC_PAD, iv, AES_BLOCK_SIZE }; + CK_BYTE cipher[MAX_BLOBSIZE]; + CK_ULONG cipher_l = sizeof(cipher); + DL_NODE *node; + CK_ATTRIBUTE_PTR p_attrs = NULL; + CK_ULONG attrs_len = 0; + CK_ATTRIBUTE_PTR new_p_attrs = NULL; + CK_ULONG new_attrs_len = 0; + CK_BYTE csum[MAX_BLOBSIZE]; + CK_ULONG cslen = sizeof(csum); + CK_OBJECT_CLASS class; + CK_BYTE *data = NULL; + CK_ULONG data_len; + unsigned char *ep11_pin_blob = NULL; + CK_ULONG ep11_pin_blob_len = 0; + ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data; + + memcpy(iv, "1234567812345678", AES_BLOCK_SIZE); + + /* need class for private/public key info */ + if (!template_attribute_find(dsa_key_obj->template, CKA_CLASS, &attr)) { + TRACE_ERROR("%s no CKA_CLASS\n", __func__); + return CKR_TEMPLATE_INCOMPLETE; + } + + /* m_Unwrap builds key blob in the card, + * tell ep11 the attributes the user specified for that key. + */ + node = dsa_key_obj->template->attribute_list; + while (node != NULL) { + CK_ATTRIBUTE_PTR a = node->data; + + /* ep11 handles this as 'read only' */ + if (CKA_NEVER_EXTRACTABLE == a->type || + CKA_MODIFIABLE == a->type || CKA_LOCAL == a->type) { + ; + } else { + rc = add_to_attribute_array(&p_attrs, &attrs_len, + a->type, a->pValue, a->ulValueLen); + if (rc != CKR_OK) { + TRACE_ERROR("%s adding attribute failed type=0x%lx rc=0x%lx\n", + __func__, a->type, rc); + goto import_DSA_key_end; + } + } + + node = node->next; + } + + class = *(CK_OBJECT_CLASS *) attr->pValue; + + if (class != CKO_PRIVATE_KEY) { + + /* an imported public DSA key, we need a SPKI for it. */ + + CK_ATTRIBUTE *prime; + CK_ATTRIBUTE *subprime; + CK_ATTRIBUTE *base; + CK_ATTRIBUTE *value; + + if (!template_attribute_find(dsa_key_obj->template, + CKA_PRIME, &prime)) { + rc = CKR_TEMPLATE_INCOMPLETE; + goto import_DSA_key_end; + } + if (!template_attribute_find(dsa_key_obj->template, + CKA_SUBPRIME, &subprime)) { + rc = CKR_TEMPLATE_INCOMPLETE; + goto import_DSA_key_end; + } + if (!template_attribute_find(dsa_key_obj->template, CKA_BASE, &base)) { + rc = CKR_TEMPLATE_INCOMPLETE; + goto import_DSA_key_end; + } + if (!template_attribute_find(dsa_key_obj->template, + CKA_VALUE, &value)) { + rc = CKR_TEMPLATE_INCOMPLETE; + goto import_DSA_key_end; + } + + /* + * Builds the DER encoding (ansi_x962) SPKI. + * (get the length first) + */ + rc = ber_encode_DSAPublicKey(TRUE, &data, &data_len, + prime, subprime, base, value); + data = malloc(data_len); + + rc = ber_encode_DSAPublicKey(FALSE, &data, &data_len, + prime, subprime, base, value); + if (rc != CKR_OK) { + TRACE_ERROR("%s public key import class=0x%lx rc=0x%lx " + "data_len=0x%lx\n", __func__, class, rc, data_len); + goto import_DSA_key_end; + } else { + TRACE_INFO("%s public key import class=0x%lx rc=0x%lx " + "data_len=0x%lx\n", __func__, class, rc, data_len); + } + + /* save the SPKI as blob although it is not a blob. + * The card expects MACed-SPKIs as public keys. + */ + rc = make_maced_spki(tokdata, sess, dsa_key_obj, data, data_len, + blob, blob_size); + if (rc != CKR_OK) { + TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n", + __func__, rc); + goto import_DSA_key_end; + } + + } else { + + /* imported private DSA key goes here */ + + /* extract the secret data to be wrapped + * since this is AES_CBC_PAD, padding is done in mechanism. + */ + rc = dsa_priv_wrap_get_data(dsa_key_obj->template, FALSE, + &data, &data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("%s DSA wrap get data failed\n", __func__); + goto import_DSA_key_end; + } + + /* encrypt */ + RETRY_START + rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_l, + &mech_w, data, data_len, + cipher, &cipher_l, ep11_data->target); + RETRY_END(rc, tokdata, sess) + + + TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", + __func__, rc, cipher_l); + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, sess); + TRACE_ERROR("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", + __func__, rc, cipher_l); + goto import_DSA_key_end; + } + + rc = check_key_attributes(tokdata, CKK_DSA, CKO_PRIVATE_KEY, p_attrs, + attrs_len, &new_p_attrs, &new_attrs_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s DSA check private key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto import_DSA_key_end; + } + + ep11_get_pin_blob(ep11_session, object_is_session_object(dsa_key_obj), + &ep11_pin_blob, &ep11_pin_blob_len); + + /* calls the card, it decrypts the private EC key, + * reads its BER format and builds a blob. + */ + RETRY_START + rc = dll_m_UnwrapKey(cipher, cipher_l, + ep11_data->raw2key_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, csum, &cslen, ep11_data->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, sess); + TRACE_ERROR("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n", + __func__, rc, *blob_size); + } else { + TRACE_INFO("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n", + __func__, rc, *blob_size); + } + + cleanse_attribute(dsa_key_obj->template, CKA_VALUE); + } + +import_DSA_key_end: + if (data) { + OPENSSL_cleanse(data, data_len); + free(data); + } + if (p_attrs != NULL) + cleanse_and_free_attribute_array(p_attrs, attrs_len); + if (new_p_attrs) + cleanse_and_free_attribute_array(new_p_attrs, new_attrs_len); + return rc; +} + +/* + * makes blobs for private imported DH keys and + * SPKIs for public imported DH keys. + * Similar to rawkey_2_blob, but keys must follow a standard BER encoding. + */ +static CK_RV import_DH_key(STDLL_TokData_t * tokdata, SESSION * sess, + OBJECT * dh_key_obj, + CK_BYTE * blob, size_t * blob_size) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE iv[AES_BLOCK_SIZE]; + CK_MECHANISM mech_w = { CKM_AES_CBC_PAD, iv, AES_BLOCK_SIZE }; + CK_BYTE cipher[MAX_BLOBSIZE]; + CK_ULONG cipher_l = sizeof(cipher); + DL_NODE *node; + CK_ATTRIBUTE_PTR p_attrs = NULL; + CK_ULONG attrs_len = 0; + CK_ATTRIBUTE_PTR new_p_attrs = NULL; + CK_ULONG new_attrs_len = 0; + CK_BYTE csum[MAX_BLOBSIZE]; + CK_ULONG cslen = sizeof(csum); + CK_OBJECT_CLASS class; + CK_BYTE *data = NULL; + CK_ULONG data_len; + unsigned char *ep11_pin_blob = NULL; + CK_ULONG ep11_pin_blob_len = 0; + ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data; + + memcpy(iv, "1234567812345678", AES_BLOCK_SIZE); + + /* need class for private/public key info */ + if (!template_attribute_find(dh_key_obj->template, CKA_CLASS, &attr)) { + TRACE_ERROR("%s no CKA_CLASS\n", __func__); + return CKR_TEMPLATE_INCOMPLETE; + } + + /* m_Unwrap builds key blob in the card, + * tell ep11 the attributes the user specified for that key. + */ + node = dh_key_obj->template->attribute_list; + while (node != NULL) { + CK_ATTRIBUTE_PTR a = node->data; + + /* ep11 handles this as 'read only' */ + if (CKA_NEVER_EXTRACTABLE == a->type || + CKA_MODIFIABLE == a->type || CKA_LOCAL == a->type) { + ; + } else { + rc = add_to_attribute_array(&p_attrs, &attrs_len, + a->type, a->pValue, a->ulValueLen); + if (rc != CKR_OK) { + TRACE_ERROR("%s adding attribute failed type=0x%lx rc=0x%lx\n", + __func__, a->type, rc); + goto import_DH_key_end; + } + } + + node = node->next; + } + + class = *(CK_OBJECT_CLASS *) attr->pValue; + + if (class != CKO_PRIVATE_KEY) { + + /* an imported public DH key, we need a SPKI for it. */ + + CK_ATTRIBUTE *prime; + CK_ATTRIBUTE *base; + CK_ATTRIBUTE *value; + + if (!template_attribute_find(dh_key_obj->template, CKA_PRIME, &prime)) { + rc = CKR_TEMPLATE_INCOMPLETE; + goto import_DH_key_end; + } + if (!template_attribute_find(dh_key_obj->template, CKA_BASE, &base)) { + rc = CKR_TEMPLATE_INCOMPLETE; + goto import_DH_key_end; + } + if (!template_attribute_find(dh_key_obj->template, CKA_VALUE, &value)) { + rc = CKR_TEMPLATE_INCOMPLETE; + goto import_DH_key_end; + } + + /* + * Builds the DER encoding (ansi_x962) SPKI. + * (get the length first) + */ + rc = ber_encode_DHPublicKey(TRUE, &data, &data_len, prime, base, value); + data = malloc(data_len); + + rc = ber_encode_DHPublicKey(FALSE, &data, &data_len, + prime, base, value); + if (rc != CKR_OK) { + TRACE_ERROR("%s public key import class=0x%lx rc=0x%lx " + "data_len=0x%lx\n", __func__, class, rc, data_len); + goto import_DH_key_end; + } else { + TRACE_INFO("%s public key import class=0x%lx rc=0x%lx " + "data_len=0x%lx\n", __func__, class, rc, data_len); + } + + /* save the SPKI as blob although it is not a blob. + * The card expects MACed-SPKIs as public keys. + */ + rc = make_maced_spki(tokdata, sess, dh_key_obj, data, data_len, + blob, blob_size); + if (rc != CKR_OK) { + TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n", + __func__, rc); + goto import_DH_key_end; + } + + } else { + + /* imported private DH key goes here */ + + /* extract the secret data to be wrapped + * since this is AES_CBC_PAD, padding is done in mechanism. + */ + rc = dh_priv_wrap_get_data(dh_key_obj->template, FALSE, + &data, &data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("%s DH wrap get data failed\n", __func__); + goto import_DH_key_end; + } + + /* encrypt */ + RETRY_START + rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_l, + &mech_w, data, data_len, + cipher, &cipher_l, ep11_data->target); + RETRY_END(rc, tokdata, sess) + + TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", + __func__, rc, cipher_l); + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, sess); + TRACE_ERROR("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", + __func__, rc, cipher_l); + goto import_DH_key_end; + } + + rc = check_key_attributes(tokdata, CKK_DH, CKO_PRIVATE_KEY, p_attrs, + attrs_len, &new_p_attrs, &new_attrs_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s DH check private key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto import_DH_key_end; + } + + ep11_get_pin_blob(ep11_session, object_is_session_object(dh_key_obj), + &ep11_pin_blob, &ep11_pin_blob_len); + + /* calls the card, it decrypts the private EC key, + * reads its BER format and builds a blob. + */ + RETRY_START + rc = dll_m_UnwrapKey(cipher, cipher_l, + ep11_data->raw2key_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, csum, &cslen, ep11_data->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, sess); + TRACE_ERROR("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n", + __func__, rc, *blob_size); + } else { + TRACE_INFO("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n", + __func__, rc, *blob_size); + } + + cleanse_attribute(dh_key_obj->template, CKA_VALUE); + } + +import_DH_key_end: + if (data) { + OPENSSL_cleanse(data, data_len); + free(data); + } + if (p_attrs != NULL) + cleanse_and_free_attribute_array(p_attrs, attrs_len); + if (new_p_attrs) + cleanse_and_free_attribute_array(new_p_attrs, new_attrs_len); + return rc; +} + +/* + * makes blobs for private imported IBM Dilithium keys and + * SPKIs for public imported IBM Dilithium keys. + * Similar to rawkey_2_blob, but keys must follow a standard BER encoding. + */ +static CK_RV import_IBM_Dilithium_key(STDLL_TokData_t * tokdata, SESSION * sess, + OBJECT * dilithium_key_obj, + CK_BYTE * blob, size_t * blob_size) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE iv[AES_BLOCK_SIZE]; + CK_MECHANISM mech_w = { CKM_AES_CBC_PAD, iv, AES_BLOCK_SIZE }; + CK_BYTE cipher[MAX_BLOBSIZE]; + CK_ULONG cipher_l = sizeof(cipher); + DL_NODE *node; + CK_ATTRIBUTE_PTR p_attrs = NULL; + CK_ULONG attrs_len = 0; + CK_ATTRIBUTE_PTR new_p_attrs = NULL; + CK_ULONG new_attrs_len = 0; + CK_BYTE csum[MAX_BLOBSIZE]; + CK_ULONG cslen = sizeof(csum); + CK_OBJECT_CLASS class; + CK_BYTE *data = NULL; + CK_ULONG data_len; + 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 *pubkey = NULL; + + memcpy(iv, "1234567812345678", AES_BLOCK_SIZE); + + /* need class for secret/public key info */ + if (!template_attribute_find(dilithium_key_obj->template, CKA_CLASS, &attr)) { + TRACE_ERROR("%s no CKA_CLASS\n", __func__); + return CKR_TEMPLATE_INCOMPLETE; + } + + /* m_Unwrap builds key blob in the card, + * tell ep11 the attributes the user specified for that key. + */ + node = dilithium_key_obj->template->attribute_list; + while (node != NULL) { + CK_ATTRIBUTE_PTR a = node->data; + + /* ep11 handles this as 'read only' */ + if (CKA_NEVER_EXTRACTABLE == a->type || + CKA_MODIFIABLE == a->type || CKA_LOCAL == a->type) { + ; + } else { + rc = add_to_attribute_array(&p_attrs, &attrs_len, + a->type, a->pValue, a->ulValueLen); + if (rc != CKR_OK) { + TRACE_ERROR("%s adding attribute failed type=0x%lx rc=0x%lx\n", + __func__, a->type, rc); + goto done; + } + } + + node = node->next; + } + + class = *(CK_OBJECT_CLASS *) attr->pValue; + + if (class != CKO_PRIVATE_KEY) { + + /* Make an SPKI for the public IBM Dilithium key */ + CK_ATTRIBUTE *keyform; + CK_ATTRIBUTE *rho; + CK_ATTRIBUTE *t1; + + /* A public IBM Dilithium key must have a keyform value */ + if (!template_attribute_find(dilithium_key_obj->template, + CKA_IBM_DILITHIUM_KEYFORM, &keyform)) { + rc = CKR_TEMPLATE_INCOMPLETE; + goto done; + } + + /* Check if it's an expected keyform */ + if (*(CK_ULONG *) keyform->pValue != IBM_DILITHIUM_KEYFORM_ROUND2) { + rc = CKR_TEMPLATE_INCONSISTENT; + goto done; + } + + /* A public IBM Dilithium key must have a rho value */ + if (!template_attribute_find(dilithium_key_obj->template, + CKA_IBM_DILITHIUM_RHO, &rho)) { + rc = CKR_TEMPLATE_INCOMPLETE; + goto done; + } + + /* A public IBM Dilithium key must have a t1 value */ + if (!template_attribute_find(dilithium_key_obj->template, + CKA_IBM_DILITHIUM_T1, &t1)) { + rc = CKR_TEMPLATE_INCOMPLETE; + goto done; + } + + /* Encode the public key */ + rc = ber_encode_IBM_DilithiumPublicKey(0, &data, &data_len, rho, t1); + if (rc != CKR_OK) { + TRACE_ERROR("%s public key import class=0x%lx rc=0x%lx " + "data_len=0x%lx\n", __func__, class, rc, data_len); + goto done; + } else { + TRACE_INFO("%s public key import class=0x%lx rc=0x%lx " + "data_len=0x%lx\n", __func__, class, rc, data_len); + } + + /* save the SPKI as blob although it is not a blob. + * The card expects MACed-SPKIs as public keys. + */ + rc = make_maced_spki(tokdata, sess, dilithium_key_obj, data, data_len, + blob, blob_size); + if (rc != CKR_OK) { + TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n", + __func__, rc); + goto done; + } + + } else { + + /* imported private IBM Dilithium key goes here */ + + /* extract the secret data to be wrapped + * since this is AES_CBC_PAD, padding is done in mechanism. + */ + rc = ibm_dilithium_priv_wrap_get_data(dilithium_key_obj->template, FALSE, + &data, &data_len); + if (rc != CKR_OK) { + TRACE_DEVEL("%s Dilithium wrap get data failed\n", __func__); + goto done; + } + + /* encrypt */ + RETRY_START + rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_l, + &mech_w, data, data_len, + cipher, &cipher_l, ep11_data->target); + RETRY_END(rc, tokdata, sess) + + TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", + __func__, rc, cipher_l); + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, sess); + TRACE_ERROR("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", + __func__, rc, cipher_l); + goto done; + } + + rc = check_key_attributes(tokdata, CKK_IBM_PQC_DILITHIUM, + CKO_PRIVATE_KEY, + p_attrs, attrs_len, + &new_p_attrs, &new_attrs_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s EC check private key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto done; + } + + ep11_get_pin_blob(ep11_session, object_is_session_object(dilithium_key_obj), + &ep11_pin_blob, &ep11_pin_blob_len); + + /* calls the card, it decrypts the private Dilithium key, + * reads its BER format and builds a blob. + */ + RETRY_START + rc = dll_m_UnwrapKey(cipher, cipher_l, + ep11_data->raw2key_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, csum, &cslen, ep11_data->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, sess); + TRACE_ERROR("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n", + __func__, rc, *blob_size); + } else { + TRACE_INFO("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n", + __func__, rc, *blob_size); + } + + cleanse_attribute(dilithium_key_obj->template, CKA_VALUE); + } + +done: + + if (pubkey) + free(pubkey); + if (data) { + OPENSSL_cleanse(data, data_len); + free(data); + } + if (p_attrs != NULL) + cleanse_and_free_attribute_array(p_attrs, attrs_len); + if (new_p_attrs) + cleanse_and_free_attribute_array(new_p_attrs, new_attrs_len); + + return rc; +} + +CK_RV token_specific_object_add(STDLL_TokData_t * tokdata, SESSION * sess, + OBJECT * obj) +{ + CK_KEY_TYPE keytype; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE blob[MAX_BLOBSIZE]; + size_t blobsize = sizeof(blob); + CK_RV rc; + + /* get key type */ + if (template_attribute_find(obj->template, CKA_KEY_TYPE, &attr) == FALSE) { + /* not a key, so nothing to do. Just return. */ + return CKR_OK; + } + + keytype = *(CK_KEY_TYPE *) attr->pValue; + + memset(blob, 0, sizeof(blob)); + + /* only these keys can be imported */ + switch (keytype) { + case CKK_RSA: + rc = import_RSA_key(tokdata, sess, obj, blob, &blobsize); + if (rc != CKR_OK) { + TRACE_ERROR("%s import RSA key rc=0x%lx blobsize=0x%zx\n", + __func__, rc, blobsize); + return rc; + } + TRACE_INFO("%s import RSA key rc=0x%lx blobsize=0x%zx\n", + __func__, rc, blobsize); + break; + case CKK_EC: + rc = import_EC_key(tokdata, sess, obj, blob, &blobsize); + if (rc != CKR_OK) { + TRACE_ERROR("%s import EC key rc=0x%lx blobsize=0x%zx\n", + __func__, rc, blobsize); + return rc; + } + TRACE_INFO("%s import EC key rc=0x%lx blobsize=0x%zx\n", + __func__, rc, blobsize); + break; + case CKK_DSA: + rc = import_DSA_key(tokdata, sess, obj, blob, &blobsize); + if (rc != CKR_OK) { + TRACE_ERROR("%s import DSA key rc=0x%lx blobsize=0x%zx\n", + __func__, rc, blobsize); + return rc; + } + TRACE_INFO("%s import DSA key rc=0x%lx blobsize=0x%zx\n", + __func__, rc, blobsize); + break; + case CKK_DH: + rc = import_DH_key(tokdata, sess, obj, blob, &blobsize); + if (rc != CKR_OK) { + TRACE_ERROR("%s import DH key rc=0x%lx blobsize=0x%zx\n", + __func__, rc, blobsize); + return rc; + } + TRACE_INFO("%s import DH key rc=0x%lx blobsize=0x%zx\n", + __func__, rc, blobsize); + break; + case CKK_IBM_PQC_DILITHIUM: + rc = import_IBM_Dilithium_key(tokdata, sess, obj, blob, &blobsize); + if (rc != CKR_OK) { + TRACE_ERROR("%s import IBM Dilithium key rc=0x%lx blobsize=0x%zx\n", + __func__, rc, blobsize); + return rc; + } + TRACE_INFO("%s import IBM Dilithium key rc=0x%lx blobsize=0x%zx\n", + __func__, rc, blobsize); + break; + case CKK_DES2: + case CKK_DES3: + case CKK_AES: + case CKK_GENERIC_SECRET: + /* get key value */ + if (template_attribute_find(obj->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("%s token_specific_object_add incomplete template\n", + __func__); + return CKR_TEMPLATE_INCOMPLETE; + } + /* attr holds key value specified by user, + * import that key (make a blob) + */ + rc = rawkey_2_blob(tokdata, sess, attr->pValue, attr->ulValueLen, + keytype, blob, &blobsize, obj); + if (rc != CKR_OK) { + TRACE_ERROR("%s rawkey_2_blob rc=0x%lx " + "blobsize=0x%zx\n", __func__, rc, blobsize); + return rc; + } + + /* clear value attribute */ + OPENSSL_cleanse(attr->pValue, attr->ulValueLen); + + TRACE_INFO("%s rawkey_2_blob rc=0x%lx blobsize=0x%zx\n", + __func__, rc, blobsize); + + break; + default: + return CKR_KEY_FUNCTION_NOT_PERMITTED; + } + + /* store the blob in the key obj */ + rc = build_attribute(CKA_IBM_OPAQUE, blob, 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); + return rc; + } + + return CKR_OK; +} + + +CK_RV ep11tok_generate_key(STDLL_TokData_t * tokdata, SESSION * session, + 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]; + size_t blobsize = sizeof(blob); + CK_BYTE csum[MAX_CSUMSIZE]; + size_t csum_len = sizeof(csum); + CK_ATTRIBUTE *attr = NULL; + OBJECT *key_obj = NULL; + CK_ULONG ktype; + CK_ULONG class; + CK_ATTRIBUTE_PTR new_attrs = NULL; + CK_ULONG new_attrs_len = 0; + CK_RV rc; + unsigned char *ep11_pin_blob = NULL; + CK_ULONG ep11_pin_blob_len = 0; + ep11_session_t *ep11_session = (ep11_session_t *) session->private_data; + + memset(blob, 0, sizeof(blob)); + memset(csum, 0, sizeof(csum)); + + /* Get the keytype to use when creating the key object */ + rc = ep11_get_keytype(attrs, attrs_len, mech, &ktype, &class); + if (rc != CKR_OK) { + TRACE_ERROR("%s get_subclass failed with rc=0x%lx\n", __func__, rc); + goto error; + } + + rc = check_key_attributes(tokdata, ktype, CKO_SECRET_KEY, attrs, attrs_len, + &new_attrs, &new_attrs_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s check secret key attributes failed: rc=0x%lx\n", + __func__, rc); + return rc; + } + + ep11_get_pin_blob(ep11_session, ep11_is_session_object(attrs, attrs_len), + &ep11_pin_blob, &ep11_pin_blob_len); + + RETRY_START + rc = dll_m_GenerateKey(mech, new_attrs, new_attrs_len, ep11_pin_blob, + ep11_pin_blob_len, blob, &blobsize, + csum, &csum_len, ep11_data->target); + RETRY_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", + __func__, rc, ep11_get_ckm(mech->mechanism), attrs_len); + return rc; + } + + TRACE_INFO("%s m_GenerateKey rc=0x%lx mech='%s' attrs_len=0x%lx\n", + __func__, rc, ep11_get_ckm(mech->mechanism), attrs_len); + + /* Start creating the key object */ + rc = object_mgr_create_skel(tokdata, session, new_attrs, new_attrs_len, + MODE_KEYGEN, CKO_SECRET_KEY, ktype, &key_obj); + if (rc != CKR_OK) { + TRACE_ERROR("%s object_mgr_create_skel failed with rc=0x%lx\n", + __func__, rc); + goto error; + } + + rc = build_attribute(CKA_IBM_OPAQUE, 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; + } + + /* key should be fully constructed. + * Assign an object handle and store key + */ + rc = object_mgr_create_final(tokdata, session, key_obj, handle); + if (rc != CKR_OK) { + TRACE_ERROR("%s object_mgr_create_final with rc=0x%lx\n", __func__, rc); + goto error; + } + + goto done; +error: + if (key_obj) + object_free(key_obj); + *handle = 0; +done: + if (new_attrs) + free_attribute_array(new_attrs, new_attrs_len); + return rc; +} + +static CK_BBOOL ep11tok_libica_digest_available(ep11_private_data_t *ep11_data, + CK_MECHANISM_TYPE mech) +{ + int use_libica; + + switch (mech) { + case CKM_SHA_1: + use_libica = ep11_data->libica.ica_sha1 != NULL; + break; + case CKM_SHA224: + use_libica = ep11_data->libica.ica_sha224 != NULL; + break; + case CKM_SHA256: + use_libica = ep11_data->libica.ica_sha256 != NULL; + break; + case CKM_SHA384: + use_libica = ep11_data->libica.ica_sha384 != NULL; + break; + case CKM_SHA512: + use_libica = ep11_data->libica.ica_sha512 != NULL; + break; + case CKM_SHA512_224: + use_libica = ep11_data->libica.ica_sha512_224 != NULL; + break; + case CKM_SHA512_256: + use_libica = ep11_data->libica.ica_sha512_256 != NULL; + break; +#ifdef SHA3_224 + case CKM_IBM_SHA3_224: + use_libica = ep11_data->libica.ica_sha3_224 != NULL; + break; + case CKM_IBM_SHA3_256: + use_libica = ep11_data->libica.ica_sha3_256 != NULL; + break; + case CKM_IBM_SHA3_384: + use_libica = ep11_data->libica.ica_sha3_384 != NULL; + break; + case CKM_IBM_SHA3_512: + use_libica = ep11_data->libica.ica_sha3_512 != NULL; + break; +#endif + default: + use_libica = 0; + } + + if (use_libica == 0) + TRACE_DEVEL("%s mech=%s is not supported by libica\n", __func__, + ep11_get_ckm(mech)); + + return use_libica ? CK_TRUE : CK_FALSE; +} + +static CK_RV ep11tok_digest_from_mech(CK_MECHANISM_TYPE mech, + CK_MECHANISM_TYPE *digest_mech) +{ + switch (mech) { + case CKM_SHA_1: + case CKM_SHA1_RSA_PKCS: + case CKM_SHA1_RSA_PKCS_PSS: + case CKM_ECDSA_SHA1: + *digest_mech = CKM_SHA_1; + break; + + case CKM_SHA224: + case CKM_SHA224_RSA_PKCS: + case CKM_SHA224_RSA_PKCS_PSS: + case CKM_ECDSA_SHA224: + *digest_mech = CKM_SHA224; + break; + + case CKM_SHA256: + case CKM_SHA256_RSA_PKCS: + case CKM_SHA256_RSA_PKCS_PSS: + case CKM_ECDSA_SHA256: + *digest_mech = CKM_SHA256; + break; + + case CKM_SHA384: + case CKM_SHA384_RSA_PKCS: + case CKM_SHA384_RSA_PKCS_PSS: + case CKM_ECDSA_SHA384: + *digest_mech = CKM_SHA384; + break; + + case CKM_SHA512: + case CKM_SHA512_RSA_PKCS: + case CKM_SHA512_RSA_PKCS_PSS: + case CKM_ECDSA_SHA512: + *digest_mech = CKM_SHA512; + break; + + case CKM_SHA512_224: + *digest_mech = CKM_SHA512_224; + break; + + case CKM_SHA512_256: + *digest_mech = CKM_SHA512_256; + break; + + case CKM_IBM_SHA3_224: + *digest_mech = CKM_IBM_SHA3_224; + break; + + case CKM_IBM_SHA3_256: + *digest_mech = CKM_IBM_SHA3_256; + break; + + case CKM_IBM_SHA3_384: + *digest_mech = CKM_IBM_SHA3_384; + break; + + case CKM_IBM_SHA3_512: + *digest_mech = CKM_IBM_SHA3_512; + break; + + default: + return CKR_MECHANISM_INVALID; + } + + return CKR_OK; +} + +static CK_BBOOL ep11tok_ec_curve_supported(STDLL_TokData_t *tokdata, + CK_OBJECT_HANDLE hKey) +{ + CK_RV rc; + OBJECT *key_obj; + CK_ATTRIBUTE *attr = NULL; + int i; + + rc = object_mgr_find_in_map1(tokdata, hKey, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("%s key 0x%lx not mapped\n", __func__, hKey); + return CK_FALSE; + } + + if (!template_attribute_find(key_obj->template, CKA_ECDSA_PARAMS, &attr)) { + TRACE_ERROR("%s Could not find CKA_ECDSA_PARAMS for the key.\n", + __func__); + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + return CK_FALSE; + } + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + for (i = 0; i < NUMEC; i++) { + if ((memcmp(attr->pValue, der_ec_supported[i].data, + attr->ulValueLen) == 0)) { + return CK_TRUE; + } + } + + TRACE_DEVEL("%s EC curve not supported\n", __func__); + return CK_FALSE; +} + +CK_BBOOL ep11tok_libica_mech_available(STDLL_TokData_t *tokdata, + CK_MECHANISM_TYPE mech, + CK_OBJECT_HANDLE hKey) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_MECHANISM_TYPE digest_mech; + CK_RV rc; + + rc = ep11tok_digest_from_mech(mech, &digest_mech); + if (rc != CKR_OK) + return CK_FALSE; + + switch (mech) { + case CKM_ECDSA_SHA1: + case CKM_ECDSA_SHA224: + case CKM_ECDSA_SHA256: + case CKM_ECDSA_SHA384: + case CKM_ECDSA_SHA512: + if (!ep11tok_ec_curve_supported(tokdata, hKey)) + return CK_FALSE; + break; + } + + return ep11tok_libica_digest_available(ep11_data, digest_mech); +} + +static CK_RV ep11tok_libica_digest(ep11_private_data_t *ep11_data, + CK_MECHANISM_TYPE mech, libica_sha_context_t *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len, + unsigned int message_part) +{ + CK_ULONG hsize; + CK_RV rc; + + rc = get_sha_size(mech, &hsize); + if (rc != CKR_OK) + return rc; + + if (*out_data_len < hsize) + return CKR_BUFFER_TOO_SMALL; + + TRACE_DEVEL("%s mech=%s part=%u\n", __func__, + ep11_get_ckm(mech), message_part); + + switch (mech) { + case CKM_SHA_1: + rc = ep11_data->libica.ica_sha1(message_part, in_data_len, in_data, + &ctx->ctx.sha1, out_data); + break; + case CKM_SHA224: + rc = ep11_data->libica.ica_sha224(message_part, in_data_len, in_data, + &ctx->ctx.sha256, out_data); + break; + case CKM_SHA256: + rc = ep11_data->libica.ica_sha256(message_part, in_data_len, in_data, + &ctx->ctx.sha256, out_data); + break; + case CKM_SHA384: + rc = ep11_data->libica.ica_sha384(message_part, in_data_len, in_data, + &ctx->ctx.sha512, out_data); + break; + case CKM_SHA512: + rc = ep11_data->libica.ica_sha512(message_part, in_data_len, in_data, + &ctx->ctx.sha512, out_data); + break; + case CKM_SHA512_224: + rc = ep11_data->libica.ica_sha512_224(message_part, in_data_len, in_data, + &ctx->ctx.sha512, out_data); + break; + case CKM_SHA512_256: + rc = ep11_data->libica.ica_sha512_256(message_part, in_data_len, in_data, + &ctx->ctx.sha512, out_data); + break; +#ifdef SHA3_224 + case CKM_IBM_SHA3_224: + rc = ep11_data->libica.ica_sha3_224(message_part, in_data_len, in_data, + &ctx->ctx.sha3_224, out_data); + break; + case CKM_IBM_SHA3_256: + rc = ep11_data->libica.ica_sha3_256(message_part, in_data_len, in_data, + &ctx->ctx.sha3_256, out_data); + break; + case CKM_IBM_SHA3_384: + rc = ep11_data->libica.ica_sha3_384(message_part, in_data_len, in_data, + &ctx->ctx.sha3_384, out_data); + break; + case CKM_IBM_SHA3_512: + rc = ep11_data->libica.ica_sha3_512(message_part, in_data_len, in_data, + &ctx->ctx.sha3_512, out_data); + break; +#endif + default: + TRACE_ERROR("%s Invalid mechanism: mech=%s\n", __func__, + ep11_get_ckm(mech)); + return CKR_MECHANISM_INVALID; + } + + if (rc != CKR_OK) { + TRACE_ERROR("%s Libica SHA failed. mech=%s rc=0x%lx\n", __func__, + ep11_get_ckm(mech), rc); + + switch (rc) { + case EINVAL: + return CKR_ARGUMENTS_BAD; + case ENODEV: + return CKR_DEVICE_ERROR; + default: + return CKR_FUNCTION_FAILED; + } + } + + *out_data_len = hsize; + return CKR_OK; +} + +CK_RV token_specific_sha_init(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * c, + CK_MECHANISM * mech) +{ + 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; + libica_sha_context_t *libica_ctx; + + state = calloc(state_len, 1); /* freed by dig_mgr.c */ + if (!state) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + return CKR_HOST_MEMORY; + } + + if (ep11tok_libica_digest_available(ep11_data, mech->mechanism)) { + libica_ctx = (libica_sha_context_t *)state; + state_len = sizeof(libica_sha_context_t); + 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, ep11_data->target); + } + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); + free(state); + } else { + /* DIGEST_CONTEXT will show up with following + * requests (sha_update), 'state' is build by the card + * and holds all to continue, even by another adapter + */ + c->mech.ulParameterLen = mech->ulParameterLen; + c->mech.mechanism = mech->mechanism; + c->mech.pParameter = NULL; + c->context = state; + c->context_len = state_len; + + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + + +CK_RV token_specific_sha(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * c, + CK_BYTE * in_data, + CK_ULONG in_data_len, CK_BYTE * out_data, + CK_ULONG * out_data_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + + if (ep11tok_libica_digest_available(ep11_data, c->mech.mechanism)) { + rc = ep11tok_libica_digest(ep11_data, c->mech.mechanism, + (libica_sha_context_t *)c->context, + in_data, in_data_len, + 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, ep11_data->target); + } + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + return rc; +} + + +CK_RV token_specific_sha_update(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * c, + CK_BYTE * in_data, CK_ULONG in_data_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + libica_sha_context_t *libica_ctx = (libica_sha_context_t *)c->context; + CK_BYTE temp_out[MAX_SHA_HASH_SIZE]; + CK_ULONG out_len = sizeof(temp_out); + CK_ULONG len; + CK_RV rc = CKR_OK; + + if (ep11tok_libica_digest_available(ep11_data, c->mech.mechanism)) { + if (libica_ctx->offset > 0 || in_data_len < libica_ctx->block_size) { + len = MIN(libica_ctx->block_size - libica_ctx->offset, + in_data_len); + memcpy(&libica_ctx->buffer[libica_ctx->offset], in_data, len); + libica_ctx->offset += len; + + in_data += len; + in_data_len -= len; + + if (libica_ctx->offset == libica_ctx->block_size) { + rc = ep11tok_libica_digest(ep11_data, c->mech.mechanism, + libica_ctx, libica_ctx->buffer, + libica_ctx->offset, temp_out, + &out_len, libica_ctx->first ? + SHA_MSG_PART_FIRST : + SHA_MSG_PART_MIDDLE); + if (rc != CKR_OK) + goto out; + + libica_ctx->first = CK_FALSE; + + libica_ctx->offset = 0; + } + } + + if (in_data_len > 0) { + len = (in_data_len / libica_ctx->block_size) * libica_ctx->block_size; + rc = ep11tok_libica_digest(ep11_data, c->mech.mechanism, + libica_ctx, in_data, len, temp_out, + &out_len, libica_ctx->first ? + SHA_MSG_PART_FIRST : + SHA_MSG_PART_MIDDLE); + if (rc != CKR_OK) + goto out; + + libica_ctx->first = CK_FALSE; + + in_data += len; + in_data_len -= len; + + if (in_data_len > 0) { + memcpy(libica_ctx->buffer, in_data, in_data_len); + libica_ctx->offset = in_data_len; + } + } + } else { + rc = dll_m_DigestUpdate(c->context, c->context_len, + in_data, in_data_len, ep11_data->target); + } + +out: + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + return rc; +} + + +CK_RV token_specific_sha_final(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * c, + CK_BYTE * out_data, CK_ULONG * out_data_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + libica_sha_context_t *libica_ctx = (libica_sha_context_t *)c->context; + CK_RV rc; + + if (ep11tok_libica_digest_available(ep11_data, c->mech.mechanism)) { + rc = ep11tok_libica_digest(ep11_data, c->mech.mechanism, + libica_ctx, libica_ctx->buffer, + libica_ctx->offset, + out_data, out_data_len, + libica_ctx->first ? + SHA_MSG_PART_ONLY : + SHA_MSG_PART_FINAL); + } else { + rc = dll_m_DigestFinal(c->context, c->context_len, + out_data, out_data_len, ep11_data->target); + } + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + +CK_RV token_specific_rsa_sign(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_obj) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + size_t keyblobsize = 0; + CK_BYTE *keyblob; + CK_MECHANISM mech; + + rc = obj_opaque_2_blob(tokdata, key_obj, &keyblob, &keyblobsize); + if (rc != CKR_OK) { + TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc); + return rc; + } + + mech.mechanism = CKM_RSA_PKCS; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + + RETRY_START + rc = dll_m_SignSingle(keyblob, keyblobsize, &mech, in_data, in_data_len, + out_data, out_data_len, ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + +CK_RV token_specific_rsa_verify(STDLL_TokData_t *tokdata, SESSION *session, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len, + OBJECT *key_obj) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_BYTE *spki; + size_t spki_len = 0; + CK_MECHANISM mech; + + rc = obj_opaque_2_blob(tokdata, key_obj, &spki, &spki_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc); + return rc; + } + + mech.mechanism = CKM_RSA_PKCS; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + + RETRY_START + rc = dll_m_VerifySingle(spki, spki_len, &mech, in_data, in_data_len, + signature, sig_len, ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + +CK_RV token_specific_rsa_pss_sign(STDLL_TokData_t *tokdata, SESSION *session, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *sig, CK_ULONG *sig_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + size_t keyblobsize = 0; + CK_BYTE *keyblob; + OBJECT *key_obj; + CK_MECHANISM mech; + + rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, + READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc); + return rc; + } + + mech.mechanism = CKM_RSA_PKCS_PSS; + mech.ulParameterLen = ctx->mech.ulParameterLen; + mech.pParameter = ctx->mech.pParameter; + + RETRY_START + rc = dll_m_SignSingle(keyblob, keyblobsize, &mech, in_data, in_data_len, + sig, sig_len, ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV token_specific_rsa_pss_verify(STDLL_TokData_t *tokdata, SESSION *session, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_BYTE *spki; + size_t spki_len = 0; + OBJECT *key_obj; + CK_MECHANISM mech; + + rc = h_opaque_2_blob(tokdata, ctx->key, &spki, &spki_len, &key_obj, + READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc); + return rc; + } + + mech.mechanism = CKM_RSA_PKCS_PSS; + mech.ulParameterLen = ctx->mech.ulParameterLen; + mech.pParameter = ctx->mech.pParameter; + + RETRY_START + rc = dll_m_VerifySingle(spki, spki_len, &mech, in_data, in_data_len, + signature, sig_len, ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV token_specific_ec_sign(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_obj ) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + size_t keyblobsize = 0; + CK_BYTE *keyblob; + CK_MECHANISM mech; + + rc = obj_opaque_2_blob(tokdata, key_obj, &keyblob, &keyblobsize); + if (rc != CKR_OK) { + TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc); + return rc; + } + + mech.mechanism = CKM_ECDSA; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + + RETRY_START + rc = dll_m_SignSingle(keyblob, keyblobsize, &mech, in_data, in_data_len, + out_data, out_data_len, ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + +CK_RV token_specific_ec_verify(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_obj ) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_BYTE *spki; + size_t spki_len = 0; + CK_MECHANISM mech; + + rc = obj_opaque_2_blob(tokdata, key_obj, &spki, &spki_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc); + return rc; + } + + mech.mechanism = CKM_ECDSA; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + + RETRY_START + rc = dll_m_VerifySingle(spki, spki_len, &mech, in_data, in_data_len, + out_data, out_data_len, ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + +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]; + size_t newblobsize = sizeof(newblob); + CK_BYTE csum[MAX_BLOBSIZE]; + CK_ULONG cslen = sizeof(csum); + CK_ATTRIBUTE *opaque_attr = NULL; + OBJECT *base_key_obj = NULL; + OBJECT *key_obj = NULL; + CK_ULONG ktype; + CK_ULONG class; + CK_ATTRIBUTE_PTR new_attrs = NULL; + CK_ULONG new_attrs_len = 0; + unsigned char *ep11_pin_blob = NULL; + CK_ULONG ep11_pin_blob_len = 0; + ep11_session_t *ep11_session = (ep11_session_t *) session->private_data; + CK_ECDH1_DERIVE_PARAMS *ecdh1_parms; + CK_ECDH1_DERIVE_PARAMS ecdh1_parms2; + CK_MECHANISM ecdh1_mech, ecdh1_mech2; + CK_BYTE *ecpoint; + CK_ULONG ecpoint_len, field_len; + + memset(newblob, 0, sizeof(newblob)); + + if (mech->mechanism == CKM_ECDH1_DERIVE || + mech->mechanism == CKM_IBM_EC_C25519 || + mech->mechanism == CKM_IBM_EC_C448) { + if (mech->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS)) { + TRACE_ERROR("%s Param len for %s wrong: %lu\n", + __func__, ep11_get_ckm(mech->mechanism ), + mech->ulParameterLen); + return CKR_MECHANISM_PARAM_INVALID; + } + ecdh1_parms = mech->pParameter; + + /* As per PKCS#11, a token MUST be able to accept this value encoded + * as a raw octet string (as per section A.5.2 of [ANSI X9.62]). + * A token MAY, in addition, support accepting this value as a + * DER-encoded ECPoint (as per section E.6 of [ANSI X9.62]) i.e. + * the same as a CKA_EC_POINT encoding. + * The EP11 host library only accepts the raw form, thus convert + * it to the raw format if the caller specified it in the DER-encoded + * form. + */ + if (ecdh1_parms->pPublicData != NULL && + ecdh1_parms->ulPublicDataLen > 0) { + + ecdh1_parms2 = *ecdh1_parms; + + rc = ber_decode_OCTET_STRING(ecdh1_parms->pPublicData, &ecpoint, + &ecpoint_len, &field_len); + if (rc != CKR_OK || field_len != ecdh1_parms->ulPublicDataLen || + ecpoint_len > ecdh1_parms->ulPublicDataLen - 2) { + /* no valid BER OCTET STRING encoding, assume raw octet string */ + ecpoint = ecdh1_parms->pPublicData; + ecpoint_len = ecdh1_parms->ulPublicDataLen; + } + + ecdh1_parms2.pPublicData = ecpoint; + ecdh1_parms2.ulPublicDataLen = ecpoint_len; + + ecdh1_mech2.mechanism = mech->mechanism; + ecdh1_mech2.pParameter = &ecdh1_parms2; + ecdh1_mech2.ulParameterLen = sizeof(ecdh1_parms2); + + mech = &ecdh1_mech2; + ecdh1_parms = mech->pParameter; + } + + /* + * EP11 supports CKM_ECDH1_DERIVE (and CKM_IBM_EC_C*) slightly different + * than specified in PKCS#11 v2.11 or later. It expects the public data + * directly as mechanism param, not via CK_ECDH1_DERIVE_PARAMS. It also + * does not support KDFs and shared data. + * + * Newer EP11 crypto cards that support API version 3 support this + * mechanism in the PKCS#11 c2.11 way. If the used API version is > 2, + * then we can pass the mechanism parameters as-is, otherwise we still + * need to use the old way. + */ + if (ep11_data->used_firmware_API_version <= 2) { + if (ecdh1_parms->kdf != CKD_NULL) { + TRACE_ERROR("%s KDF for CKM_ECDH1_DERIVE not supported: %lu\n", + __func__, ecdh1_parms->kdf); + return CKR_MECHANISM_PARAM_INVALID; + } + + if (ecdh1_parms->pSharedData != NULL || + ecdh1_parms->ulSharedDataLen > 0) { + TRACE_ERROR("%s Shared data for CKM_ECDH1_DERIVE not " + "supported\n", __func__); + return CKR_MECHANISM_PARAM_INVALID; + } + + ecdh1_mech.mechanism = mech->mechanism; + ecdh1_mech.pParameter = ecdh1_parms->pPublicData; + ecdh1_mech.ulParameterLen = ecdh1_parms->ulPublicDataLen; + mech = &ecdh1_mech; + } + } + + rc = h_opaque_2_blob(tokdata, hBaseKey, &keyblob, &keyblobsize, + &base_key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("%s failedL hBaseKey=0x%lx\n", __func__, hBaseKey); + return rc; + } + + /* Get the keytype to use when creating the key object */ + rc = ep11_get_keytype(attrs, attrs_len, mech, &ktype, &class); + if (rc != CKR_OK) { + TRACE_ERROR("%s get_subclass failed with rc=0x%lx\n", __func__, rc); + goto error; + } + + rc = check_key_attributes(tokdata, ktype, class, attrs, attrs_len, + &new_attrs, &new_attrs_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s Check key attributes for derived key failed with " + "rc=0x%lx\n", __func__, rc); + goto error; + } + + ep11_get_pin_blob(ep11_session, ep11_is_session_object(attrs, attrs_len), + &ep11_pin_blob, &ep11_pin_blob_len); + + RETRY_START + rc = + dll_m_DeriveKey(mech, new_attrs, new_attrs_len, keyblob, keyblobsize, + NULL, 0, ep11_pin_blob, ep11_pin_blob_len, newblob, + &newblobsize, csum, &cslen, ep11_data->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { + TRACE_ERROR("%s hBaseKey=0x%lx rc=0x%lx handle=0x%lx blobsize=0x%zx\n", + __func__, hBaseKey, rc, *handle, newblobsize); + goto error; + } + TRACE_INFO("%s hBaseKey=0x%lx rc=0x%lx handle=0x%lx blobsize=0x%zx\n", + __func__, hBaseKey, rc, *handle, newblobsize); + + /* Start creating the key object */ + rc = object_mgr_create_skel(tokdata, session, new_attrs, new_attrs_len, + MODE_DERIVE, class, ktype, &key_obj); + if (rc != CKR_OK) { + TRACE_ERROR("%s object_mgr_create_skel failed with rc=0x%lx\n", + __func__, rc); + goto error; + } + + rc = build_attribute(CKA_IBM_OPAQUE, newblob, 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; + } + + /* key should be fully constructed. + * Assign an object handle and store key + */ + rc = object_mgr_create_final(tokdata, session, key_obj, handle); + if (rc != CKR_OK) { + TRACE_ERROR("%s object_mgr_create_final with rc=0x%lx\n", __func__, rc); + goto error; + } + + object_put(tokdata, base_key_obj, TRUE); + base_key_obj = NULL; + + return rc; + +error: + if (key_obj) + object_free(key_obj); + *handle = 0; + if (new_attrs) + free_attribute_array(new_attrs, new_attrs_len); + + object_put(tokdata, base_key_obj, TRUE); + base_key_obj = NULL; + + return rc; +} + + + +static CK_RV dh_generate_keypair(STDLL_TokData_t * tokdata, + SESSION * sess, + CK_MECHANISM_PTR pMechanism, + TEMPLATE * publ_tmpl, TEMPLATE * priv_tmpl, + CK_ATTRIBUTE_PTR pPublicKeyTemplate, + CK_ULONG ulPublicKeyAttributeCount, + CK_ATTRIBUTE_PTR pPrivateKeyTemplate, + CK_ULONG ulPrivateKeyAttributeCount, + CK_SESSION_HANDLE h) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_BYTE publblob[MAX_BLOBSIZE]; + size_t publblobsize = sizeof(publblob); + CK_BYTE privblob[MAX_BLOBSIZE]; + size_t privblobsize = sizeof(privblob); + CK_ATTRIBUTE *prime_attr = NULL; + CK_ATTRIBUTE *base_attr = NULL; + CK_ATTRIBUTE *opaque_attr = NULL; + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_ATTRIBUTE *pPublicKeyTemplate_new = NULL; + CK_ATTRIBUTE_PTR dh_pPublicKeyTemplate = NULL; + CK_ULONG dh_ulPublicKeyAttributeCount = 0; + CK_ATTRIBUTE_PTR dh_pPrivateKeyTemplate = NULL; + CK_ULONG dh_ulPrivateKeyAttributeCount = 0; + size_t p_len = 0, g_len = 0; + int new_public_attr; + CK_ULONG i; + CK_ULONG data_len; + CK_ULONG field_len; + CK_BYTE *data; + CK_BYTE *y_start, *oid, *parm; + CK_ULONG bit_str_len, oid_len, parm_len; + unsigned char *ep11_pin_blob = NULL; + CK_ULONG ep11_pin_blob_len = 0; + ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data; + + /* ep11 accepts CKA_PRIME and CKA_BASE parameters/attributes + * only in this format + */ + struct { + size_t pg_bytes; /* total size: 2*bytecount(P) */ + unsigned char *pg; + } dh_pgs; + + UNUSED(h); + + memset(&dh_pgs, 0, sizeof(dh_pgs)); + memset(publblob, 0, sizeof(publblob)); + memset(privblob, 0, sizeof(privblob)); + + /* card does not want CKA_PRIME/CKA_BASE in template but in dh_pgs */ + pPublicKeyTemplate_new = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) * + ulPublicKeyAttributeCount); + if (!pPublicKeyTemplate_new) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + return CKR_HOST_MEMORY; + } + memset(pPublicKeyTemplate_new, 0, + sizeof(CK_ATTRIBUTE) * ulPublicKeyAttributeCount); + + for (i = 0, new_public_attr = 0; i < ulPublicKeyAttributeCount; i++) { + /* filter out CKA_PRIME/CKA_BASE, + * but remember where they can be found + */ + switch (pPublicKeyTemplate[i].type) { + case CKA_PRIME: + prime_attr = &(pPublicKeyTemplate[i]); + p_len = pPublicKeyTemplate[i].ulValueLen; + break; + case CKA_BASE: + base_attr = &(pPublicKeyTemplate[i]); + g_len = pPublicKeyTemplate[i].ulValueLen; + break; + default: + /* copy all other attributes */ + memcpy(&pPublicKeyTemplate_new[new_public_attr], + &(pPublicKeyTemplate[i]), sizeof(CK_ATTRIBUTE)); + new_public_attr++; + } + } + + if (prime_attr == NULL || base_attr == NULL) { + TRACE_ERROR("%s Incomplete template prime_attr=%p base_attr=%p\n", + __func__, (void *)prime_attr, (void *)base_attr); + rc = CKR_TEMPLATE_INCOMPLETE; + goto dh_generate_keypair_end; + } + + /* copy CKA_PRIME/CKA_BASE to private template */ + rc = build_attribute(CKA_PRIME, prime_attr->pValue, + prime_attr->ulValueLen, &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, attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + goto dh_generate_keypair_end; + } + rc = build_attribute(CKA_BASE, base_attr->pValue, + base_attr->ulValueLen, &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, attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + goto dh_generate_keypair_end; + } + + /* copy CKA_PRIME/CKA_BASE values */ + dh_pgs.pg = malloc(p_len * 2); + if (!dh_pgs.pg) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + rc = CKR_HOST_MEMORY; + goto dh_generate_keypair_end; + } + memset(dh_pgs.pg, 0, p_len * 2); + memcpy(dh_pgs.pg, prime_attr->pValue, p_len); /* copy CKA_PRIME value */ + /* copy CKA_BASE value, it must have leading zeros + * if it is shorter than CKA_PRIME + */ + memcpy(dh_pgs.pg + p_len + (p_len - g_len), base_attr->pValue, g_len); + dh_pgs.pg_bytes = p_len * 2; + +#ifdef DEBUG + TRACE_DEBUG("%s P:\n", __func__); + TRACE_DEBUG_DUMP(&dh_pgs.pg[0], p_len); + TRACE_DEBUG("%s G:\n", __func__); + TRACE_DEBUG_DUMP(&dh_pgs.pg[p_len], p_len); +#endif + + /* add special attribute, do not add it to ock's pPublicKeyTemplate */ + CK_ATTRIBUTE pgs[] = { {CKA_IBM_STRUCT_PARAMS, (CK_VOID_PTR) dh_pgs.pg, + dh_pgs.pg_bytes} + }; + memcpy(&(pPublicKeyTemplate_new[new_public_attr]), + &(pgs[0]), sizeof(CK_ATTRIBUTE)); + + rc = check_key_attributes(tokdata, CKK_DH, CKO_PUBLIC_KEY, + pPublicKeyTemplate_new, new_public_attr + 1, + &dh_pPublicKeyTemplate, + &dh_ulPublicKeyAttributeCount); + if (rc != CKR_OK) { + TRACE_ERROR("%s DH check public key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto dh_generate_keypair_end; + } + + rc = check_key_attributes(tokdata, CKK_DH, CKO_PRIVATE_KEY, + pPrivateKeyTemplate, ulPrivateKeyAttributeCount, + &dh_pPrivateKeyTemplate, + &dh_ulPrivateKeyAttributeCount); + if (rc != CKR_OK) { + TRACE_ERROR("%s DH check private key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto dh_generate_keypair_end; + } + + rc = override_key_attributes(tokdata, CKK_DH, CKO_PUBLIC_KEY, + dh_pPublicKeyTemplate, + dh_ulPublicKeyAttributeCount); + if (rc != CKR_OK) { + TRACE_ERROR("%s DH override public key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto dh_generate_keypair_end; + } + + rc = override_key_attributes(tokdata, CKK_DH, CKO_PRIVATE_KEY, + dh_pPrivateKeyTemplate, + dh_ulPrivateKeyAttributeCount); + if (rc != CKR_OK) { + TRACE_ERROR("%s DH override private key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto dh_generate_keypair_end; + } + + ep11_get_pin_blob(ep11_session, + (ep11_is_session_object + (pPublicKeyTemplate, ulPublicKeyAttributeCount) + || ep11_is_session_object(pPrivateKeyTemplate, + ulPrivateKeyAttributeCount)), + &ep11_pin_blob, &ep11_pin_blob_len); + + RETRY_START + rc = dll_m_GenerateKeyPair(pMechanism, dh_pPublicKeyTemplate, + dh_ulPublicKeyAttributeCount, + dh_pPrivateKeyTemplate, + dh_ulPrivateKeyAttributeCount, ep11_pin_blob, + ep11_pin_blob_len, privblob, &privblobsize, + publblob, &publblobsize, ep11_data->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, sess); + TRACE_ERROR("%s m_GenerateKeyPair failed rc=0x%lx\n", __func__, rc); + goto dh_generate_keypair_end; + } + + TRACE_INFO("%s rc=0x%lx plen=%zd publblobsize=0x%zx privblobsize=0x%zx\n", + __func__, rc, p_len, publblobsize, privblobsize); + + /* store the blobs */ + rc = build_attribute(CKA_IBM_OPAQUE, publblob, 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); + 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); + 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); + goto dh_generate_keypair_end; + } +#ifdef DEBUG + TRACE_DEBUG("%s DH SPKI\n", __func__); + TRACE_DEBUG_DUMP(publblob, publblobsize); +#endif + + /* CKA_VALUE of the public key must hold 'y' */ + rc = ber_decode_SPKI(publblob, &oid, &oid_len, &parm, &parm_len, + &y_start, &bit_str_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_decode SKPI failed rc=0x%lx\n", __func__, rc); + goto dh_generate_keypair_end; + } + + /* DHPublicKey ::= INTEGER -- public key, y = g^x mod p */ + rc = ber_decode_INTEGER(y_start, &data, &data_len, &field_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s ber_decode_INTEGER failed rc=0x%lx\n", __func__, rc); + goto dh_generate_keypair_end; + } + + TRACE_INFO("%s DH SPKI decode INTEGER rc=0x%lx y_start=0x%x" + " field_len=%lu data_len=%lu data=0x%hhx\n", + __func__, rc, y_start[1], field_len, data_len, data[0]); + + /* remove leading zero, a leading zero is needed + * (according to standard) if left most bit of first byte is 1, + * in order to indicate a positive number. + * ock, like many others, interpret 'y' always as positive number, + * a leading zero is not expected by ock. + */ + if (data[0] == 0) { + data_len = data_len - 1; + data = data + 1; + TRACE_INFO("%s DH SPKI removed leading zero rc=0x%lx" + " y_start=0x%x field_len=%lu data_len=%lu data=0x%hhx\n", + __func__, rc, y_start[1], field_len, data_len, data[0]); + } + + rc = build_attribute(CKA_VALUE, data, data_len, &value_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, value_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + } + +dh_generate_keypair_end: + free(pPublicKeyTemplate_new); + if (dh_pgs.pg != NULL) + free(dh_pgs.pg); + if (dh_pPublicKeyTemplate) + free_attribute_array(dh_pPublicKeyTemplate, + dh_ulPublicKeyAttributeCount); + if (dh_pPrivateKeyTemplate) + free_attribute_array(dh_pPrivateKeyTemplate, + dh_ulPrivateKeyAttributeCount); + return rc; +} + +static CK_RV dsa_generate_keypair(STDLL_TokData_t * tokdata, + SESSION * sess, + CK_MECHANISM_PTR pMechanism, + TEMPLATE * publ_tmpl, TEMPLATE * priv_tmpl, + CK_ATTRIBUTE_PTR pPublicKeyTemplate, + CK_ULONG ulPublicKeyAttributeCount, + CK_ATTRIBUTE_PTR pPrivateKeyTemplate, + CK_ULONG ulPrivateKeyAttributeCount, + CK_SESSION_HANDLE h) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_BYTE publblob[MAX_BLOBSIZE]; + size_t publblobsize = sizeof(publblob); + CK_BYTE privblob[MAX_BLOBSIZE]; + size_t privblobsize = sizeof(privblob); + CK_ATTRIBUTE *prime_attr = NULL; + CK_ATTRIBUTE *sub_prime_attr = NULL; + CK_ATTRIBUTE *base_attr = NULL; + CK_ATTRIBUTE *opaque_attr = NULL; + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *attr = NULL; + size_t p_len = 0, q_len = 0, g_len = 0; + int new_public_attr; + CK_ULONG i; + CK_ATTRIBUTE *pPublicKeyTemplate_new = NULL; + CK_BYTE *key; + CK_BYTE *data, *oid, *parm; + CK_ULONG data_len, field_len, bit_str_len, oid_len, parm_len; + CK_ATTRIBUTE_PTR dsa_pPublicKeyTemplate = NULL; + CK_ULONG dsa_ulPublicKeyAttributeCount = 0; + CK_ATTRIBUTE_PTR dsa_pPrivateKeyTemplate = NULL; + CK_ULONG dsa_ulPrivateKeyAttributeCount = 0; + unsigned char *ep11_pin_blob = NULL; + CK_ULONG ep11_pin_blob_len = 0; + ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data; + + /* ep11 accepts CKA_PRIME,CKA_SUBPRIME,CKA_BASE only in this format */ + struct { + size_t pqg_bytes; /* total size: 3*bytecount(P) */ + unsigned char *pqg; + } dsa_pqgs; + + UNUSED(h); + + memset(&dsa_pqgs, 0, sizeof(dsa_pqgs)); + memset(publblob, 0, sizeof(publblob)); + memset(privblob, 0, sizeof(privblob)); + + /* card does not want CKA_PRIME/CKA_BASE/CKA_SUBPRIME + * in template but in dsa_pqgs + */ + pPublicKeyTemplate_new = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) * + ulPublicKeyAttributeCount); + if (!pPublicKeyTemplate_new) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + return CKR_HOST_MEMORY; + } + memset(pPublicKeyTemplate_new, 0, + sizeof(CK_ATTRIBUTE) * ulPublicKeyAttributeCount); + + for (i = 0, new_public_attr = 0; i < ulPublicKeyAttributeCount; i++) { + switch (pPublicKeyTemplate[i].type) { + case CKA_PRIME: + prime_attr = &(pPublicKeyTemplate[i]); + p_len = pPublicKeyTemplate[i].ulValueLen; + break; + case CKA_SUBPRIME: + sub_prime_attr = &(pPublicKeyTemplate[i]); + q_len = pPublicKeyTemplate[i].ulValueLen; + break; + case CKA_BASE: + base_attr = &(pPublicKeyTemplate[i]); + g_len = pPublicKeyTemplate[i].ulValueLen; + break; + default: + /* copy all other attributes */ + memcpy(&pPublicKeyTemplate_new[new_public_attr], + &(pPublicKeyTemplate[i]), sizeof(CK_ATTRIBUTE)); + new_public_attr++; + } + } + + if (prime_attr == NULL || sub_prime_attr == NULL || base_attr == NULL) { + rc = CKR_TEMPLATE_INCOMPLETE; + goto dsa_generate_keypair_end; + } + + /* copy CKA_PRIME/CKA_BASE/CKA_SUBPRIME to private template */ + rc = build_attribute(CKA_PRIME, prime_attr->pValue, + prime_attr->ulValueLen, &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, attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + goto dsa_generate_keypair_end; + } + + rc = build_attribute(CKA_BASE, base_attr->pValue, + base_attr->ulValueLen, &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, attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + goto dsa_generate_keypair_end; + } + + rc = build_attribute(CKA_PRIME, sub_prime_attr->pValue, + sub_prime_attr->ulValueLen, &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, attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + goto dsa_generate_keypair_end; + } + + /* if CKA_SUBPRIME,CKA_BASE are smaller than CKA_PRIME + * then they are extented by leading zeros till they have + * the size of CKA_PRIME + */ + dsa_pqgs.pqg = malloc(p_len * 3); + if (!dsa_pqgs.pqg) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + rc = CKR_HOST_MEMORY; + goto dsa_generate_keypair_end; + } + memset(dsa_pqgs.pqg, 0, p_len * 3); + memcpy(dsa_pqgs.pqg, prime_attr->pValue, p_len); + memcpy(dsa_pqgs.pqg + p_len + (p_len - q_len), + sub_prime_attr->pValue, q_len); + memcpy(dsa_pqgs.pqg + 2 * p_len + (p_len - g_len), + base_attr->pValue, g_len); + dsa_pqgs.pqg_bytes = p_len * 3; + +#ifdef DEBUG + TRACE_DEBUG("%s P:\n", __func__); + TRACE_DEBUG_DUMP(&dsa_pqgs.pqg[0], p_len); + TRACE_DEBUG("%s Q:\n", __func__); + TRACE_DEBUG_DUMP(&dsa_pqgs.pqg[p_len], p_len); + TRACE_DEBUG("%s G:\n", __func__); + TRACE_DEBUG_DUMP(&dsa_pqgs.pqg[2 * p_len], p_len); +#endif + + CK_ATTRIBUTE pqgs[] = { {CKA_IBM_STRUCT_PARAMS, + (CK_VOID_PTR) dsa_pqgs.pqg, dsa_pqgs.pqg_bytes} + }; + + /* add special attribute, do not add it to ock's pPublicKeyTemplate */ + memcpy(&(pPublicKeyTemplate_new[new_public_attr]), + &(pqgs[0]), sizeof(CK_ATTRIBUTE)); + + rc = check_key_attributes(tokdata, CKK_DSA, CKO_PUBLIC_KEY, + pPublicKeyTemplate_new, new_public_attr + 1, + &dsa_pPublicKeyTemplate, + &dsa_ulPublicKeyAttributeCount); + if (rc != CKR_OK) { + TRACE_ERROR("%s RSA/EC check public key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto dsa_generate_keypair_end; + } + + rc = check_key_attributes(tokdata, CKK_DSA, CKO_PRIVATE_KEY, + pPrivateKeyTemplate, ulPrivateKeyAttributeCount, + &dsa_pPrivateKeyTemplate, + &dsa_ulPrivateKeyAttributeCount); + if (rc != CKR_OK) { + TRACE_ERROR("%s RSA/EC check private key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto dsa_generate_keypair_end; + } + + rc = override_key_attributes(tokdata, CKK_DSA, CKO_PUBLIC_KEY, + dsa_pPublicKeyTemplate, + dsa_ulPublicKeyAttributeCount); + if (rc != CKR_OK) { + TRACE_ERROR("%s RSA/EC override public key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto dsa_generate_keypair_end; + } + + rc = override_key_attributes(tokdata, CKK_DSA, CKO_PRIVATE_KEY, + dsa_pPrivateKeyTemplate, + dsa_ulPrivateKeyAttributeCount); + if (rc != CKR_OK) { + TRACE_ERROR("%s RSA/EC override private key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto dsa_generate_keypair_end; + } + + ep11_get_pin_blob(ep11_session, + (ep11_is_session_object + (pPublicKeyTemplate, ulPublicKeyAttributeCount) + || ep11_is_session_object(pPrivateKeyTemplate, + ulPrivateKeyAttributeCount)), + &ep11_pin_blob, &ep11_pin_blob_len); + + RETRY_START + rc = dll_m_GenerateKeyPair(pMechanism, dsa_pPublicKeyTemplate, + dsa_ulPublicKeyAttributeCount, + dsa_pPrivateKeyTemplate, + dsa_ulPrivateKeyAttributeCount, + ep11_pin_blob, ep11_pin_blob_len, privblob, + &privblobsize, publblob, &publblobsize, + ep11_data->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, sess); + TRACE_ERROR("%s m_GenerateKeyPair failed with rc=0x%lx\n", __func__, + rc); + goto dsa_generate_keypair_end; + } + + TRACE_INFO("%s rc=0x%lx p_len=%zd publblobsize=0x%zx privblobsize=0x%zx " + "npattr=0x%x\n", + __func__, rc, p_len, publblobsize, privblobsize, + new_public_attr + 1); + + rc = build_attribute(CKA_IBM_OPAQUE, publblob, 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); + 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); + 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); + 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); + if (rc != CKR_OK) { + TRACE_ERROR("%s reading DSA SPKI failed with rc=0x%lx\n", __func__, rc); + goto dsa_generate_keypair_end; + } + + /* key must be an integer */ + rc = ber_decode_INTEGER(key, &data, &data_len, &field_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s reading DSA public key failed with rc=0x%lx\n", + __func__, rc); + goto dsa_generate_keypair_end; + } +#ifdef DEBUG + TRACE_DEBUG("%s dsa_generate_keypair public key:\n", __func__); + TRACE_DEBUG_DUMP(data, data_len); +#endif + + rc = build_attribute(CKA_VALUE, data, data_len, &value_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, value_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n", + __func__, rc); + } + +dsa_generate_keypair_end: + free(pPublicKeyTemplate_new); + if (dsa_pqgs.pqg != NULL) + free(dsa_pqgs.pqg); + if (dsa_pPublicKeyTemplate) + free_attribute_array(dsa_pPublicKeyTemplate, + dsa_ulPublicKeyAttributeCount); + if (dsa_pPrivateKeyTemplate) + free_attribute_array(dsa_pPrivateKeyTemplate, + dsa_ulPrivateKeyAttributeCount); + return rc; +} + +static CK_RV rsa_ec_generate_keypair(STDLL_TokData_t * tokdata, + SESSION * sess, + CK_MECHANISM_PTR pMechanism, + TEMPLATE * publ_tmpl, TEMPLATE * priv_tmpl, + CK_ATTRIBUTE_PTR pPublicKeyTemplate, + CK_ULONG ulPublicKeyAttributeCount, + CK_ATTRIBUTE_PTR pPrivateKeyTemplate, + CK_ULONG ulPrivateKeyAttributeCount, + CK_SESSION_HANDLE h) +{ + 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]; + size_t privkey_blob_len = sizeof(privkey_blob); + unsigned char spki[MAX_BLOBSIZE]; + size_t spki_len = sizeof(spki); + CK_ULONG i; + CK_ULONG bit_str_len; + CK_BYTE *key; + CK_BYTE *data, *oid, *parm; + CK_ULONG data_len, oid_len, parm_len; + CK_ULONG field_len; + CK_ATTRIBUTE_PTR new_pPublicKeyTemplate = NULL; + CK_ULONG new_ulPublicKeyAttributeCount = 0; + CK_ATTRIBUTE_PTR new_pPrivateKeyTemplate = NULL; + CK_ULONG new_ulPrivateKeyAttributeCount = 0; + CK_ULONG ktype; + unsigned char *ep11_pin_blob = NULL; + CK_ULONG ep11_pin_blob_len = 0; + ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data; + + UNUSED(h); + + if (pMechanism->mechanism == CKM_EC_KEY_PAIR_GEN) { + ktype = CKK_EC; + } else if ((pMechanism->mechanism == CKM_RSA_PKCS_KEY_PAIR_GEN) || + (pMechanism->mechanism == CKM_RSA_X9_31_KEY_PAIR_GEN)) { + ktype = CKK_RSA; + } else { + TRACE_ERROR("%s Neither RSA nor EC mech type provided for " + "RSA/EC_key_pair_gen\n", __func__); + return CKR_MECHANISM_INVALID; + } + + rc = check_key_attributes(tokdata, ktype, CKO_PUBLIC_KEY, + pPublicKeyTemplate, ulPublicKeyAttributeCount, + &new_pPublicKeyTemplate, + &new_ulPublicKeyAttributeCount); + if (rc != CKR_OK) { + TRACE_ERROR("%s RSA/EC check public key attributes failed with " + "rc=0x%lx\n", __func__, rc); + return rc; + } + + rc = check_key_attributes(tokdata, ktype, CKO_PRIVATE_KEY, + pPrivateKeyTemplate, ulPrivateKeyAttributeCount, + &new_pPrivateKeyTemplate, + &new_ulPrivateKeyAttributeCount); + if (rc != CKR_OK) { + TRACE_ERROR("%s RSA/EC check private key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto error; + } + + rc = override_key_attributes(tokdata, ktype, CKO_PUBLIC_KEY, + new_pPublicKeyTemplate, + new_ulPublicKeyAttributeCount); + if (rc != CKR_OK) { + TRACE_ERROR("%s RSA/EC override public key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto error; + } + + rc = override_key_attributes(tokdata, ktype, CKO_PRIVATE_KEY, + new_pPrivateKeyTemplate, + new_ulPrivateKeyAttributeCount); + if (rc != CKR_OK) { + TRACE_ERROR("%s RSA/EC override private key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto error; + } + + /* debug */ + for (i = 0; i < new_ulPrivateKeyAttributeCount; i++) { + TRACE_INFO("%s gen priv attr type=0x%lx valuelen=0x%lx attrcnt=0x%lx\n", + __func__, new_pPrivateKeyTemplate[i].type, + new_pPrivateKeyTemplate[i].ulValueLen, + new_ulPrivateKeyAttributeCount); + } + + ep11_get_pin_blob(ep11_session, + (ep11_is_session_object + (pPublicKeyTemplate, ulPublicKeyAttributeCount) + || ep11_is_session_object(pPrivateKeyTemplate, + ulPrivateKeyAttributeCount)), + &ep11_pin_blob, &ep11_pin_blob_len); + + RETRY_START + rc = dll_m_GenerateKeyPair(pMechanism, new_pPublicKeyTemplate, + new_ulPublicKeyAttributeCount, + new_pPrivateKeyTemplate, + new_ulPrivateKeyAttributeCount, + ep11_pin_blob, ep11_pin_blob_len, + privkey_blob, &privkey_blob_len, spki, + &spki_len, ep11_data->target); + RETRY_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 " + "privkey_blob_len=0x%zx mech='%s'\n", + __func__, rc, spki_len, privkey_blob_len, + ep11_get_ckm(pMechanism->mechanism)); + goto error; + } + TRACE_INFO("%s m_GenerateKeyPair rc=0x%lx spki_len=0x%zx " + "privkey_blob_len=0x%zx mech='%s'\n", + __func__, rc, spki_len, privkey_blob_len, + ep11_get_ckm(pMechanism->mechanism)); + + if (spki_len > MAX_BLOBSIZE || privkey_blob_len > MAX_BLOBSIZE) { + TRACE_ERROR("%s blobsize error\n", __func__); + rc = CKR_KEY_INDIGESTIBLE; + goto error; + } + + rc = build_attribute(CKA_IBM_OPAQUE, spki, 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); + 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); + 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); + goto error; + } + + if (pMechanism->mechanism == CKM_EC_KEY_PAIR_GEN) { + /* scan the SPKI for CKA_EC_POINT */ + +#ifdef DEBUG + TRACE_DEBUG("%s ec_generate_keypair spki:\n", __func__); + TRACE_DEBUG_DUMP(spki, spki_len); +#endif + rc = ber_decode_SPKI(spki, &oid, &oid_len, &parm, &parm_len, + &key, &bit_str_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s read key from SPKI failed with rc=0x%lx\n", + __func__, rc); + goto error; + } + + /* 'key' is already EC point, + * SEC 1: Elliptic Curve Cryptography: + * The elliptic curve public key (a value of type ECPoint + * that is an OCTET STRING) is mapped to a subjectPublicKey + * (a value encoded as type BIT STRING) as follows: The most + * significant bit of the value of the OCTET STRING becomes + * the most significant bit of the value of the BIT STRING + * and so on with consecutive bits until the least significant + * bit of the OCTET STRING becomes the least significant bit + * of the BIT STRING. + */ + TRACE_INFO("%s ecpoint length 0x%lx\n", __func__, bit_str_len); + data_len = bit_str_len; + data = key; + +#ifdef DEBUG + TRACE_DEBUG("%s ec_generate_keypair ecpoint:\n", __func__); + TRACE_DEBUG_DUMP(data, data_len); +#endif + + /* build and add CKA_EC_POINT as BER encoded OCTET STRING */ + rc = ber_encode_OCTET_STRING(FALSE, &data, &data_len, + key, bit_str_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_OCTET_STRING failed\n"); + goto error; + } + + rc = build_attribute(CKA_EC_POINT, data, data_len, &attr); + free(data); + 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); + goto error; + } + + /* copy CKA_EC_PARAMS/CKA_ECDSA_PARAMS to private template */ + if (template_attribute_find(publ_tmpl, CKA_EC_PARAMS, &attr)) { + rc = build_attribute(attr->type, attr->pValue, + attr->ulValueLen, &n_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, n_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with " + "rc=0x%lx\n", __func__, rc); + goto error; + } + } + + if (template_attribute_find(publ_tmpl, CKA_ECDSA_PARAMS, &attr)) { + rc = build_attribute(attr->type, attr->pValue, + attr->ulValueLen, &n_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, n_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with " + "rc=0x%lx\n", __func__, rc); + goto error; + } + } + } else { + /* scan the SPKI for modulus and public exponent and + * set the public key attributes, a user would use the + * already built SPKI (in CKA_IBM_OPAQUE of the public key). + */ + CK_BYTE *modulus, *publ_exp; + + rc = ber_decode_SPKI(spki, &oid, &oid_len, &parm, &parm_len, + &key, &bit_str_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s read key from SPKI failed with rc=0x%lx\n", + __func__, rc); + goto error; + } + + /* key must be a sequence holding two integers, + * modulus and public exponent + */ + rc = ber_decode_SEQUENCE(key, &data, &data_len, &field_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s read sequence failed with rc=0x%lx\n", + __func__, rc); + goto error; + } + + modulus = key + field_len - data_len; + rc = ber_decode_INTEGER(modulus, &data, &data_len, &field_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s read modulus failed with rc=0x%lx\n", __func__, rc); + goto error; + } +#ifdef DEBUG + TRACE_DEBUG("%s rsa_generate_keypair modulus:\n", __func__); + TRACE_DEBUG_DUMP(data, data_len); +#endif + + /* build and add CKA_MODULUS */ + rc = build_attribute(CKA_MODULUS, data, data_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); + goto error; + } + + /* read public exponent */ + publ_exp = modulus + field_len; + rc = ber_decode_INTEGER(publ_exp, &data, &data_len, &field_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s read public exponent failed with rc=0x%lx\n", + __func__, rc); + goto error; + } +#ifdef DEBUG + TRACE_DEBUG("%s rsa_generate_keypair public exponent:\n", __func__); + TRACE_DEBUG_DUMP(data, data_len); +#endif + + /* build and add CKA_PUBLIC_EXPONENT */ + rc = build_attribute(CKA_PUBLIC_EXPONENT, data, data_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); + goto error; + } + } + +error: + if (new_pPrivateKeyTemplate) + free_attribute_array(new_pPrivateKeyTemplate, + new_ulPrivateKeyAttributeCount); + if (new_pPublicKeyTemplate) + free_attribute_array(new_pPublicKeyTemplate, + new_ulPublicKeyAttributeCount); + return rc; +} + +static CK_RV ibm_dilithium_generate_keypair(STDLL_TokData_t * tokdata, + SESSION * sess, + CK_MECHANISM_PTR pMechanism, + TEMPLATE * publ_tmpl, TEMPLATE * priv_tmpl, + CK_ATTRIBUTE_PTR pPublicKeyTemplate, + CK_ULONG ulPublicKeyAttributeCount, + CK_ATTRIBUTE_PTR pPrivateKeyTemplate, + CK_ULONG ulPrivateKeyAttributeCount, + CK_SESSION_HANDLE h) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE privkey_blob[MAX_BLOBSIZE]; + size_t privkey_blob_len = sizeof(privkey_blob); + unsigned char spki[MAX_BLOBSIZE]; + size_t spki_len = sizeof(spki); + CK_ULONG i; + CK_ULONG bit_str_len; + CK_BYTE *key; + CK_BYTE *data, *oid, *parm; + CK_ULONG data_len, oid_len, parm_len; + CK_ULONG field_len; + CK_ATTRIBUTE_PTR new_pPublicKeyTemplate = NULL; + CK_ULONG new_ulPublicKeyAttributeCount = 0; + CK_ATTRIBUTE_PTR new_pPrivateKeyTemplate = NULL; + CK_ULONG new_ulPrivateKeyAttributeCount = 0; + CK_ULONG ktype = CKK_IBM_PQC_DILITHIUM; + 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 *rho, *t1; + + UNUSED(h); + + if (pMechanism->mechanism != CKM_IBM_DILITHIUM) { + TRACE_ERROR("Invalid mechanism provided for %s\n ", __func__); + return CKR_MECHANISM_INVALID; + } + + rc = check_key_attributes(tokdata, ktype, CKO_PUBLIC_KEY, + pPublicKeyTemplate, ulPublicKeyAttributeCount, + &new_pPublicKeyTemplate, + &new_ulPublicKeyAttributeCount); + if (rc != CKR_OK) { + TRACE_ERROR("%s Dilithium check public key attributes failed with " + "rc=0x%lx\n", __func__, rc); + return rc; + } + + rc = check_key_attributes(tokdata, ktype, CKO_PRIVATE_KEY, + pPrivateKeyTemplate, ulPrivateKeyAttributeCount, + &new_pPrivateKeyTemplate, + &new_ulPrivateKeyAttributeCount); + if (rc != CKR_OK) { + TRACE_ERROR("%s Dilithium check private key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto error; + } + + rc = override_key_attributes(tokdata, ktype, CKO_PUBLIC_KEY, + new_pPublicKeyTemplate, + new_ulPublicKeyAttributeCount); + if (rc != CKR_OK) { + TRACE_ERROR("%s Dilithium override public key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto error; + } + + rc = override_key_attributes(tokdata, ktype, CKO_PRIVATE_KEY, + new_pPrivateKeyTemplate, + new_ulPrivateKeyAttributeCount); + if (rc != CKR_OK) { + TRACE_ERROR("%s Dilithium override private key attributes failed with " + "rc=0x%lx\n", __func__, rc); + goto error; + } + + /* debug */ + for (i = 0; i < new_ulPrivateKeyAttributeCount; i++) { + TRACE_INFO("%s gen priv attr type=0x%lx valuelen=0x%lx attrcnt=0x%lx\n", + __func__, new_pPrivateKeyTemplate[i].type, + new_pPrivateKeyTemplate[i].ulValueLen, + new_ulPrivateKeyAttributeCount); + } + + ep11_get_pin_blob(ep11_session, + (ep11_is_session_object + (pPublicKeyTemplate, ulPublicKeyAttributeCount) + || ep11_is_session_object(pPrivateKeyTemplate, + ulPrivateKeyAttributeCount)), + &ep11_pin_blob, &ep11_pin_blob_len); + + RETRY_START + rc = dll_m_GenerateKeyPair(pMechanism, new_pPublicKeyTemplate, + new_ulPublicKeyAttributeCount, + new_pPrivateKeyTemplate, + new_ulPrivateKeyAttributeCount, + ep11_pin_blob, ep11_pin_blob_len, + privkey_blob, &privkey_blob_len, spki, + &spki_len, ep11_data->target); + RETRY_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 " + "privkey_blob_len=0x%zx mech='%s'\n", + __func__, rc, spki_len, privkey_blob_len, + ep11_get_ckm(pMechanism->mechanism)); + goto error; + } + TRACE_INFO("%s m_GenerateKeyPair rc=0x%lx spki_len=0x%zx " + "privkey_blob_len=0x%zx mech='%s'\n", + __func__, rc, spki_len, privkey_blob_len, + ep11_get_ckm(pMechanism->mechanism)); + + if (spki_len > MAX_BLOBSIZE || privkey_blob_len > MAX_BLOBSIZE) { + TRACE_ERROR("%s blobsize error\n", __func__); + rc = CKR_KEY_INDIGESTIBLE; + goto error; + } + + rc = build_attribute(CKA_IBM_OPAQUE, spki, 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); + 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); + 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); + goto error; + } + + /* Decode SPKI */ + rc = ber_decode_SPKI(spki, &oid, &oid_len, &parm, &parm_len, &key, + &bit_str_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s read key from SPKI failed with rc=0x%lx\n", __func__, + rc); + goto error; + } + + /* Public key must be a sequence holding two bit-strings: (rho, t1) */ + rc = ber_decode_SEQUENCE(key, &data, &data_len, &field_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s read sequence failed with rc=0x%lx\n", __func__, rc); + goto error; + } + + /* Decode rho */ + rho = key + field_len - data_len; + rc = ber_decode_BIT_STRING(rho, &data, &data_len, &field_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s read rho failed with rc=0x%lx\n", __func__, rc); + goto error; + } + /* Remove leading unused-bits byte, returned by ber_decode_BIT_STRING */ + data++; + data_len--; +#ifdef DEBUG + TRACE_DEBUG("%s dilithium_generate_keypair (rho):\n", __func__); + TRACE_DEBUG_DUMP(data, data_len); +#endif + + /* build and add CKA_IBM_DILITHIUM_RHO */ + rc = build_attribute(CKA_IBM_DILITHIUM_RHO, data, data_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); + goto error; + } + + /* Decode t1 */ + t1 = rho + field_len; + rc = ber_decode_BIT_STRING(t1, &data, &data_len, &field_len); + if (rc != CKR_OK) { + TRACE_ERROR("%s read t failed with rc=0x%lx\n", __func__, rc); + goto error; + } + /* Remove leading unused-bits byte, returned by ber_decode_BIT_STRING */ + data++; + data_len--; +#ifdef DEBUG + TRACE_DEBUG("%s dilithium_generate_keypair (t1):\n", __func__); + TRACE_DEBUG_DUMP(data, data_len); +#endif + + /* build and add CKA_IBM_DILITHIUM_T1 */ + rc = build_attribute(CKA_IBM_DILITHIUM_T1, data, data_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); + goto error; + } + +error: + if (new_pPrivateKeyTemplate) + free_attribute_array(new_pPrivateKeyTemplate, + new_ulPrivateKeyAttributeCount); + if (new_pPublicKeyTemplate) + free_attribute_array(new_pPublicKeyTemplate, + new_ulPublicKeyAttributeCount); + return rc; +} + +/* generic function to generate RSA,DH,EC and DSA key pairs */ +CK_RV ep11tok_generate_key_pair(STDLL_TokData_t * tokdata, SESSION * sess, + CK_MECHANISM_PTR pMechanism, + CK_ATTRIBUTE_PTR pPublicKeyTemplate, + CK_ULONG ulPublicKeyAttributeCount, + CK_ATTRIBUTE_PTR pPrivateKeyTemplate, + CK_ULONG ulPrivateKeyAttributeCount, + CK_OBJECT_HANDLE_PTR phPublicKey, + CK_OBJECT_HANDLE_PTR phPrivateKey) +{ + CK_RV rc; + OBJECT *public_key_obj = NULL; + OBJECT *private_key_obj = NULL; + CK_ULONG priv_ktype, publ_ktype; + CK_ULONG class; + CK_ATTRIBUTE *attr = NULL; + CK_ATTRIBUTE *n_attr = NULL; + + /* Get the keytype to use when creating the key object */ + rc = ep11_get_keytype(pPrivateKeyTemplate, ulPrivateKeyAttributeCount, + pMechanism, &priv_ktype, &class); + if (rc != CKR_OK) { + TRACE_ERROR("%s get_keytype failed with rc=0x%lx\n", __func__, rc); + goto error; + } + + rc = ep11_get_keytype(pPublicKeyTemplate, ulPublicKeyAttributeCount, + pMechanism, &publ_ktype, &class); + if (rc != CKR_OK) { + TRACE_ERROR("%s get_keytype failed with rc=0x%lx\n", __func__, rc); + goto error; + } + + /* Now build the skeleton key. */ + rc = object_mgr_create_skel(tokdata, sess, pPublicKeyTemplate, + ulPublicKeyAttributeCount, MODE_KEYGEN, + CKO_PUBLIC_KEY, publ_ktype, &public_key_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("%s Object mgr create skeleton failed\n", __func__); + goto error; + } + + rc = object_mgr_create_skel(tokdata, sess, pPrivateKeyTemplate, + ulPrivateKeyAttributeCount, MODE_KEYGEN, + CKO_PRIVATE_KEY, priv_ktype, &private_key_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("%s Object mgr create skeleton failed\n", __func__); + goto error; + } + + switch (pMechanism->mechanism) { + case CKM_DH_PKCS_KEY_PAIR_GEN: + rc = dh_generate_keypair(tokdata, sess, pMechanism, + public_key_obj->template, + private_key_obj->template, + pPublicKeyTemplate, + ulPublicKeyAttributeCount, + pPrivateKeyTemplate, + ulPrivateKeyAttributeCount, sess->handle); + break; + case CKM_EC_KEY_PAIR_GEN: /* takes same parameters as RSA */ + case CKM_RSA_PKCS_KEY_PAIR_GEN: + case CKM_RSA_X9_31_KEY_PAIR_GEN: + rc = rsa_ec_generate_keypair(tokdata, sess, pMechanism, + public_key_obj->template, + private_key_obj->template, + pPublicKeyTemplate, + ulPublicKeyAttributeCount, + pPrivateKeyTemplate, + ulPrivateKeyAttributeCount, sess->handle); + break; + case CKM_DSA_PARAMETER_GEN: + case CKM_DSA_KEY_PAIR_GEN: + rc = dsa_generate_keypair(tokdata, sess, pMechanism, + public_key_obj->template, + private_key_obj->template, + pPublicKeyTemplate, + ulPublicKeyAttributeCount, + pPrivateKeyTemplate, + ulPrivateKeyAttributeCount, sess->handle); + break; + case CKM_IBM_DILITHIUM: + rc = ibm_dilithium_generate_keypair(tokdata, sess, pMechanism, + public_key_obj->template, + private_key_obj->template, + pPublicKeyTemplate, + ulPublicKeyAttributeCount, + pPrivateKeyTemplate, + ulPrivateKeyAttributeCount, + sess->handle); + break; + default: + TRACE_ERROR("%s invalid mech %s\n", __func__, + ep11_get_ckm(pMechanism->mechanism)); + rc = CKR_MECHANISM_INVALID; + goto error; + } + + if (rc != CKR_OK) { + TRACE_ERROR("%s rc=0x%lx hpubkey=0x%lx hprivkey=0x%lx" + " pub_name='%s' priv_name='%s' pub_obj=%p priv_obj=%p\n", + __func__, rc, *phPublicKey, *phPrivateKey, + public_key_obj->name, private_key_obj->name, + (void *)public_key_obj, (void *)private_key_obj); + goto error; + } else { + TRACE_INFO("%s rc=0x%lx hpubkey=0x%lx hprivkey=0x%lx" + " pub_name='%s' priv_name='%s' pub_obj=%p priv_obj=%p\n", + __func__, rc, *phPublicKey, *phPrivateKey, + public_key_obj->name, private_key_obj->name, + (void *)public_key_obj, (void *)private_key_obj); + } + + /* Copy CKA_MODULUS and CKA_PUBLIC_EXPONENT attributes from + * public key object to private key object to fulfill PKCS#11 + * private key template requirements + */ + + if (template_attribute_find(public_key_obj->template, CKA_MODULUS, &attr)) { + rc = build_attribute(attr->type, attr->pValue, attr->ulValueLen, + &n_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", + __func__, rc); + goto error; + } + + rc = template_update_attribute(private_key_obj->template, n_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with " + "rc=0x%lx\n", __func__, rc); + goto error; + } + } + + if (template_attribute_find(public_key_obj->template, + CKA_PUBLIC_EXPONENT, &attr)) { + rc = build_attribute(attr->type, attr->pValue, attr->ulValueLen, + &n_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", + __func__, rc); + goto error; + } + + rc = template_update_attribute(private_key_obj->template, n_attr); + if (rc != CKR_OK) { + TRACE_ERROR("%s template_update_attribute failed with " + "rc=0x%lx\n", __func__, rc); + goto error; + } + } + + /* Keys should be fully constructed, + * assign object handles and store keys. + */ + rc = object_mgr_create_final(tokdata, sess, public_key_obj, phPublicKey); + if (rc != CKR_OK) { + TRACE_DEVEL("%s Object mgr create final failed\n", __func__); + goto error; + } + + rc = object_mgr_create_final(tokdata, sess, private_key_obj, phPrivateKey); + if (rc != CKR_OK) { + TRACE_DEVEL("%s Object mgr create final failed\n", __func__); + object_mgr_destroy_object(tokdata, sess, *phPublicKey); + public_key_obj = NULL; + goto error; + } + return rc; + +error: + if (public_key_obj) + object_free(public_key_obj); + if (private_key_obj) + object_free(private_key_obj); + + *phPublicKey = 0; + *phPrivateKey = 0; + + return rc; +} + + +/* Returns a blob for a key object. + * The blob is created if none was build yet. + * The passed key_obj must hold the READ lock! + */ +static CK_RV obj_opaque_2_blob(STDLL_TokData_t *tokdata, OBJECT *key_obj, + CK_BYTE **blob, size_t *blobsize) +{ + CK_ATTRIBUTE *attr = NULL; + + UNUSED(tokdata); + + /* blob already exists */ + if (template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr) && + (attr->ulValueLen > 0)) { + *blob = attr->pValue; + *blobsize = (size_t) attr->ulValueLen; + TRACE_INFO("%s blob found blobsize=0x%zx\n", __func__, *blobsize); + return CKR_OK; + } else { + + /* should not happen, imported key types not supported + * should cause a failing token_specific_object_add + */ + TRACE_ERROR("%s no blob\n", __func__); + return CKR_ATTRIBUTE_VALUE_INVALID; + } +} + +/* 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. + * The caller must unlock the returned kobj when no longer needed + */ +static CK_RV h_opaque_2_blob(STDLL_TokData_t *tokdata, CK_OBJECT_HANDLE handle, + CK_BYTE **blob, size_t *blobsize, OBJECT **kobj, + OBJ_LOCK_TYPE lock_type) +{ + OBJECT *key_obj; + CK_RV rc; + + /* find the key obj by the key handle */ + rc = object_mgr_find_in_map1(tokdata, handle, &key_obj, lock_type); + if (rc != CKR_OK) { + TRACE_ERROR("%s key 0x%lx not mapped\n", __func__, handle); + if (rc == CKR_OBJECT_HANDLE_INVALID) + rc = CKR_KEY_HANDLE_INVALID; + return rc; + } + + rc = obj_opaque_2_blob(tokdata, key_obj, blob, blobsize); + + if (rc == CKR_OK) { + *kobj = key_obj; + } else { + object_put(tokdata, key_obj, lock_type != NO_LOCK); + key_obj = NULL; + } + + return rc; +} + +CK_RV ep11tok_sign_init(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM * mech, CK_BBOOL recover_mode, + CK_OBJECT_HANDLE key) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + size_t keyblobsize = 0; + 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); + + UNUSED(recover_mode); + + if (!ep11_sign_state) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + return CKR_HOST_MEMORY; + } + + rc = h_opaque_2_blob(tokdata, key, &keyblob, &keyblobsize, &key_obj, + READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc); + return rc; + } + + RETRY_START + rc = dll_m_SignInit(ep11_sign_state, &ep11_sign_state_l, + mech, keyblob, keyblobsize, ep11_data->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, session); + TRACE_ERROR("%s rc=0x%lx blobsize=0x%zx key=0x%lx mech=0x%lx\n", + __func__, rc, keyblobsize, key, mech->mechanism); + free(ep11_sign_state); + } else { + /* SIGN_VERIFY_CONTEX holds all needed for continuing, + * also by another adapter (stateless requests) + */ + ctx->key = key; + ctx->active = TRUE; + ctx->context = ep11_sign_state; + ctx->context_len = ep11_sign_state_l; + + TRACE_INFO("%s rc=0x%lx blobsize=0x%zx key=0x%lx mech=0x%lx\n", + __func__, rc, keyblobsize, key, mech->mechanism); + } + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +CK_RV ep11tok_sign(STDLL_TokData_t * tokdata, SESSION * session, + CK_BBOOL length_only, CK_BYTE * in_data, + CK_ULONG in_data_len, CK_BYTE * signature, + CK_ULONG * sig_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx; + + UNUSED(length_only); + + RETRY_START + rc = dll_m_Sign(ctx->context, ctx->context_len, in_data, in_data_len, + signature, sig_len, ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + + +CK_RV ep11tok_sign_update(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE * in_data, CK_ULONG in_data_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx; + + if (!in_data || !in_data_len) + return CKR_OK; + + RETRY_START + rc = dll_m_SignUpdate(ctx->context, ctx->context_len, in_data, + in_data_len, ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + + +CK_RV ep11tok_sign_final(STDLL_TokData_t * tokdata, SESSION * session, + CK_BBOOL length_only, CK_BYTE * signature, + CK_ULONG * sig_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx; + + UNUSED(length_only); + + RETRY_START + rc = dll_m_SignFinal(ctx->context, ctx->context_len, signature, sig_len, + ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + +CK_RV ep11tok_sign_single(STDLL_TokData_t *tokdata, SESSION *session, + CK_MECHANISM *mech, CK_BBOOL length_only, + CK_OBJECT_HANDLE key, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *signature, + CK_ULONG *sig_len) +{ + CK_RV rc; + size_t keyblobsize = 0; + CK_BYTE *keyblob; + OBJECT *key_obj = NULL; + ep11_private_data_t *ep11_data = tokdata->private_data; + + UNUSED(length_only); + + rc = h_opaque_2_blob(tokdata, key, &keyblob, &keyblobsize, &key_obj, + READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc); + return rc; + } + + RETRY_START + rc = dll_m_SignSingle(keyblob, keyblobsize, mech, in_data, in_data_len, + signature, sig_len, ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +CK_RV ep11tok_verify_init(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM * mech, CK_BBOOL recover_mode, + CK_OBJECT_HANDLE key) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_BYTE *spki; + 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); + + if (!ep11_sign_state) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + return CKR_HOST_MEMORY; + } + + rc = h_opaque_2_blob(tokdata, key, &spki, &spki_len, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc); + return rc; + } + + /* + * Enforce key usage restrictions. EP11 does not allow to restrict + * public keys with CKA_VERIFY=FALSE. Thus we need to enforce the + * restriction here. + */ + rc = check_key_restriction(key_obj, + recover_mode ? CKA_VERIFY_RECOVER : CKA_VERIFY); + if (rc != CKR_OK) { + TRACE_ERROR("%s check_key_restriction rc=0x%lx\n", __func__, rc); + goto done; + } + + RETRY_START + rc = dll_m_VerifyInit(ep11_sign_state, &ep11_sign_state_l, mech, + spki, spki_len, ep11_data->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, session); + TRACE_ERROR("%s rc=0x%lx spki_len=0x%zx key=0x%lx " + "ep11_sign_state_l=0x%zx mech=0x%lx\n", __func__, + rc, spki_len, key, ep11_sign_state_l, mech->mechanism); + } else { + ctx->key = key; + ctx->active = TRUE; + ctx->context = ep11_sign_state; + ctx->context_len = ep11_sign_state_l; + + TRACE_INFO("%s rc=0x%lx spki_len=0x%zx key=0x%lx " + "ep11_sign_state_l=0x%zx mech=0x%lx\n", __func__, + rc, spki_len, key, ep11_sign_state_l, mech->mechanism); + } + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +CK_RV ep11tok_verify(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE * in_data, CK_ULONG in_data_len, + CK_BYTE * signature, CK_ULONG sig_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx; + + RETRY_START + rc = dll_m_Verify(ctx->context, ctx->context_len, in_data, in_data_len, + signature, sig_len, ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + + +CK_RV ep11tok_verify_update(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE * in_data, CK_ULONG in_data_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx; + + if (!in_data || !in_data_len) + return CKR_OK; + + RETRY_START + rc = dll_m_VerifyUpdate(ctx->context, ctx->context_len, in_data, + in_data_len, ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + + +CK_RV ep11tok_verify_final(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE * signature, CK_ULONG sig_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx; + + RETRY_START + rc = dll_m_VerifyFinal(ctx->context, ctx->context_len, signature, + sig_len, ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + +CK_RV ep11tok_verify_single(STDLL_TokData_t *tokdata, SESSION *session, + CK_MECHANISM *mech, CK_OBJECT_HANDLE key, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) +{ + CK_RV rc; + CK_BYTE *spki; + size_t spki_len = 0; + OBJECT *key_obj = NULL; + ep11_private_data_t *ep11_data = tokdata->private_data; + + rc = h_opaque_2_blob(tokdata, key, &spki, &spki_len, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc); + return rc; + } + + /* + * Enforce key usage restrictions. EP11 does not allow to restrict + * public keys with CKA_VERIFY=FALSE. Thus we need to enforce the + * restriction here. + */ + rc = check_key_restriction(key_obj, CKA_VERIFY); + if (rc != CKR_OK) { + TRACE_ERROR("%s check_key_restriction rc=0x%lx\n", __func__, rc); + goto done; + } + + RETRY_START + rc = dll_m_VerifySingle(spki, spki_len, mech, in_data, in_data_len, + signature, sig_len, ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV ep11tok_decrypt_final(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc = CKR_OK; + ENCR_DECR_CONTEXT *ctx = &session->decr_ctx; + + RETRY_START + rc = dll_m_DecryptFinal(ctx->context, ctx->context_len, + output_part, p_output_part_len, + ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + + +CK_RV ep11tok_decrypt(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE_PTR input_data, CK_ULONG input_data_len, + CK_BYTE_PTR output_data, CK_ULONG_PTR p_output_data_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc = CKR_OK; + ENCR_DECR_CONTEXT *ctx = &session->decr_ctx; + + RETRY_START + rc = dll_m_Decrypt(ctx->context, ctx->context_len, input_data, + input_data_len, output_data, p_output_data_len, + ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + + +CK_RV ep11tok_decrypt_update(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE_PTR input_part, CK_ULONG input_part_len, + CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc = CKR_OK; + ENCR_DECR_CONTEXT *ctx = &session->decr_ctx; + + if (!input_part || !input_part_len) { + *p_output_part_len = 0; + return CKR_OK; /* nothing to update, keep context */ + } + + RETRY_START + rc = dll_m_DecryptUpdate(ctx->context, ctx->context_len, + input_part, input_part_len, output_part, + p_output_part_len, ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + +CK_RV ep11tok_decrypt_single(STDLL_TokData_t *tokdata, SESSION *session, + CK_MECHANISM *mech, CK_BBOOL length_only, + CK_OBJECT_HANDLE key, CK_BYTE_PTR input_data, + CK_ULONG input_data_len, CK_BYTE_PTR output_data, + CK_ULONG_PTR p_output_data_len) +{ + CK_RV rc; + size_t keyblobsize = 0; + CK_BYTE *keyblob; + OBJECT *key_obj = NULL; + ep11_private_data_t *ep11_data = tokdata->private_data; + + UNUSED(length_only); + + rc = h_opaque_2_blob(tokdata, key, &keyblob, &keyblobsize, &key_obj, + READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc); + return rc; + } + + RETRY_START + rc = dll_m_DecryptSingle(keyblob, keyblobsize, mech, input_data, + input_data_len, output_data, p_output_data_len, + ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV ep11tok_encrypt_final(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc = CKR_OK; + ENCR_DECR_CONTEXT *ctx = &session->encr_ctx; + + RETRY_START + rc = dll_m_EncryptFinal(ctx->context, ctx->context_len, + output_part, p_output_part_len, + ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + + +CK_RV ep11tok_encrypt(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE_PTR input_data, CK_ULONG input_data_len, + CK_BYTE_PTR output_data, CK_ULONG_PTR p_output_data_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc = CKR_OK; + ENCR_DECR_CONTEXT *ctx = &session->encr_ctx; + + RETRY_START + rc = dll_m_Encrypt(ctx->context, ctx->context_len, input_data, + input_data_len, output_data, p_output_data_len, + ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + + +CK_RV ep11tok_encrypt_update(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE_PTR input_part, CK_ULONG input_part_len, + CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc = CKR_OK; + ENCR_DECR_CONTEXT *ctx = &session->encr_ctx; + + if (!input_part || !input_part_len) { + *p_output_part_len = 0; + return CKR_OK; /* nothing to update, keep context */ + } + + RETRY_START + rc = dll_m_EncryptUpdate(ctx->context, ctx->context_len, + input_part, input_part_len, output_part, + p_output_part_len, ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + +CK_RV ep11tok_encrypt_single(STDLL_TokData_t *tokdata, SESSION *session, + CK_MECHANISM *mech, CK_BBOOL length_only, + CK_OBJECT_HANDLE key, CK_BYTE_PTR input_data, + CK_ULONG input_data_len, CK_BYTE_PTR output_data, + CK_ULONG_PTR p_output_data_len) +{ + CK_RV rc; + size_t keyblobsize = 0; + CK_BYTE *keyblob; + OBJECT *key_obj = NULL; + ep11_private_data_t *ep11_data = tokdata->private_data; + + UNUSED(length_only); + + rc = h_opaque_2_blob(tokdata, key, &keyblob, &keyblobsize, &key_obj, + READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc); + return rc; + } + + /* + * Enforce key usage restrictions. EP11 does not allow to restrict + * public keys with CKA_ENCRYPT=FALSE. Thus we need to enforce the + * restriction here. + */ + rc = check_key_restriction(key_obj, CKA_ENCRYPT); + if (rc != CKR_OK) { + TRACE_ERROR("%s check_key_restriction rc=0x%lx\n", __func__, rc); + goto done; + } + + RETRY_START + rc = dll_m_EncryptSingle(keyblob, keyblobsize, mech, input_data, + input_data_len, output_data, p_output_data_len, + ep11_data->target); + RETRY_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); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +static CK_RV ep11_ende_crypt_init(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM_PTR mech, CK_OBJECT_HANDLE key, + int op) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc = CKR_OK; + CK_BYTE *blob; + size_t blob_len = 0; + OBJECT *key_obj = NULL; + size_t ep11_state_l = MAX_CRYPT_STATE_BYTES; + CK_BYTE *ep11_state; + + ep11_state = malloc(ep11_state_l); /* freed by encr/decr_mgr.c */ + if (!ep11_state) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + return CKR_HOST_MEMORY; + } + + rc = h_opaque_2_blob(tokdata, key, &blob, &blob_len, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc); + goto error; + } + + if (op == DECRYPT) { + ENCR_DECR_CONTEXT *ctx = &session->decr_ctx; + RETRY_START + rc = dll_m_DecryptInit(ep11_state, &ep11_state_l, mech, blob, + blob_len, ep11_data->target); + RETRY_END(rc, tokdata, session) + ctx->key = key; + ctx->active = TRUE; + ctx->context = ep11_state; + ctx->context_len = ep11_state_l; + if (rc != CKR_OK) { + decr_mgr_cleanup(ctx); + rc = ep11_error_to_pkcs11_error(rc, session); + TRACE_ERROR("%s m_DecryptInit rc=0x%lx blob_len=0x%zx " + "mech=0x%lx\n", __func__, rc, blob_len, + mech->mechanism); + } else { + TRACE_INFO("%s m_DecryptInit rc=0x%lx blob_len=0x%zx " + "mech=0x%lx\n", __func__, rc, blob_len, mech->mechanism); + } + } else { + ENCR_DECR_CONTEXT *ctx = &session->encr_ctx; + + /* + * Enforce key usage restrictions. EP11 does not allow to restrict + * public keys with CKA_ENCRYPT=FALSE. Thus we need to enforce the + * restriction here. + */ + rc = check_key_restriction(key_obj, CKA_ENCRYPT); + if (rc != CKR_OK) { + TRACE_ERROR("%s check_key_restriction rc=0x%lx\n", __func__, rc); + goto error; + } + + RETRY_START + rc = dll_m_EncryptInit(ep11_state, &ep11_state_l, mech, blob, + blob_len, ep11_data->target); + RETRY_END(rc, tokdata, session) + ctx->key = key; + ctx->active = TRUE; + ctx->context = ep11_state; + ctx->context_len = ep11_state_l; + if (rc != CKR_OK) { + encr_mgr_cleanup(ctx); + rc = ep11_error_to_pkcs11_error(rc, session); + TRACE_ERROR("%s m_EncryptInit rc=0x%lx blob_len=0x%zx " + "mech=0x%lx\n", __func__, rc, blob_len, + mech->mechanism); + } else { + TRACE_INFO("%s m_EncryptInit rc=0x%lx blob_len=0x%zx " + "mech=0x%lx\n", __func__, rc, blob_len, mech->mechanism); + } + } + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; + +error: + if (ep11_state != NULL) + free(ep11_state); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + return rc; +} + + +CK_RV ep11tok_encrypt_init(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM_PTR mech, CK_OBJECT_HANDLE key) +{ + CK_RV rc; + + TRACE_INFO("%s key=0x%lx\n", __func__, key); + + rc = ep11_ende_crypt_init(tokdata, session, mech, key, ENCRYPT); + + if (rc != CKR_OK) { + TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + + +CK_RV ep11tok_decrypt_init(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM_PTR mech, CK_OBJECT_HANDLE key) +{ + CK_RV rc; + + TRACE_INFO("%s key=0x%lx mech=0x%lx\n", __func__, key, mech->mechanism); + + rc = ep11_ende_crypt_init(tokdata, session, mech, key, DECRYPT); + + if (rc != CKR_OK) { + TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + + return rc; +} + + +CK_RV ep11tok_wrap_key(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM_PTR mech, CK_OBJECT_HANDLE wrapping_key, + CK_OBJECT_HANDLE key, CK_BYTE_PTR wrapped_key, + CK_ULONG_PTR p_wrapped_key_len) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_BYTE *wrapping_blob; + size_t wrapping_blob_len; + + CK_BYTE *wrap_target_blob; + size_t wrap_target_blob_len; + int size_query = 0; + OBJECT *key_obj = NULL, *wrap_key_obj = NULL; + CK_ATTRIBUTE *attr; + + /* ep11 weakness: + * it does not set *p_wrapped_key_len if wrapped_key == NULL + * (that is with a size query) + */ + if (wrapped_key == NULL) { + size_query = 1; + *p_wrapped_key_len = MAX_BLOBSIZE; + wrapped_key = malloc(MAX_BLOBSIZE); + if (!wrapped_key) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + return CKR_HOST_MEMORY; + } + } + + /* the key that encrypts */ + rc = h_opaque_2_blob(tokdata, wrapping_key, &wrapping_blob, + &wrapping_blob_len, &wrap_key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("%s h_opaque_2_blob(wrapping_key) failed with rc=0x%lx\n", + __func__, rc); + if (size_query) + free(wrapped_key); + return rc; + } + + /* the key to be wrapped */ + rc = h_opaque_2_blob(tokdata, key, &wrap_target_blob, + &wrap_target_blob_len, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("%s h_opaque_2_blob(key) failed with rc=0x%lx\n", __func__, + rc); + if (size_query) + free(wrapped_key); + goto done; + } + + /* check if wrap mechanism is allowed for the key to be wrapped. + * AES_ECB and AES_CBC is only allowed to wrap secret keys. + */ + if (!template_attribute_find(key_obj->template, CKA_CLASS, &attr)) { + TRACE_ERROR("%s No CKA_CLASS attribute found in key template\n", + __func__); + rc = CKR_TEMPLATE_INCOMPLETE; + goto done; + } + + if ((*(CK_OBJECT_CLASS *) attr->pValue != CKO_SECRET_KEY) && + ((mech->mechanism == CKM_AES_ECB) || + (mech->mechanism == CKM_AES_CBC))) { + TRACE_ERROR("%s Wrap mechanism does not match to target key type\n", + __func__); + rc = CKR_KEY_NOT_WRAPPABLE; + goto done; + } + + /* debug */ + TRACE_INFO("%s start wrapKey: mech=0x%lx wr_key=0x%lx\n", + __func__, mech->mechanism, wrapping_key); + + /* The key to be wrapped is extracted from its blob by the card. + * A standard BER encoding is built and encrypted by the wrapping key + * (wrapping blob). The wrapped key can be processed by any PKCS11 + * implementation. + */ + RETRY_START + rc = + dll_m_WrapKey(wrap_target_blob, wrap_target_blob_len, wrapping_blob, + wrapping_blob_len, NULL, ~0, mech, wrapped_key, + p_wrapped_key_len, ep11_data->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { + TRACE_ERROR("%s m_WrapKey failed with rc=0x%lx\n", __func__, rc); + } else { + TRACE_INFO("%s rc=0x%lx wr_key=%p wr_key_len=0x%lx\n", + __func__, rc, (void *)wrapped_key, *p_wrapped_key_len); + } + + if (size_query) + free(wrapped_key); + +done: + object_put(tokdata, wrap_key_obj, TRUE); + wrap_key_obj = NULL; + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +CK_RV ep11tok_unwrap_key(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM_PTR mech, CK_ATTRIBUTE_PTR attrs, + CK_ULONG attrs_len, CK_BYTE_PTR wrapped_key, + CK_ULONG wrapped_key_len, + 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; + size_t wrapping_blob_len; + CK_BYTE csum[MAX_BLOBSIZE]; + CK_ULONG cslen = sizeof(csum); + OBJECT *key_obj = NULL; + CK_BYTE keyblob[MAX_BLOBSIZE]; + size_t keyblobsize = sizeof(keyblob); + CK_ATTRIBUTE *attr = NULL; + CK_ULONG i; + CK_ULONG ktype; + CK_ULONG class; + CK_ULONG len; + CK_ATTRIBUTE_PTR new_attrs = NULL; + CK_ULONG new_attrs_len = 0; + OBJECT *kobj = NULL; + unsigned char *ep11_pin_blob = NULL; + CK_ULONG ep11_pin_blob_len = 0; + ep11_session_t *ep11_session = (ep11_session_t *) session->private_data; + + /* get wrapping key blob */ + rc = h_opaque_2_blob(tokdata, wrapping_key, &wrapping_blob, + &wrapping_blob_len, &kobj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("%s h_opaque_2_blob(wrapping_key) failed with rc=0x%lx\n", + __func__, rc); + return rc; + } + + TRACE_DEVEL("%s start unwrapKey: mech=0x%lx attrs_len=0x%lx " + "wr_key=0x%lx\n", __func__, mech->mechanism, attrs_len, + wrapping_key); + for (i = 0; i < attrs_len; i++) { + TRACE_DEVEL(" attribute attrs.type=0x%lx\n", attrs[i].type); + } + + memset(keyblob, 0, sizeof(keyblob)); + + /*get key type of unwrapped key */ + CK_ATTRIBUTE_PTR cla_attr = + get_attribute_by_type(attrs, attrs_len, CKA_CLASS); + CK_ATTRIBUTE_PTR keytype_attr = + get_attribute_by_type(attrs, attrs_len, CKA_KEY_TYPE); + if (!cla_attr || !keytype_attr) { + TRACE_ERROR("%s CKA_CLASS or CKA_KEY_CLASS attributes not found\n", + __func__); + rc = CKR_TEMPLATE_INCONSISTENT; + goto error; + } + switch (*(CK_KEY_TYPE *) cla_attr->pValue) { + case CKO_SECRET_KEY: + rc = check_key_attributes(tokdata, + *(CK_KEY_TYPE *) keytype_attr->pValue, + CKO_SECRET_KEY, attrs, + attrs_len, &new_attrs, &new_attrs_len); + break; + case CKO_PUBLIC_KEY: + rc = check_key_attributes(tokdata, + *(CK_KEY_TYPE *) keytype_attr->pValue, + CKO_PUBLIC_KEY, attrs, attrs_len, + &new_attrs, &new_attrs_len); + break; + case CKO_PRIVATE_KEY: + rc = check_key_attributes(tokdata, + *(CK_KEY_TYPE *) keytype_attr->pValue, + CKO_PRIVATE_KEY, attrs, attrs_len, + &new_attrs, &new_attrs_len); + break; + default: + TRACE_ERROR("%s Missing CKA_CLASS type of wrapped key\n", __func__); + rc = CKR_TEMPLATE_INCOMPLETE; + goto error; + } + if (rc != CKR_OK) { + TRACE_ERROR("%s check key attributes failed: rc=0x%lx\n", __func__, rc); + goto error; + } + + /* check if unwrap mechanism is allowed for the key to be unwrapped. + * AES_ECB and AES_CBC only allowed to unwrap secret keys. + */ + if ((*(CK_OBJECT_CLASS *) cla_attr->pValue != CKO_SECRET_KEY) && + ((mech->mechanism == CKM_AES_ECB) || + (mech->mechanism == CKM_AES_CBC))) { + rc = CKR_ARGUMENTS_BAD; + goto error; + } + + + ep11_get_pin_blob(ep11_session, ep11_is_session_object(attrs, attrs_len), + &ep11_pin_blob, &ep11_pin_blob_len); + + /* we need a blob for the new key created by unwrapping, + * the wrapped key comes in BER + */ + RETRY_START + rc = dll_m_UnwrapKey(wrapped_key, wrapped_key_len, wrapping_blob, + wrapping_blob_len, NULL, ~0, ep11_pin_blob, + ep11_pin_blob_len, mech, new_attrs, new_attrs_len, + keyblob, &keyblobsize, csum, &cslen, + ep11_data->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, session); + TRACE_ERROR("%s m_UnwrapKey rc=0x%lx blobsize=0x%zx mech=0x%lx\n", + __func__, rc, keyblobsize, mech->mechanism); + goto error; + } + TRACE_INFO("%s m_UnwrapKey rc=0x%lx blobsize=0x%zx mech=0x%lx\n", + __func__, rc, keyblobsize, mech->mechanism); + + /* Get the keytype to use when creating the key object */ + rc = ep11_get_keytype(new_attrs, new_attrs_len, mech, &ktype, &class); + if (rc != CKR_OK) { + TRACE_ERROR("%s get_subclass failed with rc=0x%lx\n", __func__, rc); + goto error; + } + + /* Start creating the key object */ + rc = object_mgr_create_skel(tokdata, session, new_attrs, new_attrs_len, + MODE_UNWRAP, class, ktype, &key_obj); + if (rc != CKR_OK) { + TRACE_ERROR("%s object_mgr_create_skel failed with rc=0x%lx\n", + __func__, rc); + goto error; + } + + rc = build_attribute(CKA_IBM_OPAQUE, keyblob, 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; + } + + switch (*(CK_KEY_TYPE *) cla_attr->pValue) { + case CKO_SECRET_KEY: + /* card provides bit length in csum last 4 bytes big endian */ + if (cslen < 4) { + rc = CKR_FUNCTION_FAILED; + TRACE_ERROR("%s Invalid csum length cslen=%lu\n", __func__, cslen); + goto error; + } + + len = csum[cslen - 1] + 256 * csum[cslen - 2] + + 256 * 256 * csum[cslen - 3] + 256 * 256 * 256 * csum[cslen - 4]; + len = len / 8; /* comes in bits */ + TRACE_INFO("%s m_UnwrapKey length %lu 0x%lx\n", __func__, len, len); + + rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE *)&len, sizeof(CK_ULONG), + &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; + } + break; + + case CKO_PRIVATE_KEY: + /* + * In case of unwrapping a private key (CKA_CLASS == CKO_PRIVATE_KEY), + * the public key attributes needs to be added to the new template. + */ + switch (*(CK_KEY_TYPE *) keytype_attr->pValue) { + case CKK_EC: + rc = ecdsa_priv_unwrap_get_data(key_obj->template, csum, cslen); + break; + case CKK_RSA: + rc = rsa_priv_unwrap_get_data(key_obj->template, csum, cslen); + break; + case CKK_DSA: + rc = dsa_priv_unwrap_get_data(key_obj->template, csum, cslen); + break; + case CKK_DH: + rc = dh_priv_unwrap_get_data(key_obj->template, csum, cslen); + break; + case CKK_IBM_PQC_DILITHIUM: + rc = ibm_dilithium_priv_unwrap_get_data(key_obj->template, csum, cslen); + break; + } + + if (rc != 0) { + TRACE_ERROR("%s xxx_priv_unwrap_get_data rc=0x%lx\n", + __func__, rc); + goto error; + } + break; + } + + /* key should be fully constructed. + * Assign an object handle and store key. + */ + rc = object_mgr_create_final(tokdata, session, key_obj, p_key); + if (rc != CKR_OK) { + TRACE_ERROR("%s object_mgr_create_final with rc=0x%lx\n", __func__, rc); + goto error; + } + + goto done; + +error: + if (key_obj) + object_free(key_obj); + *p_key = 0; +done: + if (new_attrs) + free_attribute_array(new_attrs, new_attrs_len); + + object_put(tokdata, kobj, TRUE); + kobj = NULL; + + return rc; +} + + +/* mechanisms ep11 reports but should be hidden because e.g. + the EP11 card operates in a FIPS mode that forbides the mechanism, + add here other mechanisms if required */ +static const CK_MECHANISM_TYPE ep11_banned_mech_list[] = { +#ifdef DEFENSIVE_MECHLIST + CKM_DES_KEY_GEN, + CKM_DES_ECB, + CKM_DES_CBC, + CKM_DES_CBC_PAD, + CKM_GENERIC_SECRET_KEY_GEN, + + /* Wrong/outdated */ + CKM_EP11_SHA512_224, + CKM_EP11_SHA512_224_HMAC, + CKM_EP11_SHA512_224_HMAC_GENERAL, + CKM_EP11_SHA512_256, + CKM_EP11_SHA512_256_HMAC, + CKM_EP11_SHA512_256_HMAC_GENERAL, + + /* Vendor specific */ + CKM_IBM_ECDSA_SHA224, + CKM_IBM_ECDSA_SHA256, + CKM_IBM_ECDSA_SHA384, + CKM_IBM_ECDSA_SHA512, + CKM_IBM_EC_MULTIPLY, + CKM_IBM_EAC, + CKM_IBM_TESTCODE, + CKM_IBM_SHA512_256, + CKM_IBM_SHA512_224, + CKM_IBM_SHA512_256_HMAC, + CKM_IBM_SHA512_224_HMAC, + CKM_IBM_SHA512_256_KEY_DERIVATION, + CKM_IBM_SHA512_224_KEY_DERIVATION, + CKM_IBM_EDDSA_PH_SHA512, + CKM_IBM_SIPHASH, + CKM_IBM_CLEARKEY_TRANSPORT, + CKM_IBM_ATTRIBUTEBOUND_WRAP, + CKM_IBM_TRANSPORTKEY, + CKM_IBM_DH_PKCS_DERIVE_RAW, + CKM_IBM_ECDH1_DERIVE_RAW, + CKM_IBM_WIRETEST, + CKM_IBM_RETAINKEY, + CKM_IBM_CPACF_WRAP, + CKM_IBM_SM3, +#endif +}; + +static const CK_ULONG banned_mech_list_len = + (sizeof(ep11_banned_mech_list) / sizeof(CK_MECHANISM_TYPE)); + + +/* filtering out some mechanisms we do not want to provide + * makes it complicated + */ +CK_RV ep11tok_get_mechanism_list(STDLL_TokData_t * tokdata, + CK_MECHANISM_TYPE_PTR pMechanismList, + CK_ULONG_PTR pulCount) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc = 0; + CK_ULONG counter = 0, size = 0; + CK_MECHANISM_TYPE_PTR mlist = NULL; + CK_ULONG i; + + /* size querry */ + if (pMechanismList == NULL) { + rc = dll_m_GetMechanismList(0, pMechanismList, pulCount, + ep11_data->target); + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #1\n", + __func__, rc); + return rc; + } + + /* adjust the size according to the ban list, + * for this we need to know what the card provides + */ + counter = *pulCount; + + /* + * For mixed card levels, the size query call and the call to obtain the + * list may run on different cards. When the size query call runs on a + * card with less mechanisms than the second call, return code + * CKR_BUFFER_TOO_SMALL may be encountered, when the card where the + * second call runs supports more mechanisms than the one where the + * size query was run. Repeat the call to obtain the list with the + * larger list. + */ + do { + mlist = (CK_MECHANISM_TYPE *) malloc( + sizeof(CK_MECHANISM_TYPE) * counter); + if (!mlist) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + return CKR_HOST_MEMORY; + } + rc = dll_m_GetMechanismList(0, mlist, &counter, ep11_data->target); + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #2\n", + __func__, rc); + free(mlist); + if (rc != CKR_BUFFER_TOO_SMALL) + return rc; + } + } while (rc == CKR_BUFFER_TOO_SMALL); + + for (i = 0; i < counter; i++) { + if (ep11tok_is_mechanism_supported(tokdata, mlist[i]) != CKR_OK) { + /* banned mech found, + * decrement reported list size + */ + *pulCount = *pulCount - 1; + } + } + } else { + /* 2. call, content request */ + size = *pulCount; + + /* find out size ep11 will report, cannot use the size + * that comes as parameter, this is a 'reduced size', + * ep11 would complain about insufficient list size + */ + rc = dll_m_GetMechanismList(0, mlist, &counter, ep11_data->target); + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #3\n", + __func__, rc); + return rc; + } + + /* + * For mixed card levels, the size query call and the call to obtain the + * list may run on different cards. When the size query call runs on a + * card with less mechanisms than the second call, return code + * CKR_BUFFER_TOO_SMALL may be encountered, when the card where the + * second call runs supports more mechanisms than the one where the + * size query was run. Repeat the call to obtain the list with the + * larger list. + */ + do { + mlist = (CK_MECHANISM_TYPE *) malloc( + sizeof(CK_MECHANISM_TYPE) * counter); + if (!mlist) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + return CKR_HOST_MEMORY; + } + /* all the card has */ + rc = dll_m_GetMechanismList(0, mlist, &counter, ep11_data->target); + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #4\n", + __func__, rc); + free(mlist); + if (rc != CKR_BUFFER_TOO_SMALL) + return rc; + } + } while (rc == CKR_BUFFER_TOO_SMALL); + + for (i = 0; i < counter; i++) + TRACE_INFO("%s raw mech list entry '%s'\n", + __func__, ep11_get_ckm(mlist[i])); + + /* copy only mechanisms not banned */ + *pulCount = 0; + for (i = 0; i < counter; i++) { + if (ep11tok_is_mechanism_supported(tokdata, mlist[i]) == CKR_OK) { + if (*pulCount < size) + pMechanismList[*pulCount] = mlist[i]; + *pulCount = *pulCount + 1; + } + } + if (*pulCount > size) + rc = CKR_BUFFER_TOO_SMALL; + } + + if (mlist) + free(mlist); + return rc; +} + + +CK_RV ep11tok_is_mechanism_supported(STDLL_TokData_t *tokdata, + CK_MECHANISM_TYPE type) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_VERSION ver1_3 = { .major = 1, .minor = 3 }; + CK_VERSION ver3 = { .major = 3, .minor = 0 }; + CK_ULONG i; + int status; + + for (i = 0; i < banned_mech_list_len; i++) { + if (type == ep11_banned_mech_list[i]) { + TRACE_INFO("%s Mech '%s' banned\n", __func__, ep11_get_ckm(type)); + return CKR_MECHANISM_INVALID; + } + } + + if (check_cps_for_mechanism(ep11_data->cp_config, + type, ep11_data->control_points, + ep11_data->control_points_len, + ep11_data->max_control_point_index) != CKR_OK) { + TRACE_INFO("%s Mech '%s' banned due to control point\n", + __func__, ep11_get_ckm(type)); + return CKR_MECHANISM_INVALID; + } + + switch(type) { + case CKM_SHA_1_HMAC: + case CKM_SHA_1_HMAC_GENERAL: + case CKM_SHA224_HMAC: + case CKM_SHA224_HMAC_GENERAL: + case CKM_SHA256_HMAC: + case CKM_SHA256_HMAC_GENERAL: + case CKM_SHA384_HMAC: + case CKM_SHA384_HMAC_GENERAL: + case CKM_SHA512_HMAC: + case CKM_SHA512_HMAC_GENERAL: + case CKM_SHA512_224_HMAC: + case CKM_SHA512_224_HMAC_GENERAL: + case CKM_SHA512_256_HMAC: + case CKM_SHA512_256_HMAC_GENERAL: + /* + * Older levels of the EP11 firmware report ulMinKeySize in bytes, + * but ulMaxKeySize in bits for HMAC mechanisms. Newer levels of the + * EP11 firmware report both ulMinKeySize and ulMaxKeySize in bytes. + * HMAC mechanisms are only supported when all configured EP11 + * crypto adapters either have the fix, or all don't have the fix. + */ + status = check_required_versions(tokdata, hmac_req_versions, + NUM_HMAC_REQ); + if (status == -1) { + TRACE_INFO("%s Mech '%s' banned due to mixed firmware versions\n", + __func__, ep11_get_ckm(type)); + return CKR_MECHANISM_INVALID; + } + break; + + case CKM_RSA_PKCS_OAEP: + /* CKM_RSA_PKCS_OAEP is not supported with EP11 host library <= 1.3 */ + if (compare_ck_version(&ep11_data->ep11_lib_version, &ver1_3) <= 0) + return CKR_MECHANISM_INVALID; + break; + + case CKM_IBM_SHA3_224: + case CKM_IBM_SHA3_256: + case CKM_IBM_SHA3_384: + case CKM_IBM_SHA3_512: + case CKM_IBM_SHA3_224_HMAC: + case CKM_IBM_SHA3_256_HMAC: + case CKM_IBM_SHA3_384_HMAC: + case CKM_IBM_SHA3_512_HMAC: + status = check_required_versions(tokdata, ibm_sha3_req_versions, + NUM_IBM_SHA3_REQ); + if (status != 1) { + TRACE_INFO("%s Mech '%s' banned due to mixed firmware versions\n", + __func__, ep11_get_ckm(type)); + return CKR_MECHANISM_INVALID; + } + break; + + case CKM_DES3_CMAC: + case CKM_DES3_CMAC_GENERAL: + case CKM_AES_CMAC: + case CKM_AES_CMAC_GENERAL: + status = check_required_versions(tokdata, cmac_req_versions, + NUM_CMAC_REQ); + if (status != 1) { + TRACE_INFO("%s Mech '%s' banned due to mixed firmware versions\n", + __func__, ep11_get_ckm(type)); + return CKR_MECHANISM_INVALID; + } + break; + + case CKM_IBM_EC_C25519: + case CKM_IBM_EDDSA_SHA512: + case CKM_IBM_EC_C448: + case CKM_IBM_ED448_SHA3: + if (compare_ck_version(&ep11_data->ep11_lib_version, &ver3) < 0) { + TRACE_INFO("%s Mech '%s' banned due to host library version\n", + __func__, ep11_get_ckm(type)); + return CKR_MECHANISM_INVALID; + } + + status = check_required_versions(tokdata, edwards_req_versions, + NUM_EDWARDS_REQ); + if (status != 1) { + TRACE_INFO("%s Mech '%s' banned due to mixed firmware versions\n", + __func__, ep11_get_ckm(type)); + return CKR_MECHANISM_INVALID; + } + break; + + case CKM_IBM_DILITHIUM: + if (compare_ck_version(&ep11_data->ep11_lib_version, &ver3) <= 0) { + TRACE_INFO("%s Mech '%s' banned due to host library version\n", + __func__, ep11_get_ckm(type)); + return CKR_MECHANISM_INVALID; + } + status = check_required_versions(tokdata, ibm_dilithium_req_versions, + NUM_DILITHIUM_REQ); + if (status != 1) { + TRACE_INFO("%s Mech '%s' banned due to mixed firmware versions\n", + __func__, ep11_get_ckm(type)); + return CKR_MECHANISM_INVALID; + } + break; + } + + return CKR_OK; +} + +CK_RV ep11tok_is_mechanism_supported_ex(STDLL_TokData_t *tokdata, + CK_MECHANISM_PTR mech) +{ + CK_RSA_PKCS_OAEP_PARAMS *params; + int status; + CK_RV rc; + + rc = ep11tok_is_mechanism_supported(tokdata, mech->mechanism); + if (rc != CKR_OK) + return rc; + + switch (mech->mechanism) { + case CKM_RSA_PKCS_OAEP: + if (mech->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS) || + mech->pParameter == NULL) + return CKR_MECHANISM_PARAM_INVALID; + + params = (CK_RSA_PKCS_OAEP_PARAMS *)mech->pParameter; + + status = check_required_versions(tokdata, oaep_sha2_req_versions, + NUM_OAEP_SHA2_REQ); + if (status == 1) + return CKR_OK; + + /* + * Not all APQNs have the required firmware level, restrict to SHA1 + * for hashing algorithm and MGF. + */ + if (params->hashAlg == CKM_SHA_1 && params->mgf == CKG_MGF1_SHA1) + return CKR_OK; + + TRACE_INFO("%s RSA-OAEP supports SHA1 only due to mixed firmware " + " versions\n", __func__); + return CKR_MECHANISM_PARAM_INVALID; + } + return CKR_OK; +} + +CK_RV ep11tok_get_mechanism_info(STDLL_TokData_t * tokdata, + CK_MECHANISM_TYPE type, + CK_MECHANISM_INFO_PTR pInfo) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + int status; + + rc = ep11tok_is_mechanism_supported(tokdata, type); + if (rc != CKR_OK) { + TRACE_DEBUG("%s rc=0x%lx unsupported '%s'\n", __func__, rc, + ep11_get_ckm(type)); + return rc; + } + + rc = dll_m_GetMechanismInfo(0, type, pInfo, ep11_data->target); + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s m_GetMechanismInfo(0x%lx) failed with rc=0x%lx\n", + __func__, type, rc); + return rc; + } + + /* The card operates always in a FISP mode that requires stronger + * key sizes, but, in theory, can also operate with weaker key sizes. + * Customers are not interested in theory but in what mechanism + * they can use (mechanisms that are not rejected by the card). + */ +#ifdef DEFENSIVE_MECHLIST + switch (type) { + case CKM_RSA_PKCS: + case CKM_RSA_PKCS_KEY_PAIR_GEN: + case CKM_RSA_X9_31_KEY_PAIR_GEN: + case CKM_RSA_PKCS_PSS: + case CKM_RSA_PKCS_OAEP: + case CKM_SHA1_RSA_X9_31: + case CKM_SHA1_RSA_PKCS: + case CKM_SHA1_RSA_PKCS_PSS: + case CKM_SHA256_RSA_PKCS: + case CKM_SHA256_RSA_PKCS_PSS: + case CKM_SHA224_RSA_PKCS: + case CKM_SHA224_RSA_PKCS_PSS: + case CKM_SHA384_RSA_PKCS: + case CKM_SHA384_RSA_PKCS_PSS: + case CKM_SHA512_RSA_PKCS: + case CKM_SHA512_RSA_PKCS_PSS: + case CKM_RSA_X_509: + case CKM_RSA_X9_31: + /* EP11 card always in a FIPS mode rejecting + * lower key sizes + */ + pInfo->ulMinKeySize = 1024; + break; + + case CKM_SHA_1_HMAC: + case CKM_SHA_1_HMAC_GENERAL: + case CKM_SHA224_HMAC: + case CKM_SHA224_HMAC_GENERAL: + case CKM_SHA256_HMAC: + case CKM_SHA256_HMAC_GENERAL: + case CKM_SHA384_HMAC: + case CKM_SHA384_HMAC_GENERAL: + case CKM_SHA512_HMAC: + case CKM_SHA512_HMAC_GENERAL: + case CKM_SHA512_224_HMAC: + case CKM_SHA512_224_HMAC_GENERAL: + case CKM_SHA512_256_HMAC: + case CKM_SHA512_256_HMAC_GENERAL: + case CKM_IBM_SHA3_224_HMAC: + case CKM_IBM_SHA3_256_HMAC: + case CKM_IBM_SHA3_384_HMAC: + case CKM_IBM_SHA3_512_HMAC: + /* + * Older levels of the EP11 firmware report ulMinKeySize in bytes, + * but ulMaxKeySize in bits for HMAC mechanisms. Adjust ulMinKeySize + * so that both are in bits, as required by the PKCS#11 standard. + * Newer levels of the EP11 firmware report both ulMinKeySize and + * ulMaxKeySize in bytes. Adjust both, so that both are in bits, as + * required by the PKCS#11 standard. + */ + status = check_required_versions(tokdata, hmac_req_versions, + NUM_HMAC_REQ); + if (status == -1) + return CKR_MECHANISM_INVALID; + + pInfo->ulMinKeySize *= 8; + if (status == 1) + pInfo->ulMaxKeySize *= 8; + break; + + case CKM_DES3_ECB: + case CKM_DES3_CBC: + case CKM_DES3_CBC_PAD: + /* EP11 card always in a FIPS mode rejecting + * lower key sizes < 80 bits. + */ + if (pInfo->ulMinKeySize == 8) + pInfo->ulMinKeySize = 16; + break; + + default: + ; /* do not touch */ + } +#endif /* DEFENSIVE_MECHLIST */ + + return CKR_OK; +} + + +/* used for reading in the adapter config file, + * converts a 'token' to a number, returns 0 with success + */ +static inline short check_n(ep11_target_t * target, char *nptr, int *apqn_i) +{ + int num; + + if (sscanf(nptr, "%i", &num) != 1) { + TRACE_ERROR("%s invalid number '%s'\n", __func__, nptr); + return -1; + } + + if (num < 0 || num > 255) { + TRACE_ERROR("%s invalid number '%s' %d\n", __func__, nptr, num); + return -1; + } else if (*apqn_i < 0 || *apqn_i >= MAX_APQN * 2) { + TRACE_ERROR("%s invalid amount of numbers %d\n", __func__, num); + return -1; + } else { + /* insert number into target variable */ + target->apqns[*apqn_i] = (short) num; + /* how many APQNs numbers so far */ + *apqn_i = *apqn_i + 1; + return 0; + } +} + + +static int read_adapter_config_file(STDLL_TokData_t * tokdata, + const char *conf_name) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + FILE *ap_fp = NULL; /* file pointer adapter config file */ + int i, ap_file_size = 0; /* size adapter config file */ + char *token, *str; + char filebuf[EP11_CFG_FILE_SIZE]; + char line[1024]; + int whitemode = 0; + int anymode = 0; + int apqn_i = 0; /* how many APQN numbers */ + char *conf_dir = getenv("OCK_EP11_TOKEN_DIR"); + char fname[PATH_MAX]; + int rc = 0; + char *cfg_dir; + char cfgname[2*PATH_MAX + 1]; + + if (tokdata->initialized) + return 0; + + memset(fname, 0, PATH_MAX); + + /* via envrionment variable it is possible to overwrite the + * directory where the ep11 token config file is searched. + */ + if (conf_dir) { + if (conf_name && strlen(conf_name) > 0) { + /* extract filename part from conf_name */ + for (i = strlen(conf_name) - 1; i >= 0 && conf_name[i] != '/'; i--); + + snprintf(fname, sizeof(fname), "%s/%s", conf_dir, + conf_name + i + 1); + fname[sizeof(fname) - 1] = '\0'; + ap_fp = fopen(fname, "r"); + + if (!ap_fp) + TRACE_DEVEL("%s fopen('%s') failed with errno %d\n", + __func__, fname, errno); + } + if (!ap_fp) { + snprintf(fname, sizeof(fname), "%s/%s", conf_dir, + EP11_DEFAULT_CFG_FILE); + fname[sizeof(fname) - 1] = '\0'; + ap_fp = fopen(fname, "r"); + if (!ap_fp) + TRACE_DEVEL("%s fopen('%s') failed with errno %d\n", + __func__, fname, errno); + } + } else { + if (conf_name && strlen(conf_name) > 0) { + strncpy(fname, conf_name, sizeof(fname) - 1); + fname[sizeof(fname) - 1] = '\0'; + ap_fp = fopen(fname, "r"); + if (!ap_fp) { + TRACE_DEVEL("%s fopen('%s') failed with errno %d\n", + __func__, fname, errno); + snprintf(fname, sizeof(fname), "%s/%s", OCK_CONFDIR, conf_name); + fname[sizeof(fname) - 1] = '\0'; + ap_fp = fopen(fname, "r"); + if (!ap_fp) + TRACE_DEVEL("%s fopen('%s') failed with errno %d\n", + __func__, fname, errno); + } + } else { + snprintf(fname, sizeof(fname), "%s/%s", OCK_CONFDIR, + EP11_DEFAULT_CFG_FILE); + fname[sizeof(fname) - 1] = '\0'; + ap_fp = fopen(fname, "r"); + if (!ap_fp) + TRACE_DEVEL("%s fopen('%s') failed with errno %d\n", + __func__, fname, errno); + } + } + + /* now we should really have an open ep11 token config file */ + if (!ap_fp) { + TRACE_ERROR("%s no valid EP 11 config file found\n", __func__); + OCK_SYSLOG(LOG_ERR, "%s: Error: EP 11 config file '%s' not found\n", + __func__, fname); + return APQN_FILE_INV; + } + + TRACE_INFO("%s EP 11 token config file is '%s'\n", __func__, fname); + + /* read config file line by line, + * ignore empty and # and copy rest into file buf + */ + memset(filebuf, 0, EP11_CFG_FILE_SIZE); + while (fgets((char *) line, sizeof(line), ap_fp)) { + char *p; + int len; + /* skip over leading spaces */ + for (p = line; *p == ' ' || *p == '\t'; p++); + /* if line is empty or starts with # skip line */ + len = strlen(p); + if (*p != '#' && *p != '\n' && len > 0) { + /* store line in buffer */ + if (ap_file_size + len < EP11_CFG_FILE_SIZE) { + memcpy(filebuf + ap_file_size, p, len); + ap_file_size += len; + } else { + TRACE_ERROR("%s EP 11 config file '%s' is too large\n", + __func__, fname); + fclose(ap_fp); + OCK_SYSLOG(LOG_ERR, + "%s: Error: EP 11 config file '%s' is too large\n", + __func__, fname); + return APQN_FILE_INV_FILE_SIZE; + } + } + } + fclose(ap_fp); + + ep11_data->target_list.length = 0; + + /* Default to use default libica library for digests */ + ep11_data->digest_libica = 1; + strcpy(ep11_data->digest_libica_path, ""); + + /* parse the file buf + * please note, we still accept the LOGLEVEL entry + * for compatibility reasons but just ignore it. + */ + for (i = 0, str = filebuf; rc == 0; str = NULL) { + /* strtok tokenizes the string, + * delimiters are newline and whitespace. + */ + token = strtok(str, "\n\t "); + + if (i == 0) { + /* expecting APQN_WHITELIST or APQN_ANY or LOGLEVEL or eof */ + if (token == NULL) + break; + if (strncmp(token, "APQN_WHITELIST", 14) == 0) { + whitemode = 1; + i = 1; + } else if (strncmp(token, "APQN_ANY", 8) == 0) { + anymode = 1; + i = 0; + } else if (strncmp(token, "LOGLEVEL", 8) == 0) { + i = 3; + } else if (strncmp(token, "FORCE_SENSITIVE", 15) == 0) { + i = 0; + ep11_data->cka_sensitive_default_true = 1; + } else if (strncmp(token, "CPFILTER", 8) == 0) { + i = 4; + } else if (strncmp(token, "STRICT_MODE", 11) == 0) { + i = 0; + ep11_data->strict_mode = 1; + } else if (strncmp(token, "VHSM_MODE", 11) == 0) { + i = 0; + ep11_data->vhsm_mode = 1; + } else if (strncmp(token, "OPTIMIZE_SINGLE_PART_OPERATIONS", + 31) == 0) { + i = 0; + ep11_data->optimize_single_ops = 1; + } else if (strncmp(token, "DIGEST_LIBICA", 13) == 0) { + i = 5; + } else if (strncmp(token, "USE_PRANDOM", 11) == 0) { + i = 0; + token_specific.t_rng = NULL; + } else { + /* syntax error */ + TRACE_ERROR("%s Expected APQN_WHITELIST," + " APQN_ANY, LOGLEVEL, FORCE_SENSITIVE, CPFILTER," + " STRICT_MODE, VHSM_MODE, " + " OPTIMIZE_SINGLE_PART_OPERATIONS, DIGEST_LIBICA, " + "or USE_PRANDOM keyword, found '%s' in config file " + "'%s'\n", __func__, + token, fname); + OCK_SYSLOG(LOG_ERR, "%s: Error: Expected APQN_WHITELIST," + " APQN_ANY, LOGLEVEL, FORCE_SENSITIVE, CPFILTER," + " STRICT_MODE, VHSM_MODE," + " OPTIMIZE_SINGLE_PART_OPERATIONS, DIGEST_LIBICA, " + "or USE_PRANDOM keyword, found '%s' in config file " + "'%s'\n", + __func__, token, fname); + rc = APQN_FILE_SYNTAX_ERROR_0; + break; + } + } else if (i == 1) { + /* expecting END or first number of a number + * pair (number range 0...255) + */ + if (token == NULL) { + rc = APQN_FILE_UNEXPECTED_END_OF_FILE; + OCK_SYSLOG(LOG_ERR, "%s: Error: Unexpected end of file found" + " in config file '%s', expected 'END' or adapter" + " number\n", + __func__, fname); + break; + } + if (strncmp(token, "END", 3) == 0) { + i = 0; + } else { + if (check_n(&ep11_data->target_list, token, &apqn_i) < 0) { + rc = APQN_FILE_SYNTAX_ERROR_1; + OCK_SYSLOG(LOG_ERR, "%s: Error: Expected valid adapter" + " number, found '%s' in config file '%s'\n", + __func__, token, fname); + break; + } + i = 2; + } + } else if (i == 2) { + /* expecting second number of a number pair + * (number range 0...255) + */ + if (token == NULL) { + rc = APQN_FILE_UNEXPECTED_END_OF_FILE; + OCK_SYSLOG(LOG_ERR, "%s: Error: Unexpected end of file found" + " in config file '%s', expected domain number" + " (2nd number)\n", __func__, fname); + break; + } + if (strncmp(token, "END", 3) == 0) { + TRACE_ERROR("%s Expected 2nd number, found '%s' in config " + "file\n", __func__, token); + OCK_SYSLOG(LOG_ERR, + "%s: Error: Expected valid domain" + " number (2nd number), found '%s' in config file" + " '%s'\n", __func__, token, fname); + rc = APQN_FILE_SYNTAX_ERROR_2; + break; + } + if (check_n(&ep11_data->target_list, token, &apqn_i) < 0) { + OCK_SYSLOG(LOG_ERR, "%s: Error: Expected valid domain" + " number (2nd number), found '%s' in config file" + " '%s'\n", __func__, token, fname); + rc = APQN_FILE_SYNTAX_ERROR_3; + break; + } + ep11_data->target_list.length++; + if (ep11_data->target_list.length > MAX_APQN) { + TRACE_ERROR("%s Too many APQNs in config file (max %d)\n", + __func__, (int) MAX_APQN); + OCK_SYSLOG(LOG_ERR, + "%s: Error: Too many APQNs in config file '%s'\n", + __func__, fname); + rc = APQN_FILE_SYNTAX_ERROR_4; + break; + } + i = 1; + } else if (i == 3) { + /* expecting log level value + * (a number in the range 0...9) + */ + if (token == NULL) { + rc = APQN_FILE_UNEXPECTED_END_OF_FILE; + OCK_SYSLOG(LOG_ERR, "%s: Error: Unexpected end of file found" + " in config file '%s', expected LOGLEVEL value\n", + __func__, fname); + break; + } + char *endptr; + int loglevel = strtol(token, &endptr, 10); + if (*endptr != '\0' || loglevel < 0 || loglevel > 9) { + TRACE_ERROR("%s Invalid loglevel value '%s' in config file\n", + __func__, token); + OCK_SYSLOG(LOG_ERR, + "%s: Error: Invalid LOGLEVEL value '%s' in config " + "file '%s'\n", + __func__, token, fname); + rc = APQN_FILE_SYNTAX_ERROR_5; + break; + } + TRACE_WARNING("%s LOGLEVEL setting is not supported any more !\n", + __func__); + TRACE_WARNING + ("%s Use opencryptoki logging/tracing facilities instead.\n", + __func__); + OCK_SYSLOG(LOG_WARNING, + "%s: Warning: LOGLEVEL setting is not supported any " + "more. Use opencryptoki logging/tracing facilities " + "instead.\n", __func__); + i = 0; + } else if (i == 4) { + /* expecting CP-filter config file name */ + if (token == NULL) { + rc = APQN_FILE_UNEXPECTED_END_OF_FILE; + OCK_SYSLOG(LOG_ERR, "%s: Error: Unexpected end of file found" + " in config file '%s', expected CP-Filter file " + "name\n", __func__, fname); + break; + } + if (strlen(token) > + sizeof(ep11_data->cp_filter_config_filename) - 1) { + TRACE_ERROR("%s CP-Filter config file name is too long: '%s'\n", + __func__, token); + OCK_SYSLOG(LOG_ERR, + "%s: Error: CP-Filter config file name '%s' is too " + "long in config file '%s'\n", + __func__, token, fname); + rc = APQN_FILE_SYNTAX_ERROR_6; + break; + } + strncpy(ep11_data->cp_filter_config_filename, token, + sizeof(ep11_data->cp_filter_config_filename) - 1); + ep11_data->cp_filter_config_filename[ + sizeof(ep11_data->cp_filter_config_filename) - 1] = '\0'; + i = 0; + } else if (i == 5) { + /* expecting libica path, 'DEFAULT', or 'OFF' */ + if (token == NULL) { + rc = APQN_FILE_UNEXPECTED_END_OF_FILE; + OCK_SYSLOG(LOG_ERR,"%s: Error: Unexpected end of file found" + " in config file '%s', expected libica path, " + "'DEFAULT', or 'OFF'\n", + __func__, fname); + break; + } + if (strcmp(token, "OFF") == 0) { + ep11_data->digest_libica = 0; + } else if (strcmp(token, "DEFAULT") == 0) { + ep11_data->digest_libica = 1; + strcpy(ep11_data->digest_libica_path, ""); + } else { + if (strlen(token) > sizeof(ep11_data->digest_libica_path)-1) { + TRACE_ERROR("%s libica path is too long: '%s'\n", + __func__, token); + OCK_SYSLOG(LOG_ERR,"%s: Error: libica path '%s' is too long" + " in config file '%s'\n", + __func__, token, fname); + rc = APQN_FILE_SYNTAX_ERROR_6; + break; + } + ep11_data->digest_libica = 1; + strncpy(ep11_data->digest_libica_path, token, + sizeof(ep11_data->digest_libica_path)-1); + ep11_data->digest_libica_path[sizeof(ep11_data->digest_libica_path)-1] = '\0'; + } + i = 0; + } + } + + /* do some checks: */ + if (rc == 0) { + if (!(whitemode || anymode)) { + TRACE_ERROR("%s At least one APQN mode needs to be present in " + "config file: APQN_WHITEMODE or APQN_ANY\n", __func__); + OCK_SYSLOG(LOG_ERR, + "%s: Error: At least one APQN mode needs to be present " + " in config file '%s': APQN_WHITEMODE or APQN_ANY\n", + __func__, fname); + rc = APQN_FILE_NO_APQN_MODE; + } else if (whitemode && anymode) { + TRACE_ERROR("%s Only one APQN mode can be present in config file:" + " APQN_WHITEMODE or APQN_ANY\n", __func__); + OCK_SYSLOG(LOG_ERR, + "%s: Error: Only one APQN mode can be present in" + " config file '%s': APQN_WHITEMODE or APQN_ANY\n", + __func__, fname); + rc = APQN_FILE_NO_APQN_MODE; + } else if (whitemode) { + /* at least one APQN needs to be defined */ + if (ep11_data->target_list.length < 1) { + TRACE_ERROR("%s At least one APQN needs to be defined in the " + "config file\n", __func__); + OCK_SYSLOG(LOG_ERR, + "%s: Error: At least one APQN needs to be defined in" + " config file '%s'\n", __func__, fname); + rc = APQN_FILE_NO_APQN_GIVEN; + } + } + } + + /* log the whitelist of APQNs */ + if (rc == 0 && whitemode) { + TRACE_INFO("%s whitelist with %d APQNs defined:\n", + __func__, ep11_data->target_list.length); + for (i = 0; i < ep11_data->target_list.length; i++) { + TRACE_INFO(" APQN entry %d: adapter=%d domain=%d\n", i, + ep11_data->target_list.apqns[2 * i], + ep11_data->target_list.apqns[2 * i + 1]); + } + } + + /* read CP-filter config file */ + if (rc == 0) { + cfg_dir = dirname(fname); + if (strlen(ep11_data->cp_filter_config_filename) == 0) { + snprintf(ep11_data->cp_filter_config_filename, + sizeof(ep11_data->cp_filter_config_filename) - 1, + "%s/%s", cfg_dir, EP11_DEFAULT_CPFILTER_FILE); + ep11_data->cp_filter_config_filename[ + sizeof(ep11_data->cp_filter_config_filename) - 1] = '\0'; + } + + if (strchr(ep11_data->cp_filter_config_filename, '/') == NULL) { + cfgname[0] = '\0'; + + if (strlen(cfg_dir) + 1 + + strlen(ep11_data->cp_filter_config_filename) + <= sizeof(cfgname) - 1) { + strcpy(cfgname, cfg_dir); + cfgname[strlen(cfg_dir)] = '/'; + strcpy(cfgname + strlen(cfg_dir) + 1, + ep11_data->cp_filter_config_filename); + } + if (strlen(cfgname) < sizeof(ep11_data->cp_filter_config_filename)) + strcpy(ep11_data->cp_filter_config_filename, cfgname); + ep11_data->cp_filter_config_filename[ + sizeof(ep11_data->cp_filter_config_filename) - 1] = '\0'; + } + + rc = read_cp_filter_config_file(ep11_data->cp_filter_config_filename, + &ep11_data->cp_config); + } + + tokdata->initialized = TRUE; + return rc; +} + +#define UNKNOWN_CP 0xFFFFFFFF + +#define CP_BYTE_NO(cp) ((cp) / 8) +#define CP_BIT_IN_BYTE(cp) ((cp) % 8) +#define CP_BIT_MASK(cp) (0x80 >> CP_BIT_IN_BYTE(cp)) + +static int read_cp_filter_config_file(const char *conf_name, + cp_config_t ** cp_config) +{ + int rc = 0; + FILE *fp = NULL; + char line[1024]; + char *tok; + unsigned long int val; + char *endp; + cp_config_t *cp; + cp_config_t *last_cp = NULL; + cp_mech_config_t *mech; + cp_mech_config_t *last_mech; + + TRACE_INFO("%s EP 11 CP-filter config file is '%s'\n", __func__, conf_name); + + fp = fopen(conf_name, "r"); + if (fp == NULL) { + TRACE_ERROR("%s no valid EP 11 CP-filter config file found\n", + __func__); + OCK_SYSLOG(LOG_WARNING, + "%s: Warning: EP 11 CP-filter config file '%s'" + " does not exist, no filtering will be used\n", __func__, + conf_name); + /* this is not an error condition. When no CP-filter file is available, + * then the mechanisms are not filtered. */ + return 0; + } + + while (fgets((char *) line, sizeof(line), fp)) { + tok = strtok(line, ": \t\n"); + + if (tok == NULL) + continue; + if (*tok == '#') + continue; + + val = strtoul(tok, &endp, 0); + if (*endp != '\0') { + val = ep11_get_cp_by_name(tok); + if (val == UNKNOWN_CP) { + TRACE_ERROR("%s Syntax error in EP 11 CP-filter config file " + "found. \n", __func__); + OCK_SYSLOG(LOG_ERR, + "%s: Error: Expected valid control point name or " + "number, found '%s' in CP-filter config file '%s'\n", + __func__, tok, conf_name); + rc = APQN_FILE_SYNTAX_ERROR_7; + goto out_fclose; + } + } + + cp = (cp_config_t *) malloc(sizeof(cp_config_t)); + if (cp == NULL) { + TRACE_ERROR("%s Out of memory.\n", __func__); + rc = APQN_OUT_OF_MEMORY; + goto out_fclose; + } + cp->cp = val; + cp->mech = NULL; + cp->next = NULL; + + last_mech = NULL; + while ((tok = strtok(NULL, ", \t\n")) != NULL) { + if (*tok == '#') + break; + + val = strtoul(tok, &endp, 0); + if (*endp != '\0') { + val = ep11_get_mechanisms_by_name(tok); + if (val == UNKNOWN_MECHANISM) { + TRACE_ERROR("%s Syntax error in EP 11 CP-filter config file" + " found. \n", __func__); + OCK_SYSLOG(LOG_ERR, + "%s: Error: Expected valid mechanism name or " + "number, found '%s' in CP-filter config file " + "'%s'\n", __func__, tok, conf_name); + rc = APQN_FILE_SYNTAX_ERROR_8; + free_cp_config(cp); + goto out_fclose; + } + } + + mech = (cp_mech_config_t *) malloc(sizeof(cp_mech_config_t)); + if (mech == NULL) { + TRACE_ERROR("%s Out of memory.\n", __func__); + OCK_SYSLOG(LOG_ERR, "%s: Error: Out of memory while parsing the" + " CP-filter config file '%s'\n", + __func__, conf_name); + rc = APQN_OUT_OF_MEMORY; + free_cp_config(cp); + goto out_fclose; + } + mech->mech = val; + mech->next = NULL; + + if (last_mech == NULL) + cp->mech = mech; + else + last_mech->next = mech; + last_mech = mech; + } + + if (cp->mech == NULL) { + /* empty CP, skip this one */ + free(cp); + continue; + } + + if (last_cp == NULL) + *cp_config = cp; + else + last_cp->next = cp; + last_cp = cp; + } + +#ifdef DEBUG + /* print CP filter config */ + TRACE_INFO("%s CP-Filter defined:\n", __func__); + cp = *cp_config; + while (cp != NULL) { + TRACE_INFO(" CP %lu (%s):\n", cp->cp, ep11_get_cp(cp->cp)); + mech = cp->mech; + while (mech != NULL) { + TRACE_INFO(" Mechanism 0x%08lx (%s)\n", mech->mech, + ep11_get_ckm(mech->mech)); + mech = mech->next; + } + cp = cp->next; + } +#endif + +out_fclose: + fclose(fp); + return rc; +} + +static void free_cp_config(cp_config_t * cp) +{ + cp_config_t *next_cp = cp; + cp_mech_config_t *mech; + cp_mech_config_t *next_mech; + + TRACE_INFO("%s running\n", __func__); + + while (cp != NULL) { + mech = cp->mech; + while (mech != NULL) { + next_mech = mech->next; + free(mech); + mech = next_mech; + } + + next_cp = cp->next; + free(cp); + cp = next_cp; + } +} + +static const_info_t ep11_cps[] = { + CONSTINFO(XCP_CPB_ADD_CPBS), + CONSTINFO(XCP_CPB_DELETE_CPBS), + CONSTINFO(XCP_CPB_SIGN_ASYMM), + CONSTINFO(XCP_CPB_SIGN_SYMM), + CONSTINFO(XCP_CPB_SIGVERIFY_SYMM), + CONSTINFO(XCP_CPB_ENCRYPT_SYMM), + CONSTINFO(XCP_CPB_DECRYPT_ASYMM), + CONSTINFO(XCP_CPB_DECRYPT_SYMM), + CONSTINFO(XCP_CPB_WRAP_ASYMM), + CONSTINFO(XCP_CPB_WRAP_SYMM), + CONSTINFO(XCP_CPB_UNWRAP_ASYMM), + CONSTINFO(XCP_CPB_UNWRAP_SYMM), + CONSTINFO(XCP_CPB_KEYGEN_ASYMM), + CONSTINFO(XCP_CPB_KEYGEN_SYMM), + CONSTINFO(XCP_CPB_RETAINKEYS), + CONSTINFO(XCP_CPB_SKIP_KEYTESTS), + CONSTINFO(XCP_CPB_NON_ATTRBOUND), + CONSTINFO(XCP_CPB_MODIFY_OBJECTS), + CONSTINFO(XCP_CPB_RNG_SEED), + CONSTINFO(XCP_CPB_ALG_RAW_RSA), + CONSTINFO(XCP_CPB_ALG_NFIPS2009), + CONSTINFO(XCP_CPB_ALG_NBSI2009), + CONSTINFO(XCP_CPB_KEYSZ_HMAC_ANY), + CONSTINFO(XCP_CPB_KEYSZ_BELOW80BIT), + CONSTINFO(XCP_CPB_KEYSZ_80BIT), + CONSTINFO(XCP_CPB_KEYSZ_112BIT), + CONSTINFO(XCP_CPB_KEYSZ_128BIT), + CONSTINFO(XCP_CPB_KEYSZ_192BIT), + CONSTINFO(XCP_CPB_KEYSZ_256BIT), + CONSTINFO(XCP_CPB_KEYSZ_RSA65536), + CONSTINFO(XCP_CPB_ALG_RSA), + CONSTINFO(XCP_CPB_ALG_DSA), + CONSTINFO(XCP_CPB_ALG_EC), + CONSTINFO(XCP_CPB_ALG_EC_BPOOLCRV), + CONSTINFO(XCP_CPB_ALG_EC_NISTCRV), + CONSTINFO(XCP_CPB_ALG_NFIPS2011), + CONSTINFO(XCP_CPB_ALG_NBSI2011), + CONSTINFO(XCP_CPB_USER_SET_TRUSTED), + CONSTINFO(XCP_CPB_ALG_SKIP_CROSSCHK), + CONSTINFO(XCP_CPB_WRAP_CRYPT_KEYS), + CONSTINFO(XCP_CPB_SIGN_CRYPT_KEYS), + CONSTINFO(XCP_CPB_WRAP_SIGN_KEYS), + CONSTINFO(XCP_CPB_USER_SET_ATTRBOUND), + CONSTINFO(XCP_CPB_ALLOW_PASSPHRASE), + CONSTINFO(XCP_CPB_WRAP_STRONGER_KEY), + CONSTINFO(XCP_CPB_WRAP_WITH_RAW_SPKI), + CONSTINFO(XCP_CPB_ALG_DH), + CONSTINFO(XCP_CPB_DERIVE), + CONSTINFO(XCP_CPB_ALG_EC_25519), + CONSTINFO(XCP_CPB_ALG_NBSI2017), + CONSTINFO(XCP_CPB_CPACF_PK), + CONSTINFO(XCP_CPB_ALG_PQC_DILITHIUM), +}; + +#ifdef DEBUG +static const char *ep11_get_cp(unsigned int cp) +{ + unsigned int i; + + for (i = 0; i < (sizeof(ep11_cps) / sizeof(ep11_cps[0])); i++) { + if (ep11_cps[i].code == cp) + return ep11_cps[i].name; + } + + TRACE_WARNING("%s unknown control point %u\n", __func__, cp); + return "UNKNOWN"; +} +#endif + +static CK_ULONG ep11_get_cp_by_name(const char *name) +{ + unsigned int i; + + for (i = 0; i < (sizeof(ep11_cps) / sizeof(ep11_cps[0])); i++) { + if (strcmp(ep11_cps[i].name, name) == 0) + return ep11_cps[i].code; + } + + TRACE_WARNING("%s unknown control point name '%s'\n", __func__, name); + return UNKNOWN_CP; +} + +static CK_RV check_cps_for_mechanism(cp_config_t * cp_config, + CK_MECHANISM_TYPE mech, + unsigned char *cp, size_t cp_len, + size_t max_cp_index) +{ + cp_config_t *cp_cfg = cp_config; + cp_mech_config_t *mech_cfg; + + TRACE_DEBUG("%s Check mechanism 0x%08lx ('%s')\n", __func__, mech, + ep11_get_ckm(mech)); + + while (cp_cfg != NULL) { + if (CP_BYTE_NO(cp_cfg->cp) < cp_len && + cp_cfg->cp <= max_cp_index && + (cp[CP_BYTE_NO(cp_cfg->cp)] & CP_BIT_MASK(cp_cfg->cp)) == 0) { + /* CP is off, check if the current mechanism is + * associated with it */ + mech_cfg = cp_cfg->mech; + while (mech_cfg != NULL) { + if (mech_cfg->mech == mech) { + TRACE_DEBUG("%s mechanism 0x%08lx ('%s') not enabled\n", + __func__, mech, ep11_get_ckm(mech)); + return CKR_MECHANISM_INVALID; + } + mech_cfg = mech_cfg->next; + } + } + cp_cfg = cp_cfg->next; + } + + return CKR_OK; +} + +#define SYSFS_DEVICES_AP "/sys/devices/ap/" +#define REGEX_CARD_PATTERN "card[0-9a-fA-F]+" +#define REGEX_SUB_CARD_PATTERN "[0-9a-fA-F]+\\.[0-9a-fA-F]+" +#define MASK_EP11 0x04000000 + +typedef CK_RV(*adapter_handler_t) (uint_32 adapter, uint_32 domain, + void *handler_data); + +static CK_RV file_fgets(const char *fname, char *buf, size_t buflen) +{ + FILE *fp; + char *end; + CK_RV rc = CKR_OK; + + buf[0] = '\0'; + + fp = fopen(fname, "r"); + if (fp == NULL) { + TRACE_ERROR("Failed to open file '%s'\n", fname); + return CKR_FUNCTION_FAILED; + } + if (fgets(buf, buflen, fp) == NULL) { + TRACE_ERROR("Failed to read from file '%s'\n", fname); + rc = CKR_FUNCTION_FAILED; + goto out_fclose; + } + + end = memchr(buf, '\n', buflen); + if (end) + *end = 0; + else + buf[buflen - 1] = 0; + + if (strlen(buf) == 0) { + rc = CKR_FUNCTION_FAILED; + goto out_fclose; + } + +out_fclose: + fclose(fp); + return rc; +} + +static CK_RV is_card_ep11_and_online(const char *name) +{ + char fname[290]; + char buf[250]; + CK_RV rc; + unsigned long val; + +#ifdef EP11_HSMSIM + return CKR_OK; +#endif + + sprintf(fname, "%s%s/online", SYSFS_DEVICES_AP, name); + rc = file_fgets(fname, buf, sizeof(buf)); + if (rc != CKR_OK) + return rc; + if (strcmp(buf, "1") != 0) + return CKR_FUNCTION_FAILED; + + sprintf(fname, "%s%s/ap_functions", SYSFS_DEVICES_AP, name); + rc = file_fgets(fname, buf, sizeof(buf)); + if (rc != CKR_OK) + return rc; + if (sscanf(buf, "%lx", &val) != 1) + val = 0x00000000; + if ((val & MASK_EP11) == 0) + return CKR_FUNCTION_FAILED; + + return CKR_OK; +} + +static CK_RV scan_for_card_domains(const char *name, adapter_handler_t handler, + void *handler_data) +{ + char fname[290]; + regex_t reg_buf; + regmatch_t pmatch[1]; + DIR *d; + struct dirent *de; + char *tok; + uint_32 adapter, domain; + +#ifdef EP11_HSMSIM + return handler(0, 0, handler_data); +#endif + + if (regcomp(®_buf, REGEX_SUB_CARD_PATTERN, REG_EXTENDED) != 0) { + TRACE_ERROR("Failed to compile regular expression '%s'\n", + REGEX_SUB_CARD_PATTERN); + return CKR_FUNCTION_FAILED; + } + + sprintf(fname, "%s%s/", SYSFS_DEVICES_AP, name); + d = opendir(fname); + if (d == NULL) { + TRACE_ERROR("Directory %s is not available\n", fname); + regfree(®_buf); + // ignore this error, card may have been removed in the meantime + return CKR_OK; + } + + while ((de = readdir(d)) != NULL) { + if (regexec(®_buf, de->d_name, (size_t) 1, pmatch, 0) == 0) { + tok = strtok(de->d_name, "."); + if (tok == NULL) + continue; + if (sscanf(tok, "%x", &adapter) != 1) + continue; + + tok = strtok(NULL, ","); + if (tok == NULL) + continue; + if (sscanf(tok, "%x", &domain) != 1) + continue; + + if (handler(adapter, domain, handler_data) != CKR_OK) + break; + } + } + + closedir(d); + regfree(®_buf); + return CKR_OK; +} + +/* + * Iterate over all cards in the sysfs directorys /sys/device/ap/cardxxx + * and check if the card is online. Calls the handler function for all + * online EP11 cards. + */ +static CK_RV scan_for_ep11_cards(adapter_handler_t handler, void *handler_data) +{ + DIR *d; + struct dirent *de; + regex_t reg_buf; + regmatch_t pmatch[1]; + + if (handler == NULL) + return CKR_ARGUMENTS_BAD; + +#ifdef EP11_HSMSIM + return handler(0, 0, handler_data); +#endif + + 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; + } + + 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) { + if (is_card_ep11_and_online(de->d_name) != CKR_OK) + continue; + + if (scan_for_card_domains(de->d_name, handler, handler_data) != + CKR_OK) + break; + } + } + + closedir(d); + regfree(®_buf); + return CKR_OK; +} + +static CK_RV handle_all_ep11_cards(ep11_target_t * ep11_targets, + adapter_handler_t handler, + void *handler_data) +{ + int i; + CK_RV rc; + + if (ep11_targets->length > 0) { + /* APQN_WHITELIST is specified */ + for (i = 0; i < ep11_targets->length; i++) { + rc = handler(ep11_targets->apqns[2 * i], + ep11_targets->apqns[2 * i + 1], handler_data); + if (rc != CKR_OK) + return rc; + } + } else { + /* APQN_ANY used, scan sysfs for available cards */ + return scan_for_ep11_cards(handler, handler_data); + } + + return CKR_OK; +} + +static CK_RV get_control_points_for_adapter(uint_32 adapter, uint_32 domain, + unsigned char *cp, size_t * cp_len, + size_t *max_cp_index) +{ + unsigned char rsp[200]; + unsigned char cmd[100]; + struct XCPadmresp rb; + size_t rlen, clen; + long rc; + CK_RV rv = 0; + target_t target; + CK_IBM_XCP_INFO xcp_info; + CK_ULONG xcp_info_len = sizeof(xcp_info); + + rc = get_ep11_target_for_apqn(adapter, domain, &target); + if (rc != CKR_OK) + return rc; + + memset(cmd, 0, sizeof(cmd)); + rc = dll_xcpa_queryblock(cmd, sizeof(cmd), XCP_ADMQ_DOM_CTRLPOINTS, + (uint64_t) adapter << 32 | domain, NULL, 0); + if (rc < 0) { + TRACE_ERROR("%s xcpa_queryblock failed: rc=%ld\n", __func__, rc); + rc = CKR_DEVICE_ERROR; + goto out; + } + clen = rc; + + memset(rsp, 0, sizeof(rsp)); + rlen = sizeof(rsp); + rc = dll_m_admin(rsp, &rlen, NULL, NULL, cmd, clen, NULL, 0, target); + if (rc < 0) { + TRACE_ERROR("%s m_admin rc=%ld\n", __func__, rc); + rc = CKR_DEVICE_ERROR; + goto out; + } + + memset(&rb, 0, sizeof(rb)); + rc = dll_xcpa_internal_rv(rsp, rlen, &rb, &rv); + if (rc < 0 || rv != 0) { + TRACE_ERROR("%s xcpa_internal_rv failed: rc=%ld rv=%ld\n", + __func__, rc, rv); + rc = CKR_DEVICE_ERROR; + goto out; + } + + if (*cp_len < rb.pllen) { + TRACE_ERROR("%s Cp_len is too small. cp_len=%lu required=%lu\n", + __func__, *cp_len, rb.pllen); + *cp_len = rb.pllen; + rc = CKR_ARGUMENTS_BAD; + goto out; + } + + memcpy(cp, rb.payload, rb.pllen); + *cp_len = rb.pllen; + + rc = dll_m_get_xcp_info(&xcp_info, &xcp_info_len, CK_IBM_XCPQ_MODULE, 0, + target); + if (rc != CKR_OK) { + TRACE_ERROR("%s Failed to query xcp info from adapter %02X.%04X\n", + __func__, adapter, domain); + rc = CKR_DEVICE_ERROR; + goto out; + } + + *max_cp_index = xcp_info.controlPoints; + +out: + free_ep11_target_for_apqn(target); + return rc; +} + +typedef struct cp_handler_data { + unsigned char combined_cp[XCP_CP_BYTES]; + unsigned char first_cp[XCP_CP_BYTES]; + uint32_t first_adapter; + uint32_t first_domain; + int first; + size_t max_cp_index; +} cp_handler_data_t; + +static CK_RV control_point_handler(uint_32 adapter, uint_32 domain, + void *handler_data) +{ + CK_RV rc; + cp_handler_data_t *data = (cp_handler_data_t *) handler_data; + unsigned char cp[XCP_CP_BYTES]; + size_t cp_len = sizeof(cp); + size_t max_cp_index; + CK_ULONG i; + + TRACE_INFO("Getting control points for adapter %02X.%04X\n", adapter, + domain); + + memset(cp, 0, sizeof(cp)); + rc = get_control_points_for_adapter(adapter, domain, cp, &cp_len, + &max_cp_index); + if (rc != CKR_OK) { + TRACE_ERROR("%s Failed to get CPS from adapter %02X.%04X\n", + __func__, adapter, domain); + // card may no longer be online, so ignore this error situation + return CKR_OK; + } +#ifdef DEBUG + TRACE_DEBUG("Control points from adapter %02X.%04X\n", adapter, domain); + TRACE_DEBUG_DUMP(cp, cp_len); +#endif + + if (data->first) { + data->first_adapter = adapter; + data->first_domain = domain; + memcpy(data->first_cp, cp, cp_len); + memcpy(data->combined_cp, cp, cp_len); + data->max_cp_index = max_cp_index; + data->first = 0; + } else { + // check if subsequent adapters have the same CPs + if (memcmp(cp, data->first_cp, sizeof(cp)) != 0) { + TRACE_WARNING("%s Adapter %02X.%04X has different control points " + "than adapter %02X.%04X, using minimum.\n", + __func__, adapter, domain, data->first_adapter, + data->first_domain); + OCK_SYSLOG(LOG_WARNING, + "Warning: Adapter %02X.%04X has different control points" + " than adapter %02X.%04X, using minimum\n", + adapter, domain, data->first_adapter, + data->first_domain); + } + + for (i = 0; i < cp_len; i++) { + data->combined_cp[i] &= cp[i]; + } + + if (max_cp_index != data->max_cp_index) { + TRACE_WARNING("%s Adapter %02X.%04X has a different number of " + "control points than adapter %02X.%04X, using " + "maximum.\n", __func__, adapter, domain, + data->first_adapter, data->first_domain); + OCK_SYSLOG(LOG_WARNING, + "Warning: Adapter %02X.%04X has a different number of " + "control points than adapter %02X.%04X, using maximum\n", + adapter, domain, data->first_adapter, + data->first_domain); + + data->max_cp_index = MAX(max_cp_index, data->max_cp_index); + } + } + + return CKR_OK; +} + +#ifdef DEBUG +static void print_control_points(unsigned char *cp, size_t cp_len, + size_t max_cp_index) +{ + unsigned int i; + + for (i = 0; i <= max_cp_index && CP_BYTE_NO(i) < cp_len; i++) { + if ((cp[CP_BYTE_NO(i)] & CP_BIT_MASK(i)) == 0) + TRACE_INFO("CP %u (%s)is off\n", i, ep11_get_cp(i)); + else + TRACE_INFO("CP %u (%s) is on\n", i, ep11_get_cp(i)); + } +} +#endif + +static CK_RV get_control_points(STDLL_TokData_t * tokdata, + unsigned char *cp, size_t * cp_len, + size_t *max_cp_index) +{ + CK_RV rc; + cp_handler_data_t data; + ep11_private_data_t *ep11_data = tokdata->private_data; + + memset(&data, 0, sizeof(data)); + data.first = 1; + rc = handle_all_ep11_cards(&ep11_data->target_list, control_point_handler, + &data); + if (rc != CKR_OK) + return rc; + + *cp_len = MIN(*cp_len, sizeof(data.combined_cp)); + memcpy(cp, data.combined_cp, *cp_len); + *max_cp_index = data.max_cp_index; + +#ifdef DEBUG + TRACE_DEBUG("Combined control points from all cards (%lu CPs):\n", + data.max_cp_index); + TRACE_DEBUG_DUMP(cp, *cp_len); + print_control_points(cp, *cp_len, data.max_cp_index); +#endif + + return CKR_OK; +} + + +CK_RV SC_CreateObject(STDLL_TokData_t * tokdata, + ST_SESSION_HANDLE * sSession, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject); +CK_RV SC_DestroyObject(STDLL_TokData_t * tokdata, + ST_SESSION_HANDLE * sSession, CK_OBJECT_HANDLE hObject); +CK_RV SC_FindObjectsInit(STDLL_TokData_t * tokdata, + ST_SESSION_HANDLE * sSession, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount); +CK_RV SC_FindObjects(STDLL_TokData_t * tokdata, + ST_SESSION_HANDLE * sSession, + CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, + CK_ULONG_PTR pulObjectCount); +CK_RV SC_FindObjectsFinal(STDLL_TokData_t * tokdata, + ST_SESSION_HANDLE * sSession); +CK_RV SC_GetAttributeValue(STDLL_TokData_t * tokdata, + ST_SESSION_HANDLE * sSession, + CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount); +CK_RV SC_OpenSession(STDLL_TokData_t * tokdata, CK_SLOT_ID sid, CK_FLAGS flags, + CK_SESSION_HANDLE_PTR phSession); +CK_RV SC_CloseSession(STDLL_TokData_t * tokdata, ST_SESSION_HANDLE * sSession); + +static CK_RV generate_ep11_session_id(STDLL_TokData_t * tokdata, + SESSION * session, + ep11_session_t * ep11_session) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + struct { + CK_SESSION_HANDLE handle; + struct timeval timeofday; + clock_t clock; + pid_t pid; + } session_id_data; + CK_MECHANISM mech; + CK_ULONG len; + libica_sha_context_t ctx; + + session_id_data.handle = session->handle; + gettimeofday(&session_id_data.timeofday, NULL); + session_id_data.clock = clock(); + session_id_data.pid = getpid(); + + mech.mechanism = CKM_SHA256; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + + len = sizeof(ep11_session->session_id); + if (ep11tok_libica_digest_available(ep11_data, mech.mechanism)) + rc = ep11tok_libica_digest(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, + ep11_data->target); + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, session); + TRACE_ERROR("%s Digest failed: 0x%lx\n", __func__, rc); + return rc; + } + + return CKR_OK; +} + +static CK_RV create_ep11_object(STDLL_TokData_t * tokdata, + ST_SESSION_HANDLE * handle, + ep11_session_t * ep11_session, + CK_BYTE * pin_blob, CK_ULONG pin_blob_len, + CK_OBJECT_HANDLE * obj) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_OBJECT_CLASS class = CKO_HW_FEATURE; + CK_HW_FEATURE_TYPE type = CKH_IBM_EP11_SESSION; + CK_BYTE subject[] = "EP11 Session Object"; + pid_t pid; + CK_DATE date; + CK_BYTE cktrue = TRUE; + time_t t; + struct tm *tm; + char tmp[40]; + + CK_ATTRIBUTE attrs[] = { + {CKA_CLASS, &class, sizeof(class)} + , + {CKA_TOKEN, &cktrue, sizeof(cktrue)} + , + {CKA_PRIVATE, &cktrue, sizeof(cktrue)} + , + {CKA_HIDDEN, &cktrue, sizeof(cktrue)} + , + {CKA_HW_FEATURE_TYPE, &type, sizeof(type)} + , + {CKA_SUBJECT, &subject, sizeof(subject)} + , + {CKA_VALUE, pin_blob, pin_blob_len} + , + {CKA_ID, ep11_session->session_id, PUBLIC_SESSION_ID_LENGTH} + , + {CKA_APPLICATION, &ep11_data->target_list, sizeof(ep11_target_t)} + , + {CKA_OWNER, &pid, sizeof(pid)} + , + {CKA_START_DATE, &date, sizeof(date)} + }; + + pid = getpid(); + time(&t); + tm = localtime(&t); + sprintf(tmp, "%4d%2d%2d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); + memcpy(date.year, tmp, 4); + memcpy(date.month, tmp + 4, 2); + memcpy(date.day, tmp + 4 + 2, 2); + + rc = SC_CreateObject(tokdata, handle, + attrs, sizeof(attrs) / sizeof(CK_ATTRIBUTE), obj); + if (rc != CKR_OK) { + TRACE_ERROR("%s SC_CreateObject failed: 0x%lx\n", __func__, rc); + return rc; + } + + return CKR_OK; +} + +static CK_RV get_vhsmpin(STDLL_TokData_t * tokdata, + SESSION * session, ep11_session_t * ep11_session) +{ + CK_RV rc; + ST_SESSION_HANDLE handle = {.slotID = + session->session_info.slotID,.sessionh = session->handle + }; + CK_OBJECT_HANDLE obj_store[16]; + CK_ULONG objs_found = 0; + CK_OBJECT_CLASS class = CKO_HW_FEATURE; + CK_HW_FEATURE_TYPE type = CKH_IBM_EP11_VHSMPIN; + CK_BYTE cktrue = TRUE; + CK_ATTRIBUTE vhsmpin_template[] = { + {CKA_CLASS, &class, sizeof(class)} + , + {CKA_TOKEN, &cktrue, sizeof(cktrue)} + , + {CKA_PRIVATE, &cktrue, sizeof(cktrue)} + , + {CKA_HIDDEN, &cktrue, sizeof(cktrue)} + , + {CKA_HW_FEATURE_TYPE, &type, sizeof(type)} + , + }; + CK_ATTRIBUTE attrs[] = { + {CKA_VALUE, ep11_session->vhsm_pin, sizeof(ep11_session->vhsm_pin)} + , + }; + + rc = SC_FindObjectsInit(tokdata, &handle, + vhsmpin_template, + sizeof(vhsmpin_template) / sizeof(CK_ATTRIBUTE)); + if (rc != CKR_OK) { + TRACE_ERROR("%s SC_FindObjectsInit failed: 0x%lx\n", __func__, rc); + goto out; + } + + rc = SC_FindObjects(tokdata, &handle, obj_store, 16, &objs_found); + if (rc != CKR_OK) { + TRACE_ERROR("%s SC_FindObjects failed: 0x%lx\n", __func__, rc); + goto out; + } + + if (objs_found == 0) { + rc = CKR_FUNCTION_FAILED; + TRACE_ERROR("%s No VHSMPIN object found\n", __func__); + goto out; + } + + rc = SC_GetAttributeValue(tokdata, &handle, obj_store[0], + attrs, sizeof(attrs) / sizeof(CK_ATTRIBUTE)); + if (rc != CKR_OK) { + TRACE_ERROR("%s SC_GetAttributeValue failed: 0x%lx\n", __func__, rc); + goto out; + } + + ep11_session->flags |= EP11_VHSMPIN_VALID; + +out: + SC_FindObjectsFinal(tokdata, &handle); + return rc; +} + +static CK_RV ep11_login_handler(uint_32 adapter, uint_32 domain, + void *handler_data) +{ + ep11_session_t *ep11_session = (ep11_session_t *) handler_data; + target_t target; + CK_RV rc; + CK_BYTE pin_blob[XCP_PINBLOB_BYTES]; + CK_ULONG pin_blob_len = XCP_PINBLOB_BYTES; + CK_BYTE *pin = (CK_BYTE *)DEFAULT_EP11_PIN; + CK_ULONG pin_len = strlen(DEFAULT_EP11_PIN); + CK_BYTE *nonce = NULL; + CK_ULONG nonce_len = 0; + + TRACE_INFO("Logging in adapter %02X.%04X\n", adapter, domain); + + rc = get_ep11_target_for_apqn(adapter, domain, &target); + if (rc != CKR_OK) + return rc; + + if (ep11_session->flags & EP11_VHSM_MODE) { + pin = ep11_session->vhsm_pin; + pin_len = sizeof(ep11_session->vhsm_pin); + + rc = dll_m_Login(pin, pin_len, nonce, nonce_len, + pin_blob, &pin_blob_len, target); + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s dll_m_Login failed: 0x%lx\n", __func__, rc); + /* ignore the error here, the adapter may not be able to perform + * m_Login at this moment */ + goto strict_mode; + } +#ifdef DEBUG + TRACE_DEBUG("EP11 VHSM Pin blob (size: %lu):\n", XCP_PINBLOB_BYTES); + TRACE_DEBUG_DUMP(pin_blob, XCP_PINBLOB_BYTES); +#endif + + if (ep11_session->flags & EP11_VHSM_PINBLOB_VALID) { + /* First part of pin-blob (keypart and session) must be equal */ + if (memcmp(ep11_session->vhsm_pin_blob, pin_blob, XCP_WK_BYTES) != + 0) { + TRACE_ERROR("%s VHSM-Pin blob not equal to previous one\n", + __func__); + OCK_SYSLOG(LOG_ERR, + "%s: Error: VHSM-Pin blob of adapter %02X.%04X is " + "not equal to other adapters for same session\n", + __func__, adapter, domain); + rc = CKR_DEVICE_ERROR; + goto out; + } + } else { + memcpy(ep11_session->vhsm_pin_blob, pin_blob, XCP_PINBLOB_BYTES); + ep11_session->flags |= EP11_VHSM_PINBLOB_VALID; + } + } + +strict_mode: + if (ep11_session->flags & EP11_STRICT_MODE) { + nonce = ep11_session->session_id; + nonce_len = sizeof(ep11_session->session_id); + /* pin is already set to default pin or vhsm pin (if VHSM mode) */ + + rc = dll_m_Login(pin, pin_len, nonce, nonce_len, + pin_blob, &pin_blob_len, target); + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s dll_m_Login failed: 0x%lx\n", __func__, rc); + /* ignore the error here, the adapter may not be able to perform + * m_Login at this moment */ + rc = CKR_OK; + goto out; + } +#ifdef DEBUG + TRACE_DEBUG("EP11 Session Pin blob (size: %lu):\n", XCP_PINBLOB_BYTES); + TRACE_DEBUG_DUMP(pin_blob, XCP_PINBLOB_BYTES); +#endif + + if (ep11_session->flags & EP11_SESS_PINBLOB_VALID) { + /* First part of pin-blob (keypart and session) must be equal */ + if (memcmp(ep11_session->session_pin_blob, pin_blob, XCP_WK_BYTES) + != 0) { + TRACE_ERROR("%s Pin blob not equal to previous one\n", + __func__); + OCK_SYSLOG(LOG_ERR, + "%s: Error: Pin blob of adapter %02X.%04X is not " + "equal to other adapters for same session\n", + __func__, adapter, domain); + rc = CKR_DEVICE_ERROR; + goto out; + } + } else { + memcpy(ep11_session->session_pin_blob, pin_blob, XCP_PINBLOB_BYTES); + ep11_session->flags |= EP11_SESS_PINBLOB_VALID; + } + } + +out: + free_ep11_target_for_apqn(target); + return rc; +} + +static CK_RV ep11_logout_handler(uint_32 adapter, uint_32 domain, + void *handler_data) +{ + ep11_session_t *ep11_session = (ep11_session_t *) handler_data; + target_t target; + CK_RV rc; + + TRACE_INFO("Logging out adapter %02X.%04X\n", adapter, domain); + + rc = get_ep11_target_for_apqn(adapter, domain, &target); + if (rc != CKR_OK) + return rc; + + if (ep11_session->flags & EP11_SESS_PINBLOB_VALID) { +#ifdef DEBUG + TRACE_DEBUG("EP11 Session Pin blob (size: %lu):\n", XCP_PINBLOB_BYTES); + TRACE_DEBUG_DUMP(ep11_session->session_pin_blob, XCP_PINBLOB_BYTES); +#endif + + rc = dll_m_Logout(ep11_session->session_pin_blob, XCP_PINBLOB_BYTES, + target); + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s dll_m_Logout failed: 0x%lx\n", __func__, rc); + /* ignore any errors during m_logout */ + } + } + + if (ep11_session->flags & EP11_VHSM_PINBLOB_VALID) { +#ifdef DEBUG + TRACE_DEBUG("EP11 VHSM Pin blob (size: %lu):\n", XCP_PINBLOB_BYTES); + TRACE_DEBUG_DUMP(ep11_session->vhsm_pin_blob, XCP_PINBLOB_BYTES); +#endif + + rc = dll_m_Logout(ep11_session->vhsm_pin_blob, XCP_PINBLOB_BYTES, + target); + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s dll_m_Logout failed: 0x%lx\n", __func__, rc); + /* ignore any errors during m_logout */ + } + } + + free_ep11_target_for_apqn(target); + return CKR_OK; +} + +CK_RV ep11tok_login_session(STDLL_TokData_t * tokdata, SESSION * session) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + ep11_session_t *ep11_session; + CK_RV rc; + CK_RV rc2; + ST_SESSION_HANDLE handle = {.slotID = + session->session_info.slotID,.sessionh = session->handle + }; + CK_SESSION_HANDLE helper_session = CK_INVALID_HANDLE; + + TRACE_INFO("%s session=%lu\n", __func__, session->handle); + + if (!ep11_data->strict_mode && !ep11_data->vhsm_mode) + return CKR_OK; + + if (session->session_info.flags & CKF_EP11_HELPER_SESSION) + return CKR_OK; + + switch (session->session_info.state) { + case CKS_RW_SO_FUNCTIONS: + case CKS_RO_PUBLIC_SESSION: + case CKS_RW_PUBLIC_SESSION: + TRACE_INFO("%s Public or SO session\n", __func__); + return CKR_OK; + case CKS_RO_USER_FUNCTIONS: + rc = ep11_open_helper_session(tokdata, session, &helper_session); + if (rc != CKR_OK) + return rc; + handle.sessionh = helper_session; + break; + default: + break; + } + + if (session->private_data != NULL) { + TRACE_INFO("%s Session already logged in\n", __func__); + return CKR_USER_ALREADY_LOGGED_IN; + } + + ep11_session = (ep11_session_t *) calloc(1, sizeof(ep11_session_t)); + if (ep11_session == NULL) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + return CKR_HOST_MEMORY; + } + ep11_session->session = session; + ep11_session->session_object = CK_INVALID_HANDLE; + ep11_session->vhsm_object = CK_INVALID_HANDLE; + if (ep11_data->strict_mode) + ep11_session->flags |= EP11_STRICT_MODE; + if (ep11_data->vhsm_mode) + ep11_session->flags |= EP11_VHSM_MODE; + session->private_data = ep11_session; + + rc = generate_ep11_session_id(tokdata, session, ep11_session); + if (rc != CKR_OK) { + TRACE_ERROR("%s _generate_ep11_session_id failed: 0x%lx\n", __func__, + rc); + goto done; + } +#ifdef DEBUG + TRACE_DEBUG("EP11 Session-ID for PKCS#11 session %lu:\n", session->handle); + TRACE_DEBUG_DUMP(ep11_session->session_id, + sizeof(ep11_session->session_id)); +#endif + + if (ep11_data->vhsm_mode) { + rc = get_vhsmpin(tokdata, session, ep11_session); + if (rc != CKR_OK) { + TRACE_ERROR("%s get_vhsmpin failed: 0x%lx\n", __func__, rc); + OCK_SYSLOG(LOG_ERR, + "%s: Error: A VHSM-PIN is required for VHSM_MODE.\n", + __func__); + goto done; + } + } + + rc = handle_all_ep11_cards(&ep11_data->target_list, ep11_login_handler, + ep11_session); + if (rc != CKR_OK) { + TRACE_ERROR("%s handle_all_ep11_cards failed: 0x%lx\n", __func__, rc); + goto done; + } + + if (ep11_data->strict_mode) { + if ((ep11_session->flags & EP11_SESS_PINBLOB_VALID) == 0) { + rc = CKR_DEVICE_ERROR; + TRACE_ERROR("%s no pinblob available\n", __func__); + goto done; + } + + rc = create_ep11_object(tokdata, &handle, ep11_session, + ep11_session->session_pin_blob, + sizeof(ep11_session->session_pin_blob), + &ep11_session->session_object); + if (rc != CKR_OK) { + TRACE_ERROR("%s _create_ep11_object failed: 0x%lx\n", __func__, rc); + goto done; + } + } + + if (ep11_data->vhsm_mode) { + if ((ep11_session->flags & EP11_VHSM_PINBLOB_VALID) == 0) { + rc = CKR_DEVICE_ERROR; + TRACE_ERROR("%s no VHSM pinblob available\n", __func__); + goto done; + } + + rc = create_ep11_object(tokdata, &handle, ep11_session, + ep11_session->vhsm_pin_blob, + sizeof(ep11_session->vhsm_pin_blob), + &ep11_session->vhsm_object); + if (rc != CKR_OK) { + TRACE_ERROR("%s _create_ep11_object failed: 0x%lx\n", __func__, rc); + goto done; + } + } + +done: + if (rc != CKR_OK) { + if (ep11_session->flags & + (EP11_SESS_PINBLOB_VALID | EP11_VHSM_PINBLOB_VALID)) { + rc2 = + handle_all_ep11_cards(&ep11_data->target_list, + ep11_logout_handler, ep11_session); + if (rc2 != CKR_OK) + TRACE_ERROR("%s handle_all_ep11_cards failed: 0x%lx\n", + __func__, rc2); + } + + if (ep11_session->session_object != CK_INVALID_HANDLE) { + rc2 = + SC_DestroyObject(tokdata, &handle, + ep11_session->session_object); + if (rc2 != CKR_OK) + TRACE_ERROR("%s SC_DestroyObject failed: 0x%lx\n", __func__, + rc2); + } + + if (ep11_session->vhsm_object != CK_INVALID_HANDLE) { + rc2 = SC_DestroyObject(tokdata, &handle, ep11_session->vhsm_object); + if (rc2 != CKR_OK) + TRACE_ERROR("%s SC_DestroyObject failed: 0x%lx\n", __func__, + rc2); + } + + free(ep11_session); + session->private_data = NULL; + + TRACE_ERROR("%s: failed: 0x%lx\n", __func__, rc); + } + + if (helper_session != CK_INVALID_HANDLE) { + rc2 = ep11_close_helper_session(tokdata, &handle); + if (rc2 != CKR_OK) + TRACE_ERROR("%s ep11_close_helper_session failed: 0x%lx\n", + __func__, rc2); + } + + return rc; +} + +static CK_RV ep11tok_relogin_session(STDLL_TokData_t * tokdata, + SESSION * session) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + ep11_session_t *ep11_session = (ep11_session_t *) session->private_data; + CK_RV rc; + + TRACE_INFO("%s session=%lu\n", __func__, session->handle); + + if (ep11_session == NULL) { + TRACE_INFO("%s Session not yet logged in\n", __func__); + return CKR_USER_NOT_LOGGED_IN; + } + + rc = handle_all_ep11_cards(&ep11_data->target_list, ep11_login_handler, + ep11_session); + if (rc != CKR_OK) + TRACE_ERROR("%s handle_all_ep11_cards failed: 0x%lx\n", __func__, rc); + + return CKR_OK; +} + +CK_RV ep11tok_logout_session(STDLL_TokData_t * tokdata, SESSION * session) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + ep11_session_t *ep11_session = (ep11_session_t *) session->private_data; + CK_RV rc, rc2; + ST_SESSION_HANDLE handle = {.slotID = + session->session_info.slotID,.sessionh = session->handle + }; + CK_SESSION_HANDLE helper_session = CK_INVALID_HANDLE; + + TRACE_INFO("%s session=%lu\n", __func__, session->handle); + + if (!ep11_data->strict_mode && !ep11_data->vhsm_mode) + return CKR_OK; + + if (session->session_info.flags & CKF_EP11_HELPER_SESSION) + return CKR_OK; + + switch (session->session_info.state) { + case CKS_RW_SO_FUNCTIONS: + case CKS_RO_PUBLIC_SESSION: + case CKS_RW_PUBLIC_SESSION: + TRACE_INFO("%s Public or SO session\n", __func__); + return CKR_OK; + case CKS_RO_USER_FUNCTIONS: + rc = ep11_open_helper_session(tokdata, session, &helper_session); + if (rc != CKR_OK) + return rc; + handle.sessionh = helper_session; + break; + default: + break; + } + + if (ep11_session == NULL) { + TRACE_INFO("%s CKR_USER_NOT_LOGGED_IN\n", __func__); + return CKR_USER_NOT_LOGGED_IN; + } + + rc = handle_all_ep11_cards(&ep11_data->target_list, ep11_logout_handler, + ep11_session); + if (rc != CKR_OK) + TRACE_ERROR("%s handle_all_ep11_cards failed: 0x%lx\n", __func__, rc); + + if (ep11_session->session_object != CK_INVALID_HANDLE) { + rc = SC_DestroyObject(tokdata, &handle, ep11_session->session_object); + if (rc != CKR_OK) + TRACE_ERROR("%s SC_DestroyObject failed: 0x%lx\n", __func__, rc); + } + if (ep11_session->vhsm_object != CK_INVALID_HANDLE) { + rc = SC_DestroyObject(tokdata, &handle, ep11_session->vhsm_object); + if (rc != CKR_OK) + TRACE_ERROR("%s SC_DestroyObject failed: 0x%lx\n", __func__, rc); + } + + free(ep11_session); + session->private_data = NULL; + + if (helper_session != CK_INVALID_HANDLE) { + rc2 = ep11_close_helper_session(tokdata, &handle); + if (rc2 != CKR_OK) + TRACE_ERROR("%s ep11_close_helper_session failed: 0x%lx\n", + __func__, rc2); + } + + return rc; +} + + +static CK_BOOL ep11_is_session_object(CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len) +{ + CK_ATTRIBUTE_PTR attr; + + attr = get_attribute_by_type(attrs, attrs_len, CKA_TOKEN); + if (attr == NULL) + return TRUE; + + if (attr->pValue == NULL) + return TRUE; + + if (*((CK_BBOOL *) attr->pValue) == FALSE) + return TRUE; + + return FALSE; +} + +static void ep11_get_pin_blob(ep11_session_t * ep11_session, CK_BOOL is_session_obj, + CK_BYTE ** pin_blob, CK_ULONG * pin_blob_len) +{ + if (ep11_session != NULL && + (ep11_session->flags & EP11_STRICT_MODE) && is_session_obj) { + *pin_blob = ep11_session->session_pin_blob; + *pin_blob_len = sizeof(ep11_session->session_pin_blob); + TRACE_DEVEL + ("%s Strict mode and CKA_TOKEN=FALSE -> pass session pin_blob\n", + __func__); + } else if (ep11_session != NULL && (ep11_session->flags & EP11_VHSM_MODE)) { + *pin_blob = ep11_session->vhsm_pin_blob; + *pin_blob_len = sizeof(ep11_session->vhsm_pin_blob); + TRACE_DEVEL("%s vHSM mode -> pass VHSM pin_blob\n", __func__); + } else { + *pin_blob = NULL; + *pin_blob_len = 0; + } +} + +static CK_RV ep11_open_helper_session(STDLL_TokData_t * tokdata, SESSION * sess, + CK_SESSION_HANDLE_PTR phSession) +{ + CK_RV rc; + + TRACE_INFO("%s\n", __func__); + + rc = SC_OpenSession(tokdata, sess->session_info.slotID, + CKF_RW_SESSION | CKF_SERIAL_SESSION | + CKF_EP11_HELPER_SESSION, phSession); + if (rc != CKR_OK) + TRACE_ERROR("%s SC_OpenSession failed: 0x%lx\n", __func__, rc); + + return rc; +} + +static CK_RV ep11_close_helper_session(STDLL_TokData_t * tokdata, + ST_SESSION_HANDLE * sSession) +{ + CK_RV rc; + + TRACE_INFO("%s\n", __func__); + + rc = SC_CloseSession(tokdata, sSession); + if (rc != CKR_OK) + TRACE_ERROR("%s SC_CloseSession failed: 0x%lx\n", __func__, rc); + + return rc; +} + +CK_BBOOL ep11tok_optimize_single_ops(STDLL_TokData_t *tokdata) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + + return ep11_data->optimize_single_ops ? CK_TRUE : CK_FALSE; +} + +/* return -1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2 */ +static int compare_ck_version(const CK_VERSION *v1, const CK_VERSION *v2) +{ + + if (v1->major < v2->major) + return -1; + if (v1->major > v2->major) + return 1; + if (v1->minor < v2->minor) + return -1; + if (v1->minor > v2->minor) + return 1; + return 0; +} + +static CK_RV get_card_type(uint_32 adapter, CK_ULONG *type) +{ + char fname[PATH_MAX]; + char buf[250]; + CK_RV rc; + CK_ULONG hwtype, rawtype; + +#ifdef EP11_HSMSIM +#ifdef EP11_HSMSIM_CARD_TYPE + *type = EP11_HSMSIM_CARD_TYPE; +#else + *type = 7; +#endif + return CKR_OK; +#endif + + sprintf(fname, "%scard%02x/type", SYSFS_DEVICES_AP, adapter); + rc = file_fgets(fname, buf, sizeof(buf)); + if (rc != CKR_OK) + return rc; + if (sscanf(buf, "CEX%luP", type) != 1) + return CKR_FUNCTION_FAILED; + + sprintf(fname, "%scard%02x/hwtype", SYSFS_DEVICES_AP, adapter); + rc = file_fgets(fname, buf, sizeof(buf)); + if (rc != CKR_OK) + return rc; + if (sscanf(buf, "%lu", &hwtype) != 1) + return CKR_FUNCTION_FAILED; + + sprintf(fname, "%scard%02x/raw_hwtype", SYSFS_DEVICES_AP, adapter); + rc = file_fgets(fname, buf, sizeof(buf)); + if (rc != CKR_OK) + return rc; + if (sscanf(buf, "%lu", &rawtype) != 1) + return CKR_FUNCTION_FAILED; + + if (rawtype > hwtype) { + TRACE_DEVEL("%s adapter: %u hwtype: %lu raw_hwtype: %lu\n", + __func__, adapter, hwtype, rawtype); + /* Tolerated new card level: report calculated type */ + *type += (rawtype - hwtype); + } + + return CKR_OK; +} + +typedef struct query_version +{ + ep11_private_data_t *ep11_data; + CK_CHAR serialNumber[16]; + CK_BBOOL first; + CK_BBOOL error; +} query_version_t; + +static CK_RV version_query_handler(uint_32 adapter, uint_32 domain, + void *handler_data) +{ + query_version_t *qv = (query_version_t *)handler_data; + CK_IBM_XCP_INFO xcp_info; + CK_ULONG xcp_info_len = sizeof(xcp_info); + CK_RV rc; + target_t target; + CK_ULONG card_type; + ep11_card_version_t *card_version; + + rc = get_ep11_target_for_apqn(adapter, domain, &target); + if (rc != CKR_OK) + return rc; + + rc = dll_m_get_xcp_info(&xcp_info, &xcp_info_len, CK_IBM_XCPQ_MODULE, 0, + target); + if (rc != CKR_OK) { + TRACE_ERROR("%s Failed to query module version from adapter %02X.%04X\n", + __func__, adapter, domain); + /* card may no longer be online, so ignore this error situation */ + rc = CKR_OK; + goto out; + } + + rc = get_card_type(adapter, &card_type); + if (rc != CKR_OK) { + TRACE_ERROR("%s Failed to get card type for adapter %02X.%04X\n", + __func__, adapter, domain); + /* card may no longer be online, so ignore this error situation */ + rc = CKR_OK; + goto out; + } + + /* Try to find existing version info for this card type */ + card_version = qv->ep11_data->card_versions; + while (card_version != NULL) { + if (card_version->card_type == card_type) + break; + card_version = card_version->next; + } + + if (card_version == NULL) { + /* + * No version info for this card type found, create new entry and add + * it to the list + */ + card_version = calloc(1, sizeof(ep11_card_version_t)); + if (card_version == NULL) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); + qv->error = TRUE; + rc = CKR_HOST_MEMORY; + goto out; + } + + card_version->card_type = card_type; + card_version->firmware_API_version = xcp_info.firmwareApi; + card_version->firmware_version = xcp_info.firmwareVersion; + + card_version->next = qv->ep11_data->card_versions; + qv->ep11_data->card_versions = card_version; + } else { + /* + * Version info for this card type is already available, so check this + * card against the existing info + */ + if (card_version->firmware_API_version != xcp_info.firmwareApi) { + TRACE_ERROR("%s Adapter %02X.%04X has a different API version " + "than the previous CEX%luP adapters: %lu\n", __func__, + adapter, domain, card_version->card_type, + xcp_info.firmwareApi); + OCK_SYSLOG(LOG_ERR, + "Warning: Adapter %02X.%04X has a different API version " + "than the previous CEX%luP adapters: %lu\n", + adapter, domain, card_version->card_type, + xcp_info.firmwareApi); + qv->error = TRUE; + rc = CKR_OK; + goto out; + } + + if (compare_ck_version(&card_version->firmware_version, + &xcp_info.firmwareVersion) != 0) { + TRACE_ERROR("%s Adapter %02X.%04X has a different firmware version " + "than the previous CEX%luP adapters: %d.%d\n", __func__, + adapter, domain, card_version->card_type, + xcp_info.firmwareVersion.major, + xcp_info.firmwareVersion.minor); + OCK_SYSLOG(LOG_ERR, + "Warning: Adapter %02X.%04X has a different firmware " + "version than the previous CEX%luP adapters: %d.%d\n", + adapter, domain, card_version->card_type, + xcp_info.firmwareVersion.major, + xcp_info.firmwareVersion.minor); + qv->error = TRUE; + rc = CKR_OK; + goto out; + } + } + + if (qv->first) + memcpy(qv->serialNumber, xcp_info.serialNumber, + sizeof(qv->serialNumber)); + qv->first = FALSE; + +out: + free_ep11_target_for_apqn(target); + return rc; +} + +static CK_RV ep11tok_get_ep11_library_version(CK_VERSION *lib_version) +{ + unsigned int host_version; + CK_ULONG version_len = sizeof(host_version); + CK_RV rc; + + if (dll_m_get_xcp_info == NULL) { + TRACE_ERROR("%s Function dll_m_get_xcp_info is not available\n", + __func__); + return CKR_FUNCTION_FAILED; + } + + rc = dll_m_get_xcp_info(&host_version, &version_len, + CK_IBM_XCPHQ_VERSION, 0, 0); + if (rc != CKR_OK) { + TRACE_ERROR("%s dll_m_get_xcp_info (HOST) failed: rc=0x%lx\n", __func__, + rc); + return rc; + } + lib_version->major = (host_version & 0x00FF0000) >> 16; + lib_version->minor = host_version & 0x000000FF; + /* + * EP11 host library < v2.0 returns an invalid version (i.e. 0x100). This + * can safely be treated as version 1.0 + */ + if (lib_version->major == 0) { + lib_version->major = 1; + lib_version->minor = 0; + } + + return CKR_OK; +} + +static CK_RV ep11tok_get_ep11_version(STDLL_TokData_t *tokdata) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + ep11_card_version_t *card_version; + query_version_t qv; + CK_RV rc; + + rc = ep11tok_get_ep11_library_version(&ep11_data->ep11_lib_version); + if (rc != CKR_OK) + return rc; + + TRACE_INFO("%s Host library version: %d.%d\n", __func__, + ep11_data->ep11_lib_version.major, + ep11_data->ep11_lib_version.minor); + + memset(&qv, 0, sizeof(qv)); + qv.ep11_data = ep11_data; + qv.first = TRUE; + + rc = handle_all_ep11_cards(&ep11_data->target_list, version_query_handler, + &qv); + if (rc != CKR_OK) { + TRACE_ERROR("%s handle_all_ep11_cards failed: rc=0x%lx\n", + __func__, rc); + return rc; + } + if (qv.first) { + TRACE_ERROR("%s No EP11 adapters are online or configured\n", __func__); + return CKR_DEVICE_ERROR; + } + if (qv.error) { + TRACE_ERROR("%s Failed to query version of EP11 adapters\n", __func__); + return CKR_DEVICE_ERROR; + } + + memcpy(ep11_data->serialNumber, qv.serialNumber, + sizeof(ep11_data->serialNumber)); + + TRACE_INFO("%s Serial number: %.16s\n", __func__, ep11_data->serialNumber); + + /* EP11 host lib version <= 2 only support API version 2 */ + if (ep11_data->ep11_lib_version.major <= 2) + ep11_data->used_firmware_API_version = 2; + else + ep11_data->used_firmware_API_version = 0; + + card_version = ep11_data->card_versions; + while (card_version != NULL) { + TRACE_INFO("%s Card type: CEX%luP\n", __func__, + card_version->card_type); + TRACE_INFO("%s Firmware API: %lu\n", __func__, + card_version->firmware_API_version); + TRACE_INFO("%s Firmware Version: %d.%d\n", __func__, + card_version->firmware_version.major, + card_version->firmware_version.minor); + + if (ep11_data->used_firmware_API_version == 0) + ep11_data->used_firmware_API_version = + card_version->firmware_API_version; + else + ep11_data->used_firmware_API_version = + MIN(ep11_data->used_firmware_API_version, + card_version->firmware_API_version); + + card_version = card_version->next; + } + + TRACE_INFO("%s Used Firmware API: %lu\n", __func__, + ep11_data->used_firmware_API_version); + + return CKR_OK; +} + +static void free_card_versions(ep11_card_version_t *card_version) +{ + ep11_card_version_t *next_card_version; + + TRACE_INFO("%s running\n", __func__); + + while (card_version != NULL) { + next_card_version = card_version->next; + free(card_version); + card_version = next_card_version; + } +} + +void ep11tok_copy_firmware_info(STDLL_TokData_t *tokdata, + CK_TOKEN_INFO_PTR pInfo) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + + /* + * report the EP11 firmware version as hardware version, and + * the EP11 host library version as firmware version + */ + if (ep11_data->card_versions != NULL) + pInfo->hardwareVersion = ep11_data->card_versions->firmware_version; + pInfo->firmwareVersion = ep11_data->ep11_lib_version; + memcpy(pInfo->serialNumber, ep11_data->serialNumber, + sizeof(pInfo->serialNumber)); +} + +/** + * Returns 1 if all APQNs that are present are at least at the required + * versions. If non of the APQNs are at the required versions, 0 is returned. + * If the APQN versions are inconsistent, -1 is returned. + * Card types > the highest card type contained in the requirements array are + * assumed to fulfill the minimum version requirements. + */ +static int check_required_versions(STDLL_TokData_t *tokdata, + const version_req_t req[], + CK_ULONG num_req) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_ULONG i, max_card_type = 0, min_card_type = 0xFFFFFFFF; + CK_BBOOL req_not_fullfilled = CK_FALSE; + CK_BBOOL req_fullfilled = CK_FALSE; + ep11_card_version_t *card_version; + int status; + + for (i = 0; i < num_req; i++) { + status = check_card_version(tokdata, req[i].card_type, + req[i].min_lib_version, + req[i].min_firmware_version, + req[i].min_firmware_API_version); + if (status == 0) + req_not_fullfilled = CK_TRUE; + if (status == 1) + req_fullfilled = CK_TRUE; + max_card_type = MAX(max_card_type, req[i].card_type); + min_card_type = MIN(min_card_type, req[i].card_type); + } + + /* Are card types < min_card_type present? */ + card_version = ep11_data->card_versions; + while (card_version != NULL) { + if (card_version->card_type < min_card_type) + req_not_fullfilled = CK_TRUE; + card_version = card_version->next; + } + + /* Are card types > max_card_type present? */ + card_version = ep11_data->card_versions; + while (card_version != NULL) { + if (card_version->card_type > max_card_type) { + /* + * Card types > the highest card type contained in the requirements + * array are assumed to fulfill the minimum version requirements. + * So all others must also meet the version requirements or be + * not present. + */ + if (req_not_fullfilled == CK_TRUE) + return -1; + return 1; + } + card_version = card_version->next; + } + + /* No newer cards then max_card_type are present */ + if (req_not_fullfilled == CK_TRUE) { + /* + * At least one don't meet the requirements, so all other must not + * fulfill the requirements, too, or are not present. + */ + if (req_fullfilled == CK_TRUE) + return -1; + return 0; + } else { + /* All of the cards that are present fulfill the requirements */ + return 1; + } +} + +/** + * returns 1 if all APQNs of the specified card type are at least at the + * specified versions, 0 otherwise. If no APQN of that card type is online, + * then -1 is returned. + * Those parameters that are NULL are not checked. + */ +static int check_card_version(STDLL_TokData_t *tokdata, CK_ULONG card_type, + const CK_VERSION *ep11_lib_version, + const CK_VERSION *firmware_version, + const CK_ULONG *firmware_API_version) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + ep11_card_version_t *card_version; + + TRACE_DEBUG("%s checking versions for CEX%luP cards.\n", __func__, card_type); + + if (ep11_lib_version != NULL) { + if (compare_ck_version(&ep11_data->ep11_lib_version, + ep11_lib_version) < 0) { + TRACE_DEBUG("%s ep11_lib_version is less than required\n", __func__); + return 0; + } + } + + card_version = ep11_data->card_versions; + while (card_version != NULL) { + if (card_version->card_type == card_type) + break; + card_version = card_version->next; + } + + if (card_version == NULL) + return -1; + + if (firmware_version != NULL) { + if (compare_ck_version(&card_version->firmware_version, + firmware_version) < 0) { + TRACE_DEBUG("%s firmware_version is less than required\n", __func__); + return 0; + } + } + + if (firmware_API_version != NULL) { + if (card_version->firmware_API_version < *firmware_API_version) { + TRACE_DEBUG("%s firmware_API_version is less than required\n", + __func__); + return 0; + } + } + + return 1; +} + +static CK_RV ep11tok_setup_target(STDLL_TokData_t *tokdata) +{ + ep11_private_data_t *ep11_data = tokdata->private_data; + struct XCP_Module module; + CK_RV rc; + short i; + + if (dll_m_add_module == NULL) { + TRACE_WARNING("%s Function dll_m_add_module is not available, falling " + "back to old target handling\n", __func__); + + if (ep11_data->used_firmware_API_version > 2) { + TRACE_ERROR("%s selecting an API version is not possible with old " + "target handling\n", __func__); + return CKR_FUNCTION_FAILED; + } + + ep11_data->target = (target_t)&ep11_data->target_list; + return CKR_OK; + } + + if (ep11_data->used_firmware_API_version > 2 && + ep11_data->ep11_lib_version.major < 3) { + TRACE_ERROR("%s selecting an API version is not possible with an EP11" + " host library version < 3.0\n", __func__); + return CKR_FUNCTION_FAILED; + } + + ep11_data->target = XCP_TGT_INIT; + memset(&module, 0, sizeof(module)); + module.version = ep11_data->ep11_lib_version.major >= 3 ? XCP_MOD_VERSION_2 + : XCP_MOD_VERSION_1; + module.flags = XCP_MFL_VIRTUAL | XCP_MFL_MODULE; + module.api = ep11_data->used_firmware_API_version; + + TRACE_DEVEL("%s XCP_MOD_VERSION: %u\n", __func__, module.version); + + if (ep11_data->target_list.length == 0) { + /* APQN_ANY: Create an empty module group */ + rc = dll_m_add_module(&module, &ep11_data->target); + if (rc != CKR_OK) { + TRACE_ERROR("%s dll_m_add_module (ANY) failed: rc=%ld\n", + __func__, rc); + return CKR_FUNCTION_FAILED; + } + return CKR_OK; + } + + for (i = 0; i < ep11_data->target_list.length; i++) { + module.module_nr = ep11_data->target_list.apqns[2 * i]; + memset(module.domainmask, 0, sizeof(module.domainmask)); + XCPTGTMASK_SET_DOM(module.domainmask, + ep11_data->target_list.apqns[2 * i + 1]); + + rc = dll_m_add_module(&module, &ep11_data->target); + if (rc != CKR_OK) { + TRACE_ERROR("%s dll_m_add_module (%02x.%04x) failed: rc=%ld\n", + __func__, ep11_data->target_list.apqns[2 * i], + ep11_data->target_list.apqns[2 * i + 1], rc); + return CKR_FUNCTION_FAILED; + } + } + + return CKR_OK; +} +static CK_RV get_ep11_target_for_apqn(uint_32 adapter, uint_32 domain, + target_t *target) +{ + ep11_target_t *target_list; + struct XCP_Module module; + CK_VERSION lib_version; + CK_RV rc; + + *target = XCP_TGT_INIT; + + rc = ep11tok_get_ep11_library_version(&lib_version); + if (rc != CKR_OK) + return rc; + + if (dll_m_add_module != NULL) { + memset(&module, 0, sizeof(module)); + module.version = lib_version.major >= 3 ? XCP_MOD_VERSION_2 + : XCP_MOD_VERSION_1; + module.flags = XCP_MFL_MODULE; + module.module_nr = adapter; + XCPTGTMASK_SET_DOM(module.domainmask, domain); + rc = dll_m_add_module(&module, target); + if (rc != 0) { + TRACE_ERROR("%s dll_m_add_module (%02x.%04x) failed: rc=%ld\n", + __func__, adapter, domain, rc); + return CKR_FUNCTION_FAILED; + } + } else { + /* Fall back to old target handling */ + target_list = (ep11_target_t *)calloc(1, sizeof(ep11_target_t)); + if (target_list == NULL) + return CKR_HOST_MEMORY; + target_list->length = 1; + target_list->apqns[0] = adapter; + target_list->apqns[1] = domain; + *target = (target_t)target_list; + } + + return CKR_OK; +} + +static void free_ep11_target_for_apqn(target_t target) +{ + CK_RV rc; + + if (dll_m_rm_module != NULL) { + rc = dll_m_rm_module(NULL, target); + if (rc != 0) { + TRACE_DEBUG("%s dll_m_rm_module failed: rc=%ld\n", __func__, rc); + } + } else { + /* With the old target handling, target is a pointer to ep11_target_t */ + free((ep11_target_t *)target); + } +} + diff --git a/usr/lib/ep11_stdll/ep11_specific.h b/usr/lib/ep11_stdll/ep11_specific.h new file mode 100644 index 0000000..19bf77d --- /dev/null +++ b/usr/lib/ep11_stdll/ep11_specific.h @@ -0,0 +1,166 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2015-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 + */ + +/* + * OpenCryptoki EP11 token - EP11 token functions + * + */ + +#ifndef EP11_SPECIFIC_H +#define EP11_SPECIFIC_H + +CK_RV ep11tok_get_mechanism_list(STDLL_TokData_t * tokdata, + CK_MECHANISM_TYPE_PTR pMechanismList, + CK_ULONG_PTR pulCount); + +CK_RV ep11tok_get_mechanism_info(STDLL_TokData_t * tokdata, + CK_MECHANISM_TYPE type, + CK_MECHANISM_INFO_PTR pInfo); + +CK_RV ep11tok_is_mechanism_supported(STDLL_TokData_t *tokdata, + CK_MECHANISM_TYPE type); + +CK_RV ep11tok_is_mechanism_supported_ex(STDLL_TokData_t *tokdata, + CK_MECHANISM_PTR mech); + +CK_RV ep11tok_init(STDLL_TokData_t * tokdata, CK_SLOT_ID SlotNumber, + char *conf_name); + +CK_RV ep11tok_final(STDLL_TokData_t * tokdata); + +CK_RV ep11tok_generate_key(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM_PTR mech, CK_ATTRIBUTE_PTR attrs, + CK_ULONG attrs_len, CK_OBJECT_HANDLE_PTR handle); + +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); + +CK_RV ep11tok_generate_key_pair(STDLL_TokData_t * tokdata, SESSION * sess, + CK_MECHANISM_PTR pMechanism, + CK_ATTRIBUTE_PTR pPublicKeyTemplate, + CK_ULONG ulPublicKeyAttributeCount, + CK_ATTRIBUTE_PTR pPrivateKeyTemplate, + CK_ULONG ulPrivateKeyAttributeCount, + CK_OBJECT_HANDLE_PTR phPublicKey, + CK_OBJECT_HANDLE_PTR phPrivateKey); + +CK_RV ep11tok_sign_init(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM * mech, CK_BBOOL recover_mode, + CK_OBJECT_HANDLE key); + +CK_RV ep11tok_sign(STDLL_TokData_t * tokdata, SESSION * session, + CK_BBOOL length_only, CK_BYTE * in_data, + CK_ULONG in_data_len, CK_BYTE * signature, + CK_ULONG * sig_len); + +CK_RV ep11tok_sign_update(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE * in_data, CK_ULONG in_data_len); + +CK_RV ep11tok_sign_final(STDLL_TokData_t * tokdata, SESSION * session, + CK_BBOOL length_only, CK_BYTE * signature, + CK_ULONG * sig_len); + +CK_RV ep11tok_sign_single(STDLL_TokData_t *tokdata, SESSION *session, + CK_MECHANISM *mech, CK_BBOOL length_only, + CK_OBJECT_HANDLE key, CK_BYTE_PTR in_data, + CK_ULONG in_data_len, CK_BYTE_PTR signature, + CK_ULONG_PTR sig_len); + +CK_RV ep11tok_verify_init(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM * mech, CK_BBOOL recover_mode, + CK_OBJECT_HANDLE key); + +CK_RV ep11tok_verify(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE * in_data, CK_ULONG in_data_len, + CK_BYTE * signature, CK_ULONG sig_len); + +CK_RV ep11tok_verify_update(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE * in_data, CK_ULONG in_data_len); + +CK_RV ep11tok_verify_final(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE * signature, CK_ULONG sig_len); + +CK_RV ep11tok_verify_single(STDLL_TokData_t *tokdata, SESSION *session, + CK_MECHANISM *mech, CK_OBJECT_HANDLE key, + CK_BYTE_PTR in_data, CK_ULONG in_data_len, + CK_BYTE_PTR signature, CK_ULONG sig_len); + +CK_RV ep11tok_decrypt_final(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len); + +CK_RV ep11tok_decrypt(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE_PTR input_data, CK_ULONG input_data_len, + CK_BYTE_PTR output_data, CK_ULONG_PTR p_output_data_len); + +CK_RV ep11tok_decrypt_update(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE_PTR input_part, CK_ULONG input_part_len, + CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len); + +CK_RV ep11tok_encrypt_final(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len); + +CK_RV ep11tok_encrypt(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE_PTR input_data, CK_ULONG input_data_len, + CK_BYTE_PTR output_data, CK_ULONG_PTR p_output_data_len); + +CK_RV ep11tok_encrypt_update(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE_PTR input_part, + CK_ULONG input_part_len, CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len); + +CK_RV ep11tok_encrypt_init(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM_PTR mech, CK_OBJECT_HANDLE key); + +CK_RV ep11tok_encrypt_single(STDLL_TokData_t *tokdata, SESSION *session, + CK_MECHANISM *mech, CK_BBOOL length_only, + CK_OBJECT_HANDLE key, CK_BYTE *input_data, + CK_ULONG input_data_len, CK_BYTE *output_data, + CK_ULONG_PTR p_output_data_len); + +CK_RV ep11tok_decrypt_init(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM_PTR mech, CK_OBJECT_HANDLE key); + +CK_RV ep11tok_decrypt_single(STDLL_TokData_t *tokdata, SESSION *session, + CK_MECHANISM *mech, CK_BBOOL length_only, + CK_OBJECT_HANDLE key, CK_BYTE_PTR input_data, + CK_ULONG input_data_len, CK_BYTE_PTR output_data, + CK_ULONG_PTR p_output_data_len); + +CK_RV ep11tok_wrap_key(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM_PTR mech, CK_OBJECT_HANDLE wrapping_key, + CK_OBJECT_HANDLE key, CK_BYTE_PTR wrapped_key, + CK_ULONG_PTR p_wrapped_key_len); + +CK_RV ep11tok_unwrap_key(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM_PTR mech, CK_ATTRIBUTE_PTR attrs, + CK_ULONG attrs_len, CK_BYTE_PTR wrapped_key, + CK_ULONG wrapped_key_len, + CK_OBJECT_HANDLE wrapping_key, + CK_OBJECT_HANDLE_PTR p_key); + +CK_RV ep11tok_login_session(STDLL_TokData_t * tokdata, SESSION * session); + +CK_RV ep11tok_logout_session(STDLL_TokData_t * tokdata, SESSION * session); + +CK_BBOOL ep11tok_optimize_single_ops(STDLL_TokData_t *tokdata); + +CK_BBOOL ep11tok_libica_mech_available(STDLL_TokData_t *tokdata, + CK_MECHANISM_TYPE mech, + CK_OBJECT_HANDLE hKey); + +void ep11tok_copy_firmware_info(STDLL_TokData_t *tokdata, + CK_TOKEN_INFO_PTR pInfo); + +#endif diff --git a/usr/lib/ep11_stdll/ep11_stdll.mk b/usr/lib/ep11_stdll/ep11_stdll.mk new file mode 100644 index 0000000..99b3b37 --- /dev/null +++ b/usr/lib/ep11_stdll/ep11_stdll.mk @@ -0,0 +1,45 @@ +nobase_lib_LTLIBRARIES += opencryptoki/stdll/libpkcs11_ep11.la + +noinst_HEADERS += \ + usr/lib/ep11_stdll/ep11.h usr/lib/ep11_stdll/ep11_func.h usr/lib/ep11_stdll/ep11_specific.h usr/lib/ep11_stdll/tok_struct.h + +opencryptoki_stdll_libpkcs11_ep11_la_CFLAGS = \ + -DDEV -D_THREAD_SAFE -DSHALLOW=0 -DEPSWTOK=1 -DLITE=0 -DNOCDMF \ + -DNOMD2 -DNORIPE -fPIC -DDEFENSIVE_MECHLIST \ + -DTOK_NEW_DATA_STORE=0x0003000c \ + -DSTDLL_NAME=\"ep11tok\" \ + -I${srcdir}/usr/lib/ep11_stdll -I${srcdir}/usr/lib/common \ + -I${srcdir}/usr/include + +opencryptoki_stdll_libpkcs11_ep11_la_LDFLAGS = \ + -shared -Wl,-z,defs,-Bsymbolic -lc -lpthread -lcrypto -lrt \ + -llber -ldl -Wl,--version-script=${srcdir}/opencryptoki_tok.map + +opencryptoki_stdll_libpkcs11_ep11_la_SOURCES = \ + usr/lib/common/asn1.c usr/lib/common/cert.c \ + usr/lib/common/hwf_obj.c usr/lib/common/dp_obj.c \ + usr/lib/common/data_obj.c usr/lib/common/dig_mgr.c \ + usr/lib/common/encr_mgr.c usr/lib/common/decr_mgr.c \ + usr/lib/common/globals.c usr/lib/common/loadsave.c \ + usr/lib/common/mech_aes.c usr/lib/common/mech_des.c \ + usr/lib/common/mech_des3.c usr/lib/common/mech_ec.c \ + usr/lib/common/mech_md5.c usr/lib/common/mech_md2.c \ + usr/lib/common/mech_rng.c usr/lib/common/mech_rsa.c \ + usr/lib/common/mech_sha.c usr/lib/common/mech_dsa.c \ + usr/lib/common/mech_dh.c usr/lib/common/mech_ssl3.c \ + usr/lib/common/obj_mgr.c usr/lib/common/object.c \ + usr/lib/common/sign_mgr.c usr/lib/common/verify_mgr.c \ + usr/lib/common/key.c usr/lib/common/key_mgr.c \ + usr/lib/common/template.c usr/lib/common/p11util.c \ + usr/lib/common/utility.c usr/lib/common/trace.c \ + usr/lib/common/mech_list.c usr/lib/common/shared_memory.c \ + usr/lib/common/attributes.c usr/lib/common/sw_crypt.c \ + usr/lib/ep11_stdll/new_host.c usr/lib/ep11_stdll/ep11_specific.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/btree.c usr/lib/common/sess_mgr.c +endif diff --git a/usr/lib/ep11_stdll/ep11cpfilter.conf b/usr/lib/ep11_stdll/ep11cpfilter.conf new file mode 100644 index 0000000..e27c4ea --- /dev/null +++ b/usr/lib/ep11_stdll/ep11cpfilter.conf @@ -0,0 +1,76 @@ +# +# EP11 token CP-filter configuration +# +# The list of mechanisms returned by C_GetMechanismList is filtered +# using the control point settings of the used crypto adapters. +# The EP11 CP-filter config file is used to associate certain control +# points with mechanisms that are dependent on these control points. +# +# Syntax: +# cp: mech1, mech2, ... +# +# Both, cp as well as mech is specified as name or in decimal, octal +# (with leading 0) or hexadecimal (with leading 0x): +# +# XCP_CPB_SIGN_SYMM: CKM_SHA256_HMAC, CKM_SHA256_HMAC_GENERAL +# 4: 0x00000251, 0x00000252 +# +# sign with HMAC or CMAC +XCP_CPB_SIGN_SYMM: CKM_SHA256_HMAC, CKM_SHA256_HMAC_GENERAL, CKM_SHA224_HMAC, CKM_SHA224_HMAC_GENERAL, CKM_SHA384_HMAC, CKM_SHA384_HMAC_GENERAL, CKM_SHA512_HMAC, CKM_SHA512_HMAC_GENERAL, CKM_SHA_1_HMAC, CKM_SHA_1_HMAC_GENERAL, CKM_IBM_SHA3_224_HMAC, CKM_IBM_SHA3_256_HMAC,CKM_IBM_SHA3_384_HMAC, CKM_IBM_SHA3_512_HMAC, CKM_IBM_CMAC, CKM_DES3_CMAC, CKM_DES3_CMAC_GENERAL, CKM_AES_CMAC, CKM_AES_CMAC_GENERAL + +# verify with HMAC or CMAC +XCP_CPB_SIGVERIFY_SYMM: CKM_SHA256_HMAC, CKM_SHA256_HMAC_GENERAL, CKM_SHA224_HMAC, CKM_SHA224_HMAC_GENERAL, CKM_SHA384_HMAC, CKM_SHA384_HMAC_GENERAL, CKM_SHA512_HMAC, CKM_SHA512_HMAC_GENERAL, CKM_SHA_1_HMAC, CKM_SHA_1_HMAC_GENERAL, CKM_IBM_SHA3_224_HMAC, CKM_IBM_SHA3_256_HMAC,CKM_IBM_SHA3_384_HMAC, CKM_IBM_SHA3_512_HMAC, CKM_IBM_CMAC, CKM_DES3_CMAC, CKM_DES3_CMAC_GENERAL, CKM_AES_CMAC, CKM_AES_CMAC_GENERAL + +# sign with private keys +XCP_CPB_SIGN_ASYMM: CKM_RSA_PKCS, CKM_RSA_PKCS_PSS, CKM_SHA1_RSA_X9_31, CKM_SHA1_RSA_PKCS, CKM_SHA1_RSA_PKCS_PSS, CKM_SHA256_RSA_PKCS, CKM_SHA256_RSA_PKCS_PSS, CKM_SHA224_RSA_PKCS, CKM_SHA224_RSA_PKCS_PSS, CKM_SHA384_RSA_PKCS, CKM_SHA384_RSA_PKCS_PSS, CKM_SHA512_RSA_PKCS, CKM_SHA512_RSA_PKCS_PSS, CKM_ECDSA, CKM_ECDSA_SHA1, CKM_DSA, CKM_DSA_SHA1, CKM_RSA_X9_31, CKM_ECDSA_SHA224, CKM_ECDSA_SHA256, CKM_ECDSA_SHA384, CKM_ECDSA_SHA512 + +# encrypt with symmetric keys +XCP_CPB_ENCRYPT_SYMM: CKM_AES_ECB, CKM_AES_CBC, CKM_AES_CBC_PAD, CKM_DES3_ECB, CKM_DES3_CBC, CKM_DES3_CBC_PAD, CKM_DES_ECB, CKM_DES_CBC + +#decrypt with private keys +XCP_CPB_DECRYPT_ASYMM: CKM_RSA_PKCS + +# decrypt with symmetric keys +XCP_CPB_DECRYPT_SYMM: CKM_AES_ECB, CKM_AES_CBC, CKM_AES_CBC_PAD, CKM_DES3_ECB, CKM_DES3_CBC, CKM_DES3_CBC_PAD, CKM_DES_ECB, CKM_DES_CBC + +# key export with public keys +XCP_CPB_WRAP_ASYMM: CKM_RSA_PKCS + +# key export with symmetric keys +XCP_CPB_WRAP_SYMM: CKM_AES_CBC, CKM_AES_CBC_PAD, CKM_DES3_CBC, CKM_DES3_CBC_PAD + +#key import with private keys +XCP_CPB_UNWRAP_ASYMM: CKM_RSA_PKCS + +# key import with symmetric keys +XCP_CPB_UNWRAP_SYMM: CKM_AES_CBC, CKM_AES_CBC_PAD, CKM_DES3_CBC, CKM_DES3_CBC_PAD + +# generate asymmetric keypairs +XCP_CPB_KEYGEN_ASYMM: CKM_RSA_PKCS_KEY_PAIR_GEN, CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_EC_KEY_PAIR_GEN, CKM_DSA_KEY_PAIR_GEN, CKM_DH_PKCS_KEY_PAIR_GEN + +# generate or derive symmetric keys, including DSA parameters +XCP_CPB_KEYGEN_SYMM: CKM_AES_KEY_GEN, CKM_DES2_KEY_GEN, CKM_DES3_KEY_GEN, CKM_DSA_PARAMETER_GEN, CKM_DH_PKCS_PARAMETER_GEN, CKM_PBE_SHA1_DES3_EDE_CBC, CKM_DES_KEY_GEN, CKM_GENERIC_SECRET_KEY_GEN + +# RSA private-key or key-encrypt use +XCP_CPB_ALG_RSA: CKM_RSA_PKCS, CKM_RSA_PKCS_KEY_PAIR_GEN, CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_PKCS_PSS, CKM_SHA1_RSA_X9_31, CKM_SHA1_RSA_PKCS, CKM_SHA1_RSA_PKCS_PSS, CKM_SHA256_RSA_PKCS, CKM_SHA256_RSA_PKCS_PSS, CKM_SHA224_RSA_PKCS, CKM_SHA224_RSA_PKCS_PSS, CKM_SHA384_RSA_PKCS, CKM_SHA384_RSA_PKCS_PSS, CKM_SHA512_RSA_PKCS, CKM_SHA512_RSA_PKCS_PSS, CKM_RSA_X9_31 + +# DSA private-key use +XCP_CPB_ALG_DSA: CKM_DSA_PARAMETER_GEN, CKM_DSA_KEY_PAIR_GEN, CKM_DSA, CKM_DSA_SHA1 + +# EC private-key use +XCP_CPB_ALG_EC: CKM_EC_KEY_PAIR_GEN, CKM_ECDH1_DERIVE, CKM_ECDSA, CKM_ECDSA_SHA224, CKM_ECDSA_SHA256, CKM_ECDSA_SHA384, CKM_ECDSA_SHA512 + +# Diffie-Hellman use (private keys) +XCP_CPB_ALG_DH: CKM_ECDH1_DERIVE, CKM_DH_PKCS_PARAMETER_GEN, CKM_DH_PKCS_KEY_PAIR_GEN, CKM_DH_PKCS_DERIVE + +# allow key derivation (symmetric+EC/DH) +XCP_CPB_DERIVE: CKM_SHA1_KEY_DERIVATION, CKM_SHA256_KEY_DERIVATION, CKM_SHA384_KEY_DERIVATION, CKM_SHA512_KEY_DERIVATION, CKM_SHA224_KEY_DERIVATION, CKM_ECDH1_DERIVE, CKM_DH_PKCS_DERIVE + +# enable support of curve25519, c448 and related algorithms incl. EdDSA (ed25519 and ed448) +XCP_CPB_ALG_EC_25519: CKM_IBM_EC_C25519, CKM_IBM_EDDSA_SHA512, CKM_IBM_EC_C448, CKM_IBM_ED448_SHA3 + +#allow non-BSI algorithms (as of 2017) including non-BSI keysizes +XCP_CPB_ALG_NBSI2017: CKM_RSA_PKCS, CKM_SHA1_RSA_PKCS, CKM_SHA224_RSA_PKCS, CKM_SHA256_RSA_PKCS, CKM_SHA384_RSA_PKCS, CKM_SHA512_RSA_PKCS + +#enable support of Dilithium +XCP_CPB_ALG_PQC_DILITHIUM: CKM_IBM_DILITHIUM diff --git a/usr/lib/ep11_stdll/ep11tok.conf b/usr/lib/ep11_stdll/ep11tok.conf new file mode 100644 index 0000000..2ef97b5 --- /dev/null +++ b/usr/lib/ep11_stdll/ep11tok.conf @@ -0,0 +1,79 @@ +# +# EP11 token configuration +# +# In order to use the EP11 Token you need to specify a list of +# adapter/domain pairs installed and configured on your system. +# +# To force that the default for CKA_SENSITIVE is CK_TRUE for +# secret keys specify the following option: +# +# FORCE_SENSITIVE +# +# To enable strict-mode, specify the following option: +# +# STRICT_MODE +# +# In strict-mode all session-keys will strictly belong to the PKCS#11 +# session that created it. When the PKCS#11 session ends, all session +# keys created for this session can no longer be used. +# +# VHSM_MODE +# +# In VHSM-mode (virtual-HSM), all keys generated by the EP-11 token will +# strictly belong to the EP11 token that created it. Every EP11 token +# requires a VHSM-pin to be set using the pkcsep11_session tool. +# +# The list of mechanisms returned by C_GetMechanismList is filtered +# using the control point settings of the used crypto adapters. +# The EP11 CP-filter config file is used to associate certain +# control points with mechanisms that are dependent on these control +# points. The default CP-filter config file is 'ep11cpfilter.conf' located +# in the same directory as this EP11 token configuration file. +# You can optionally specify the name and/or location of the CP-filter +# file: +# +# CPFILTER /etc/opencryptoki/ep11cpfilter.conf +# +# To enable optimization of single part Sign/Verify and Encrypt/Decrypt +# operations specify the following option: +# +# OPTIMIZE_SINGLE_PART_OPERATIONS +# +# To optimize digest operations using CPACF the libica library is used. +# Use the DIGEST_LIBICA option to control which libica library is loaded. +# Specify the path of the libica library to use a specific libica library, +# or specify 'DEFAULT' to use the system default libica library. +# Specify 'OFF' to turn digest optimizations off. +# +# DIGEST_LIBICA | DEFAULT | OFF +# +# By default the random number generator of the EP11 cypto adatper is used to +# generate random data. Specify the USE_PRANDOM option to read random data from +# /dev/prandom instead (or /dev/urandom if /dev/prandom is not available). +# +# USE_PRANDOM +# +# There are 2 ways to specify the crypto adapters: +# 1) explicitly list of adapter/domain pairs +# +# APQN_WHITELIST +# 8 13 +# 10 13 +# END +# +# The adapter and domain may be given in decimal, +# octal (with leading 0) or hexadecimal (with leading 0x): +# +# APQN_WHITELIST +# 8 0x0d +# 0x0a 13 +# END +# +# Valid adapter and domain values are in the range 0...255 +# +# 2) any available crypto adapters +# +# APQN_ANY +# + +APQN_ANY diff --git a/usr/lib/ep11_stdll/new_host.c b/usr/lib/ep11_stdll/new_host.c new file mode 100644 index 0000000..d4bd40a --- /dev/null +++ b/usr/lib/ep11_stdll/new_host.c @@ -0,0 +1,4186 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2015-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 + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "stdll.h" + +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "pkcs32.h" +#include "trace.h" +#include "slotmgr.h" +#include "ep11_specific.h" + +#include "../api/apiproto.h" + +void SC_SetFunctionList(void); +CK_RV SC_Finalize(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, SLOT_INFO *sinfp, + struct trace_handle_t *t, CK_BBOOL in_fork_initializer); +static void _ep11tok_logout_session(STDLL_TokData_t * tokdata, void *node_value, + unsigned long node_idx, void *p3); + + +/* verify that the mech specified is in the + * mech list for this token... + */ +CK_RV valid_mech(STDLL_TokData_t *tokdata, CK_MECHANISM_PTR m) +{ + CK_RV rc; + + if (m) { + rc = ep11tok_is_mechanism_supported_ex(tokdata, m); + if (rc != CKR_OK) + return rc; + } + + return CKR_OK; +} + + +/* In an STDLL this is called once for each card in the system + * therefore the initialized only flags certain one time things. + */ +CK_RV ST_Initialize(API_Slot_t *sltp, CK_SLOT_ID SlotNumber, + SLOT_INFO *sinfp, struct trace_handle_t t) +{ + CK_RV rc = CKR_OK; + char abs_tokdir_name[PATH_MAX]; + + if ((rc = check_user_and_group()) != CKR_OK) + return rc; + + /* set trace info */ + set_trace(t); + + if (sltp->TokData != NULL) { + TRACE_ERROR("Already initialized.\n"); + return CKR_CRYPTOKI_ALREADY_INITIALIZED; + } + + /* + * Create separate memory area for each token specific data + */ + sltp->TokData = (STDLL_TokData_t *) calloc(1, sizeof(STDLL_TokData_t)); + if (!sltp->TokData) { + TRACE_ERROR("Allocating host memory failed.\n"); + return CKR_HOST_MEMORY; + } + + 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); + + 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); + + if (strlen(sinfp->tokname)) { + sprintf(abs_tokdir_name, "%s/%s", CONFIG_PATH, sinfp->tokname); + TRACE_DEVEL("Token directory: %s\n", abs_tokdir_name); + init_data_store(sltp->TokData, (char *) abs_tokdir_name, + sltp->TokData->data_store); + } else { + init_data_store(sltp->TokData, (char *) PK_DIR, + sltp->TokData->data_store); + } + + sltp->TokData->version = sinfp->version; + TRACE_DEVEL("Token version: %u.%u\n", + (unsigned int)(sinfp->version >> 16), + (unsigned int)(sinfp->version & 0xffff)); + + /* Initialize Lock */ + if (XProcLock_Init(sltp->TokData) != CKR_OK) { + TRACE_ERROR("Thread lock failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Create lockfile */ + if (CreateXProcLock(sinfp->tokname, sltp->TokData) != CKR_OK) { + TRACE_ERROR("Process lock failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Handle global initialization issues first if we have not + * been initialized. + */ + if (sltp->TokData->initialized == FALSE) { + rc = attach_shm(sltp->TokData, SlotNumber); + if (rc != CKR_OK) { + TRACE_ERROR("Could not attach to shared memory.\n"); + goto done; + } + + sltp->TokData->nv_token_data = + &(sltp->TokData->global_shm->nv_token_data); + SC_SetFunctionList(); + + rc = ep11tok_init(sltp->TokData, SlotNumber, sinfp->confname); + if (rc != 0) { + sltp->FcnList = NULL; + detach_shm(sltp->TokData, 0); + if (sltp->TokData) + free(sltp->TokData); + sltp->TokData = NULL; + TRACE_DEVEL("Token Specific Init failed.\n"); + goto done; + } + sltp->TokData->initialized = TRUE; + } + + rc = load_token_data(sltp->TokData, SlotNumber); + if (rc != CKR_OK) { + sltp->FcnList = NULL; + if (sltp->TokData) + free(sltp->TokData); + sltp->TokData = NULL; + TRACE_DEVEL("Failed to load token data. (rc=0x%02lx)\n", rc); + goto done; + } + + rc = XProcLock(sltp->TokData); + if (rc != CKR_OK) + goto done; + + /* no need to return error here, we load the token data we can + * and syslog the rest + */ + load_public_token_objects(sltp->TokData); + + sltp->TokData->global_shm->publ_loaded = TRUE; + + rc = XProcUnLock(sltp->TokData); + if (rc != CKR_OK) + goto done; + + init_slotInfo(&(sltp->TokData->slot_info)); + + (sltp->FcnList) = &function_list; + +done: + if (rc != CKR_OK && sltp->TokData != NULL) { + if (sltp->TokData->initialized) { + SC_Finalize(sltp->TokData, SlotNumber, sinfp, NULL, 0); + } else { + CloseXProcLock(sltp->TokData); + free(sltp->TokData); + sltp->TokData = NULL; + } + } + + return rc; +} + +/* What does this really have to do in this new token... probably + * need to close the adapters that are opened, and clear the other + * stuff + */ +CK_RV SC_Finalize(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, SLOT_INFO *sinfp, + struct trace_handle_t *t, CK_BBOOL in_fork_initializer) +{ + CK_RV rc = CKR_OK; + + UNUSED(sid); + UNUSED(sinfp); + + if (t != NULL) + set_trace(*t); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + tokdata->initialized = FALSE; + + if (session_mgr_so_session_exists(tokdata) || + session_mgr_user_session_exists(tokdata)) { + bt_for_each_node(tokdata, &tokdata->sess_btree, _ep11tok_logout_session, + NULL); + } + + session_mgr_close_all_sessions(tokdata); + object_mgr_purge_token_objects(tokdata); + + /* Finally free the nodes on free list. */ + bt_destroy(&tokdata->sess_btree); + bt_destroy(&tokdata->object_map_btree); + bt_destroy(&tokdata->sess_obj_btree); + bt_destroy(&tokdata->priv_token_obj_btree); + bt_destroy(&tokdata->publ_token_obj_btree); + +#ifdef ENABLE_LOCKS + pthread_rwlock_destroy(&tokdata->sess_list_rwlock); +#endif + pthread_mutex_destroy(&tokdata->login_mutex); + + detach_shm(tokdata, in_fork_initializer); + /* close spin lock file */ + CloseXProcLock(tokdata); + rc = ep11tok_final(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Token specific final call failed.\n"); + return rc; + } + + final_data_store(tokdata); + + if (tokdata) + free(tokdata); + + return rc; +} + +CK_RV SC_GetTokenInfo(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, + CK_TOKEN_INFO_PTR pInfo) +{ + CK_RV rc = CKR_OK; + time_t now; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + if (!pInfo) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + if (sid >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + rc = CKR_SLOT_ID_INVALID; + goto done; + } + copy_token_contents_sensibly(pInfo, tokdata->nv_token_data); + ep11tok_copy_firmware_info(tokdata, pInfo); + + /* Set the time */ + now = time((time_t *) NULL); + strftime((char *) pInfo->utcTime, 16, "%Y%m%d%H%M%S", localtime(&now)); + pInfo->utcTime[14] = '0'; + pInfo->utcTime[15] = '0'; + +done: + TRACE_INFO("C_GetTokenInfo: rc = 0x%08lx\n", rc); + + return rc; +} + +CK_RV SC_WaitForSlotEvent(STDLL_TokData_t *tokdata, CK_FLAGS flags, + CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved) +{ + UNUSED(flags); + UNUSED(pSlot); + UNUSED(pReserved); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + +/* + * Get the mechanism type list for the current token. + */ +CK_RV SC_GetMechanismList(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, + CK_MECHANISM_TYPE_PTR pMechList, CK_ULONG_PTR count) +{ + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto out; + } + if (count == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto out; + } + if (sid >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + rc = CKR_SLOT_ID_INVALID; + goto out; + } + + rc = ep11tok_get_mechanism_list(tokdata, pMechList, count); + if (rc == CKR_OK) { + /* To accomodate certain special cases, we may need to + * make adjustments to the token's mechanism list. + */ + mechanism_list_transformations(pMechList, count); + } + +out: + TRACE_INFO("C_GetMechanismList: rc = 0x%08lx, # mechanisms: %lu\n", + rc, (count ? *count : 0)); + + return rc; +} + +/* + * Get the mechanism info for the current type and token. + */ +CK_RV SC_GetMechanismInfo(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, + CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo) +{ + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto out; + } + if (pInfo == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto out; + } + if (sid >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + rc = CKR_SLOT_ID_INVALID; + goto out; + } + + rc = ep11tok_get_mechanism_info(tokdata, type, pInfo); +out: + TRACE_INFO("C_GetMechanismInfo: rc = 0x%08lx, mech type = 0x%08lx\n", + rc, type); + + return rc; +} + +/* + * This routine should only be called if no other processes are + * attached to the token. we need to somehow check that this is the + * only process Meta API should prevent this since it knows session + * states in the shared memory. +*/ +CK_RV SC_InitToken(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, CK_CHAR_PTR pPin, + CK_ULONG ulPinLen, CK_CHAR_PTR pLabel) +{ + CK_RV rc = CKR_OK; + CK_BYTE hash_sha[SHA1_HASH_SIZE]; + unsigned char login_key[32]; + TOKEN_DATA_VERSION *dat; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + if (!pPin || !pLabel) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + if (pthread_mutex_lock(&tokdata->login_mutex)) { + TRACE_ERROR("Failed to get mutex lock.\n"); + return CKR_FUNCTION_FAILED; + } + + if (tokdata->nv_token_data->token_info.flags & CKF_SO_PIN_LOCKED) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LOCKED)); + rc = CKR_PIN_LOCKED; + goto done; + } + + dat = &tokdata->nv_token_data->dat; + if (tokdata->version < TOK_NEW_DATA_STORE) { + rc = compute_sha1(tokdata, pPin, ulPinLen, hash_sha); + if (memcmp(tokdata->nv_token_data->so_pin_sha, hash_sha, SHA1_HASH_SIZE) + != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + } else { + rc = PKCS5_PBKDF2_HMAC((char *)pPin, ulPinLen, + dat->so_login_salt, 64, + dat->so_login_it, EVP_sha512(), + 256 / 8, login_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + if (CRYPTO_memcmp(dat->so_login_key, login_key, 32) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + } + + /* Before we reconstruct all the data, we should delete the + * token objects from the filesystem. + */ + object_mgr_destroy_token_objects(tokdata); + delete_token_data(tokdata); + + load_token_data(tokdata, sid); + init_slotInfo(&(tokdata->slot_info)); + if (tokdata->version < TOK_NEW_DATA_STORE) { + memcpy(tokdata->nv_token_data->so_pin_sha, hash_sha, SHA1_HASH_SIZE); + } else { + memcpy(dat->so_login_key, login_key, 32); + } + tokdata->nv_token_data->token_info.flags |= CKF_TOKEN_INITIALIZED; + memcpy(tokdata->nv_token_data->token_info.label, pLabel, 32); + + rc = save_token_data(tokdata, sid); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to save token data.\n"); + goto done; + } + +done: + TRACE_INFO("C_InitToken: rc = 0x%08lx\n", rc); + + pthread_mutex_unlock(&tokdata->login_mutex); + + return rc; +} + + +CK_RV SC_InitPIN(STDLL_TokData_t * tokdata, ST_SESSION_HANDLE * sSession, + CK_CHAR_PTR pPin, CK_ULONG ulPinLen) +{ + SESSION *sess = NULL; + CK_BYTE hash_sha[SHA1_HASH_SIZE]; + CK_BYTE hash_md5[MD5_HASH_SIZE]; + CK_RV rc = CKR_OK; + TOKEN_DATA_VERSION *dat; + unsigned char login_key[32], wrap_key[32], login_salt[64], wrap_salt[64]; + uint64_t login_it, wrap_it; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + if (!pPin) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + if (pthread_mutex_lock(&tokdata->login_mutex)) { + TRACE_ERROR("Failed to get mutex lock.\n"); + return CKR_FUNCTION_FAILED; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + if (pin_locked(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LOCKED)); + rc = CKR_PIN_LOCKED; + goto done; + } + if (sess->session_info.state != CKS_RW_SO_FUNCTIONS) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + + if ((ulPinLen < MIN_PIN_LEN) || (ulPinLen > MAX_PIN_LEN)) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LEN_RANGE)); + rc = CKR_PIN_LEN_RANGE; + goto done; + } + + + dat = &tokdata->nv_token_data->dat; + if (tokdata->version < TOK_NEW_DATA_STORE) { + /* compute the SHA and MD5 hashes of the user pin */ + rc = compute_sha1(tokdata, pPin, ulPinLen, hash_sha); + rc |= compute_md5(tokdata, pPin, ulPinLen, hash_md5); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to compute sha or md5 for user pin.\n"); + goto done; + } + } else { + login_it = USER_KDF_LOGIN_IT; + memcpy(login_salt, USER_KDF_LOGIN_PURPOSE, 32); + rng_generate(tokdata, login_salt + 32, 32); + + rc = PKCS5_PBKDF2_HMAC((char *)pPin, ulPinLen, + login_salt, 64, + login_it, EVP_sha512(), + 256 / 8, login_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + wrap_it = USER_KDF_WRAP_IT; + memcpy(wrap_salt, USER_KDF_WRAP_PURPOSE, 32); + rng_generate(tokdata, wrap_salt + 32, 32); + + rc = PKCS5_PBKDF2_HMAC((char *)pPin, ulPinLen, + wrap_salt, 64, + wrap_it, EVP_sha512(), + 256 / 8, wrap_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + } + + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get process lock.\n"); + goto done; + } + + if (tokdata->version < TOK_NEW_DATA_STORE) { + memcpy(tokdata->nv_token_data->user_pin_sha, hash_sha, SHA1_HASH_SIZE); + } else { + memcpy(dat->user_login_key, login_key, 256 / 8); + memcpy(dat->user_login_salt, login_salt, 64); + dat->user_login_it = login_it; + } + + tokdata->nv_token_data->token_info.flags |= CKF_USER_PIN_INITIALIZED; + tokdata->nv_token_data->token_info.flags &= ~(CKF_USER_PIN_TO_BE_CHANGED); + tokdata->nv_token_data->token_info.flags &= ~(CKF_USER_PIN_LOCKED); + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release process lock.\n"); + goto done; + } + + if (tokdata->version < TOK_NEW_DATA_STORE) { + memcpy(tokdata->user_pin_md5, hash_md5, MD5_HASH_SIZE); + } else { + memcpy(tokdata->user_wrap_key, wrap_key, 256 / 8); + memcpy(dat->user_wrap_salt, wrap_salt, 64); + dat->user_wrap_it = wrap_it; + } + + rc = save_token_data(tokdata, sess->session_info.slotID); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to save token data.\n"); + goto done; + } + + rc = save_masterkey_user(tokdata); + if (rc != CKR_OK) + TRACE_DEVEL("Failed to save user's masterkey.\n"); + +done: + TRACE_INFO("C_InitPin: rc = 0x%08lx, session = %lu\n", + rc, sSession->sessionh); + + pthread_mutex_unlock(&tokdata->login_mutex); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + +CK_RV SC_SetPIN(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_CHAR_PTR pOldPin, CK_ULONG ulOldLen, CK_CHAR_PTR pNewPin, + CK_ULONG ulNewLen) +{ + SESSION *sess = NULL; + CK_BYTE old_hash_sha[SHA1_HASH_SIZE]; + CK_BYTE new_hash_sha[SHA1_HASH_SIZE]; + CK_BYTE hash_md5[MD5_HASH_SIZE]; + CK_RV rc = CKR_OK; + TOKEN_DATA_VERSION *dat; + unsigned char old_login_key[32], new_login_key[32], new_wrap_key[32], + new_login_key_old_salt[32], login_salt[64], wrap_salt[64]; + uint64_t login_it, wrap_it; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (pthread_mutex_lock(&tokdata->login_mutex)) { + TRACE_ERROR("Failed to get mutex lock.\n"); + return CKR_FUNCTION_FAILED; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + if (pin_locked(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LOCKED)); + rc = CKR_PIN_LOCKED; + goto done; + } + + /* Check if token has a specific handler for this, otherwise fall back + * to default behaviour. + */ + + if ((ulNewLen < MIN_PIN_LEN) || (ulNewLen > MAX_PIN_LEN)) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LEN_RANGE)); + rc = CKR_PIN_LEN_RANGE; + goto done; + } + + dat = &tokdata->nv_token_data->dat; + if (tokdata->version < TOK_NEW_DATA_STORE) { + rc = compute_sha1(tokdata, pOldPin, ulOldLen, old_hash_sha); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to compute sha for old pin.\n"); + goto done; + } + } + + /* From the PKCS#11 2.20 spec: "C_SetPIN modifies the PIN of + * the user that is currently logged in, or the CKU_USER PIN + * if the session is not logged in." A non R/W session fails + * with CKR_SESSION_READ_ONLY. + */ + if ((sess->session_info.state == CKS_RW_USER_FUNCTIONS) || + (sess->session_info.state == CKS_RW_PUBLIC_SESSION)) { + + if (tokdata->version < TOK_NEW_DATA_STORE) { + if (memcmp(tokdata->nv_token_data->user_pin_sha, old_hash_sha, + SHA1_HASH_SIZE) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + rc = compute_sha1(tokdata, pNewPin, ulNewLen, new_hash_sha); + rc |= compute_md5(tokdata, pNewPin, ulNewLen, hash_md5); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to compute hash for new pin.\n"); + goto done; + } + /* The old PIN matches, now make sure its different + * than the new and is not the default. */ + if ((memcmp(old_hash_sha, new_hash_sha, SHA1_HASH_SIZE) == 0) || + (memcmp(new_hash_sha, default_user_pin_sha, SHA1_HASH_SIZE) + == 0)) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INVALID)); + rc = CKR_PIN_INVALID; + goto done; + } + } else { + login_it = USER_KDF_LOGIN_IT; + memcpy(login_salt, USER_KDF_LOGIN_PURPOSE, 32); + rng_generate(tokdata, login_salt + 32, 32); + + rc = PKCS5_PBKDF2_HMAC((char *)pNewPin, ulNewLen, + login_salt, 64, + login_it, EVP_sha512(), + 256 / 8, new_login_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + wrap_it = USER_KDF_WRAP_IT; + memcpy(wrap_salt, USER_KDF_WRAP_PURPOSE, 32); + rng_generate(tokdata, wrap_salt + 32, 32); + + rc = PKCS5_PBKDF2_HMAC((char *)pNewPin, ulNewLen, + wrap_salt, 64, + wrap_it, EVP_sha512(), + 256 / 8, new_wrap_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + rc = PKCS5_PBKDF2_HMAC((char *)pOldPin, ulOldLen, + dat->user_login_salt, 64, + dat->user_login_it, EVP_sha512(), + 256 / 8, old_login_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + rc = PKCS5_PBKDF2_HMAC((char *)pNewPin, ulNewLen, + dat->user_login_salt, 64, + dat->user_login_it, EVP_sha512(), + 256 / 8, new_login_key_old_salt); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (CRYPTO_memcmp(dat->user_login_key, + old_login_key, 256 / 8) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INVALID)); + rc = CKR_PIN_INVALID; + goto done; + } + /* The old PIN matches, now make sure its different + * than the new and is not the default. */ + if (CRYPTO_memcmp(old_login_key, + new_login_key_old_salt, 256 / 8) == 0) + { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INVALID)); + rc = CKR_PIN_INVALID; + goto done; + } + } + + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to get process lock.\n"); + goto done; + } + + if (tokdata->version < TOK_NEW_DATA_STORE) { + memcpy(tokdata->nv_token_data->user_pin_sha, new_hash_sha, + SHA1_HASH_SIZE); + memcpy(tokdata->user_pin_md5, hash_md5, MD5_HASH_SIZE); + } else { + memcpy(dat->user_login_key, new_login_key, 256 / 8); + memcpy(dat->user_login_salt, login_salt, 64); + dat->user_login_it = login_it; + memcpy(tokdata->user_wrap_key, new_wrap_key, 256 / 8); + memcpy(dat->user_wrap_salt, wrap_salt, 64); + dat->user_wrap_it = wrap_it; + } + + tokdata->nv_token_data->token_info.flags &= + ~(CKF_USER_PIN_TO_BE_CHANGED); + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release process lock.\n"); + goto done; + } + + rc = save_token_data(tokdata, sess->session_info.slotID); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to save token data.\n"); + goto done; + } + rc = save_masterkey_user(tokdata); + } else if (sess->session_info.state == CKS_RW_SO_FUNCTIONS) { + + if (tokdata->version < TOK_NEW_DATA_STORE) { + if (memcmp(tokdata->nv_token_data->so_pin_sha, old_hash_sha, + SHA1_HASH_SIZE) != 0) { + rc = CKR_PIN_INCORRECT; + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + goto done; + } + rc = compute_sha1(tokdata, pNewPin, ulNewLen, new_hash_sha); + rc |= compute_md5(tokdata, pNewPin, ulNewLen, hash_md5); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to compute hash for new pin.\n"); + goto done; + } + /* The old PIN matches, now make sure its different + * than the new and is not the default. + */ + if ((memcmp(old_hash_sha, new_hash_sha, SHA1_HASH_SIZE) == 0) || + (memcmp(new_hash_sha, default_so_pin_sha, SHA1_HASH_SIZE) + == 0)) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INVALID)); + rc = CKR_PIN_INVALID; + goto done; + } + } else { + login_it = SO_KDF_LOGIN_IT; + memcpy(login_salt, SO_KDF_LOGIN_PURPOSE, 32); + rng_generate(tokdata, login_salt + 32, 32); + + rc = PKCS5_PBKDF2_HMAC((char *)pNewPin, ulNewLen, + login_salt, 64, + login_it, EVP_sha512(), + 256 / 8, new_login_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + wrap_it = SO_KDF_WRAP_IT; + memcpy(wrap_salt, SO_KDF_WRAP_PURPOSE, 32); + rng_generate(tokdata, wrap_salt + 32, 32); + + rc = PKCS5_PBKDF2_HMAC((char *)pNewPin, ulNewLen, + wrap_salt, 64, + wrap_it, EVP_sha512(), + 256 / 8, new_wrap_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + rc = PKCS5_PBKDF2_HMAC((char *)pOldPin, ulOldLen, + dat->so_login_salt, 64, + dat->so_login_it, EVP_sha512(), + 256 / 8, old_login_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + rc = PKCS5_PBKDF2_HMAC((char *)pNewPin, ulNewLen, + dat->so_login_salt, 64, + dat->so_login_it, EVP_sha512(), + 256 / 8, new_login_key_old_salt); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (CRYPTO_memcmp(dat->so_login_key, + old_login_key, 256 / 8) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INVALID)); + rc = CKR_PIN_INVALID; + goto done; + } + /* The old PIN matches, now make sure its different + * than the new and is not the default. */ + if (CRYPTO_memcmp(new_login_key_old_salt, + old_login_key, 256 / 8) == 0) + { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INVALID)); + rc = CKR_PIN_INVALID; + goto done; + } + } + + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to get process lock.\n"); + goto done; + } + + if (tokdata->version < TOK_NEW_DATA_STORE) { + memcpy(tokdata->nv_token_data->so_pin_sha, new_hash_sha, + SHA1_HASH_SIZE); + memcpy(tokdata->so_pin_md5, hash_md5, MD5_HASH_SIZE); + } else { + memcpy(dat->so_login_key, new_login_key, 256 / 8); + memcpy(dat->so_login_salt, login_salt, 64); + dat->so_login_it = login_it; + memcpy(tokdata->so_wrap_key, new_wrap_key, 256 / 8); + memcpy(dat->so_wrap_salt, wrap_salt, 64); + dat->so_wrap_it = wrap_it; + } + + tokdata->nv_token_data->token_info.flags &= ~(CKF_SO_PIN_TO_BE_CHANGED); + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release process lock.\n"); + goto done; + } + + rc = save_token_data(tokdata, sess->session_info.slotID); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to save token data.\n"); + goto done; + } + + rc = save_masterkey_so(tokdata); + if (rc != CKR_OK) + TRACE_DEVEL("Failed to save SO's masterkey.\n"); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY)); + rc = CKR_SESSION_READ_ONLY; + } + +done: + TRACE_INFO("C_SetPin: rc = 0x%08lx, session = %lu\n", + rc, sSession->sessionh); + + pthread_mutex_unlock(&tokdata->login_mutex); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + +CK_RV SC_OpenSession(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, CK_FLAGS flags, + CK_SESSION_HANDLE_PTR phSession) +{ + CK_RV rc = CKR_OK; + SESSION *sess; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + if (phSession == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + if (sid >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + return CKR_SLOT_ID_INVALID; + } + flags |= CKF_SERIAL_SESSION; + if ((flags & CKF_RW_SESSION) == 0) { + if (session_mgr_so_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_WRITE_SO_EXISTS)); + return CKR_SESSION_READ_WRITE_SO_EXISTS; + } + } + + rc = session_mgr_new(tokdata, flags, sid, phSession); + if (rc != CKR_OK) { + TRACE_DEVEL("session_mgr_new() failed\n"); + return rc; + } + + sess = session_mgr_find(tokdata, *phSession); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + return CKR_SESSION_HANDLE_INVALID; + } + + sess->handle = *phSession; + + if (session_mgr_so_session_exists(tokdata) || session_mgr_user_session_exists(tokdata)) { + rc = ep11tok_login_session(tokdata, sess); + } + + TRACE_INFO("C_OpenSession: rc = 0x%08lx sess = %lu\n", rc, sess->handle); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +static void _ep11tok_login_session(STDLL_TokData_t * tokdata, void *node_value, + unsigned long node_idx, void *p3) +{ + CK_RV rc; + CK_RV *r = (CK_RV *) p3; + + UNUSED(node_idx); + + rc = ep11tok_login_session(tokdata, (SESSION *) node_value); + if (rc != CKR_OK) + *r = rc; +} + +static void _ep11tok_logout_session(STDLL_TokData_t * tokdata, void *node_value, + unsigned long node_idx, void *p3) +{ + UNUSED(node_idx); + UNUSED(p3); + + ep11tok_logout_session(tokdata, (SESSION *) node_value); +} + +CK_RV SC_CloseSession(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BBOOL in_fork_initializer) +{ + CK_RV rc = CKR_OK; + SESSION *sess = NULL; + + UNUSED(in_fork_initializer); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (session_mgr_so_session_exists(tokdata) || + session_mgr_user_session_exists(tokdata)) { + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + rc = ep11tok_logout_session(tokdata, sess); + if (rc != CKR_OK) { + TRACE_ERROR("ep11tok_logout_session failed: %s\n", ock_err(rc)); + goto done; + } + + session_mgr_put(tokdata, sess); + sess = NULL; + } + + rc = session_mgr_close_session(tokdata, sSession->sessionh); +done: + if (sess != NULL) + session_mgr_put(tokdata, sess); + + TRACE_INFO("C_CloseSession: rc = 0x%08lx, sess = %lu\n", + rc, sSession->sessionh); + + return rc; +} + +CK_RV SC_CloseAllSessions(STDLL_TokData_t *tokdata, CK_SLOT_ID sid) +{ + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (session_mgr_so_session_exists(tokdata) || + session_mgr_user_session_exists(tokdata)) { + bt_for_each_node(tokdata, &tokdata->sess_btree, _ep11tok_logout_session, NULL); + } + + rc = session_mgr_close_all_sessions(tokdata); + if (rc != CKR_OK) + TRACE_DEVEL("session_mgr_close_all_sessions() failed.\n"); + +done: + TRACE_INFO("C_CloseAllSessions: rc = 0x%08lx, slot = %lu\n", rc, sid); + + return rc; +} + +CK_RV SC_GetSessionInfo(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_SESSION_INFO_PTR pInfo) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pInfo) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + memcpy(pInfo, &sess->session_info, sizeof(CK_SESSION_INFO)); + +done: + TRACE_INFO("C_GetSessionInfo: sess = %lu\n", sSession->sessionh); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + +CK_RV SC_GetOperationState(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pOperationState, + CK_ULONG_PTR pulOperationStateLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pulOperationStateLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (!pOperationState) + length_only = TRUE; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + rc = session_mgr_get_op_state(sess, length_only, pOperationState, + pulOperationStateLen); + if (rc != CKR_OK) + TRACE_DEVEL("session_mgr_get_op_state() failed.\n"); + +done: + TRACE_INFO("C_GetOperationState: rc = 0x%08lx, sess = %lu\n", + rc, sSession->sessionh); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_SetOperationState(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pOperationState, + CK_ULONG ulOperationStateLen, + CK_OBJECT_HANDLE hEncryptionKey, + CK_OBJECT_HANDLE hAuthenticationKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pOperationState || (ulOperationStateLen == 0)) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + rc = session_mgr_set_op_state(sess, hEncryptionKey, hAuthenticationKey, + pOperationState, ulOperationStateLen); + + if (rc != CKR_OK) + TRACE_DEVEL("session_mgr_set_op_state() failed.\n"); + +done: + TRACE_INFO("C_SetOperationState: rc = 0x%08lx, sess = %lu\n", + rc, sSession->sessionh); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Login(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_USER_TYPE userType, CK_CHAR_PTR pPin, CK_ULONG ulPinLen) +{ + SESSION *sess = NULL; + CK_FLAGS_32 *flags = NULL; + CK_BYTE hash_sha[SHA1_HASH_SIZE]; + CK_RV rc = CKR_OK; + unsigned char login_key[32], wrap_key[32]; + TOKEN_DATA_VERSION *dat; + + /* In v2.11, logins should be exclusive, since token + * specific flags may need to be set for a bad login. - KEY + */ + if (pthread_mutex_lock(&tokdata->login_mutex)) { + TRACE_ERROR("Failed to get mutex lock.\n"); + return CKR_FUNCTION_FAILED; + } + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + flags = &tokdata->nv_token_data->token_info.flags; + + if (!pPin || ulPinLen > MAX_PIN_LEN) { + set_login_flags(userType, flags); + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + + /* PKCS #11 v2.01 requires that all sessions have the same login status: + * --> all sessions are public, all are SO or all are USER + */ + if (userType == CKU_USER) { + if (session_mgr_so_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_ANOTHER_ALREADY_LOGGED_IN)); + rc = CKR_USER_ANOTHER_ALREADY_LOGGED_IN; + } + if (session_mgr_user_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_ALREADY_LOGGED_IN)); + rc = CKR_USER_ALREADY_LOGGED_IN; + } + } else if (userType == CKU_SO) { + if (session_mgr_user_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_ANOTHER_ALREADY_LOGGED_IN)); + rc = CKR_USER_ANOTHER_ALREADY_LOGGED_IN; + } + if (session_mgr_so_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_ALREADY_LOGGED_IN)); + rc = CKR_USER_ALREADY_LOGGED_IN; + } + if (session_mgr_readonly_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY_EXISTS)); + rc = CKR_SESSION_READ_ONLY_EXISTS; + } + } else { + rc = CKR_USER_TYPE_INVALID; + TRACE_ERROR("%s\n", ock_err(ERR_USER_TYPE_INVALID)); + } + if (rc != CKR_OK) + goto done; + + dat = &tokdata->nv_token_data->dat; + + if (userType == CKU_USER) { + if (*flags & CKF_USER_PIN_LOCKED) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LOCKED)); + rc = CKR_PIN_LOCKED; + goto done; + } + + if (tokdata->version < TOK_NEW_DATA_STORE) { + if (memcmp(tokdata->nv_token_data->user_pin_sha, + "00000000000000000000", SHA1_HASH_SIZE) == 0) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_PIN_NOT_INITIALIZED)); + rc = CKR_USER_PIN_NOT_INITIALIZED; + goto done; + } + + rc = compute_sha1(tokdata, pPin, ulPinLen, hash_sha); + if (memcmp(tokdata->nv_token_data->user_pin_sha, hash_sha, + SHA1_HASH_SIZE) != 0) { + set_login_flags(userType, flags); + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + /* Successful login, clear flags */ + *flags &= ~(CKF_USER_PIN_LOCKED | + CKF_USER_PIN_FINAL_TRY | CKF_USER_PIN_COUNT_LOW); + + compute_md5(tokdata, pPin, ulPinLen, tokdata->user_pin_md5); + memset(tokdata->so_pin_md5, 0x0, MD5_HASH_SIZE); + } else { + rc = PKCS5_PBKDF2_HMAC((char *)pPin, ulPinLen, + dat->user_login_salt, 64, + dat->user_login_it, EVP_sha512(), + 256 / 8, login_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + rc = PKCS5_PBKDF2_HMAC((char *)pPin, ulPinLen, + dat->user_wrap_salt, 64, + dat->user_wrap_it, EVP_sha512(), + 256 / 8, wrap_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (CRYPTO_memcmp(dat->user_login_key, + login_key, 256 / 8) != 0) { + set_login_flags(userType, flags); + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + + /* Successful login, clear flags */ + *flags &= ~(CKF_USER_PIN_LOCKED | + CKF_USER_PIN_FINAL_TRY | CKF_USER_PIN_COUNT_LOW); + + memcpy(tokdata->user_wrap_key, wrap_key, 256 / 8); + memset(tokdata->so_wrap_key, 0, 256 / 8); + } + + rc = load_masterkey_user(tokdata); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to load user's masterkey.\n"); + goto done; + } + + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get process lock.\n"); + goto done; + } + + /* no need to return error here, we load the token data + * we can and syslog the rest + */ + load_private_token_objects(tokdata); + + tokdata->global_shm->priv_loaded = TRUE; + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release process lock.\n"); + goto done; + } + } else { + if (*flags & CKF_SO_PIN_LOCKED) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LOCKED)); + rc = CKR_PIN_LOCKED; + goto done; + } + + if (tokdata->version < TOK_NEW_DATA_STORE) { + rc = compute_sha1(tokdata, pPin, ulPinLen, hash_sha); + if (memcmp(tokdata->nv_token_data->so_pin_sha, hash_sha, SHA1_HASH_SIZE) + != 0) { + set_login_flags(userType, flags); + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + /* Successful login, clear flags */ + *flags &= ~(CKF_SO_PIN_LOCKED | CKF_SO_PIN_FINAL_TRY | + CKF_SO_PIN_COUNT_LOW); + + compute_md5(tokdata, pPin, ulPinLen, tokdata->so_pin_md5); + memset(tokdata->user_pin_md5, 0x0, MD5_HASH_SIZE); + } else { + rc = PKCS5_PBKDF2_HMAC((char *)pPin, ulPinLen, + dat->so_login_salt, 64, + dat->so_login_it, EVP_sha512(), + 256 / 8, login_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + rc = PKCS5_PBKDF2_HMAC((char *)pPin, ulPinLen, + dat->so_wrap_salt, 64, + dat->so_wrap_it, EVP_sha512(), + 256 / 8, wrap_key); + if (rc != 1) { + TRACE_DEVEL("PBKDF2 failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (CRYPTO_memcmp(dat->so_login_key, + login_key, 256 / 8) != 0) { + set_login_flags(userType, flags); + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + + /* Successful login, clear flags */ + *flags &= ~(CKF_SO_PIN_LOCKED | CKF_SO_PIN_FINAL_TRY | + CKF_SO_PIN_COUNT_LOW); + + memcpy(tokdata->so_wrap_key, wrap_key, 256 / 8); + memset(tokdata->user_wrap_key, 0, 256 / 8); + } + + rc = load_masterkey_so(tokdata); + if (rc != CKR_OK) + TRACE_DEVEL("Failed to load SO's masterkey.\n"); + } + +done: + if (rc == CKR_OK) { + rc = session_mgr_login_all(tokdata, userType); + if (rc != CKR_OK) + TRACE_DEVEL("session_mgr_login_all failed.\n"); + } + + if (rc == CKR_OK) { + bt_for_each_node(tokdata, &tokdata->sess_btree, _ep11tok_login_session, + &rc); + if (rc != CKR_OK) + TRACE_DEVEL("_ep11tok_login_session failed.\n"); + } + + TRACE_INFO("C_Login: rc = 0x%08lx\n", rc); + if (sess) + save_token_data(tokdata, sess->session_info.slotID); + + pthread_mutex_unlock(&tokdata->login_mutex); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Logout(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (pthread_mutex_lock(&tokdata->login_mutex)) { + TRACE_ERROR("Failed to get mutex lock.\n"); + return CKR_FUNCTION_FAILED; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + /* all sessions have the same state so we just have to check one */ + if (session_mgr_public_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + + bt_for_each_node(tokdata, &tokdata->sess_btree, _ep11tok_logout_session, + NULL); + + rc = session_mgr_logout_all(tokdata); + if (rc != CKR_OK) + TRACE_DEVEL("session_mgr_logout_all failed.\n"); + + memset(tokdata->user_pin_md5, 0x0, MD5_HASH_SIZE); + memset(tokdata->so_pin_md5, 0x0, MD5_HASH_SIZE); + + object_mgr_purge_private_token_objects(tokdata); + +done: + TRACE_INFO("C_Logout: rc = 0x%08lx\n", rc); + + pthread_mutex_unlock(&tokdata->login_mutex); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_CreateObject(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phObject) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags)) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = object_mgr_add(tokdata, sess, pTemplate, ulCount, phObject); + if (rc != CKR_OK) + TRACE_DEVEL("object_mgr_add() failed.\n"); + +done: + if (sess != NULL) + session_mgr_put(tokdata, sess); + + TRACE_INFO("C_CreateObject: rc = 0x%08lx\n", rc); + +#ifdef DEBUG + CK_ULONG i; + + for (i = 0; i < ulCount; i++) { + if (pTemplate[i].type == CKA_CLASS) { + TRACE_DEBUG("Object Type: 0x%02lx\n", + *((CK_ULONG *) pTemplate[i].pValue)); + } + } + if (rc == CKR_OK) + TRACE_DEBUG("Handle: %lu\n", *phObject); +#endif + + return rc; +} + + +CK_RV SC_CopyObject(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = object_mgr_copy(tokdata, sess, pTemplate, ulCount, hObject, + phNewObject); + if (rc != CKR_OK) + TRACE_DEVEL("object_mgr_copy() failed\n"); + +done: + if (sess != NULL) + session_mgr_put(tokdata, sess); + + TRACE_INFO("C_CopyObject:rc = 0x%08lx,old handle = %lu, " + "new handle = %lu\n", rc, hObject, *phNewObject); + + return rc; +} + + +CK_RV SC_DestroyObject(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE hObject) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = object_mgr_destroy_object(tokdata, sess, hObject); + if (rc != CKR_OK) + TRACE_DEVEL("object_mgr_destroy_object() failed\n"); + +done: + if (sess != NULL) + session_mgr_put(tokdata, sess); + + TRACE_INFO("C_DestroyObject: rc = 0x%08lx, handle = %lu\n", rc, hObject); + + return rc; +} + + +CK_RV SC_GetObjectSize(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + rc = object_mgr_get_object_size(tokdata, hObject, pulSize); + if (rc != CKR_OK) + TRACE_ERROR("object_mgr_get_object_size() failed.\n"); + +done: + TRACE_INFO("C_GetObjectSize: rc = 0x%08lx, handle = %lu\n", rc, hObject); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_GetAttributeValue(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + rc = object_mgr_get_attribute_values(tokdata, sess, hObject, pTemplate, + ulCount); + if (rc != CKR_OK) + TRACE_DEVEL("object_mgr_get_attribute_value() failed.\n"); + +done: + TRACE_INFO("C_GetAttributeValue: rc = 0x%08lx, handle = %lu\n", + rc, hObject); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *ptr = NULL; + CK_ULONG i; + + attr = pTemplate; + for (i = 0; i < ulCount; i++, attr++) { + ptr = (CK_BYTE *) attr->pValue; + + TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + + if (attr->ulValueLen != (CK_ULONG) (-1) && (ptr != NULL)) + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } +#endif + + return rc; +} + + +CK_RV SC_SetAttributeValue(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + rc = object_mgr_set_attribute_values(tokdata, sess, hObject, pTemplate, + ulCount); + if (rc != CKR_OK) + TRACE_DEVEL("object_mgr_set_attribute_values() failed.\n"); + +done: + TRACE_INFO("C_SetAttributeValue: rc = 0x%08lx, handle = %lu\n", + rc, hObject); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_ULONG i; + + attr = pTemplate; + for (i = 0; i < ulCount; i++, attr++) { + CK_BYTE *ptr = (CK_BYTE *) attr->pValue; + + TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + + if (attr->ulValueLen != (CK_ULONG) (-1) && (ptr != NULL)) + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } +#endif + + return rc; +} + + +CK_RV SC_FindObjectsInit(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->find_active == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + rc = object_mgr_find_init(tokdata, sess, pTemplate, ulCount); + +done: + TRACE_INFO("C_FindObjectsInit: rc = 0x%08lx\n", rc); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_ULONG i; + + attr = pTemplate; + for (i = 0; i < ulCount; i++, attr++) { + CK_BYTE *ptr = (CK_BYTE *) attr->pValue; + + TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + + if (attr->ulValueLen != (CK_ULONG) (-1) && (ptr != NULL)) + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } +#endif + + return rc; +} + + +CK_RV SC_FindObjects(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, + CK_ULONG_PTR pulObjectCount) +{ + SESSION *sess = NULL; + CK_ULONG count = 0; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!phObject || !pulObjectCount) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->find_active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!sess->find_list) { + TRACE_DEVEL("sess->find_list is NULL.\n"); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + count = MIN(ulMaxObjectCount, (sess->find_count - sess->find_idx)); + + memcpy(phObject, sess->find_list + sess->find_idx, + count * sizeof(CK_OBJECT_HANDLE)); + *pulObjectCount = count; + + sess->find_idx += count; + rc = CKR_OK; + +done: + TRACE_INFO("C_FindObjects: rc = 0x%08lx, returned %lu objects\n", + rc, count); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_FindObjectsFinal(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->find_active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (sess->find_list) + free(sess->find_list); + + sess->find_list = NULL; + sess->find_len = 0; + sess->find_idx = 0; + sess->find_active = FALSE; + + rc = CKR_OK; + +done: + TRACE_INFO("C_FindObjectsFinal: rc = 0x%08lx\n", rc); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_EncryptInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->encr_ctx.active == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + sess->encr_ctx.multi_init = FALSE; + sess->encr_ctx.multi = FALSE; + + if (ep11tok_optimize_single_ops(tokdata)) { + /* In case of a single part encrypt operation we don't need the + * EncryptInit, instead we can use the EncryptSingle which is much + * faster. In case of multi-part operations we are doing the EncryptInit + * when EncryptUpdate comes into play. + */ + sess->encr_ctx.init_pending = TRUE; + sess->encr_ctx.active = TRUE; + sess->encr_ctx.key = hKey; + + sess->encr_ctx.mech.mechanism = pMechanism->mechanism; + sess->encr_ctx.mech.pParameter = malloc(pMechanism->ulParameterLen); + memcpy(sess->encr_ctx.mech.pParameter, pMechanism->pParameter, + pMechanism->ulParameterLen); + sess->encr_ctx.mech.ulParameterLen = pMechanism->ulParameterLen; + } else { + rc = ep11tok_encrypt_init(tokdata, sess, pMechanism, hKey); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_encrypt_init() failed.\n"); + } + +done: + TRACE_INFO("C_EncryptInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)(-1))); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Encrypt(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pData, CK_ULONG ulDataLen, + CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (!pData || !pulEncryptedDataLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (sess->encr_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pEncryptedData) + length_only = TRUE; + + if (sess->encr_ctx.multi_init == FALSE) { + sess->encr_ctx.multi = FALSE; + sess->encr_ctx.multi_init = TRUE; + } + + if (sess->encr_ctx.multi == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + if (ep11tok_optimize_single_ops(tokdata)) { + rc = ep11tok_encrypt_single(tokdata, sess, &sess->encr_ctx.mech, + length_only, sess->encr_ctx.key, + pData, ulDataLen, pEncryptedData, + pulEncryptedDataLen); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_encrypt_single() failed.\n"); + } else { + rc = ep11tok_encrypt(tokdata, sess, pData, ulDataLen, pEncryptedData, + pulEncryptedDataLen); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_encrypt() failed.\n"); + } + +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { + if (sess) + encr_mgr_cleanup(&sess->encr_ctx); + } + + TRACE_INFO("C_Encrypt: rc = 0x%08lx, sess = %ld, amount = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulDataLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_EncryptUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if ((!pPart && ulPartLen != 0) || !pulEncryptedPartLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (sess->encr_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (sess->encr_ctx.multi_init == FALSE) { + sess->encr_ctx.multi = TRUE; + sess->encr_ctx.multi_init = TRUE; + } + + if (sess->encr_ctx.multi == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + if (sess->encr_ctx.init_pending) { + rc = ep11tok_encrypt_init(tokdata, sess, &sess->encr_ctx.mech, + sess->encr_ctx.key); + if (rc != CKR_OK) { + TRACE_DEVEL("ep11tok_encr_init() failed.\n"); + goto done; + } + + sess->encr_ctx.init_pending = 0; + } + + rc = ep11tok_encrypt_update(tokdata, sess, pPart, ulPartLen, pEncryptedPart, + pulEncryptedPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_encrypt_update() failed.\n"); + +done: + if (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL) { + if (sess) + encr_mgr_cleanup(&sess->encr_ctx); + } + + TRACE_INFO("C_EncryptUpdate: rc = 0x%08lx, sess = %ld, amount = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_EncryptFinal(STDLL_TokData_t * tokdata, ST_SESSION_HANDLE * sSession, + CK_BYTE_PTR pLastEncryptedPart, + CK_ULONG_PTR pulLastEncryptedPartLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (!pulLastEncryptedPartLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (sess->encr_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (sess->encr_ctx.multi_init == FALSE) { + sess->encr_ctx.multi = TRUE; + sess->encr_ctx.multi_init = TRUE; + } + + if (sess->encr_ctx.multi == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + if (!pLastEncryptedPart) + length_only = TRUE; + + if (sess->encr_ctx.init_pending) { + /* EncryptInit without Update, no EncryptFinal necessary */ + sess->encr_ctx.init_pending = 0; + goto done; + } + + rc = ep11tok_encrypt_final(tokdata, sess, pLastEncryptedPart, + pulLastEncryptedPartLen); + if (rc != CKR_OK) + TRACE_ERROR("ep11tok_encrypt_final() failed.\n"); + +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { + if (sess) + encr_mgr_cleanup(&sess->encr_ctx); + } + + TRACE_INFO("C_EncryptFinal: rc = 0x%08lx, sess = %ld\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DecryptInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->decr_ctx.active == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + sess->decr_ctx.multi_init = FALSE; + sess->decr_ctx.multi = FALSE; + + if (ep11tok_optimize_single_ops(tokdata)) { + /* In case of a single part decrypt operation we don't need the + * DecryptInit, instead we can use the EncryptSingle which is much + * faster. In case of multi-part operations we are doing the DecryptInit + * when DecryptUpdate comes into play. + */ + sess->decr_ctx.init_pending = TRUE; + sess->decr_ctx.active = TRUE; + sess->decr_ctx.key = hKey; + + sess->decr_ctx.mech.mechanism = pMechanism->mechanism; + sess->decr_ctx.mech.pParameter = malloc(pMechanism->ulParameterLen); + memcpy(sess->decr_ctx.mech.pParameter, pMechanism->pParameter, + pMechanism->ulParameterLen); + sess->decr_ctx.mech.ulParameterLen = pMechanism->ulParameterLen; + } else { + rc = ep11tok_decrypt_init(tokdata, sess, pMechanism, hKey); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_decrypt_init() failed.\n"); + } + +done: + TRACE_INFO("C_DecryptInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)-1)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Decrypt(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, + CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (!pEncryptedData || !pulDataLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (sess->decr_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pData) + length_only = TRUE; + + if (sess->decr_ctx.multi_init == FALSE) { + sess->decr_ctx.multi = FALSE; + sess->decr_ctx.multi_init = TRUE; + } + + if (sess->decr_ctx.multi == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + if (ep11tok_optimize_single_ops(tokdata)) { + rc = ep11tok_decrypt_single(tokdata, sess, &sess->decr_ctx.mech, + length_only, sess->decr_ctx.key, + pEncryptedData, ulEncryptedDataLen, + pData, pulDataLen); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_decrypt_single() failed.\n"); + } else { + rc = ep11tok_decrypt(tokdata, sess, pEncryptedData, ulEncryptedDataLen, + pData, pulDataLen); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_decrypt() failed.\n"); + } + +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { + if (sess) + decr_mgr_cleanup(&sess->decr_ctx); + } + + TRACE_INFO("C_Decrypt: rc = 0x%08lx, sess = %ld, amount = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + ulEncryptedDataLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DecryptUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, + CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if ((!pEncryptedPart && ulEncryptedPartLen != 0) || !pulPartLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (sess->decr_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (sess->decr_ctx.multi_init == FALSE) { + sess->decr_ctx.multi = TRUE; + sess->decr_ctx.multi_init = TRUE; + } + + if (sess->decr_ctx.multi == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + if (sess->decr_ctx.init_pending) { + rc = ep11tok_decrypt_init(tokdata, sess, &sess->decr_ctx.mech, + sess->decr_ctx.key); + if (rc != CKR_OK) { + TRACE_DEVEL("ep11tok_decr_init() failed.\n"); + goto done; + } + + sess->decr_ctx.init_pending = 0; + } + + rc = ep11tok_decrypt_update(tokdata, sess, pEncryptedPart, + ulEncryptedPartLen, pPart, pulPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_decrypt_update() failed.\n"); + +done: + if (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL && sess != NULL) { + if (sess) + decr_mgr_cleanup(&sess->decr_ctx); + } + + TRACE_INFO("C_DecryptUpdate: rc = 0x%08lx, sess = %ld, amount = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + ulEncryptedPartLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DecryptFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (!pulLastPartLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (sess->decr_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (sess->decr_ctx.multi_init == FALSE) { + sess->decr_ctx.multi = TRUE; + sess->decr_ctx.multi_init = TRUE; + } + + if (sess->decr_ctx.multi == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + if (!pLastPart) + length_only = TRUE; + + if (sess->decr_ctx.init_pending) { + /* DecryptInit without Update, no DecryptFinal necessary */ + sess->decr_ctx.init_pending = 0; + goto done; + } + + rc = ep11tok_decrypt_final(tokdata, sess, pLastPart, pulLastPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_decrypt_final() failed.\n"); +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { + if (sess) + decr_mgr_cleanup(&sess->decr_ctx); + } + + TRACE_INFO("C_DecryptFinal: rc = 0x%08lx, sess = %ld, amount = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pulLastPartLen ? *pulLastPartLen : 0)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DigestInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->digest_ctx.active == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + rc = digest_mgr_init(tokdata, sess, &sess->digest_ctx, pMechanism); + if (rc != CKR_OK) + TRACE_DEVEL("digest_mgr_init() failed.\n"); + +done: + TRACE_INFO("C_DigestInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)-1)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Digest(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, + CK_ULONG_PTR pulDigestLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->digest_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pDigest) + length_only = TRUE; + + rc = digest_mgr_digest(tokdata, sess, length_only, &sess->digest_ctx, + pData, ulDataLen, pDigest, pulDigestLen); + if (rc != CKR_OK) + TRACE_DEVEL("digest_mgr_digest() failed.\n"); + +done: + TRACE_INFO("C_Digest: rc = 0x%08lx, sess = %ld, datalen = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulDataLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DigestUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->digest_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + /* If there is data to hash, do so. */ + if (ulPartLen) { + rc = digest_mgr_digest_update(tokdata, sess, &sess->digest_ctx, + pPart, ulPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("digest_mgr_digest_update() failed.\n"); + } + +done: + TRACE_INFO("C_DigestUpdate: rc = 0x%08lx, sess = %ld, datalen = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DigestKey(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE hKey) +{ + UNUSED(sSession); + UNUSED(hKey); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + /* The EP11 library does not support DigestKey */ + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + return CKR_KEY_INDIGESTIBLE; +} + + +CK_RV SC_DigestFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->digest_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pDigest) + length_only = TRUE; + + rc = digest_mgr_digest_final(tokdata, sess, length_only, + &sess->digest_ctx, pDigest, pulDigestLen); + if (rc != CKR_OK) + TRACE_ERROR("digest_mgr_digest_final() failed.\n"); + +done: + TRACE_INFO("C_DigestFinal: rc = 0x%08lx, sess = %ld\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_SignInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + rc = valid_mech(tokdata, pMechanism); + if (rc != CKR_OK) + goto done; + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->sign_ctx.active == TRUE) { + rc = CKR_OPERATION_ACTIVE; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + goto done; + } + + if (ep11tok_libica_mech_available(tokdata, pMechanism->mechanism, hKey)) { + rc = sign_mgr_init(tokdata, sess, &sess->sign_ctx, pMechanism, FALSE, + hKey); + if (rc != CKR_OK) + TRACE_DEVEL("sign_mgr_init() failed.\n"); + + goto done; + } + + sess->sign_ctx.multi_init = FALSE; + sess->sign_ctx.multi = FALSE; + + if (ep11tok_optimize_single_ops(tokdata)) { + /* In case of a single part sign operation we don't need the SignInit, + * instead we can use the SignSingle which is much faster. + * In case of multi-part operations we are doing the SignInit when + * SignUpdate comes into play. + */ + sess->sign_ctx.init_pending = TRUE; + sess->sign_ctx.active = TRUE; + sess->sign_ctx.key = hKey; + + sess->sign_ctx.mech.mechanism = pMechanism->mechanism; + sess->sign_ctx.mech.pParameter = malloc(pMechanism->ulParameterLen); + memcpy(sess->sign_ctx.mech.pParameter, pMechanism->pParameter, + pMechanism->ulParameterLen); + sess->sign_ctx.mech.ulParameterLen = pMechanism->ulParameterLen; + } else { + rc = ep11tok_sign_init(tokdata, sess, pMechanism, FALSE, hKey); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_sign_init() failed.\n"); + } + +done: + TRACE_INFO("C_SignInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)-1)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Sign(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG_PTR pulSignatureLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pData || !pulSignatureLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->sign_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pSignature) + length_only = TRUE; + + if (ep11tok_libica_mech_available(tokdata, sess->sign_ctx.mech.mechanism, + sess->sign_ctx.key)) { + rc = sign_mgr_sign(tokdata, sess, length_only, &sess->sign_ctx, pData, + ulDataLen, pSignature, pulSignatureLen); + if (rc != CKR_OK) + TRACE_DEVEL("sign_mgr_sign() failed.\n"); + + goto done; + } + + if (sess->sign_ctx.multi_init == FALSE) { + sess->sign_ctx.multi = FALSE; + sess->sign_ctx.multi_init = TRUE; + } + + if (sess->sign_ctx.multi == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + if (ep11tok_optimize_single_ops(tokdata)) { + rc = ep11tok_sign_single(tokdata, sess, &sess->sign_ctx.mech, + length_only, sess->sign_ctx.key, + pData, ulDataLen, pSignature, pulSignatureLen); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_sign_single() failed.\n"); + } else { + rc = ep11tok_sign(tokdata, sess, length_only, pData, ulDataLen, + pSignature, pulSignatureLen); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_sign() failed.\n"); + } + +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) + sign_mgr_cleanup(&sess->sign_ctx); + + TRACE_INFO("C_Sign: rc = 0x%08lx, sess = %ld, datalen = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulDataLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_SignUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pPart && ulPartLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->sign_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (ep11tok_libica_mech_available(tokdata, sess->sign_ctx.mech.mechanism, + sess->sign_ctx.key)) { + rc = sign_mgr_sign_update(tokdata, sess, &sess->sign_ctx, pPart, + ulPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("sign_mgr_sign_update() failed.\n"); + + goto done; + } + + if (sess->sign_ctx.multi_init == FALSE) { + sess->sign_ctx.multi = TRUE; + sess->sign_ctx.multi_init = TRUE; + } + + if (sess->sign_ctx.multi == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + if (sess->sign_ctx.init_pending) { + rc = ep11tok_sign_init(tokdata, sess, &sess->sign_ctx.mech, + FALSE, sess->sign_ctx.key); + if (rc != CKR_OK) { + TRACE_DEVEL("ep11tok_sign_init() failed.\n"); + goto done; + } + + sess->sign_ctx.init_pending = 0; + } + + rc = ep11tok_sign_update(tokdata, sess, pPart, ulPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_sign_update() failed.\n"); + +done: + if (rc != CKR_OK) + sign_mgr_cleanup(&sess->sign_ctx); + + TRACE_INFO("C_SignUpdate: rc = 0x%08lx, sess = %ld, datalen = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_SignFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pulSignatureLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->sign_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pSignature) + length_only = TRUE; + + if (ep11tok_libica_mech_available(tokdata, sess->sign_ctx.mech.mechanism, + sess->sign_ctx.key)) { + rc = sign_mgr_sign_final(tokdata, sess, length_only, &sess->sign_ctx, + pSignature, pulSignatureLen); + if (rc != CKR_OK) + TRACE_ERROR("sign_mgr_sign_final() failed.\n"); + + goto done; + } + + if (sess->sign_ctx.multi_init == FALSE) { + sess->sign_ctx.multi = TRUE; + sess->sign_ctx.multi_init = TRUE; + } + + if (sess->sign_ctx.multi == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + if (sess->sign_ctx.init_pending) { + /* SignInit without Update, no SignFinal necessary */ + sess->sign_ctx.init_pending = 0; + goto done; + } + rc = ep11tok_sign_final(tokdata, sess, length_only, pSignature, + pulSignatureLen); + if (rc != CKR_OK) + TRACE_ERROR("ep11tok_sign_final() failed.\n"); + +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) + sign_mgr_cleanup(&sess->sign_ctx); + + TRACE_INFO("C_SignFinal: rc = 0x%08lx, sess = %ld\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_SignRecoverInit(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + UNUSED(sSession); + UNUSED(pMechanism); + UNUSED(hKey); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV SC_SignRecover(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pData, CK_ULONG ulDataLen, + CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) +{ + UNUSED(sSession); + UNUSED(pData); + UNUSED(ulDataLen); + UNUSED(pSignature); + UNUSED(pulSignatureLen); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV SC_VerifyInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->verify_ctx.active == TRUE) { + rc = CKR_OPERATION_ACTIVE; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + goto done; + } + + if (ep11tok_libica_mech_available(tokdata, pMechanism->mechanism, hKey)) { + rc = verify_mgr_init(tokdata, sess, &sess->verify_ctx, pMechanism, + FALSE, hKey); + if (rc != CKR_OK) + TRACE_DEVEL("verify_mgr_init() failed.\n"); + + goto done; + } + + sess->verify_ctx.multi_init = FALSE; + sess->verify_ctx.multi = FALSE; + + if (ep11tok_optimize_single_ops(tokdata)) { + /* In case of a single part verify operation we don't need the + * VerifyInit, instead we can use the VerifySingle which is much + * faster. In case of multi-part operations we are doing the VerifyInit + * when VerifyUpdate comes into play. + */ + sess->verify_ctx.init_pending = TRUE; + sess->verify_ctx.active = TRUE; + sess->verify_ctx.multi = FALSE; + sess->verify_ctx.key = hKey; + + sess->verify_ctx.mech.mechanism = pMechanism->mechanism; + sess->verify_ctx.mech.pParameter = malloc(pMechanism->ulParameterLen); + memcpy(sess->verify_ctx.mech.pParameter, pMechanism->pParameter, + pMechanism->ulParameterLen); + sess->verify_ctx.mech.ulParameterLen = pMechanism->ulParameterLen; + } else { + rc = ep11tok_verify_init(tokdata, sess, pMechanism, FALSE, hKey); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_verify_init() failed.\n"); + } + +done: + TRACE_INFO("C_VerifyInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)-1)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Verify(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG ulSignatureLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pData || !pSignature) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->verify_ctx.active == FALSE) { + rc = CKR_OPERATION_NOT_INITIALIZED; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + goto done; + } + + if (ep11tok_libica_mech_available(tokdata, sess->verify_ctx.mech.mechanism, + sess->verify_ctx.key)) { + rc = verify_mgr_verify(tokdata, sess, &sess->verify_ctx, pData, + ulDataLen, pSignature, ulSignatureLen); + if (rc != CKR_OK) + TRACE_DEVEL("verify_mgr_verify() failed.\n"); + + goto done; + } + + if (sess->verify_ctx.multi_init == FALSE) { + sess->verify_ctx.multi = FALSE; + sess->verify_ctx.multi_init = TRUE; + } + + if (sess->verify_ctx.multi == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + if (ep11tok_optimize_single_ops(tokdata)) { + rc = ep11tok_verify_single(tokdata, sess, &sess->verify_ctx.mech, + sess->verify_ctx.key, pData, ulDataLen, + pSignature, ulSignatureLen); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_verify_single() failed.\n"); + } else { + rc = ep11tok_verify(tokdata, sess, pData, ulDataLen, pSignature, + ulSignatureLen); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_verify() failed.\n"); + } + +done: + verify_mgr_cleanup(&sess->verify_ctx); + + TRACE_INFO("C_Verify: rc = 0x%08lx, sess = %ld, datalen = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulDataLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_VerifyUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pPart && ulPartLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->verify_ctx.active == FALSE) { + rc = CKR_OPERATION_NOT_INITIALIZED; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + goto done; + } + + if (ep11tok_libica_mech_available(tokdata, sess->verify_ctx.mech.mechanism, + sess->verify_ctx.key)) { + rc = verify_mgr_verify_update(tokdata, sess, &sess->verify_ctx, pPart, + ulPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("verify_mgr_verify_update() failed.\n"); + + goto done; + } + + if (sess->verify_ctx.multi_init == FALSE) { + sess->verify_ctx.multi = TRUE; + sess->verify_ctx.multi_init = TRUE; + } + + if (sess->verify_ctx.multi == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + if (sess->verify_ctx.init_pending) { + rc = ep11tok_verify_init(tokdata, sess, &sess->verify_ctx.mech, + FALSE, sess->verify_ctx.key); + if (rc != CKR_OK) { + TRACE_DEVEL("ep11tok_verify_init() failed.\n"); + goto done; + } + + sess->verify_ctx.init_pending = 0; + } + + rc = ep11tok_verify_update(tokdata, sess, pPart, ulPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_verify_update() failed.\n"); + +done: + if (rc != CKR_OK) + verify_mgr_cleanup(&sess->verify_ctx); + + TRACE_INFO("C_VerifyUpdate: rc = 0x%08lx, sess = %ld, datalen = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_VerifyFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pSignature) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (sess->verify_ctx.active == FALSE) { + rc = CKR_OPERATION_NOT_INITIALIZED; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + goto done; + } + + if (ep11tok_libica_mech_available(tokdata, sess->verify_ctx.mech.mechanism, + sess->verify_ctx.key)) { + rc = verify_mgr_verify_final(tokdata, sess, &sess->verify_ctx, + pSignature, ulSignatureLen); + if (rc != CKR_OK) + TRACE_DEVEL("verify_mgr_verify_final() failed.\n"); + + goto done; + } + + if (sess->verify_ctx.multi_init == FALSE) { + sess->verify_ctx.multi = TRUE; + sess->verify_ctx.multi_init = TRUE; + } + + if (sess->verify_ctx.multi == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + if (sess->verify_ctx.init_pending) { + /* VerifyInit without Update, no VerifyFinal necessary */ + sess->verify_ctx.init_pending = 0; + goto done; + } + rc = ep11tok_verify_final(tokdata, sess, pSignature, ulSignatureLen); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_verify_final() failed.\n"); + +done: + verify_mgr_cleanup(&sess->verify_ctx); + + TRACE_INFO("C_VerifyFinal: rc = 0x%08lx, sess = %ld\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_VerifyRecoverInit(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + UNUSED(sSession); + UNUSED(pMechanism); + UNUSED(hKey); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + return CKR_FUNCTION_NOT_SUPPORTED; + +} + + +CK_RV SC_VerifyRecover(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen, + CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) +{ + UNUSED(sSession); + UNUSED(pSignature); + UNUSED(ulSignatureLen); + UNUSED(pData); + UNUSED(pulDataLen); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV SC_DigestEncryptUpdate(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, CK_BYTE_PTR pPart, + CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen) +{ + UNUSED(sSession); + UNUSED(pPart); + UNUSED(ulPartLen); + UNUSED(pEncryptedPart); + UNUSED(pulEncryptedPartLen); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV SC_DecryptDigestUpdate(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, + CK_ULONG_PTR pulPartLen) +{ + UNUSED(sSession); + UNUSED(pEncryptedPart); + UNUSED(ulEncryptedPartLen); + UNUSED(pPart); + UNUSED(pulPartLen); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV SC_SignEncryptUpdate(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, CK_BYTE_PTR pPart, + CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen) +{ + UNUSED(sSession); + UNUSED(pPart); + UNUSED(ulPartLen); + UNUSED(pEncryptedPart); + UNUSED(pulEncryptedPartLen); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV SC_DecryptVerifyUpdate(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, + CK_ULONG_PTR pulPartLen) +{ + UNUSED(sSession); + UNUSED(pEncryptedPart); + UNUSED(ulEncryptedPartLen); + UNUSED(pPart); + UNUSED(pulPartLen); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV SC_GenerateKey(STDLL_TokData_t * tokdata, ST_SESSION_HANDLE * sSession, + CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism || !phKey || (pTemplate == NULL && ulCount != 0)) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = ep11tok_generate_key(tokdata, sess, pMechanism, pTemplate, + ulCount, phKey); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_generate_key() failed.\n"); + +done: + TRACE_INFO("C_GenerateKey: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", rc, + (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)-1)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_ULONG i; + + attr = pTemplate; + if (attr != NULL) { + for (i = 0; i < ulCount; i++, attr++) { + CK_BYTE *ptr = (CK_BYTE *) attr->pValue; + TRACE_DEBUG("%lu: Attribute type: 0x%08lx,Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + if (attr->ulValueLen != ((CK_ULONG) - 1) && (ptr != NULL)) { + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } + } + } else { + TRACE_DEBUG("No attributes\n"); + } +#endif + + return rc; +} + + +CK_RV SC_GenerateKeyPair(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, + CK_ATTRIBUTE_PTR pPublicKeyTemplate, + CK_ULONG ulPublicKeyAttributeCount, + CK_ATTRIBUTE_PTR pPrivateKeyTemplate, + CK_ULONG ulPrivateKeyAttributeCount, + CK_OBJECT_HANDLE_PTR phPublicKey, + CK_OBJECT_HANDLE_PTR phPrivateKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism || !phPublicKey || !phPrivateKey || + (!pPublicKeyTemplate && (ulPublicKeyAttributeCount != 0)) || + (!pPrivateKeyTemplate && (ulPrivateKeyAttributeCount != 0))) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = ep11tok_generate_key_pair(tokdata, sess, pMechanism, + pPublicKeyTemplate, + ulPublicKeyAttributeCount, + pPrivateKeyTemplate, + ulPrivateKeyAttributeCount, + phPublicKey, phPrivateKey); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_generate_key_pair() failed.\n"); + +done: + TRACE_INFO("C_GenerateKeyPair: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : ((CK_LONG) sess->handle), + (pMechanism ? pMechanism->mechanism : (CK_ULONG)-1)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_ULONG i; + + if (rc == CKR_OK) { + TRACE_DEBUG("Public handle: %lu, Private handle: %lu\n", + *phPublicKey, *phPrivateKey); + } + + TRACE_DEBUG("Public Template:\n"); + attr = pPublicKeyTemplate; + if (attr != NULL) { + for (i = 0; i < ulPublicKeyAttributeCount; i++, attr++) { + CK_BYTE *ptr = (CK_BYTE *) attr->pValue; + TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + if (attr->ulValueLen != ((CK_ULONG) - 1) && (ptr != NULL)) + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } + } else { + TRACE_DEBUG("No Attributes\n"); + } + + TRACE_DEBUG("Private Template:\n"); + attr = pPublicKeyTemplate; + if (attr != NULL) { + for (i = 0; i < ulPublicKeyAttributeCount; i++, attr++) { + CK_BYTE *ptr = (CK_BYTE *) attr->pValue; + TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + if (attr->ulValueLen != (CK_ULONG) (-1) && (ptr != NULL)) + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } + } else { + TRACE_DEBUG("No Attributes\n"); + } +#endif + + return rc; +} + + +CK_RV SC_WrapKey(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey, + CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey, + CK_ULONG_PTR pulWrappedKeyLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism || !pulWrappedKeyLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = ep11tok_wrap_key(tokdata, sess, pMechanism, hWrappingKey, hKey, + pWrappedKey, pulWrappedKeyLen); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_wrap_key() failed.\n"); + +done: + TRACE_INFO("C_WrapKey: rc = 0x%08lx, sess = %ld, encrypting key = %lu, " + "wrapped key = %lu\n", rc, + (sess == NULL) ? -1 : (CK_LONG) sess->handle, + hWrappingKey, hKey); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_UnwrapKey(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey, + CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism || !pWrappedKey || (!pTemplate && ulCount != 0) || !phKey) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = ep11tok_unwrap_key(tokdata, sess, pMechanism, pTemplate, ulCount, + pWrappedKey, ulWrappedKeyLen, hUnwrappingKey, + phKey); + if (rc != CKR_OK) + TRACE_DEVEL("ep11tok_unwrap_key() failed.\n"); + +done: + TRACE_INFO("C_UnwrapKey: rc = 0x%08lx, sess = %ld, decrypting key = %lu," + "unwrapped key = %lu\n", rc, + (sess == NULL) ? -1 : (CK_LONG) sess->handle, + hUnwrappingKey, (phKey ? *phKey : 0)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *ptr = NULL; + CK_ULONG i; + + attr = pTemplate; + if (attr != NULL) { + for (i = 0; i < ulCount; i++, attr++) { + ptr = (CK_BYTE *) attr->pValue; + TRACE_DEBUG("%lu: Attribute type: 0x%08lx,Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + if (attr->ulValueLen != ((CK_ULONG) - 1) && (ptr != NULL)) { + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } + } + } else { + TRACE_DEBUG("No attributes\n"); + } +#endif + + return rc; +} + + +CK_RV SC_DeriveKey(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism || (!pTemplate && ulCount != 0)) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + if (pMechanism->mechanism != CKM_SSL3_KEY_AND_MAC_DERIVE && !phKey) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = ep11tok_derive_key(tokdata, sess, pMechanism, hBaseKey, phKey, + pTemplate, ulCount); + if (rc != CKR_OK) + TRACE_DEVEL("epl11tok_derive_key() failed.\n"); + +done: + TRACE_INFO("C_DeriveKey: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)(-1))); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *ptr = NULL; + CK_ULONG i; + + if (rc == CKR_OK) { + switch (pMechanism->mechanism) { + case CKM_SSL3_KEY_AND_MAC_DERIVE: + { + CK_SSL3_KEY_MAT_PARAMS *pReq; + CK_SSL3_KEY_MAT_OUT *pPtr; + pReq = (CK_SSL3_KEY_MAT_PARAMS *) pMechanism->pParameter; + pPtr = pReq->pReturnedKeyMaterial; + + TRACE_DEBUG("Client MAC key: %lu, Server MAC key: %lu, " + "Client Key: %lu, Server Key: %lu\n", + pPtr->hClientMacSecret, + pPtr->hServerMacSecret, pPtr->hClientKey, + pPtr->hServerKey); + } + break; + case CKM_DH_PKCS_DERIVE: + TRACE_DEBUG("DH Shared Secret:\n"); + break; + default: + TRACE_DEBUG("Derived key: %lu\n", *phKey); + } + } + + attr = pTemplate; + if (attr != NULL) { + for (i = 0; i < ulCount; i++, attr++) { + ptr = (CK_BYTE *) attr->pValue; + TRACE_DEBUG("%lu: Attribute type: 0x%08lx,Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + if (attr->ulValueLen != ((CK_ULONG) - 1) && (ptr != NULL)) { + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } + } + } else { + TRACE_DEBUG("No attributes\n"); + } +#endif /* DEBUG */ + return rc; +} + + +CK_RV SC_SeedRandom(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen) +{ + UNUSED(sSession); + UNUSED(pSeed); + UNUSED(ulSeedLen); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_RANDOM_SEED_NOT_SUPPORTED)); + + return CKR_RANDOM_SEED_NOT_SUPPORTED; +} + + +CK_RV SC_GenerateRandom(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pRandomData && ulRandomLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + rc = rng_generate(tokdata, pRandomData, ulRandomLen); + if (rc != CKR_OK) + TRACE_DEVEL("rng_generate() failed.\n"); + +done: + TRACE_INFO("C_GenerateRandom: rc = 0x%08lx, %lu bytes\n", rc, ulRandomLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_GetFunctionStatus(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession) +{ + UNUSED(sSession); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_PARALLEL)); + + return CKR_FUNCTION_NOT_PARALLEL; +} + + +CK_RV SC_CancelFunction(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession) +{ + UNUSED(sSession); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_PARALLEL)); + + return CKR_FUNCTION_NOT_PARALLEL; +} + + +void SC_SetFunctionList(void) +{ + function_list.ST_Initialize = ST_Initialize; + function_list.ST_GetTokenInfo = SC_GetTokenInfo; + function_list.ST_GetMechanismList = SC_GetMechanismList; + function_list.ST_GetMechanismInfo = SC_GetMechanismInfo; + function_list.ST_InitToken = SC_InitToken; + function_list.ST_InitPIN = SC_InitPIN; + function_list.ST_SetPIN = SC_SetPIN; + function_list.ST_OpenSession = SC_OpenSession; + function_list.ST_CloseSession = SC_CloseSession; + function_list.ST_GetSessionInfo = SC_GetSessionInfo; + function_list.ST_GetOperationState = SC_GetOperationState; + function_list.ST_SetOperationState = SC_SetOperationState; + function_list.ST_Login = SC_Login; + function_list.ST_Logout = SC_Logout; + function_list.ST_CreateObject = SC_CreateObject; + function_list.ST_CopyObject = SC_CopyObject; + function_list.ST_DestroyObject = SC_DestroyObject; + function_list.ST_GetObjectSize = SC_GetObjectSize; + function_list.ST_GetAttributeValue = SC_GetAttributeValue; + function_list.ST_SetAttributeValue = SC_SetAttributeValue; + function_list.ST_FindObjectsInit = SC_FindObjectsInit; + function_list.ST_FindObjects = SC_FindObjects; + function_list.ST_FindObjectsFinal = SC_FindObjectsFinal; + function_list.ST_EncryptInit = SC_EncryptInit; + function_list.ST_Encrypt = SC_Encrypt; + function_list.ST_EncryptUpdate = SC_EncryptUpdate; + function_list.ST_EncryptFinal = SC_EncryptFinal; + function_list.ST_DecryptInit = SC_DecryptInit; + function_list.ST_Decrypt = SC_Decrypt; + function_list.ST_DecryptUpdate = SC_DecryptUpdate; + function_list.ST_DecryptFinal = SC_DecryptFinal; + function_list.ST_DigestInit = SC_DigestInit; + function_list.ST_Digest = SC_Digest; + function_list.ST_DigestUpdate = SC_DigestUpdate; + function_list.ST_DigestKey = SC_DigestKey; + function_list.ST_DigestFinal = SC_DigestFinal; + function_list.ST_SignInit = SC_SignInit; + function_list.ST_Sign = SC_Sign; + function_list.ST_SignUpdate = SC_SignUpdate; + function_list.ST_SignFinal = SC_SignFinal; + function_list.ST_SignRecoverInit = SC_SignRecoverInit; + function_list.ST_SignRecover = SC_SignRecover; + function_list.ST_VerifyInit = SC_VerifyInit; + function_list.ST_Verify = SC_Verify; + function_list.ST_VerifyUpdate = SC_VerifyUpdate; + function_list.ST_VerifyFinal = SC_VerifyFinal; + function_list.ST_VerifyRecoverInit = SC_VerifyRecoverInit; + function_list.ST_VerifyRecover = SC_VerifyRecover; + function_list.ST_DigestEncryptUpdate = NULL; // SC_DigestEncryptUpdate; + function_list.ST_DecryptDigestUpdate = NULL; // SC_DecryptDigestUpdate; + function_list.ST_SignEncryptUpdate = NULL; //SC_SignEncryptUpdate; + function_list.ST_DecryptVerifyUpdate = NULL; // SC_DecryptVerifyUpdate; + function_list.ST_GenerateKey = SC_GenerateKey; + function_list.ST_GenerateKeyPair = SC_GenerateKeyPair; + function_list.ST_WrapKey = SC_WrapKey; + function_list.ST_UnwrapKey = SC_UnwrapKey; + function_list.ST_DeriveKey = SC_DeriveKey; + function_list.ST_SeedRandom = SC_SeedRandom; + function_list.ST_GenerateRandom = SC_GenerateRandom; + function_list.ST_GetFunctionStatus = NULL; // SC_GetFunctionStatus; + function_list.ST_CancelFunction = NULL; // SC_CancelFunction; +} diff --git a/usr/lib/ep11_stdll/tok_struct.h b/usr/lib/ep11_stdll/tok_struct.h new file mode 100644 index 0000000..b900897 --- /dev/null +++ b/usr/lib/ep11_stdll/tok_struct.h @@ -0,0 +1,137 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2002-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 + */ + +/*************************************************************************** + Change Log + ========== + 4/25/03 Kapil Sood (kapil@corrent.com) + Added DH key pair generation and DH shared key derivation + functions. + + + +****************************************************************************/ + +// SAB FIXME need to figure out a better way... +// // to get the variant dependency out +#ifndef __TOK_STRUCT_H +#define __TOK_STRUCT_H +#include + +#include "tok_spec_struct.h" + +#ifndef SW_CONFIG_PATH + +#ifndef CONFIG_PATH +#warning CONFIG_PATH not set, using default (/usr/local/var/lib/opencryptoki) +#define CONFIG_PATH "/usr/local/var/lib/opencryptoki" +#endif // #ifndef CONFIG_PATH + +#define SW_CONFIG_PATH CONFIG_PATH "/ep11tok" +#endif // #ifndef SW_CONFIG_PATH + +token_spec_t token_specific = { + SW_CONFIG_PATH, + "ep11tok", + 24, // keysize + // Token data info: + { + FALSE, // Don't use per guest data store + TRUE, // Use master key + CKM_DES3_CBC, // Data store encryption + (CK_BYTE *)"12345678", // Default initialization vector for pins + (CK_BYTE *)"10293847", // Default initialization vector for objects + }, + NULL, // t_creatlock + NULL, // t_attach_shm + NULL, // init + NULL, // init_token_data + NULL, // load_token_data + NULL, // save_token_data + &token_specific_rng, + NULL, // final + NULL, // init_token + NULL, // token_specific_login, + NULL, // token_specific_logout, + NULL, // init_pin, + NULL, // set_pin + // DES + NULL, // des_key_gen, + NULL, // des_ecb, + NULL, // des_cbc, + // Triple DES + NULL, // tdes_ecb, + NULL, // tdes_cbc, + NULL, // des3_ofb + NULL, // des3_cfb + NULL, // des3_mac + NULL, // des3_cmac + // RSA + NULL, // rsa_decrypt + NULL, // rsa_encrypt + &token_specific_rsa_sign, + &token_specific_rsa_verify, + NULL, // rsa_verify_recover + NULL, // rsa_x509_decrypt + NULL, // rsa_x509_encrypt + NULL, // rsa_x509_sign + NULL, // rsa_x509_verify + NULL, // rsa_x509_verify_recover + NULL, // rsa_oaep_decrypt + NULL, // rsa_oaep_encrypt + &token_specific_rsa_pss_sign, + &token_specific_rsa_pss_verify, + NULL, // rsa_generate_keypair + // Elliptic Curve + &token_specific_ec_sign, + &token_specific_ec_verify, + NULL, // ec_generate_keypair + NULL, // ecdh_derive + // DH + NULL, // dh_pkcs_derive, + NULL, // dh_pkcs_key_pair_gen + // SHA + &token_specific_sha_init, + &token_specific_sha, + &token_specific_sha_update, + &token_specific_sha_final, + // HMAC + NULL, // hmac_sign_init + NULL, // hmac_sign + NULL, // hmac_sign_update + NULL, // hmac_sign_final + NULL, // hmac_verify_init + NULL, // hmac_verify + NULL, // hmac_verify_update + NULL, // hmac_verify_final + NULL, // generic_secret_key_gen + // AES + NULL, // aes_key_gen, + NULL, // aes_ecb, + NULL, // aes_cbc, + NULL, // aes_ctr + NULL, // aes_gcm_init + NULL, // aes_gcm + NULL, // aes_gcm_update + NULL, // aes_gcm_final + NULL, // aes_ofb + NULL, // aes_cfb + NULL, // aes_mac + NULL, // aes_cmac + // DSA + NULL, // dsa_generate_keypair, + NULL, // dsa_sign + NULL, // dsa_verify + NULL, // get_mechanism_list + NULL, // get mechanism_info + &token_specific_object_add +}; + +#endif diff --git a/usr/lib/ica_s390_stdll/ica_s390_stdll.mk b/usr/lib/ica_s390_stdll/ica_s390_stdll.mk new file mode 100644 index 0000000..0d972c5 --- /dev/null +++ b/usr/lib/ica_s390_stdll/ica_s390_stdll.mk @@ -0,0 +1,44 @@ +nobase_lib_LTLIBRARIES += opencryptoki/stdll/libpkcs11_ica.la + +noinst_HEADERS += usr/lib/ica_s390_stdll/tok_struct.h + +opencryptoki_stdll_libpkcs11_ica_la_CFLAGS = \ + -DDEV -D_THREAD_SAFE -fPIC -DSHALLOW=0 -DSWTOK=0 -DLITE=1 \ + -DNODH -DNOCDMF -DNOMD2 -DNODSA -DSTDLL_NAME=\"icatok\" \ + -DTOK_NEW_DATA_STORE=0x0003000c \ + $(ICA_INC_DIRS) -I${srcdir}/usr/lib/ica_s390_stdll \ + -I${srcdir}/usr/lib/common -I${srcdir}/usr/include + +opencryptoki_stdll_libpkcs11_ica_la_LDFLAGS = \ + $(LCRYPTO) $(ICA_LIB_DIRS) -nostartfiles -shared \ + -Wl,-z,defs,-Bsymbolic -Wl,-soname,$@ -lc -lpthread -lica -ldl \ + -lcrypto -lrt \ + -Wl,--version-script=${srcdir}/opencryptoki_tok.map + +opencryptoki_stdll_libpkcs11_ica_la_SOURCES = \ + usr/lib/common/asn1.c usr/lib/common/cert.c \ + usr/lib/common/hwf_obj.c usr/lib/common/dp_obj.c \ + usr/lib/common/data_obj.c usr/lib/common/decr_mgr.c \ + usr/lib/common/dig_mgr.c usr/lib/common/encr_mgr.c \ + usr/lib/common/globals.c usr/lib/common/sw_crypt.c \ + usr/lib/common/loadsave.c usr/lib/common/key.c \ + usr/lib/common/key_mgr.c usr/lib/common/mech_des.c \ + usr/lib/common/mech_des3.c usr/lib/common/mech_aes.c \ + usr/lib/common/mech_md5.c usr/lib/common/mech_md2.c \ + usr/lib/common/mech_rng.c usr/lib/common/mech_rsa.c \ + usr/lib/common/mech_sha.c usr/lib/common/mech_ssl3.c \ + usr/lib/common/mech_ec.c usr/lib/common/new_host.c \ + usr/lib/common/obj_mgr.c usr/lib/common/object.c \ + usr/lib/common/sign_mgr.c usr/lib/common/template.c \ + usr/lib/common/p11util.c usr/lib/common/utility.c \ + usr/lib/common/verify_mgr.c usr/lib/common/trace.c \ + usr/lib/common/mech_list.c usr/lib/common/shared_memory.c \ + usr/lib/ica_s390_stdll/ica_specific.c +if ENABLE_LOCKS +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 +endif diff --git a/usr/lib/ica_s390_stdll/ica_specific.c b/usr/lib/ica_s390_stdll/ica_specific.c new file mode 100644 index 0000000..8f58b9f --- /dev/null +++ b/usr/lib/ica_s390_stdll/ica_specific.c @@ -0,0 +1,4392 @@ +/* + * 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 + */ + +/* Modified for S390 by Robert Burroughs */ + +#include +#include // for memcmp() et al +#include +#include +#include // for dlopen() +#include + +#ifndef NOAES +#include +#endif + +#include "pkcs11types.h" +#include "p11util.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "trace.h" + +#include + +#ifndef EC_DH +#define NO_EC +#warning "Your Libica does not provide ECC support, use Libica 3.3.0 or newer for ECC." +#endif + +#include "tok_specific.h" +#include "tok_struct.h" + +#ifndef NO_EC +#include "ec_defs.h" +#include "openssl/obj_mac.h" +#include +#endif +#include + +#define ICA_MAX_MECH_LIST_ENTRIES 84 + +typedef struct { + ica_adapter_handle_t adapter_handle; + int ica_ec_support_available; + MECH_LIST_ELEMENT mech_list[ICA_MAX_MECH_LIST_ENTRIES]; + CK_ULONG mech_list_len; +} ica_private_data_t; + +// Linux really does not need these so we just dummy them up +// so the common code across platforms is usable... +#define KEYTYPE_MODEXPO 1 +#define KEYTYPE_PKCSCRT 2 + +#define MAX_GENERIC_KEY_SIZE 256 + +const char manuf[] = "IBM"; +const char model[] = "ICA"; +const char descr[] = "IBM ICA token"; +const char label[] = "icatok"; + +static pthread_mutex_t rngmtx = PTHREAD_MUTEX_INITIALIZER; + +#define LIBICA_SHARED_LIB "libica.so.3" +#define BIND(dso, sym) do { \ + if (p_##sym == NULL) \ + *(void **)(&p_##sym) = dlsym(dso, #sym); \ + } while (0) + +#ifndef NO_EC +typedef ICA_EC_KEY *(*ica_ec_key_new_t) (unsigned int nid, + unsigned int *privlen); +typedef int (*ica_ec_key_init_t) (const unsigned char *X, + const unsigned char *Y, + const unsigned char *D, ICA_EC_KEY *key); +typedef int (*ica_ec_key_generate_t) (ica_adapter_handle_t adapter_handle, + ICA_EC_KEY *key); +typedef int (*ica_ecdh_derive_secret_t) (ica_adapter_handle_t adapter_handle, + const ICA_EC_KEY *privkey_A, + const ICA_EC_KEY *pubkey_B, + unsigned char *z, + unsigned int z_length); +typedef int (*ica_ecdsa_sign_t) (ica_adapter_handle_t adapter_handle, + const ICA_EC_KEY *privkey, + const unsigned char *hash, + unsigned int hash_length, + unsigned char *signature, + unsigned int signature_length); +typedef int (*ica_ecdsa_verify_t) (ica_adapter_handle_t adapter_handle, + const ICA_EC_KEY *pubkey, + const unsigned char *hash, + unsigned int hash_length, + const unsigned char *signature, + unsigned int signature_length); +typedef int (*ica_ec_key_get_public_key_t) (ICA_EC_KEY *key, + unsigned char *q, + unsigned int *q_len); +typedef int (*ica_ec_key_get_private_key_t) (ICA_EC_KEY *key, + unsigned char *d, + unsigned int *d_len); +typedef void (*ica_ec_key_free_t) (ICA_EC_KEY *key); + +static ica_ec_key_new_t p_ica_ec_key_new; +static ica_ec_key_init_t p_ica_ec_key_init; +static ica_ec_key_generate_t p_ica_ec_key_generate; +static ica_ecdh_derive_secret_t p_ica_ecdh_derive_secret; +static ica_ecdsa_sign_t p_ica_ecdsa_sign; +static ica_ecdsa_verify_t p_ica_ecdsa_verify; +static ica_ec_key_get_public_key_t p_ica_ec_key_get_public_key; +static ica_ec_key_get_private_key_t p_ica_ec_key_get_private_key; +static ica_ec_key_free_t p_ica_ec_key_free; + +static CK_RV mech_list_ica_initialize(STDLL_TokData_t *tokdata); + +#define ICATOK_EC_MAX_D_LEN 66 /* secp521 */ +#define ICATOK_EC_MAX_Q_LEN (2*ICATOK_EC_MAX_D_LEN) +#define ICATOK_EC_MAX_SIG_LEN ICATOK_EC_MAX_Q_LEN +#define ICATOK_EC_MAX_Z_LEN ICATOK_EC_MAX_D_LEN + +static CK_RV ecc_support_in_libica_available(void) +{ + if (p_ica_ec_key_new != NULL && + p_ica_ec_key_init != NULL && + p_ica_ec_key_generate != NULL && + p_ica_ecdh_derive_secret != NULL && + p_ica_ecdsa_sign != NULL && + p_ica_ecdsa_verify != NULL && + p_ica_ec_key_get_public_key != NULL && + p_ica_ec_key_get_private_key != NULL && + p_ica_ec_key_free != NULL) + return 1; + + return 0; +} +#endif + +#ifdef SHA512_224 +typedef unsigned int (*ica_sha512_224_t)(unsigned int message_part, + unsigned int input_length, + unsigned char *input_data, + sha512_context_t *sha_context, + unsigned char *output_data); + +static ica_sha512_224_t p_ica_sha512_224; +#endif + +#ifdef SHA512_256 +typedef unsigned int (*ica_sha512_256_t)(unsigned int message_part, + unsigned int input_length, + unsigned char *input_data, + sha512_context_t *sha_context, + unsigned char *output_data); + +static ica_sha512_256_t p_ica_sha512_256; +#endif + +static CK_RV load_libica(void) +{ + void *ibmca_dso = NULL; + + /* Load libica */ + ibmca_dso = dlopen(LIBICA_SHARED_LIB, RTLD_NOW); + if (ibmca_dso == NULL) { + TRACE_ERROR("%s: dlopen(%s) failed\n", __func__, LIBICA_SHARED_LIB); + return CKR_FUNCTION_FAILED; + } + +#ifndef NO_EC + /* Try to resolve all needed functions for ecc support */ + BIND(ibmca_dso, ica_ec_key_new); + BIND(ibmca_dso, ica_ec_key_init); + BIND(ibmca_dso, ica_ec_key_generate); + BIND(ibmca_dso, ica_ecdh_derive_secret); + BIND(ibmca_dso, ica_ecdsa_sign); + BIND(ibmca_dso, ica_ecdsa_verify); + BIND(ibmca_dso, ica_ec_key_get_public_key); + BIND(ibmca_dso, ica_ec_key_get_private_key); + BIND(ibmca_dso, ica_ec_key_free); +#endif + +#ifdef SHA512_224 + BIND(ibmca_dso, ica_sha512_224); +#endif +#ifdef SHA512_256 + BIND(ibmca_dso, ica_sha512_256); +#endif + + return CKR_OK; +} + +CK_RV token_specific_rng(STDLL_TokData_t *tokdata, CK_BYTE *output, + CK_ULONG bytes) +{ + unsigned int rc; + + UNUSED(tokdata); + + pthread_mutex_lock(&rngmtx); + + rc = ica_random_number_generate((unsigned int) bytes, output); + + if (rc != 0) { + pthread_mutex_unlock(&rngmtx); + return CKR_GENERAL_ERROR; + /* report error */ + } + + pthread_mutex_unlock(&rngmtx); + + return CKR_OK; +} + +CK_RV token_specific_init(STDLL_TokData_t *tokdata, CK_SLOT_ID SlotNumber, + char *conf_name) +{ + ica_private_data_t *ica_data; + CK_ULONG rc = CKR_OK; + + UNUSED(conf_name); + + ica_data = (ica_private_data_t *)calloc(1, sizeof(ica_private_data_t)); + tokdata->private_data = ica_data; + + rc = load_libica(); + if (rc != CKR_OK) + goto out; + +#ifndef NO_EC + ica_data->ica_ec_support_available = ecc_support_in_libica_available(); +#endif + + rc = mech_list_ica_initialize(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("mech_list_ica_initialize failed\n"); + goto out; + } + + tokdata->mech_list = ica_data->mech_list; + tokdata->mech_list_len = ica_data->mech_list_len; + + TRACE_INFO("ica %s slot=%lu running\n", __func__, SlotNumber); + + rc = ica_open_adapter(&ica_data->adapter_handle); + if (rc != 0) { + TRACE_ERROR("ica_open_adapter failed\n"); + goto out; + } + +out: + if (rc != CKR_OK) { + free(ica_data); + tokdata->private_data = NULL; + } + return rc; +} + +CK_RV token_specific_final(STDLL_TokData_t *tokdata, + CK_BBOOL in_fork_initializer) +{ + ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; + + UNUSED(in_fork_initializer); + + TRACE_INFO("ica %s running\n", __func__); + ica_close_adapter(ica_data->adapter_handle); + + free(ica_data); + tokdata->private_data = NULL; + + return CKR_OK; +} + +// count_ones_in_byte: for use in adjust_des_key_parity_bits below +static CK_BYTE count_ones_in_byte(CK_BYTE byte) +{ + CK_BYTE and_mask, // bit selector + number_of_ones = 0; + + for (and_mask = 1; and_mask != 0; and_mask <<= 1) // for each bit, + if (byte & and_mask) // if it's a one, + ++number_of_ones; // count it + + return number_of_ones; +} + +#define EVEN_PARITY TRUE +#define ODD_PARITY FALSE + // adjust_des_key_parity_bits: to conform to NIST spec for DES and 3DES keys +static void adjust_des_key_parity_bits(CK_BYTE *des_key, CK_ULONG key_size, + CK_BBOOL parity) +{ + CK_ULONG i; + + for (i = 0; i < key_size; i++) // look at each byte in the key + { + if ((count_ones_in_byte(des_key[i]) % 2) ^ (parity == ODD_PARITY)) { + // if parity for this byte isn't what it should be, + // flip the parity (least significant) bit + des_key[i] ^= 1; + } + } +} + +CK_RV token_specific_des_key_gen(STDLL_TokData_t *tokdata, CK_BYTE *des_key, + CK_ULONG len, CK_ULONG keysize) +{ + UNUSED(keysize); + + // Nothing different to do for DES or TDES here as this is just + // random data... Validation handles the rest + // Only check for weak keys when DES. + if (len == (3 * DES_KEY_SIZE)) { + rng_generate(tokdata, des_key, len); + adjust_des_key_parity_bits(des_key, len, ODD_PARITY); + } else { + do { + rng_generate(tokdata, des_key, len); + adjust_des_key_parity_bits(des_key, len, ODD_PARITY); + } while (des_check_weak_key(des_key) == TRUE); + } + + + // we really need to validate the key for parity etc... + // we should do that here... The caller validates the single des keys + // against the known and suspected poor keys..<< + return CKR_OK; +} + +CK_RV token_specific_des_ecb(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, + OBJECT *key, CK_BYTE encrypt) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + + UNUSED(tokdata); + + /* + * checks for input and output data length and block sizes + * are already being carried out in mech_des.c + * so we skip those + */ + + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + + if (encrypt) { + rc = ica_des_ecb(in_data, out_data, in_data_len, attr->pValue, + ICA_ENCRYPT); + } else { + rc = ica_des_ecb(in_data, out_data, in_data_len, attr->pValue, + ICA_DECRYPT); + } + + if (rc != 0) { + rc = CKR_FUNCTION_FAILED; + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + } else { + *out_data_len = in_data_len; + rc = CKR_OK; + } + + return rc; +} + +CK_RV token_specific_des_cbc(STDLL_TokData_t *tokdata, + 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) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + + UNUSED(tokdata); + + /* + * checks for input and output data length and block sizes + * are already being carried out in mech_des.c + * so we skip those + */ + + // get the key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + + if (encrypt) { + rc = ica_des_cbc(in_data, out_data, in_data_len, attr->pValue, init_v, + ICA_ENCRYPT); + } else { + rc = ica_des_cbc(in_data, out_data, in_data_len, attr->pValue, init_v, + ICA_DECRYPT); + } + if (rc != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + } else { + *out_data_len = in_data_len; + rc = CKR_OK; + } + + return rc; +} + +CK_RV token_specific_tdes_ecb(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, + OBJECT *key, CK_BYTE encrypt) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + CK_KEY_TYPE keytype; + CK_BYTE key_value[3 * DES_KEY_SIZE]; + + UNUSED(tokdata); + + /* + * checks for input and output data length and block sizes + * are already being carried out in mech_des3.c + * so we skip those + */ + + // get the key type + rc = template_attribute_find(key->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + keytype = *(CK_KEY_TYPE *) attr->pValue; + + // get the key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + if (keytype == CKK_DES2) { + memcpy(key_value, attr->pValue, 2 * DES_KEY_SIZE); + memcpy(key_value + (2 * DES_KEY_SIZE), attr->pValue, DES_KEY_SIZE); + } else { + memcpy(key_value, attr->pValue, 3 * DES_KEY_SIZE); + } + + if (encrypt) { + rc = ica_3des_ecb(in_data, out_data, in_data_len, key_value, + ICA_ENCRYPT); + } else { + rc = ica_3des_ecb(in_data, out_data, in_data_len, key_value, + ICA_DECRYPT); + } + + if (rc != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + } else { + *out_data_len = in_data_len; + rc = CKR_OK; + } + + return rc; +} + +CK_RV token_specific_tdes_cbc(STDLL_TokData_t *tokdata, + 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) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + CK_KEY_TYPE keytype; + CK_BYTE key_value[3 * DES_KEY_SIZE]; + + UNUSED(tokdata); + + /* + * checks for input and output data length and block sizes + * are already being carried out in mech_des3.c + * so we skip those + */ + + // get the key type + rc = template_attribute_find(key->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + keytype = *(CK_KEY_TYPE *) attr->pValue; + // get the key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + if (keytype == CKK_DES2) { + memcpy(key_value, attr->pValue, 2 * DES_KEY_SIZE); + memcpy(key_value + (2 * DES_KEY_SIZE), attr->pValue, DES_KEY_SIZE); + } else { + memcpy(key_value, attr->pValue, 3 * DES_KEY_SIZE); + } + + if (encrypt) { + rc = ica_3des_cbc(in_data, out_data, in_data_len, key_value, init_v, + ICA_ENCRYPT); + } else { + rc = ica_3des_cbc(in_data, out_data, in_data_len, key_value, init_v, + ICA_DECRYPT); + } + if (rc != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + } else { + *out_data_len = in_data_len; + rc = CKR_OK; + } + + return rc; +} + +/* + * + * 0 Use the decrypt function. + * 1 Use the encrypt function. + */ +CK_RV token_specific_tdes_ofb(STDLL_TokData_t *tokdata, CK_BYTE *in_data, + CK_BYTE *out_data, CK_ULONG data_len, + OBJECT *key, CK_BYTE *iv, uint_32 direction) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + + UNUSED(tokdata); + + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + + rc = ica_3des_ofb(in_data, out_data, (unsigned int) data_len, + (unsigned char *) attr->pValue, (unsigned char *) iv, + direction); + + if (rc != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + } + + return rc; +} + +/* + * 0 Use the decrypt function. + * 1 Use the encrypt function. + */ +CK_RV token_specific_tdes_cfb(STDLL_TokData_t *tokdata, CK_BYTE *in_data, + CK_BYTE *out_data, CK_ULONG data_len, + OBJECT *key, CK_BYTE *iv, uint_32 cfb_len, + uint_32 direction) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + + UNUSED(tokdata); + + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + + rc = ica_3des_cfb(in_data, out_data, (unsigned int) data_len, + (unsigned char *) attr->pValue, (unsigned char *) iv, + cfb_len, direction); + + if (rc != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + } + + return rc; +} + +CK_RV token_specific_tdes_mac(STDLL_TokData_t *tokdata, CK_BYTE *message, + CK_ULONG message_len, OBJECT *key, CK_BYTE *mac) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + CK_KEY_TYPE keytype; + CK_BYTE key_value[3 * DES_KEY_SIZE]; + + UNUSED(tokdata); + + // get the key type + rc = template_attribute_find(key->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + keytype = *(CK_KEY_TYPE *) attr->pValue; + + // get the key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + if (keytype == CKK_DES2) { + memcpy(key_value, attr->pValue, 2 * DES_KEY_SIZE); + memcpy(key_value + (2 * DES_KEY_SIZE), attr->pValue, DES_KEY_SIZE); + } else { + memcpy(key_value, attr->pValue, 3 * DES_KEY_SIZE); + } + + rc = ica_3des_cmac_intermediate(message, (unsigned long) message_len, + (unsigned char *) key_value, mac); + + if (rc != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + } + + return rc; +} + +CK_RV token_specific_tdes_cmac(STDLL_TokData_t *tokdata, CK_BYTE *message, + CK_ULONG message_len, OBJECT *key, CK_BYTE *mac, + CK_BBOOL first, CK_BBOOL last, CK_VOID_PTR *ctx) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + CK_KEY_TYPE keytype; + CK_BYTE key_value[3 * DES_KEY_SIZE]; + + UNUSED(tokdata); + UNUSED(ctx); + + // get the key type + rc = template_attribute_find(key->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + keytype = *(CK_KEY_TYPE *) attr->pValue; + + // get the key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + if (keytype == CKK_DES2) { + memcpy(key_value, attr->pValue, 2 * DES_KEY_SIZE); + memcpy(key_value + (2 * DES_KEY_SIZE), attr->pValue, DES_KEY_SIZE); + } else { + memcpy(key_value, attr->pValue, 3 * DES_KEY_SIZE); + } + + if (first && last) { + rc = ica_3des_cmac(message, (unsigned long) message_len, + mac, DES_BLOCK_SIZE, + key_value, ICA_ENCRYPT); + } else if (!last) { + rc = ica_3des_cmac_intermediate(message, (unsigned long) message_len, + key_value, mac); + } else { + rc = ica_3des_cmac_last(message, (unsigned long) message_len, + mac, DES_BLOCK_SIZE, + key_value, mac, ICA_ENCRYPT); + } + + if (rc != 0) { + TRACE_ERROR("%s: rc: %lu\n", ock_err(ERR_FUNCTION_FAILED), rc); + rc = CKR_FUNCTION_FAILED; + } + + return rc; +} + +/* + * Init SHA data structures + */ +CK_RV token_specific_sha_init(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, + CK_MECHANISM *mech) +{ + unsigned int ctxsize, devctxsize; + struct oc_sha_ctx *sc; + + UNUSED(tokdata); + + ctxsize = (sizeof(struct oc_sha_ctx) + 0x000F) & ~0x000F; + switch (mech->mechanism) { + case CKM_SHA_1: + devctxsize = sizeof(sha_context_t); + break; + case CKM_SHA224: + case CKM_SHA256: + devctxsize = sizeof(sha256_context_t); + break; + case CKM_SHA384: + case CKM_SHA512: +#ifdef SHA512_224 + case CKM_SHA512_224: +#endif +#ifdef SHA512_256 + case CKM_SHA512_256: +#endif + devctxsize = sizeof(sha512_context_t); + break; + default: + return CKR_MECHANISM_INVALID; + } + + /* (re)alloc ctx in one memory area */ + if (ctx->context) + free(ctx->context); + ctx->context_len = 0; + ctx->context = malloc(ctxsize + devctxsize); + if (ctx->context == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + memset(ctx->context, 0, ctxsize + devctxsize); + ctx->context_len = ctxsize + devctxsize; + sc = (struct oc_sha_ctx *) ctx->context; + sc->dev_ctx_offs = ctxsize; + + sc->message_part = SHA_MSG_PART_ONLY; + switch (mech->mechanism) { + case CKM_SHA_1: + sc->hash_len = SHA1_HASH_SIZE; + sc->hash_blksize = SHA1_BLOCK_SIZE; + break; + case CKM_SHA224: + sc->hash_len = SHA224_HASH_SIZE; + sc->hash_blksize = SHA224_BLOCK_SIZE; + break; + case CKM_SHA256: + sc->hash_len = SHA256_HASH_SIZE; + sc->hash_blksize = SHA256_BLOCK_SIZE; + break; + case CKM_SHA384: + sc->hash_len = SHA384_HASH_SIZE; + sc->hash_blksize = SHA384_BLOCK_SIZE; + break; + case CKM_SHA512: + sc->hash_len = SHA512_HASH_SIZE; + sc->hash_blksize = SHA512_BLOCK_SIZE; + break; +#ifdef SHA512_224 + case CKM_SHA512_224: + sc->hash_len = SHA224_HASH_SIZE; + sc->hash_blksize = SHA512_BLOCK_SIZE; + break; +#endif +#ifdef SHA512_256 + case CKM_SHA512_256: + sc->hash_len = SHA256_HASH_SIZE; + sc->hash_blksize = SHA512_BLOCK_SIZE; + break; +#endif + } + + return CKR_OK; +} + +CK_RV token_specific_sha(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + int rc; + CK_RV rv = CKR_OK; + struct oc_sha_ctx *sc; + void *dev_ctx; + + UNUSED(tokdata); + + if (!ctx || !ctx->context) + return CKR_OPERATION_NOT_INITIALIZED; + + if (!in_data || !out_data) + return CKR_ARGUMENTS_BAD; + + sc = (struct oc_sha_ctx *) ctx->context; + dev_ctx = ((CK_BYTE *) sc) + sc->dev_ctx_offs; + + if (*out_data_len < sc->hash_len) + return CKR_BUFFER_TOO_SMALL; + + sc->message_part = SHA_MSG_PART_ONLY; + + switch (ctx->mech.mechanism) { + case CKM_SHA_1: + { + sha_context_t *ica_sha_ctx = (sha_context_t *) dev_ctx; + rc = ica_sha1(sc->message_part, in_data_len, + in_data, ica_sha_ctx, sc->hash); + break; + } + case CKM_SHA224: + { + sha256_context_t *ica_sha2_ctx = (sha256_context_t *) dev_ctx; + rc = ica_sha224(sc->message_part, in_data_len, + in_data, ica_sha2_ctx, sc->hash); + break; + } + case CKM_SHA256: + { + sha256_context_t *ica_sha2_ctx = (sha256_context_t *) dev_ctx; + rc = ica_sha256(sc->message_part, in_data_len, + in_data, ica_sha2_ctx, sc->hash); + break; + } + case CKM_SHA384: + { + sha512_context_t *ica_sha3_ctx = (sha512_context_t *) dev_ctx; + rc = ica_sha384(sc->message_part, in_data_len, + in_data, ica_sha3_ctx, sc->hash); + break; + } + case CKM_SHA512: + { + sha512_context_t *ica_sha5_ctx = (sha512_context_t *) dev_ctx; + rc = ica_sha512(sc->message_part, in_data_len, + in_data, ica_sha5_ctx, sc->hash); + break; + } +#ifdef SHA512_224 + case CKM_SHA512_224: + { + sha512_context_t *ica_sha5_ctx = (sha512_context_t *) dev_ctx; + + if (p_ica_sha512_224 == NULL) + return CKR_MECHANISM_INVALID; + + rc = p_ica_sha512_224(sc->message_part, in_data_len, + in_data, ica_sha5_ctx, sc->hash); + break; + } +#endif +#ifdef SHA512_256 + case CKM_SHA512_256: + { + sha512_context_t *ica_sha5_ctx = (sha512_context_t *) dev_ctx; + + if (p_ica_sha512_256 == NULL) + return CKR_MECHANISM_INVALID; + + rc = p_ica_sha512_256(sc->message_part, in_data_len, + in_data, ica_sha5_ctx, sc->hash); + break; + } +#endif + default: + return CKR_MECHANISM_INVALID; + } + + if (rc == CKR_OK) { + memcpy(out_data, sc->hash, sc->hash_len); + *out_data_len = sc->hash_len; + } else { + rv = CKR_FUNCTION_FAILED; + } + + return rv; +} + +static CK_RV ica_sha_call(DIGEST_CONTEXT *ctx, CK_BYTE *data, + CK_ULONG data_len) +{ + struct oc_sha_ctx *sc = (struct oc_sha_ctx *) ctx->context; + void *dev_ctx = ((CK_BYTE *) sc) + sc->dev_ctx_offs; + CK_RV ret; + + switch (ctx->mech.mechanism) { + case CKM_SHA_1: + { + sha_context_t *ica_sha_ctx = (sha_context_t *) dev_ctx; + if (ica_sha_ctx->runningLength == 0) + sc->message_part = SHA_MSG_PART_FIRST; + else + sc->message_part = SHA_MSG_PART_MIDDLE; + ret = ica_sha1(sc->message_part, data_len, data, + ica_sha_ctx, sc->hash); + break; + } + case CKM_SHA224: + { + sha256_context_t *ica_sha_ctx = (sha256_context_t *) dev_ctx; + if (ica_sha_ctx->runningLength == 0) + sc->message_part = SHA_MSG_PART_FIRST; + else + sc->message_part = SHA_MSG_PART_MIDDLE; + ret = ica_sha224(sc->message_part, data_len, data, + ica_sha_ctx, sc->hash); + break; + } + case CKM_SHA256: + { + sha256_context_t *ica_sha_ctx = (sha256_context_t *) dev_ctx; + if (ica_sha_ctx->runningLength == 0) + sc->message_part = SHA_MSG_PART_FIRST; + else + sc->message_part = SHA_MSG_PART_MIDDLE; + ret = ica_sha256(sc->message_part, data_len, data, + ica_sha_ctx, sc->hash); + break; + } + case CKM_SHA384: + { + sha512_context_t *ica_sha_ctx = (sha512_context_t *) dev_ctx; + if (ica_sha_ctx->runningLengthLow == 0 && + ica_sha_ctx->runningLengthHigh == 0) + sc->message_part = SHA_MSG_PART_FIRST; + else + sc->message_part = SHA_MSG_PART_MIDDLE; + ret = ica_sha384(sc->message_part, data_len, data, + ica_sha_ctx, sc->hash); + break; + } + case CKM_SHA512: + { + sha512_context_t *ica_sha_ctx = (sha512_context_t *) dev_ctx; + if (ica_sha_ctx->runningLengthLow == 0 && + ica_sha_ctx->runningLengthHigh == 0) + sc->message_part = SHA_MSG_PART_FIRST; + else + sc->message_part = SHA_MSG_PART_MIDDLE; + ret = ica_sha512(sc->message_part, data_len, data, + ica_sha_ctx, sc->hash); + break; + } +#ifdef SHA512_224 + case CKM_SHA512_224: + { + sha512_context_t *ica_sha_ctx = (sha512_context_t *) dev_ctx; + + if (p_ica_sha512_224 == NULL) + return CKR_MECHANISM_INVALID; + + if (ica_sha_ctx->runningLengthLow == 0 && + ica_sha_ctx->runningLengthHigh == 0) + sc->message_part = SHA_MSG_PART_FIRST; + else + sc->message_part = SHA_MSG_PART_MIDDLE; + ret = p_ica_sha512_224(sc->message_part, data_len, data, + ica_sha_ctx, sc->hash); + break; + } +#endif +#ifdef SHA512_256 + case CKM_SHA512_256: + { + sha512_context_t *ica_sha_ctx = (sha512_context_t *) dev_ctx; + + if (p_ica_sha512_256 == NULL) + return CKR_MECHANISM_INVALID; + + if (ica_sha_ctx->runningLengthLow == 0 && + ica_sha_ctx->runningLengthHigh == 0) + sc->message_part = SHA_MSG_PART_FIRST; + else + sc->message_part = SHA_MSG_PART_MIDDLE; + ret = p_ica_sha512_256(sc->message_part, data_len, data, + ica_sha_ctx, sc->hash); + break; + } +#endif + default: + return CKR_MECHANISM_INVALID; + } + + return (ret ? CKR_FUNCTION_FAILED : CKR_OK); +} + +CK_RV token_specific_sha_update(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + struct oc_sha_ctx *sc; + int fill, len, rest, ret; + + UNUSED(tokdata); + + if (!ctx || !ctx->context) + return CKR_OPERATION_NOT_INITIALIZED; + + if (!in_data_len) + return CKR_OK; + + if (!in_data) + return CKR_ARGUMENTS_BAD; + + sc = (struct oc_sha_ctx *) ctx->context; + + /* if less than blocksize, save to context buffer for next time */ + if (sc->tail_len + in_data_len < sc->hash_blksize) { + memcpy(sc->tail + sc->tail_len, in_data, in_data_len); + sc->tail_len += in_data_len; + return CKR_OK; + } + + /* we have at least one block */ + + /* if some leftovers from the last update are available + copy together one block into the tail buffer and hash it */ + if (sc->tail_len) { + fill = sc->hash_blksize - sc->tail_len; + memcpy(sc->tail + sc->tail_len, in_data, fill); + + /* hash blksize bytes from the tail buffer */ + ret = ica_sha_call(ctx, sc->tail, sc->hash_blksize); + if (ret != CKR_OK) + return ret; + + /* tail buffer is empty now */ + sc->tail_len = 0; + + /* adjust input data pointer and input data len */ + in_data += fill; + in_data_len -= fill; + + /* if there is no more data to process, we are done */ + if (!in_data_len) + return CKR_OK; + } + + /* The tail buffer is empty now, and in_data_len is > 0. + * Calculate amount of remaining bytes... + */ + rest = in_data_len % sc->hash_blksize; + + /* and amount of bytes fitting into hash blocks */ + len = in_data_len - rest; + + /* process the full hash blocks */ + if (len > 0) { + /* hash len bytes from input starting at the beginning */ + ret = ica_sha_call(ctx, in_data, len); + if (ret != CKR_OK) + return ret; + + /* adjust input data pointer */ + in_data += len; + } + + /* Store remaining bytes into the empty tail buffer */ + if (rest > 0) { + memcpy(sc->tail, in_data, rest); + sc->tail_len = rest; + } + + return CKR_OK; +} + +CK_RV token_specific_sha_final(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + int rc; + CK_RV rv = CKR_OK; + struct oc_sha_ctx *sc; + void *dev_ctx; + + UNUSED(tokdata); + + if (!ctx || !ctx->context) + return CKR_OPERATION_NOT_INITIALIZED; + + if (!out_data || !out_data_len) + return CKR_ARGUMENTS_BAD; + + sc = (struct oc_sha_ctx *) ctx->context; + dev_ctx = ((CK_BYTE *) sc) + sc->dev_ctx_offs; + sc->message_part = SHA_MSG_PART_FINAL; + + if (*out_data_len < sc->hash_len) + return CKR_BUFFER_TOO_SMALL; + + switch (ctx->mech.mechanism) { + case CKM_SHA_1: + { + sha_context_t *ica_sha1_ctx = (sha_context_t *) dev_ctx; + /* accommodate multi-part when input was so small + * that we never got to call into libica until final + */ + if (ica_sha1_ctx->runningLength == 0) + sc->message_part = SHA_MSG_PART_ONLY; + rc = ica_sha1(sc->message_part, sc->tail_len, + (unsigned char *) sc->tail, ica_sha1_ctx, sc->hash); + break; + } + case CKM_SHA224: + { + sha256_context_t *ica_sha2_ctx = (sha256_context_t *) dev_ctx; + /* accommodate multi-part when input was so small + * that we never got to call into libica until final + */ + if (ica_sha2_ctx->runningLength == 0) + sc->message_part = SHA_MSG_PART_ONLY; + rc = ica_sha224(sc->message_part, sc->tail_len, + sc->tail, ica_sha2_ctx, sc->hash); + break; + } + case CKM_SHA256: + { + sha256_context_t *ica_sha2_ctx = (sha256_context_t *) dev_ctx; + /* accommodate multi-part when input was so small + * that we never got to call into libica until final + */ + if (ica_sha2_ctx->runningLength == 0) + sc->message_part = SHA_MSG_PART_ONLY; + rc = ica_sha256(sc->message_part, sc->tail_len, + sc->tail, ica_sha2_ctx, sc->hash); + break; + } + case CKM_SHA384: + { + sha512_context_t *ica_sha3_ctx = (sha512_context_t *) dev_ctx; + /* accommodate multi-part when input was so small + * that we never got to call into libica until final + */ + if (ica_sha3_ctx->runningLengthLow == 0 + && ica_sha3_ctx->runningLengthHigh == 0) + sc->message_part = SHA_MSG_PART_ONLY; + rc = ica_sha384(sc->message_part, sc->tail_len, + sc->tail, ica_sha3_ctx, sc->hash); + break; + } + case CKM_SHA512: + { + sha512_context_t *ica_sha5_ctx = (sha512_context_t *) dev_ctx; + /* accommodate multi-part when input was so small + * that we never got to call into libica until final + */ + if (ica_sha5_ctx->runningLengthLow == 0 + && ica_sha5_ctx->runningLengthHigh == 0) + sc->message_part = SHA_MSG_PART_ONLY; + rc = ica_sha512(sc->message_part, sc->tail_len, + sc->tail, ica_sha5_ctx, sc->hash); + break; + } +#ifdef SHA512_224 + case CKM_SHA512_224: + { + sha512_context_t *ica_sha5_ctx = (sha512_context_t *) dev_ctx; + + if (p_ica_sha512_224 == NULL) + return CKR_MECHANISM_INVALID; + + /* accommodate multi-part when input was so small + * that we never got to call into libica until final + */ + if (ica_sha5_ctx->runningLengthLow == 0 + && ica_sha5_ctx->runningLengthHigh == 0) + sc->message_part = SHA_MSG_PART_ONLY; + rc = p_ica_sha512_224(sc->message_part, sc->tail_len, + sc->tail, ica_sha5_ctx, sc->hash); + break; + } +#endif +#ifdef SHA512_256 + case CKM_SHA512_256: + { + sha512_context_t *ica_sha5_ctx = (sha512_context_t *) dev_ctx; + + if (p_ica_sha512_256 == NULL) + return CKR_MECHANISM_INVALID; + + /* accommodate multi-part when input was so small + * that we never got to call into libica until final + */ + if (ica_sha5_ctx->runningLengthLow == 0 + && ica_sha5_ctx->runningLengthHigh == 0) + sc->message_part = SHA_MSG_PART_ONLY; + rc = p_ica_sha512_256(sc->message_part, sc->tail_len, + sc->tail, ica_sha5_ctx, sc->hash); + break; + } +#endif + default: + return CKR_MECHANISM_INVALID; + } + + if (rc != CKR_OK) { + rv = CKR_FUNCTION_FAILED; + goto out; + } + + memcpy(out_data, sc->hash, sc->hash_len); + *out_data_len = sc->hash_len; + +out: + return rv; +} + +#ifndef LITE +#define LITE +#endif + +/* Creates a libICA modulus+exponent key representation using + * PKCS#11 attributes + */ +static ica_rsa_key_mod_expo_t *rsa_convert_mod_expo_key(CK_ATTRIBUTE *modulus, + CK_ATTRIBUTE *mod_bits, + CK_ATTRIBUTE *exponent) +{ + CK_BYTE *ptr = NULL; + ica_rsa_key_mod_expo_t *modexpokey = NULL; + + /* We need at least the modulus and a (public|private) exponent */ + if (!modulus || !exponent) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return NULL; + } + + modexpokey = + (ica_rsa_key_mod_expo_t *) calloc(1, sizeof(ica_rsa_key_mod_expo_t)); + if (modexpokey == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto err; + } + + /* We can't rely solely on CKA_MODULUS_BITS here since Private Keys + * using the modulus + private exponent representation may also go + * through this path. Use modulus length in bytes as key_length if + * no mod_bits is present */ + if (mod_bits != NULL && mod_bits->ulValueLen + && (*(CK_ULONG *) mod_bits->pValue)) { + modexpokey->key_length = ((*(CK_ULONG *) mod_bits->pValue) + 7) / 8; + } else { + modexpokey->key_length = modulus->ulValueLen; + } + + /* maybe I'm over-cautious here */ + if ((modulus->ulValueLen > modexpokey->key_length) || + (exponent->ulValueLen > modexpokey->key_length)) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + goto err; + } + + modexpokey->modulus = (unsigned char *) calloc(1, modexpokey->key_length); + + if (modexpokey->modulus == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto err; + } + + /* right-justified fields */ + ptr = modexpokey->modulus + modexpokey->key_length - modulus->ulValueLen; + memcpy(ptr, modulus->pValue, modexpokey->key_length); + + modexpokey->exponent = (unsigned char *) calloc(1, modexpokey->key_length); + if (modexpokey->exponent == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto err; + } + + ptr = modexpokey->exponent + modexpokey->key_length - exponent->ulValueLen; + memcpy(ptr, exponent->pValue, exponent->ulValueLen); + return modexpokey; + +err: + free(modexpokey->modulus); + free(modexpokey->exponent); + free(modexpokey); + + return NULL; +} + +/* Creates a libICA CRT key representation using + * PKCS#11 attributes + */ +static ica_rsa_key_crt_t *rsa_convert_crt_key(CK_ATTRIBUTE *modulus, + CK_ATTRIBUTE *prime1, + CK_ATTRIBUTE *prime2, + CK_ATTRIBUTE *exp1, + CK_ATTRIBUTE *exp2, + CK_ATTRIBUTE *coeff) +{ + CK_BYTE *ptr = NULL; + ica_rsa_key_crt_t *crtkey = NULL; + + /* All the above params are required to build a CRT key + * that can be used by libICA. Private Keys with modulus + * and private exponent should use rsa_convert_mod_expo_key() */ + if (!modulus || !prime1 || !prime2 || !exp1 || !exp2 || !coeff) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return NULL; + } else { + crtkey = (ica_rsa_key_crt_t *) calloc(1, sizeof(ica_rsa_key_crt_t)); + if (crtkey == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return NULL; + } + /* use modulus length in bytes as key_length */ + 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. + * p, dp and qInverse have an additional 8-byte padding. */ + + /* need to allocate the buffers. Also, all fields are + * right-aligned, thus the use for ptr */ + + /* FIXME: if individual components lengths are bigger then + * what we support in libICA then we're in trouble, + * but maybe explicitly checking them is being over-zealous? */ + if ((prime1->ulValueLen > (crtkey->key_length / 2)) || + (prime2->ulValueLen > (crtkey->key_length / 2)) || + (exp1->ulValueLen > (crtkey->key_length / 2)) || + (exp2->ulValueLen > (crtkey->key_length / 2)) || + (coeff->ulValueLen > (crtkey->key_length / 2))) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + goto err_crtkey; + } + crtkey->p = (unsigned char *) calloc(1, (crtkey->key_length / 2) + 8); + if (crtkey->p == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto err_crtkey; + } + ptr = crtkey->p + (crtkey->key_length / 2) + 8 - prime1->ulValueLen; + memcpy(ptr, prime1->pValue, prime1->ulValueLen); + + crtkey->q = (unsigned char *) calloc(1, crtkey->key_length / 2); + + if (crtkey->q == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto err_crtkey; + } + ptr = crtkey->q + (crtkey->key_length / 2) - prime2->ulValueLen; + memcpy(ptr, prime2->pValue, prime2->ulValueLen); + + crtkey->dp = (unsigned char *) calloc(1, (crtkey->key_length / 2) + 8); + if (crtkey->dp == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto err_crtkey; + } + ptr = crtkey->dp + (crtkey->key_length / 2) + 8 - exp1->ulValueLen; + memcpy(ptr, exp1->pValue, exp1->ulValueLen); + + crtkey->dq = (unsigned char *) calloc(1, crtkey->key_length / 2); + if (crtkey->dq == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto err_crtkey; + } + ptr = crtkey->dq + (crtkey->key_length / 2) - exp2->ulValueLen; + memcpy(ptr, exp2->pValue, exp2->ulValueLen); + + crtkey->qInverse = + (unsigned char *) calloc(1, (crtkey->key_length / 2) + 8); + if (crtkey->qInverse == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto err_crtkey; + } + ptr = + crtkey->qInverse + (crtkey->key_length / 2) + 8 - coeff->ulValueLen; + memcpy(ptr, coeff->pValue, coeff->ulValueLen); + + return crtkey; + } + +err_crtkey: + free(crtkey->p); + free(crtkey->q); + free(crtkey->dp); + free(crtkey->dq); + free(crtkey->qInverse); + free(crtkey); + + return NULL; +} + + +// +static CK_RV os_specific_rsa_keygen(STDLL_TokData_t *tokdata, + TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) +{ + ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; + CK_ATTRIBUTE *publ_exp = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *ptr = NULL; + CK_ULONG mod_bits; + CK_BBOOL flag; + unsigned long tmpsize; + CK_RV rc; + ica_rsa_key_mod_expo_t *publKey = NULL; + ica_rsa_key_crt_t *privKey = NULL; + + flag = template_attribute_find(publ_tmpl, CKA_MODULUS_BITS, &attr); + if (!flag) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; // should never happen + } + mod_bits = *(CK_ULONG *) attr->pValue; + + flag = template_attribute_find(publ_tmpl, CKA_PUBLIC_EXPONENT, &publ_exp); + if (!flag) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + // FIXME: is this check really necessary? + if (mod_bits < 512 || mod_bits > 4096) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_SIZE_RANGE)); + return CKR_KEY_SIZE_RANGE; + } + + /* libICA replicates the openSSL requirement that the public exponent + * can't be larger than the size of an unsigned long + */ + if (publ_exp->ulValueLen > sizeof(unsigned long)) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_SIZE_RANGE)); + return CKR_KEY_SIZE_RANGE; + } + + /* Build publKey: + * The buffers in ica_rsa_key_mod_expo_t must be + * allocated by the caller, with key_length size + * use calloc() so that memory is zeroed (right alignment) */ + publKey = + (ica_rsa_key_mod_expo_t *) calloc(1, sizeof(ica_rsa_key_mod_expo_t)); + if (publKey == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + /* key_length is in terms of bytes */ + publKey->key_length = ((mod_bits + 7) / 8); + + publKey->modulus = (unsigned char *) calloc(1, publKey->key_length); + if (publKey->modulus == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto pubkey_cleanup; + } + + publKey->exponent = (unsigned char *) calloc(1, publKey->key_length); + if (publKey->exponent == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto pubkey_cleanup; + } + + /* Use the provided public exponent: + * all fields must be right-aligned, so make + * sure we only use the rightmost part */ + /* We know the pub_exp attribute has it's value in BIG ENDIAN * + * byte order, and we're assuming we're on s390(x) which is also * + * BIG ENDIAN, so no byte swapping required. * + * FIXME: Will need to fix that if porting for little endian */ + ptr = publKey->exponent + publKey->key_length - publ_exp->ulValueLen; + memcpy(ptr, publ_exp->pValue, publ_exp->ulValueLen); + + /* If the public exponent is zero, libica will generate a random one * + * If it is an even number, then we have a problem. Use ptr to cast * + * to unsigned int and check */ + ptr = publKey->exponent + publKey->key_length - sizeof(unsigned long); + if (*((unsigned long *) ptr) != 0 && *((unsigned long *) ptr) % 2 == 0) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); + return CKR_TEMPLATE_INCONSISTENT; + } + + + /* Build privKey: + * 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. + * p, dp and qInverse have an additional 8-byte padding */ + privKey = (ica_rsa_key_crt_t *) calloc(1, sizeof(ica_rsa_key_crt_t)); + if (privKey == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto pubkey_cleanup; + } + + /* modexpo and crt key lengths are always the same */ + privKey->key_length = publKey->key_length; + + privKey->p = (unsigned char *) calloc(1, (privKey->key_length / 2) + 8); + if (privKey->p == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto privkey_cleanup; + } + + privKey->q = (unsigned char *) calloc(1, privKey->key_length / 2); + if (privKey->q == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto privkey_cleanup; + } + + privKey->dp = (unsigned char *) calloc(1, (privKey->key_length / 2) + 8); + if (privKey->dp == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto privkey_cleanup; + } + + privKey->dq = (unsigned char *) calloc(1, privKey->key_length / 2); + if (privKey->dq == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto privkey_cleanup; + } + + privKey->qInverse = + (unsigned char *) calloc(1, (privKey->key_length / 2) + 8); + if (privKey->qInverse == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto privkey_cleanup; + } + + rc = ica_rsa_key_generate_crt(ica_data->adapter_handle, + (unsigned int) mod_bits, publKey, privKey); + + + if (rc) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + goto privkey_cleanup; + } + + + /* Build the PKCS#11 public key */ + // modulus: n + // + tmpsize = publKey->key_length; + ptr = p11_bigint_trim(publKey->modulus, &tmpsize); + if (tmpsize != publKey->key_length) { + /* This is bad */ + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + goto privkey_cleanup; + } + rc = build_attribute(CKA_MODULUS, ptr, tmpsize, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto privkey_cleanup; + } + template_update_attribute(publ_tmpl, attr); + + // public exponent + // + tmpsize = publKey->key_length; + ptr = p11_bigint_trim(publKey->exponent, &tmpsize); + rc = build_attribute(CKA_PUBLIC_EXPONENT, ptr, tmpsize, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build attribute failed\n"); + goto privkey_cleanup; + } + template_update_attribute(publ_tmpl, attr); + + + // local = TRUE + // + flag = TRUE; + rc = build_attribute(CKA_LOCAL, &flag, sizeof(CK_BBOOL), &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto privkey_cleanup; + } + template_update_attribute(publ_tmpl, attr); + + // + // now, do the private key + // + + // public exponent: e + // + tmpsize = publKey->key_length; + ptr = p11_bigint_trim(publKey->exponent, &tmpsize); + rc = build_attribute(CKA_PUBLIC_EXPONENT, ptr, tmpsize, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto privkey_cleanup; + } + template_update_attribute(priv_tmpl, attr); + + // modulus: n + // + tmpsize = publKey->key_length; + ptr = p11_bigint_trim(publKey->modulus, &tmpsize); + if (tmpsize != publKey->key_length) { + /* This is bad */ + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + goto privkey_cleanup; + } + rc = build_attribute(CKA_MODULUS, ptr, tmpsize, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto privkey_cleanup; + } + template_update_attribute(priv_tmpl, attr); + + // exponent 1: d mod(p-1) + // + tmpsize = privKey->key_length / 2; + ptr = p11_bigint_trim(privKey->dp + 8, &tmpsize); + rc = build_attribute(CKA_EXPONENT_1, ptr, tmpsize, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto privkey_cleanup; + } + template_update_attribute(priv_tmpl, attr); + + // exponent 2: d mod(q-1) + // + tmpsize = privKey->key_length / 2; + ptr = p11_bigint_trim(privKey->dq, &tmpsize); + rc = build_attribute(CKA_EXPONENT_2, ptr, tmpsize, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto privkey_cleanup; + } + template_update_attribute(priv_tmpl, attr); + + // prime #1: p + // + tmpsize = privKey->key_length / 2; + ptr = p11_bigint_trim(privKey->p + 8, &tmpsize); + rc = build_attribute(CKA_PRIME_1, ptr, tmpsize, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto privkey_cleanup; + } + template_update_attribute(priv_tmpl, attr); + + + // prime #2: q + // + tmpsize = privKey->key_length / 2; + ptr = p11_bigint_trim(privKey->q, &tmpsize); + rc = build_attribute(CKA_PRIME_2, privKey->q, + privKey->key_length / 2, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto privkey_cleanup; + } + template_update_attribute(priv_tmpl, attr); + + + // CRT coefficient: q_inverse mod(p) + // + tmpsize = privKey->key_length / 2; + ptr = p11_bigint_trim(privKey->qInverse + 8, &tmpsize); + rc = build_attribute(CKA_COEFFICIENT, ptr, tmpsize, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto privkey_cleanup; + } + template_update_attribute(priv_tmpl, attr); + +privkey_cleanup: + free(privKey->p); + free(privKey->q); + free(privKey->dp); + free(privKey->dq); + free(privKey->qInverse); + free(privKey); +pubkey_cleanup: + free(publKey->modulus); + free(publKey->exponent); + free(publKey); + + return rc; +} + +CK_RV token_specific_rsa_generate_keypair(STDLL_TokData_t *tokdata, + TEMPLATE *publ_tmpl, + TEMPLATE *priv_tmpl) +{ + CK_RV rc; + + UNUSED(tokdata); + + rc = os_specific_rsa_keygen(tokdata, publ_tmpl, priv_tmpl); + if (rc != CKR_OK) + TRACE_DEVEL("os_specific_rsa_keygen failed\n"); + + return rc; +} + + +// +// +static CK_RV os_specific_rsa_encrypt(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, OBJECT *key_obj) +{ + ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; + 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_find(key_obj->template, CKA_MODULUS, &modulus); + template_attribute_find(key_obj->template, CKA_MODULUS_BITS, &mod_bits); + template_attribute_find(key_obj->template, CKA_PUBLIC_EXPONENT, &pub_exp); + + 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; + } + + /* 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 + * be of the same length of the key */ + // FIXME: we're not cheking the size in bits of in_data - but how could we? + 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; + } + rc = ica_rsa_mod_expo(ica_data->adapter_handle, in_data, publKey, out_data); + if (rc != 0) { + if (rc == EINVAL) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + } + goto cleanup_pubkey; + } + + rc = CKR_OK; + +cleanup_pubkey: + free(publKey->modulus); + free(publKey->exponent); + free(publKey); + +done: + return rc; +} + +// +// +static CK_RV os_specific_rsa_decrypt(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, OBJECT *key_obj) +{ + ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; + CK_ATTRIBUTE *modulus = NULL; + CK_ATTRIBUTE *prime1 = NULL; + CK_ATTRIBUTE *prime2 = NULL; + CK_ATTRIBUTE *exp1 = NULL; + CK_ATTRIBUTE *exp2 = NULL; + CK_ATTRIBUTE *coeff = NULL; + CK_ATTRIBUTE *priv_exp = NULL; + ica_rsa_key_crt_t *crtKey = NULL; + ica_rsa_key_mod_expo_t *modexpoKey = 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_find(key_obj->template, CKA_MODULUS, &modulus); + template_attribute_find(key_obj->template, CKA_PRIVATE_EXPONENT, &priv_exp); + template_attribute_find(key_obj->template, CKA_PRIME_1, &prime1); + template_attribute_find(key_obj->template, CKA_PRIME_2, &prime2); + template_attribute_find(key_obj->template, CKA_EXPONENT_1, &exp1); + template_attribute_find(key_obj->template, CKA_EXPONENT_2, &exp2); + template_attribute_find(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) */ + // FIXME: Checking for non-zero lengths anyway (might be overkill) + + if (modulus && modulus->ulValueLen && + prime1 && prime1->ulValueLen && + prime2 && prime2->ulValueLen && + exp1 && exp1->ulValueLen && + exp2 && exp2->ulValueLen && coeff && coeff->ulValueLen) { + /* 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; + 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); + + if (rc != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + } else { + rc = CKR_OK; + } + goto crt_cleanup; + } else if (modulus && modulus->ulValueLen && + priv_exp && priv_exp->ulValueLen) { + /* 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"); + 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); + + if (rc != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + } else { + rc = CKR_OK; + } + goto modexpo_cleanup; + } else { + /* should never happen */ + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + 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); + +done: + return rc; +} + + +CK_RV token_specific_rsa_encrypt(STDLL_TokData_t *tokdata, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len, OBJECT *key_obj) +{ + CK_RV rc; + CK_BYTE clear[MAX_RSA_KEYLEN], cipher[MAX_RSA_KEYLEN]; + CK_ULONG modulus_bytes; + CK_BBOOL flag; + CK_ATTRIBUTE *attr = NULL; + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + return CKR_FUNCTION_FAILED; + } else { + modulus_bytes = attr->ulValueLen; + } + + /* format the data */ + rc = rsa_format_block(tokdata, in_data, in_data_len, clear, + modulus_bytes, PKCS_BT_2); + if (rc != CKR_OK) { + TRACE_DEVEL("rsa_format_block failed\n"); + return rc; + } + + rc = os_specific_rsa_encrypt(tokdata, clear, modulus_bytes, cipher, key_obj); + if (rc == CKR_OK) { + memcpy(out_data, cipher, modulus_bytes); + *out_data_len = modulus_bytes; + } else { + TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); + } + + return rc; +} + + +CK_RV token_specific_rsa_decrypt(STDLL_TokData_t *tokdata, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len, OBJECT *key_obj) +{ + CK_BYTE out[MAX_RSA_KEYLEN]; + CK_RV rc; + + UNUSED(tokdata); + + rc = os_specific_rsa_decrypt(tokdata, in_data, in_data_len, out, key_obj); + + if (rc != CKR_OK) { + TRACE_DEVEL("os_specific_rsa_decrypt failed\n"); + return rc; + } + + rc = rsa_parse_block(out, in_data_len, out_data, out_data_len, PKCS_BT_2); + if (rc != CKR_OK) { + TRACE_DEVEL("rsa_parse_block failed\n"); + return rc; + } + + /* + * For PKCS #1 v1.5 padding, out_data_len must be less + * than in_data_len (which is modulus_bytes) - 11. + */ + if (*out_data_len > (in_data_len - 11)) { + TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); + rc = CKR_ENCRYPTED_DATA_LEN_RANGE; + } + + return rc; +} + +CK_RV token_specific_rsa_sign(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_ATTRIBUTE *attr = NULL; + CK_BBOOL flag; + CK_RV rc; + CK_BYTE data[MAX_RSA_KEYLEN], sig[MAX_RSA_KEYLEN]; + CK_ULONG modulus_bytes; + + UNUSED(tokdata); + UNUSED(sess); + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + return CKR_FUNCTION_FAILED; + } else { + modulus_bytes = attr->ulValueLen; + } + + rc = rsa_format_block(tokdata, in_data, in_data_len, data, + modulus_bytes, PKCS_BT_1); + if (rc != CKR_OK) { + TRACE_DEVEL("rsa_format_block failed\n"); + return rc; + } + + /* signing is a private key operation --> decrypt */ + rc = os_specific_rsa_decrypt(tokdata, data, modulus_bytes, sig, key_obj); + if (rc == CKR_OK) { + memcpy(out_data, sig, modulus_bytes); + *out_data_len = modulus_bytes; + } else { + TRACE_DEVEL("os_specific_rsa_decrypt failed\n"); + } + + return rc; +} + +CK_RV token_specific_rsa_verify(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len, + OBJECT *key_obj) +{ + CK_RV rc; + CK_BYTE out[MAX_RSA_KEYLEN], out_data[MAX_RSA_KEYLEN]; + CK_BBOOL flag; + CK_ATTRIBUTE *attr = NULL; + CK_ULONG modulus_bytes, out_data_len; + + UNUSED(tokdata); + UNUSED(sess); + UNUSED(sig_len); + + out_data_len = MAX_RSA_KEYLEN; + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + return CKR_FUNCTION_FAILED; + } else { + modulus_bytes = attr->ulValueLen; + } + + rc = os_specific_rsa_encrypt(tokdata, signature, modulus_bytes, out, + key_obj); + if (rc != CKR_OK) { + /* + * Return CKR_SIGNATURE_INVALID in case of CKR_ARGUMENTS_BAD + * because we dont know why the RSA op failed and it may have + * failed due to a tampered signature being greater or equal + * to the modulus. + */ + TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); + return rc == CKR_ARGUMENTS_BAD ? CKR_SIGNATURE_INVALID : rc; + } + + rc = rsa_parse_block(out, modulus_bytes, out_data, &out_data_len, + PKCS_BT_1); + if (rc == CKR_ENCRYPTED_DATA_INVALID) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + return CKR_SIGNATURE_INVALID; + } else if (rc != CKR_OK) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + if (in_data_len != out_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + return CKR_SIGNATURE_INVALID; + } + + if (CRYPTO_memcmp(in_data, out_data, out_data_len) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + return CKR_SIGNATURE_INVALID; + } + + return CKR_OK; +} + +CK_RV token_specific_rsa_verify_recover(STDLL_TokData_t *tokdata, + CK_BYTE *signature, CK_ULONG sig_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, + OBJECT *key_obj) +{ + CK_RV rc; + CK_BYTE out[MAX_RSA_KEYLEN]; + CK_BBOOL flag; + CK_ATTRIBUTE *attr = NULL; + CK_ULONG modulus_bytes; + + UNUSED(tokdata); + UNUSED(sig_len); + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + return CKR_FUNCTION_FAILED; + } else { + modulus_bytes = attr->ulValueLen; + } + + rc = os_specific_rsa_encrypt(tokdata, signature, modulus_bytes, out, + key_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); + return rc; + } + + rc = rsa_parse_block(out, modulus_bytes, out_data, out_data_len, PKCS_BT_1); + if (rc == CKR_ENCRYPTED_DATA_INVALID) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + return CKR_SIGNATURE_INVALID; + } else if (rc != CKR_OK) { + TRACE_DEVEL("rsa_parse_block failed\n"); + } + + return rc; +} + +CK_RV token_specific_rsa_x509_encrypt(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, OBJECT *key_obj) +{ + CK_RV rc; + CK_BYTE clear[MAX_RSA_KEYLEN], cipher[MAX_RSA_KEYLEN]; + CK_BBOOL flag; + CK_ATTRIBUTE *attr = NULL; + CK_ULONG modulus_bytes; + + UNUSED(tokdata); + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + return CKR_FUNCTION_FAILED; + } else { + modulus_bytes = attr->ulValueLen; + } + + // prepad with zeros + // + memset(clear, 0x0, modulus_bytes - in_data_len); + memcpy(&clear[modulus_bytes - in_data_len], in_data, in_data_len); + + rc = os_specific_rsa_encrypt(tokdata, clear, modulus_bytes, cipher, key_obj); + if (rc == CKR_OK) { + memcpy(out_data, cipher, modulus_bytes); + *out_data_len = modulus_bytes; + } else { + TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); + } + + return rc; +} + +CK_RV token_specific_rsa_x509_decrypt(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, OBJECT *key_obj) +{ + CK_RV rc; + CK_BYTE out[MAX_RSA_KEYLEN]; + CK_BBOOL flag; + CK_ATTRIBUTE *attr = NULL; + CK_ULONG modulus_bytes; + + UNUSED(tokdata); + UNUSED(in_data_len); + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + return CKR_FUNCTION_FAILED; + } else { + modulus_bytes = attr->ulValueLen; + } + + rc = os_specific_rsa_decrypt(tokdata, in_data, modulus_bytes, out, key_obj); + if (rc == CKR_OK) { + memcpy(out_data, out, modulus_bytes); + *out_data_len = modulus_bytes; + } else { + TRACE_DEVEL("os_specific_rsa_decrypt failed\n"); + } + + return rc; +} + +CK_RV token_specific_rsa_x509_sign(STDLL_TokData_t *tokdata, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len, OBJECT *key_obj) +{ + CK_RV rc; + CK_BYTE data[MAX_RSA_KEYLEN], sig[MAX_RSA_KEYLEN]; + CK_BBOOL flag; + CK_ATTRIBUTE *attr = NULL; + CK_ULONG modulus_bytes; + + UNUSED(tokdata); + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + return CKR_FUNCTION_FAILED; + } else { + modulus_bytes = attr->ulValueLen; + } + + // prepad with zeros + // + memset(data, 0x0, modulus_bytes - in_data_len); + memcpy(&data[modulus_bytes - in_data_len], in_data, in_data_len); + + rc = os_specific_rsa_decrypt(tokdata, data, modulus_bytes, sig, key_obj); + if (rc == CKR_OK) { + memcpy(out_data, sig, modulus_bytes); + *out_data_len = modulus_bytes; + } else { + TRACE_DEVEL("os_specific_rsa_decrypt failed\n"); + } + + return rc; +} + + +CK_RV token_specific_rsa_x509_verify(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len, + OBJECT *key_obj) +{ + CK_RV rc; + CK_BYTE out[MAX_RSA_KEYLEN]; + CK_BBOOL flag; + CK_ATTRIBUTE *attr = NULL; + CK_ULONG modulus_bytes; + + UNUSED(tokdata); + UNUSED(sig_len); + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + return CKR_FUNCTION_FAILED; + } else { + modulus_bytes = attr->ulValueLen; + } + + rc = os_specific_rsa_encrypt(tokdata, signature, modulus_bytes, out, + key_obj); + if (rc == CKR_OK) { + CK_ULONG pos1, pos2, len; + + // it should be noted that in_data_len is not necessarily + // the same as the modulus length + // + for (pos1 = 0; pos1 < in_data_len; pos1++) + if (in_data[pos1] != 0) + break; + + for (pos2 = 0; pos2 < modulus_bytes; pos2++) + if (out[pos2] != 0) + break; + + // at this point, pos1 and pos2 point to the first non-zero + // bytes in the input data and the decrypted signature + // (the recovered data), respectively. + // + if ((in_data_len - pos1) != (modulus_bytes - pos2)) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + return CKR_SIGNATURE_INVALID; + } + len = in_data_len - pos1; + + if (CRYPTO_memcmp(&in_data[pos1], &out[pos2], len) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + return CKR_SIGNATURE_INVALID; + } + return CKR_OK; + } else { + TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); + } + + return rc; +} + + +CK_RV token_specific_rsa_x509_verify_recover(STDLL_TokData_t *tokdata, + CK_BYTE *signature, + CK_ULONG sig_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, + OBJECT *key_obj) +{ + CK_RV rc; + CK_BYTE out[MAX_RSA_KEYLEN]; + CK_BBOOL flag; + CK_ATTRIBUTE *attr = NULL; + CK_ULONG modulus_bytes; + + UNUSED(tokdata); + UNUSED(sig_len); + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + return CKR_FUNCTION_FAILED; + } else { + modulus_bytes = attr->ulValueLen; + } + + rc = os_specific_rsa_encrypt(tokdata, signature, modulus_bytes, out, + key_obj); + if (rc == CKR_OK) { + memcpy(out_data, out, modulus_bytes); + *out_data_len = modulus_bytes; + } else { + TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); + } + + return rc; +} + +CK_RV token_specific_rsa_oaep_encrypt(STDLL_TokData_t *tokdata, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_BYTE *hash, + CK_ULONG hlen) +{ + CK_RV rc; + CK_BYTE cipher[MAX_RSA_KEYLEN]; + CK_ULONG modulus_bytes; + CK_BBOOL flag; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *em_data = NULL; + OBJECT *key_obj = NULL; + CK_RSA_PKCS_OAEP_PARAMS_PTR oaepParms = NULL; + + if (!in_data || !out_data || !hash) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + oaepParms = (CK_RSA_PKCS_OAEP_PARAMS_PTR) ctx->mech.pParameter; + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_find_in_map1 failed\n"); + return rc; + } + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + modulus_bytes = attr->ulValueLen; + } + + /* pkcs1v2.2, section 7.1.1 Step 2: + * EME-OAEP encoding. + */ + em_data = (CK_BYTE *) malloc(modulus_bytes); + if (em_data == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + + rc = encode_eme_oaep(tokdata, in_data, in_data_len, em_data, + modulus_bytes, oaepParms->mgf, hash, hlen); + if (rc != CKR_OK) + goto done; + + rc = os_specific_rsa_encrypt(tokdata, em_data, modulus_bytes, cipher, + key_obj); + if (rc == CKR_OK) { + memcpy(out_data, cipher, modulus_bytes); + *out_data_len = modulus_bytes; + } else { + TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); + } + +done: + if (em_data) + free(em_data); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV token_specific_rsa_oaep_decrypt(STDLL_TokData_t *tokdata, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_BYTE *hash, + CK_ULONG hlen) +{ + CK_RV rc; + CK_BYTE *decr_data = NULL; + OBJECT *key_obj = NULL; + CK_BBOOL flag; + CK_ATTRIBUTE *attr = NULL; + CK_RSA_PKCS_OAEP_PARAMS_PTR oaepParms = NULL; + + if (!in_data || !out_data || !hash) { + TRACE_ERROR("Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + + oaepParms = (CK_RSA_PKCS_OAEP_PARAMS_PTR) ctx->mech.pParameter; + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_find_in_map1 failed\n"); + return rc; + } + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + *out_data_len = attr->ulValueLen; + } + + decr_data = (CK_BYTE *) malloc(in_data_len); + if (decr_data == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + + rc = os_specific_rsa_decrypt(tokdata, in_data, in_data_len, decr_data, + key_obj); + if (rc != CKR_OK) + goto done; + + /* pkcs1v2.2, section 7.1.2 Step 2: + * EME-OAEP decoding. + */ + rc = decode_eme_oaep(tokdata, decr_data, in_data_len, out_data, + out_data_len, oaepParms->mgf, hash, hlen); + + if (decr_data) + free(decr_data); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV token_specific_rsa_pss_sign(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *sig, CK_ULONG *sig_len) +{ + CK_RV rc; + CK_ULONG modbytes; + CK_BBOOL flag; + CK_ATTRIBUTE *attr = NULL; + OBJECT *key_obj = NULL; + CK_BYTE *emdata = NULL; + CK_RSA_PKCS_PSS_PARAMS *pssParms = NULL; + + UNUSED(sess); + + /* check the arguments */ + if (!in_data || !sig) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + if (!ctx) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + pssParms = (CK_RSA_PKCS_PSS_PARAMS *) ctx->mech.pParameter; + + /* get the key */ + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_find_in_map1 failed\n"); + return rc; + } + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + modbytes = attr->ulValueLen; + } + + + emdata = (CK_BYTE *) malloc(modbytes); + if (emdata == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + + rc = emsa_pss_encode(tokdata, pssParms, in_data, in_data_len, emdata, + &modbytes); + if (rc != CKR_OK) + goto done; + + /* signing is a private key operation --> decrypt */ + rc = os_specific_rsa_decrypt(tokdata, emdata, modbytes, sig, key_obj); + if (rc == CKR_OK) + *sig_len = modbytes; + else + TRACE_DEVEL("os_specific_rsa_decrypt failed\n"); + +done: + if (emdata) + free(emdata); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +CK_RV token_specific_rsa_pss_verify(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) +{ + CK_RV rc; + CK_ULONG modbytes; + OBJECT *key_obj = NULL; + CK_BBOOL flag; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE out[MAX_RSA_KEYLEN]; + CK_RSA_PKCS_PSS_PARAMS *pssParms = NULL; + + UNUSED(sess); + + /* check the arguments */ + if (!in_data || !signature) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + if (!ctx) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + pssParms = (CK_RSA_PKCS_PSS_PARAMS *) ctx->mech.pParameter; + + /* get the key */ + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_find_in_map1 failed\n"); + return rc; + } + + /* verify is a public key operation ... encrypt */ + rc = os_specific_rsa_encrypt(tokdata, signature, sig_len, out, key_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); + goto done; + } + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + modbytes = attr->ulValueLen; + } + + /* call the pss verify scheme */ + rc = emsa_pss_verify(tokdata, pssParms, in_data, in_data_len, out, + modbytes); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +#ifndef NOAES + +CK_RV token_specific_aes_key_gen(STDLL_TokData_t *tokdata, CK_BYTE *key, + CK_ULONG len, CK_ULONG keysize) +{ + UNUSED(keysize); + + return rng_generate(tokdata, key, len); +} + +CK_RV token_specific_aes_ecb(STDLL_TokData_t *tokdata, CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len, + OBJECT *key, CK_BYTE encrypt) +{ + int rc = CKR_OK; + CK_ATTRIBUTE *attr = NULL; + + UNUSED(tokdata); + + /* + * checks for input and output data length and block sizes + * are already being carried out in mech_aes.c + * so we skip those + */ + // get the key value + rc = template_attribute_find(key->template, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + + if (encrypt) { + rc = ica_aes_ecb(in_data, out_data, in_data_len, attr->pValue, + attr->ulValueLen, ICA_ENCRYPT); + } else { + rc = ica_aes_ecb(in_data, out_data, in_data_len, attr->pValue, + attr->ulValueLen, ICA_DECRYPT); + } + if (rc != 0) { + (*out_data_len) = 0; + rc = CKR_FUNCTION_FAILED; + } else { + (*out_data_len) = in_data_len; + rc = CKR_OK; + } + + return rc; +} + +CK_RV token_specific_aes_cbc(STDLL_TokData_t *tokdata, + 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) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + + UNUSED(tokdata); + + /* + * checks for input and output data length and block sizes + * are already being carried out in mech_aes.c + * so we skip those + */ + + // get the key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + + if (encrypt) { + rc = ica_aes_cbc(in_data, out_data, in_data_len, attr->pValue, + attr->ulValueLen, init_v, ICA_ENCRYPT); + } else { + rc = ica_aes_cbc(in_data, out_data, in_data_len, attr->pValue, + attr->ulValueLen, init_v, ICA_DECRYPT); + } + if (rc != 0) { + (*out_data_len) = 0; + rc = CKR_FUNCTION_FAILED; + } else { + (*out_data_len) = in_data_len; + rc = CKR_OK; + } + + return rc; +} + +CK_RV token_specific_aes_ctr(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, + OBJECT *key, + CK_BYTE *counterblock, + CK_ULONG counter_width, CK_BYTE encrypt) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + + UNUSED(tokdata); + + /* + * checks for input and output data length and block sizes + * are already being carried out in mech_aes.c + * so we skip those + */ + /* in libica for AES-Counter Mode if uses one function for both encrypt and + * decrypt, so they use variable direction to know if the data is to be + * encrypted or decrypted + * 0 -- Decrypt + * 1 -- Encrypt + */ + + // get the key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + + if (encrypt) { + rc = ica_aes_ctr(in_data, out_data, (unsigned int) in_data_len, + attr->pValue, (unsigned int) attr->ulValueLen, + counterblock, (unsigned int) counter_width, 1); + } else { + rc = ica_aes_ctr(in_data, out_data, (unsigned int) in_data_len, + attr->pValue, (unsigned int) attr->ulValueLen, + counterblock, (unsigned int) counter_width, 0); + } + if (rc != 0) { + (*out_data_len) = 0; + rc = CKR_FUNCTION_FAILED; + } else { + (*out_data_len) = in_data_len; + rc = CKR_OK; + } + + return rc; +} + +CK_RV token_specific_aes_gcm_init(STDLL_TokData_t *tokdata, SESSION *sess, + ENCR_DECR_CONTEXT *ctx, CK_MECHANISM *mech, + CK_OBJECT_HANDLE key, CK_BYTE encrypt) +{ + CK_RV rc = CKR_OK; + OBJECT *key_obj = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_GCM_PARAMS *aes_gcm_param = NULL; + AES_GCM_CONTEXT *context = NULL; + CK_BYTE *icv, *icb, *ucb, *subkey; + CK_ULONG icv_length; + + UNUSED(sess); + + /* find key object */ + rc = object_mgr_find_in_map1(tokdata, key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + /* get the key value */ + rc = template_attribute_find(key_obj->template, CKA_VALUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_VALUE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* prepare initial counterblock */ + aes_gcm_param = (CK_GCM_PARAMS *) mech->pParameter; + context = (AES_GCM_CONTEXT *) ctx->context; + + context->ulAlen = aes_gcm_param->ulAADLen; + icb = (CK_BYTE *) context->icb; + ucb = (CK_BYTE *) context->ucb; + subkey = (CK_BYTE *) context->subkey; + + icv = (CK_BYTE *) aes_gcm_param->pIv; + icv_length = aes_gcm_param->ulIvLen; + + if (encrypt) { + rc = ica_aes_gcm_initialize(icv, icv_length, + attr->pValue, attr->ulValueLen, + icb, ucb, subkey, 1); + } else { + rc = ica_aes_gcm_initialize(icv, icv_length, + attr->pValue, attr->ulValueLen, + icb, ucb, subkey, 0); + } + if (rc != 0) { + TRACE_ERROR("ica_aes_gcm_initialize() failed.\n"); + goto done; + } + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV token_specific_aes_gcm(STDLL_TokData_t *tokdata, SESSION *sess, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_BYTE encrypt) +{ + CK_RV rc; + OBJECT *key = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_GCM_PARAMS *aes_gcm_param = NULL; + CK_BYTE *counterblock; + CK_ULONG counter_width; + CK_BYTE *tag_data, *auth_data; + CK_ULONG auth_data_len; + CK_ULONG tag_data_len; + + UNUSED(sess); + + /* + * Checks for input and output data length and block sizes are already + * being carried out in mech_aes.c, so we skip those + * + * libica for AES-GCM Mode uses one function for both encrypt + * and decrypt, so they use the variable 'direction' to know if + * the data is to be encrypted or decrypted. + * 0 -- Decrypt + * 1 -- Encrypt + */ + + aes_gcm_param = (CK_GCM_PARAMS *) ctx->mech.pParameter; + counterblock = (CK_BYTE *) aes_gcm_param->pIv; + counter_width = aes_gcm_param->ulIvLen; + auth_data = (CK_BYTE *) aes_gcm_param->pAAD; + auth_data_len = aes_gcm_param->ulAADLen; + tag_data_len = (aes_gcm_param->ulTagBits + 7) / 8; + + /* find key object */ + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + /* get key value */ + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (encrypt) { + tag_data = out_data + in_data_len; + rc = ica_aes_gcm(in_data, (unsigned int) in_data_len, out_data, + counterblock, (unsigned int) counter_width, + auth_data, (unsigned int) auth_data_len, + tag_data, AES_BLOCK_SIZE, attr->pValue, + (unsigned int) attr->ulValueLen, 1); + if (rc == 0) { + (*out_data_len) = in_data_len + tag_data_len; + rc = CKR_OK; + } + } else { + unsigned int len; + + tag_data = in_data + in_data_len - tag_data_len; + len = in_data_len - tag_data_len; + rc = ica_aes_gcm(out_data, + (unsigned int) len, in_data, counterblock, + (unsigned int) counter_width, auth_data, + (unsigned int) auth_data_len, tag_data, + (unsigned int) tag_data_len, attr->pValue, + (unsigned int) attr->ulValueLen, 0); + if (rc == 0) { + (*out_data_len) = len; + rc = CKR_OK; + } + } + + if (rc != 0) { + TRACE_ERROR("ica_aes_gcm failed with rc = 0x%lx.\n", rc); + (*out_data_len) = 0; + rc = CKR_FUNCTION_FAILED; + } + +done: + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + +CK_RV token_specific_aes_gcm_update(STDLL_TokData_t *tokdata, SESSION *sess, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_BYTE encrypt) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + OBJECT *key = NULL; + AES_GCM_CONTEXT *context = NULL; + CK_GCM_PARAMS *aes_gcm_param = NULL; + CK_ULONG total, tag_data_len, remain, auth_data_len; + CK_ULONG out_len; + CK_BYTE *auth_data, *tag_data; + CK_BYTE *ucb, *subkey; + CK_BYTE *buffer = NULL; + + UNUSED(tokdata); + UNUSED(sess); + + context = (AES_GCM_CONTEXT *) ctx->context; + total = (context->len + in_data_len); + ucb = (CK_BYTE *) context->ucb; + tag_data = context->hash; + auth_data_len = context->ulAlen; + subkey = (CK_BYTE *) context->subkey; + + aes_gcm_param = (CK_GCM_PARAMS *) ctx->mech.pParameter; + tag_data_len = (aes_gcm_param->ulTagBits + 7) / 8; + auth_data = (CK_BYTE *) aes_gcm_param->pAAD; + + /* if there isn't enough data to make a block, just save it */ + if (encrypt) { + remain = (total % AES_BLOCK_SIZE); + if (total < AES_BLOCK_SIZE) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + *out_data_len = 0; + return CKR_OK; + } + } else { + /* decrypt */ + remain = ((total - tag_data_len) % AES_BLOCK_SIZE) + + tag_data_len; + if (total < AES_BLOCK_SIZE + tag_data_len) { + memcpy(context->data + context->len, in_data, in_data_len); + context->len += in_data_len; + *out_data_len = 0; + return CKR_OK; + } + } + + /* At least we have 1 block */ + /* find key object */ + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + /* get key value */ + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + out_len = total - remain; + + buffer = (CK_BYTE *) malloc(out_len); + if (!buffer) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + + if (encrypt) { + /* copy all the leftover data from previous encryption first */ + memcpy(buffer, context->data, context->len); + memcpy(buffer + context->len, in_data, out_len - context->len); + + TRACE_DEVEL("Ciphertext length (%ld bytes).\n", in_data_len); + + rc = ica_aes_gcm_intermediate(buffer, (unsigned int) out_len, + out_data, ucb, auth_data, + (unsigned int) auth_data_len, + tag_data, AES_BLOCK_SIZE, + attr->pValue, + (unsigned int) attr->ulValueLen, + subkey, 1); + + /* save any remaining data */ + if (remain != 0) + memcpy(context->data, in_data + (in_data_len - remain), remain); + context->len = remain; + + } else { + /* decrypt */ + /* copy all the leftover data from previous encryption first */ + if (in_data_len >= tag_data_len) { /* case 1 */ + /* copy complete context to buffer first */ + memcpy(buffer, context->data, context->len); + /* Append in_data to buffer */ + memcpy(buffer + context->len, in_data, out_len - context->len); + /* copy remaining data to context */ + memcpy(context->data, in_data + out_len - context->len, remain); + context->len = remain; + } else { /* case 2 - partial data */ + memcpy(buffer, context->data, AES_BLOCK_SIZE); + memcpy(context->data, context->data + AES_BLOCK_SIZE, + context->len - AES_BLOCK_SIZE); + memcpy(context->data + context->len - AES_BLOCK_SIZE, + in_data, in_data_len); + context->len = context->len - AES_BLOCK_SIZE + in_data_len; + } + + rc = ica_aes_gcm_intermediate(out_data, (unsigned int) out_len, + buffer, ucb, auth_data, + (unsigned int) auth_data_len, + tag_data, + (unsigned int) tag_data_len, + attr->pValue, + (unsigned int) attr->ulValueLen, + subkey, 0); + + } + + if (rc != 0) { + TRACE_ERROR("ica_aes_gcm_update failed with rc = 0x%lx.\n", rc); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + (*out_data_len) = out_len; + + context->ulClen += out_len; + + /* AAD only processed in first update seuence, + * mark it empty for all subsequent calls + */ + context->ulAlen = 0; + +done: + if (buffer) + free(buffer); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + +CK_RV token_specific_aes_gcm_final(STDLL_TokData_t *tokdata, SESSION *sess, + ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_BYTE encrypt) +{ + CK_RV rc = CKR_OK; + CK_ATTRIBUTE *attr = NULL; + OBJECT *key = NULL; + AES_GCM_CONTEXT *context = NULL; + CK_GCM_PARAMS *aes_gcm_param = NULL; + CK_BYTE *icb, *ucb; + CK_BYTE *tag_data, *subkey, *auth_data, *final_tag_data; + CK_ULONG auth_data_len, tag_data_len; + CK_BYTE *buffer = NULL; + + UNUSED(tokdata); + UNUSED(sess); + + /* find key object */ + rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + context = (AES_GCM_CONTEXT *) ctx->context; + ucb = (CK_BYTE *) context->ucb; + icb = (CK_BYTE *) context->icb; + tag_data = context->hash; + subkey = (CK_BYTE *) context->subkey; + + aes_gcm_param = (CK_GCM_PARAMS *) ctx->mech.pParameter; + auth_data = (CK_BYTE *) aes_gcm_param->pAAD; + auth_data_len = aes_gcm_param->ulAADLen; + tag_data_len = (aes_gcm_param->ulTagBits + 7) / 8; + + if (encrypt) { + if (context->len != 0) { + buffer = (CK_BYTE *) malloc(AES_BLOCK_SIZE); + if (!buffer) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memcpy(buffer, context->data, context->len); + + rc = ica_aes_gcm_intermediate(buffer, context->len, + out_data, ucb, auth_data, + context->ulAlen, tag_data, + AES_BLOCK_SIZE, attr->pValue, + (unsigned int) attr->ulValueLen, + subkey, 1); + + if (rc != 0) { + TRACE_ERROR("ica_aes_gcm_intermediate() " + "failed to encrypt\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + context->ulClen += context->len; + *out_data_len = context->len + tag_data_len; + } else { + *out_data_len = tag_data_len; + } + + TRACE_DEVEL("GCM Final: context->len=%ld, tag_data_len=%ld, " + "out_data_len=%ld\n", + context->len, tag_data_len, *out_data_len); + + rc = ica_aes_gcm_last(icb, (unsigned int) auth_data_len, + (unsigned int) context->ulClen, tag_data, + NULL, 0, attr->pValue, + (unsigned int) attr->ulValueLen, subkey, 1); + + if (rc != 0) { + TRACE_ERROR("ica_aes_gcm_final failed with rc = 0x%lx.\n", rc); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + memcpy(out_data + context->len, tag_data, tag_data_len); + } else { + /* decrypt */ + + if (context->len > tag_data_len) { + buffer = (CK_BYTE *) malloc(AES_BLOCK_SIZE); + if (!buffer) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memcpy(buffer, context->data, context->len - tag_data_len); + + rc = ica_aes_gcm_intermediate(out_data, + (unsigned int) context->len - + tag_data_len, buffer, ucb, auth_data, + (unsigned int) context->ulAlen, + tag_data, AES_BLOCK_SIZE, + attr->pValue, + (unsigned int) attr->ulValueLen, + subkey, 0); + + if (rc != 0) { + TRACE_ERROR("ica_aes_gcm_intermediate() " + "failed to decrypt.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + (*out_data_len) = context->len - tag_data_len; + context->ulClen += context->len - tag_data_len; + + } else if (context->len == tag_data_len) { + /* remaining data are tag data */ + *out_data_len = 0; + } else { /* (context->len < tag_data_len) */ + TRACE_ERROR("Incoming data are not consistent.\n"); + rc = CKR_DATA_INVALID; + goto done; + } + + final_tag_data = context->data + context->len - tag_data_len; + + rc = ica_aes_gcm_last(icb, aes_gcm_param->ulAADLen, + context->ulClen, tag_data, final_tag_data, + tag_data_len, attr->pValue, + (unsigned int) attr->ulValueLen, subkey, 0); + if (rc != 0) { + TRACE_ERROR("ica_aes_gcm_final failed with rc = 0x%lx.\n", rc); + rc = CKR_FUNCTION_FAILED; + } + } + +done: + if (buffer) + free(buffer); + + object_put(tokdata, key, TRUE); + key = NULL; + + return rc; +} + +/** + * In libica for AES-OFB Mode it uses one function for both encrypt and decrypt + * The variable direction is used as an indicator either for encrypt or decrypt + * 0 -- Decrypt + * 1 -- Encrypt + */ +CK_RV token_specific_aes_ofb(STDLL_TokData_t *tokdata, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + OBJECT *key, CK_BYTE *init_v, uint_32 direction) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + + UNUSED(tokdata); + + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + + rc = ica_aes_ofb(in_data, out_data, (unsigned long) in_data_len, + attr->pValue, (unsigned int) attr->ulValueLen, + init_v, direction); + + if (rc != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + } + + return rc; +} + +/** + * In libica for AES-CFB Mode it uses one function for both encrypt and decrypt + * The variable direction is used as an indicator either for encrypt or decrypt + * 0 -- Decrypt + * 1 -- Encrypt + */ +CK_RV token_specific_aes_cfb(STDLL_TokData_t *tokdata, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + OBJECT *key, CK_BYTE *init_v, uint_32 lcfb, + uint_32 direction) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + + UNUSED(tokdata); + + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + + rc = ica_aes_cfb(in_data, out_data, (unsigned long) in_data_len, + attr->pValue, (unsigned int) attr->ulValueLen, init_v, + lcfb, direction); + + if (rc != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + } + + return rc; +} + +CK_RV token_specific_aes_mac(STDLL_TokData_t *tokdata, CK_BYTE *message, + CK_ULONG message_len, OBJECT *key, CK_BYTE *mac) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + + UNUSED(tokdata); + + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + + rc = ica_aes_cmac_intermediate(message, (unsigned long) message_len, + attr->pValue, + (unsigned int) attr->ulValueLen, mac); + + if (rc != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + } + + return rc; +} + +CK_RV token_specific_aes_cmac(STDLL_TokData_t *tokdata, CK_BYTE *message, + CK_ULONG message_len, OBJECT *key, CK_BYTE *mac, + CK_BBOOL first, CK_BBOOL last, CK_VOID_PTR *ctx) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + + UNUSED(tokdata); + UNUSED(ctx); + + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + + if (first && last) { + rc = ica_aes_cmac(message, (unsigned long) message_len, + mac, AES_BLOCK_SIZE, + attr->pValue, (unsigned int) attr->ulValueLen, + ICA_ENCRYPT); + } else if (!last) { + rc = ica_aes_cmac_intermediate(message, (unsigned long) message_len, + attr->pValue, + (unsigned int) attr->ulValueLen, + mac); + } else { + rc = ica_aes_cmac_last(message, (unsigned long) message_len, + mac, AES_BLOCK_SIZE, + attr->pValue, (unsigned int) attr->ulValueLen, + mac, ICA_ENCRYPT); + } + + if (rc != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + } + + return rc; +} + +#endif + +typedef struct _REF_MECH_LIST_ELEMENT { + CK_ULONG lica_idx; + CK_MECHANISM_TYPE mech_type; + CK_MECHANISM_INFO mech_info; +} REF_MECH_LIST_ELEMENT; + +static const REF_MECH_LIST_ELEMENT ref_mech_list[] = { + {92, CKM_RSA_PKCS_KEY_PAIR_GEN, + {512, 4096, CKF_HW | CKF_GENERATE_KEY_PAIR} + }, +#if !(NODSA) +// {1, CKM_DSA_KEY_PAIR_GEN, {512, 1024, CKF_HW|CKF_GENERATE_KEY_PAIR}}, +#endif +#if !(NOCDMF) +// {4, CKM_CDMF_KEY_GEN, {0, 0, CKF_HW|CKF_GENERATE}}, +#endif + {80, CKM_DES_KEY_GEN, {8, 8, CKF_HW | CKF_GENERATE}}, + {80, CKM_DES3_KEY_GEN, {24, 24, CKF_HW | CKF_GENERATE}}, + {90, CKM_RSA_PKCS, + {512, 4096, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP | + CKF_SIGN | CKF_VERIFY | CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER} + }, +#if !(NOX509) + {90, CKM_RSA_X_509, + {512, 4096, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP | + CKF_SIGN | CKF_VERIFY | CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER} + }, +#endif + {90, CKM_RSA_PKCS_OAEP, + {512, 4096, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} + }, + {90, CKM_RSA_PKCS_PSS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {90, CKM_SHA1_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, + {90, CKM_SHA224_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, + {90, CKM_SHA256_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, + {90, CKM_SHA384_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, + {90, CKM_SHA512_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, + {190, CKM_SHA1_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {190, CKM_SHA224_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {190, CKM_SHA256_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {190, CKM_SHA384_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {190, CKM_SHA512_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {20, CKM_DES_ECB, + {8, 8, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} + }, + {21, CKM_DES_CBC, + {8, 8, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} + }, + {21, CKM_DES_CBC_PAD, + {8, 8, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} + }, + {41, CKM_DES3_ECB, + {24, 24, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} + }, + {42, CKM_DES3_CBC, + {24, 24, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} + }, + {42, CKM_DES3_CBC_PAD, + {24, 24, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} + }, + {49, CKM_DES3_MAC, {24, 24, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {49, CKM_DES3_MAC_GENERAL, {24, 24, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {49, CKM_DES3_CMAC, {16, 24, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {49, CKM_DES3_CMAC_GENERAL, {16, 24, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {24, CKM_DES_CFB8, {8, 8, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, + {44, CKM_DES_OFB64, {8, 8, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, + {45, CKM_DES_CFB64, {8, 8, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, + {01, CKM_SHA_1, {0, 0, CKF_HW | CKF_DIGEST}}, + {01, CKM_SHA_1_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {01, CKM_SHA_1_HMAC_GENERAL, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {03, CKM_SHA224, {0, 0, CKF_HW | CKF_DIGEST}}, + {03, CKM_SHA256, {0, 0, CKF_HW | CKF_DIGEST}}, + {03, CKM_SHA256_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {03, CKM_SHA256_HMAC_GENERAL, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {04, CKM_SHA384, {0, 0, CKF_HW | CKF_DIGEST}}, + {04, CKM_SHA384_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {04, CKM_SHA384_HMAC_GENERAL, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {05, CKM_SHA512, {0, 0, CKF_HW | CKF_DIGEST}}, + {05, CKM_SHA512_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {05, CKM_SHA512_HMAC_GENERAL, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, +#ifdef SHA512_224 + {95, CKM_SHA512_224, {0, 0, CKF_HW|CKF_DIGEST}}, +#endif +#ifdef SHA512_256 + {96, CKM_SHA512_256, {0, 0, CKF_HW|CKF_DIGEST}}, +#endif +#if !(NOMD5) + {53, CKM_MD5, {0, 0, CKF_HW | CKF_DIGEST}}, + {54, CKM_MD5_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {55, CKM_MD5_HMAC_GENERAL, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, +#endif +#if !(NOAES) + {80, CKM_AES_KEY_GEN, {16, 32, CKF_HW | CKF_GENERATE}}, + {60, CKM_AES_ECB, + {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} + }, + {61, CKM_AES_CBC, + {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} + }, + {61, CKM_AES_CBC_PAD, + {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} + }, + {63, CKM_AES_OFB, + {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} + }, + {64, CKM_AES_CFB8, + {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} + }, + {64, CKM_AES_CFB64, + {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} + }, + {64, CKM_AES_CFB128, + {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} + }, + {65, CKM_AES_CTR, + {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} + }, + {70, CKM_AES_GCM, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, + {68, CKM_AES_MAC, {16, 32, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {68, CKM_AES_MAC_GENERAL, {16, 32, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {68, CKM_AES_CMAC, {16, 32, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {68, CKM_AES_CMAC_GENERAL, {16, 32, CKF_HW | CKF_SIGN | CKF_VERIFY}}, +#endif + {80, CKM_GENERIC_SECRET_KEY_GEN, {80, 2048, CKF_HW | CKF_GENERATE}}, +#ifndef NO_EC + {85, CKM_ECDH1_DERIVE, + {160, 521, CKF_HW | CKF_DERIVE | CKF_EC_NAMEDCURVE | CKF_EC_F_P} + }, + {86, CKM_ECDSA, + {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE | CKF_EC_F_P} + }, + {86, CKM_ECDSA_SHA1, + {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE | CKF_EC_F_P} + }, + {86, CKM_ECDSA_SHA224, + {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE | CKF_EC_F_P} + }, + {86, CKM_ECDSA_SHA256, + {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE | CKF_EC_F_P} + }, + {86, CKM_ECDSA_SHA384, + {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE | CKF_EC_F_P} + }, + {86, CKM_ECDSA_SHA512, + {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE | CKF_EC_F_P} + }, + {88, CKM_EC_KEY_PAIR_GEN, + {160, 521, CKF_HW | CKF_GENERATE_KEY_PAIR | CKF_EC_NAMEDCURVE | CKF_EC_F_P} + }, +#endif + +}; + +static const CK_ULONG ref_mech_list_len = + (sizeof(ref_mech_list) / sizeof(REF_MECH_LIST_ELEMENT)); + +CK_RV token_specific_get_mechanism_list(STDLL_TokData_t *tokdata, + CK_MECHANISM_TYPE_PTR pMechanismList, + CK_ULONG_PTR pulCount) +{ + return ock_generic_get_mechanism_list(tokdata, pMechanismList, pulCount); +} + + +CK_RV token_specific_get_mechanism_info(STDLL_TokData_t *tokdata, + CK_MECHANISM_TYPE type, + CK_MECHANISM_INFO_PTR pInfo) +{ + return ock_generic_get_mechanism_info(tokdata, type, pInfo); +} + +static CK_RV getRefListIdxfromId(CK_ULONG ica_idx, CK_ULONG_PTR pRefIdx) +{ + unsigned int n; + + for (n = *pRefIdx; n < ref_mech_list_len; n++) { + if (ica_idx == ref_mech_list[n].lica_idx) { + *pRefIdx = n; + return CKR_OK; + } + } + + return CKR_MECHANISM_INVALID; +} + +static CK_RV getRefListIdxfromMech(CK_ULONG mech, CK_ULONG_PTR pRefIdx) +{ + unsigned int n; + + for (n = *pRefIdx; n < ref_mech_list_len; n++) { + if (mech == ref_mech_list[n].mech_type) { + *pRefIdx = n; + return CKR_OK; + } + } + return CKR_MECHANISM_INVALID; +} + +static CK_BBOOL isMechanismAvailable(STDLL_TokData_t *tokdata, + CK_ULONG mechanism) +{ + ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; + unsigned int i; + + for (i = 0; i < ica_data->mech_list_len; i++) { + if (ica_data->mech_list[i].mech_type == mechanism) + return TRUE; + } + + return FALSE; +} + +static CK_RV addMechanismToList(STDLL_TokData_t *tokdata, CK_ULONG mechanism) +{ + ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; + CK_ULONG ret; + CK_ULONG refIdx = 0; + + if (ica_data->mech_list_len >= ICA_MAX_MECH_LIST_ENTRIES) { + TRACE_ERROR("Not enough slots available to add mechanism\n"); + return CKR_BUFFER_TOO_SMALL; + } + + ret = getRefListIdxfromMech(mechanism, &refIdx); + if (ret != CKR_OK) { + return CKR_FUNCTION_FAILED; + } + ica_data->mech_list[ica_data->mech_list_len].mech_type = ref_mech_list[refIdx].mech_type; + ica_data->mech_list[ica_data->mech_list_len].mech_info.flags = + (ref_mech_list[refIdx].mech_info.flags & 0xfffffffe); + ica_data->mech_list[ica_data->mech_list_len].mech_info.ulMinKeySize = + ref_mech_list[refIdx].mech_info.ulMinKeySize; + ica_data->mech_list[ica_data->mech_list_len].mech_info.ulMaxKeySize = + ref_mech_list[refIdx].mech_info.ulMaxKeySize; + ica_data->mech_list_len++; + + return CKR_OK; +} + +/* + * call libica to receive list of supported mechanisms + * This method is called once per opencryptoki instance (application context) + */ +static CK_RV mech_list_ica_initialize(STDLL_TokData_t *tokdata) +{ + ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; + CK_ULONG ret, rc = CKR_OK; + unsigned int i, n; + unsigned int ica_specific_mech_list_len; + CK_ULONG tmp, ulActMechCtr, ulPreDefMechCtr, refIdx; + + ica_data->mech_list[0].mech_type = CKF_DIGEST; + ica_data->mech_list[0].mech_info.flags = CKF_DIGEST; + ica_data->mech_list[1].mech_type = CKM_MD5_HMAC; + ica_data->mech_list[1].mech_info.flags = CKF_SIGN | CKF_VERIFY; + ica_data->mech_list[2].mech_type = CKM_MD5_HMAC_GENERAL; + ica_data->mech_list[2].mech_info.flags = CKF_SIGN | CKF_VERIFY; + ica_data->mech_list_len = 3; + + rc = ica_get_functionlist(NULL, &ica_specific_mech_list_len); + if (rc != CKR_OK) { + TRACE_ERROR("ica_get_functionlist failed\n"); + return CKR_FUNCTION_FAILED; + } + libica_func_list_element libica_func_list[ica_specific_mech_list_len]; + rc = ica_get_functionlist(libica_func_list, &ica_specific_mech_list_len); + if (rc != CKR_OK) { + TRACE_ERROR("ica_get_functionlist failed\n"); + return CKR_FUNCTION_FAILED; + } + + /* + * grab the mechanism of the corresponding ID returned by libICA + * from the internal reference list put the mechanism ID and the + * HW support indication into an internal ica_mech_list and get + * additional flag information from the reference list + */ + ulPreDefMechCtr = ica_data->mech_list_len; + for (i = 0; i < ica_specific_mech_list_len; i++) { + + if (libica_func_list[i].flags == 0) + continue; + + // loop over libica supported list + ulActMechCtr = (CK_ULONG)(-1); + + /* --- walk through the whole reflist and fetch all + * matching mechanism's (if present) --- + */ + refIdx = 0; + while ((ret = getRefListIdxfromId(libica_func_list[i].mech_mode_id, + &refIdx)) == CKR_OK) { + /* + * Loop over the predefined mechanism list and check + * if we have to overrule a software implemented + * mechanism from token by libica HW supported + * mechanism. + */ + for (n = 0; n < ulPreDefMechCtr; n++) { + if (ica_data->mech_list[n].mech_type == + ref_mech_list[refIdx].mech_type) { + ulActMechCtr = n; + break; + } + } + if (ulActMechCtr == (CK_ULONG)(-1)) { + /* add a new entry */ + if (ica_data->mech_list_len >= ICA_MAX_MECH_LIST_ENTRIES) { + TRACE_ERROR("Not enough slots available to add mechanism\n"); + return CKR_BUFFER_TOO_SMALL; + } + ica_data->mech_list[ica_data->mech_list_len].mech_type = + ref_mech_list[refIdx].mech_type; + ica_data->mech_list[ica_data->mech_list_len].mech_info.flags = + (libica_func_list[i].flags & 0x01) | + (ref_mech_list[refIdx].mech_info.flags & 0xfffffffe); + ica_data->mech_list[ica_data->mech_list_len].mech_info.ulMinKeySize = + ref_mech_list[refIdx].mech_info.ulMinKeySize; + ica_data->mech_list[ica_data->mech_list_len].mech_info.ulMaxKeySize = + ref_mech_list[refIdx].mech_info.ulMaxKeySize; + ica_data->mech_list_len++; + } else { + /* replace existing entry */ + ica_data->mech_list[ulActMechCtr].mech_info.flags = + (libica_func_list[i].flags & 0x01) | + ica_data->mech_list[ulActMechCtr].mech_info.flags; + } + refIdx++; + } + } + + /* + * check if special combined mechanisms are supported + * if SHA1 and RSA is available -> insert CKM_SHA1_RSA_PKCS + * if SHA256 and RSA is available -> insert CKM_SHA256_RSA_PKCS + * if MD2 and RSA is available -> insert CKM_MD2_RSA_PKCS + * if MD5 and RSA is available -> insert CKM_MD5_RSA_PKCS + */ + if (isMechanismAvailable(tokdata, CKM_SHA_1) && + isMechanismAvailable(tokdata, CKM_RSA_PKCS)) + addMechanismToList(tokdata, CKM_SHA1_RSA_PKCS); + if (isMechanismAvailable(tokdata, CKM_SHA224) && + isMechanismAvailable(tokdata, CKM_RSA_PKCS)) + addMechanismToList(tokdata, CKM_SHA224_RSA_PKCS); + if (isMechanismAvailable(tokdata, CKM_SHA256) && + isMechanismAvailable(tokdata, CKM_RSA_PKCS)) + addMechanismToList(tokdata, CKM_SHA256_RSA_PKCS); + if (isMechanismAvailable(tokdata, CKM_SHA384) && + isMechanismAvailable(tokdata, CKM_RSA_PKCS)) + addMechanismToList(tokdata, CKM_SHA384_RSA_PKCS); + if (isMechanismAvailable(tokdata, CKM_SHA512) && + isMechanismAvailable(tokdata, CKM_RSA_PKCS)) + addMechanismToList(tokdata, CKM_SHA512_RSA_PKCS); + if (isMechanismAvailable(tokdata, CKM_MD2) && + isMechanismAvailable(tokdata, CKM_RSA_PKCS)) + addMechanismToList(tokdata, CKM_MD2_RSA_PKCS); + if (isMechanismAvailable(tokdata, CKM_MD5) && + isMechanismAvailable(tokdata, CKM_RSA_PKCS)) + addMechanismToList(tokdata, CKM_MD5_RSA_PKCS); + + /* sort the mech_list_ica by mechanism ID's (bubble sort) */ + for (i = 0; i < ica_data->mech_list_len; i++) { + for (n = i; n < ica_data->mech_list_len; n++) { + if (ica_data->mech_list[i].mech_type > ica_data->mech_list[n].mech_type) { + tmp = ica_data->mech_list[i].mech_type; + ica_data->mech_list[i].mech_type = ica_data->mech_list[n].mech_type; + ica_data->mech_list[n].mech_type = tmp; + + tmp = ica_data->mech_list[i].mech_info.ulMinKeySize; + ica_data->mech_list[i].mech_info.ulMinKeySize = + ica_data->mech_list[n].mech_info.ulMinKeySize; + ica_data->mech_list[n].mech_info.ulMinKeySize = tmp; + + tmp = ica_data->mech_list[i].mech_info.ulMaxKeySize; + ica_data->mech_list[i].mech_info.ulMaxKeySize = + ica_data->mech_list[n].mech_info.ulMaxKeySize; + ica_data->mech_list[n].mech_info.ulMaxKeySize = tmp; + + tmp = ica_data->mech_list[i].mech_info.flags; + ica_data->mech_list[i].mech_info.flags = ica_data->mech_list[n].mech_info.flags; + ica_data->mech_list[n].mech_info.flags = tmp; + } + } + } + + return rc; +} + +CK_RV token_specific_generic_secret_key_gen(STDLL_TokData_t *tokdata, + TEMPLATE *tmpl) +{ + CK_ATTRIBUTE *attr = NULL; + CK_RV rc = CKR_OK; + CK_BYTE secret_key[MAX_GENERIC_KEY_SIZE]; + CK_ULONG key_length = 0; + CK_ULONG key_length_in_bits = 0; + CK_ATTRIBUTE *value_attr = NULL; + + rc = template_attribute_find(tmpl, CKA_VALUE_LEN, &attr); + if (rc == FALSE) { + TRACE_ERROR("CKA_VALUE_LEM missing in key template\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + + key_length = *(CK_ULONG *) attr->pValue; //app specified key length in bytes + key_length_in_bits = key_length * 8; + + /* After looking at fips cavs test vectors for HMAC ops, + * it was decided that the key length should fall between + * 80 and 2048 bits inclusive. + */ + if ((key_length_in_bits < 80) || (key_length_in_bits > 2048)) { + TRACE_ERROR("Generic secret key size of %lu bits not within" + " required range of 80-2048 bits\n", key_length_in_bits); + return CKR_KEY_SIZE_RANGE; + } + + /* libica does not have generic secret key generation, + * so call token rng here. + */ + rc = rng_generate(tokdata, secret_key, key_length); + if (rc != CKR_OK) { + TRACE_DEVEL("Generic secret key generation failed.\n"); + return rc; + } + + rc = build_attribute(CKA_VALUE, secret_key, key_length, &value_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute(CKA_VALUE) failed\n"); + return rc; + } + rc = template_update_attribute(tmpl, value_attr); + if (rc != CKR_OK) + TRACE_DEVEL("template_update_attribute(CKA_VALUE) failed\n"); + + return rc; +} + +#ifndef NO_EC +static CK_RV build_update_attribute(TEMPLATE *tmpl, + CK_ATTRIBUTE_TYPE type, + CK_BYTE *data, CK_ULONG data_len) +{ + CK_ATTRIBUTE *attr; + CK_RV rv; + + if ((rv = build_attribute(type, data, data_len, &attr))) + return rv; + + template_update_attribute(tmpl, attr); + + return CKR_OK; +} + +static CK_RV is_equal(unsigned char *a, + unsigned int a_length, + unsigned char *b, unsigned int b_length) +{ + if (a_length != b_length) + return 0; + + if (memcmp(a, b, a_length) == 0) + return 1; + + return 0; +} + +static int nid_from_oid(CK_BYTE *oid, CK_ULONG oid_length) +{ + /* Supported Elliptic Curves */ + static const CK_BYTE brainpoolP160r1[] = + { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x01 }; + static const CK_BYTE brainpoolP192r1[] = + { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x03 }; + static const CK_BYTE brainpoolP224r1[] = + { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x05 }; + static const CK_BYTE brainpoolP256r1[] = + { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07 }; + static const CK_BYTE brainpoolP320r1[] = + { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x09 }; + static const CK_BYTE brainpoolP384r1[] = + { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B }; + static const CK_BYTE brainpoolP512r1[] = + { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D }; + static const CK_BYTE prime192[] = + { 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x01 }; + static const CK_BYTE secp224[] = { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x21 }; + static const CK_BYTE prime256[] = + { 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 }; + static const CK_BYTE secp384[] = { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22 }; + static const CK_BYTE secp521[] = { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23 }; + + if (is_equal + (oid, oid_length, (unsigned char *) &prime192, sizeof(prime192))) + return NID_X9_62_prime192v1; + else if (is_equal(oid, oid_length, + (unsigned char *) &secp224, sizeof(secp224))) + return NID_secp224r1; + else if (is_equal(oid, oid_length, + (unsigned char *) &prime256, sizeof(prime256))) + return NID_X9_62_prime256v1; + else if (is_equal(oid, oid_length, + (unsigned char *) &secp384, sizeof(secp384))) + return NID_secp384r1; + else if (is_equal(oid, oid_length, + (unsigned char *) &secp521, sizeof(secp521))) + return NID_secp521r1; + else if (is_equal(oid, oid_length, + (unsigned char *) &brainpoolP160r1, + sizeof(brainpoolP160r1))) + return NID_brainpoolP160r1; + else if (is_equal(oid, oid_length, + (unsigned char *) &brainpoolP192r1, + sizeof(brainpoolP192r1))) + return NID_brainpoolP192r1; + else if (is_equal(oid, oid_length, + (unsigned char *) &brainpoolP224r1, + sizeof(brainpoolP224r1))) + return NID_brainpoolP224r1; + else if (is_equal(oid, oid_length, + (unsigned char *) &brainpoolP256r1, + sizeof(brainpoolP256r1))) + return NID_brainpoolP256r1; + else if (is_equal(oid, oid_length, + (unsigned char *) &brainpoolP320r1, + sizeof(brainpoolP320r1))) + return NID_brainpoolP320r1; + else if (is_equal(oid, oid_length, + (unsigned char *) &brainpoolP384r1, + sizeof(brainpoolP384r1))) + return NID_brainpoolP384r1; + else if (is_equal(oid, oid_length, + (unsigned char *) &brainpoolP512r1, + sizeof(brainpoolP512r1))) + return NID_brainpoolP512r1; + + return -1; +} + +CK_RV token_specific_ec_generate_keypair(STDLL_TokData_t *tokdata, + TEMPLATE *publ_tmpl, + TEMPLATE *priv_tmpl) +{ + ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; + CK_RV ret = CKR_OK; + CK_ATTRIBUTE *attr = NULL; + ICA_EC_KEY *eckey; + CK_BYTE q_array[1 + ICATOK_EC_MAX_Q_LEN]; + CK_BYTE d_array[ICATOK_EC_MAX_D_LEN]; + unsigned int privlen, q_len, d_len; + CK_BYTE *ecpoint = NULL; + CK_ULONG ecpoint_len; + int rc, nid; + + if (!ica_data->ica_ec_support_available) { + TRACE_ERROR("ECC support is not available in Libica\n"); + return CKR_FUNCTION_NOT_SUPPORTED; + } + + if (!template_attribute_find(publ_tmpl, CKA_ECDSA_PARAMS, &attr)) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + /* Determine curve nid */ + nid = nid_from_oid(attr->pValue, attr->ulValueLen); + if (nid < 0) { + TRACE_ERROR("curve not supported by icatoken.\n"); + return CKR_CURVE_NOT_SUPPORTED; + } + + /* Create ICA_EC_KEY object */ + eckey = p_ica_ec_key_new(nid, &privlen); + if (!eckey) { + TRACE_ERROR("ica_ec_key_new() failed.\n"); + return CKR_FUNCTION_FAILED; + } + + /* Generate key data for this key object */ + rc = p_ica_ec_key_generate(ica_data->adapter_handle, eckey); + if (rc != 0) { + TRACE_ERROR("ica_ec_key_generate() failed with rc=%d.\n", rc); + ret = CKR_FUNCTION_FAILED; + goto end; + } + + /* Return public key (X,Y) via CKA_EC_POINT as OCTET STRING */ + rc = p_ica_ec_key_get_public_key(eckey, (unsigned char *)&q_array[1], + &q_len); + if (rc != 0) { + TRACE_ERROR("ica_ec_key_get_public_key() failed with rc=%d.\n", rc); + ret = CKR_FUNCTION_FAILED; + goto end; + } + + q_array[0] = POINT_CONVERSION_UNCOMPRESSED; + q_len++; + + rc = ber_encode_OCTET_STRING(FALSE, &ecpoint, &ecpoint_len, q_array, q_len); + if (rc != CKR_OK) { + TRACE_DEVEL("ber_encode_OCTET_STRING failed\n"); + goto end; + } + + ret = build_update_attribute(publ_tmpl, CKA_EC_POINT, ecpoint, ecpoint_len); + if (ret != 0) { + TRACE_ERROR("build_update_attribute for (X,Y) failed rc=0x%lx\n", ret); + goto end; + } + + /* Return private key (D) via CKA_VALUE */ + rc = p_ica_ec_key_get_private_key(eckey, (unsigned char *) &d_array, + &d_len); + if (rc != 0) { + TRACE_ERROR("ica_ec_key_get_private_key() failed with rc=%d.\n", rc); + ret = CKR_FUNCTION_FAILED; + goto end; + } + + ret = build_update_attribute(priv_tmpl, CKA_VALUE, d_array, d_len); + if (ret != 0) { + TRACE_ERROR("build_update_attribute for (D) failed, rc=0x%lx\n", ret); + goto end; + } + + /* Add CKA_ECDSA_PARAMS to private template also */ + ret = build_update_attribute(priv_tmpl, CKA_ECDSA_PARAMS, attr->pValue, + attr->ulValueLen); + if (ret != 0) { + TRACE_ERROR("build_update_attribute for CKA_ECDSA_PARAMS failed, " + "rc=0x%lx\n", ret); + goto end; + } + + ret = CKR_OK; + +end: + p_ica_ec_key_free(eckey); + if (ecpoint != NULL) + free(ecpoint); + + return ret; +} + +CK_RV token_specific_ec_sign(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) +{ + ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; + CK_RV ret = CKR_OK; + CK_ATTRIBUTE *attr, *attr2; + ICA_EC_KEY *eckey; + unsigned int privlen; + int rc, nid; + + UNUSED(sess); + + *out_data_len = 0; + + if (!ica_data->ica_ec_support_available) { + TRACE_ERROR("ECC support is not available in Libica\n"); + return CKR_FUNCTION_NOT_SUPPORTED; + } + + /* Get CKA_ECDSA_PARAMS from template */ + if (!template_attribute_find(key_obj->template, CKA_ECDSA_PARAMS, &attr)) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + /* Determine curve nid */ + nid = nid_from_oid(attr->pValue, attr->ulValueLen); + if (nid < 0) { + TRACE_ERROR("Cannot determine curve nid. \n"); + return CKR_CURVE_NOT_SUPPORTED; + } + + /* Create ICA_EC_KEY object */ + eckey = p_ica_ec_key_new(nid, &privlen); + if (!eckey) { + TRACE_ERROR("ica_ec_key_new() failed for curve %i.\n", nid); + return CKR_FUNCTION_FAILED; + } + + /* Get private key from template via CKA_VALUE */ + if (!template_attribute_find(key_obj->template, CKA_VALUE, &attr2)) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + ret = CKR_TEMPLATE_INCOMPLETE; + goto end; + } + + /* Plausibility check */ + if (privlen != attr2->ulValueLen) { + TRACE_ERROR("Private key length for curve %i mismatch: length from " + "ica_ec_key_new() = %i, length from attribute = %ld", + nid, privlen, attr2->ulValueLen); + ret = CKR_ATTRIBUTE_VALUE_INVALID; + goto end; + } + + /* Initialize ICA_EC_KEY with private key (D) */ + rc = p_ica_ec_key_init(NULL, NULL, attr2->pValue, eckey); + if (rc != 0) { + TRACE_ERROR("ica_ec_key_init() failed with rc = %d \n", rc); + ret = CKR_FUNCTION_FAILED; + goto end; + } + + /* Create signature */ + rc = p_ica_ecdsa_sign(ica_data->adapter_handle, eckey, + (unsigned char *) in_data, + (unsigned int) in_data_len, + (unsigned char *) out_data, 2 * privlen); + if (rc != 0) { + TRACE_ERROR("ica_ecdsa_sign() failed with rc = %d. \n", rc); + ret = CKR_FUNCTION_FAILED; + goto end; + } + + *out_data_len = 2 * privlen; + ret = CKR_OK; + +end: + p_ica_ec_key_free(eckey); + + return ret; +} + +/** + * decompress the given compressed public key. Sets x from given pub_key, + * re-calculates y from format byte, x and nid. + * + * @return 0 on success + */ +static CK_RV decompress_pubkey(unsigned int nid, + const unsigned char *pub_key, + CK_ULONG pub_len, + unsigned int priv_len, + unsigned char *x, unsigned char *y) +{ + BN_CTX *ctx = BN_CTX_new(); + BIGNUM *bn_x = BN_bin2bn((unsigned char *) &(pub_key[1]), priv_len, NULL); + BIGNUM *bn_y = BN_new(); + EC_GROUP *group = NULL; + EC_POINT *point = NULL; + int y_bit = (pub_key[0] == POINT_CONVERSION_COMPRESSED ? 0 : 1); + CK_RV ret = CKR_OK; + + UNUSED(pub_len); + + group = EC_GROUP_new_by_curve_name(nid); + if (!group) { + TRACE_ERROR("Curve %d is not supported by openssl. Cannot decompress " + "public key\n", nid); + ret = CKR_CURVE_NOT_SUPPORTED; + goto end; + } + + point = EC_POINT_new(group); + if (!point) { + ret = CKR_FUNCTION_FAILED; + goto end; + } + + if (!EC_POINT_set_compressed_coordinates_GFp(group, + point, bn_x, y_bit, ctx)) { + ret = CKR_FUNCTION_FAILED; + goto end; + } + + if (!EC_POINT_is_on_curve(group, point, ctx)) { + ret = CKR_FUNCTION_FAILED; + goto end; + } + + if (!EC_POINT_get_affine_coordinates_GFp(group, point, bn_x, bn_y, ctx)) { + ret = CKR_FUNCTION_FAILED; + goto end; + } + + memcpy(x, &(pub_key[1]), priv_len); + BN_bn2bin(bn_y, y); + +end: + if (ctx) + BN_CTX_free(ctx); + if (point) + EC_POINT_free(point); + if (group) + EC_GROUP_free(group); + if (bn_x) + BN_free(bn_x); + if (bn_y) + BN_free(bn_y); + + return ret; +} + +/** + * returns the (X,Y) coordinates of the given EC public key. + * For a compressed key, Y is calculated from X and an indication + * if Y is even or odd. + * + * Refer to X9.62, section 4.3.6, "point to octet-string conversion". + * + * @return 0 on success + */ +static CK_RV set_pubkey_coordinates(unsigned int nid, + const unsigned char *pub_key, + CK_ULONG pub_len, + unsigned int priv_len, + unsigned char *x, unsigned char *y) +{ + int i, n; + + /* Check if key has no format byte: [X || Y] */ + if (pub_len == 2 * priv_len) { + memcpy(x, pub_key, priv_len); + memcpy(y, pub_key + priv_len, priv_len); + return CKR_OK; + } + + /* Check if key is compressed: [0x0n || X] + * 0x0n: 0x02: Y is even + * 0x03: Y is odd + */ + if (pub_len == priv_len + 1 && + (pub_key[0] == POINT_CONVERSION_COMPRESSED || + pub_key[0] == POINT_CONVERSION_COMPRESSED + 1)) { + return decompress_pubkey(nid, pub_key, pub_len, priv_len, x, y); + } + + /* Check if key is uncompressed or hybrid: [0x0n || X || Y] + * 0x0n: 0x04 : uncompressed + * 0c06 : hybrid, Y is even + * 0x07 : hybrid, Y is odd + */ + if (pub_len == 2 * priv_len + 1 && + (pub_key[0] == POINT_CONVERSION_UNCOMPRESSED || + pub_key[0] == POINT_CONVERSION_HYBRID || + pub_key[0] == POINT_CONVERSION_HYBRID + 1)) { + memcpy(x, pub_key + 1, priv_len); + memcpy(y, pub_key + 1 + priv_len, priv_len); + return CKR_OK; + } + + /* Add leading null bytes to pub_key X, if necessary. In this + * case there is no format byte */ + if (pub_len < 2 * priv_len) { + n = 2 * priv_len - pub_len; + for (i = 0; i < n; i++) + x[i] = 0x00; + memcpy(x + i, pub_key, priv_len - n); + memcpy(y, pub_key + priv_len - n, priv_len); + return CKR_OK; + } + + memset(x, 0, priv_len); + memset(y, 0, priv_len); + + return CKR_FUNCTION_FAILED; +} + + +CK_RV token_specific_ec_verify(STDLL_TokData_t *tokdata, + SESSION *sess, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *signature, + CK_ULONG signature_len, OBJECT *key_obj) +{ + ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; + CK_RV ret = CKR_OK; + CK_ATTRIBUTE *attr, *attr2; + ICA_EC_KEY *eckey; + unsigned int privlen; + unsigned char x_array[ICATOK_EC_MAX_D_LEN]; + unsigned char y_array[ICATOK_EC_MAX_D_LEN]; + int rc, nid; + CK_BYTE *ecpoint; + CK_ULONG ecpoint_len, field_len; + + UNUSED(sess); + + if (!ica_data->ica_ec_support_available) { + TRACE_ERROR("ECC support is not available in Libica\n"); + return CKR_FUNCTION_NOT_SUPPORTED; + } + + /* Get CKA_ECDSA_PARAMS from template */ + if (!template_attribute_find(key_obj->template, CKA_ECDSA_PARAMS, &attr)) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + /* Create ICA_EC_KEY object */ + nid = nid_from_oid(attr->pValue, attr->ulValueLen); + if (nid < 0) { + TRACE_ERROR("Cannot determine curve nid. \n"); + return CKR_CURVE_NOT_SUPPORTED; + } + + eckey = p_ica_ec_key_new(nid, &privlen); + if (!eckey) { + TRACE_ERROR("ica_ec_key_new() failed for curve %i. \n", nid); + return CKR_FUNCTION_FAILED; + } + + /* Get public key (X,Y) from template via CKA_EC_POINT */ + if (!template_attribute_find(key_obj->template, CKA_EC_POINT, &attr2)) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + ret = CKR_TEMPLATE_INCOMPLETE; + goto end; + } + + /* CKA_EC_POINT contains the EC point as OCTET STRING */ + ret = ber_decode_OCTET_STRING(attr2->pValue, &ecpoint, &ecpoint_len, + &field_len); + if (ret != CKR_OK || field_len != attr2->ulValueLen) { + TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); + ret = CKR_ATTRIBUTE_VALUE_INVALID; + goto end; + } + + /* Signature length ok? */ + if (signature_len != 2 * privlen) { + TRACE_ERROR("Supplied signature length mismatch: " + "supplied length = %ld, length from libica = %i\n", + signature_len, 2 * privlen); + ret = CKR_SIGNATURE_LEN_RANGE; + goto end; + } + + /* Provide (X,Y), decompress key if necessary */ + ret = set_pubkey_coordinates(nid, ecpoint, ecpoint_len, + privlen, x_array, y_array); + if (ret != 0) { + TRACE_ERROR("Cannot determine public key coordinates from " + "given public key\n"); + goto end; + } + + /* Initialize ICA_EC_KEY with public key (Q) */ + rc = p_ica_ec_key_init(x_array, y_array, NULL, eckey); + if (rc != 0) { + TRACE_ERROR("ica_ec_key_init() for public key failed " + "with rc = %d \n", rc); + ret = CKR_FUNCTION_FAILED; + goto end; + } + + /* Verify signature */ + rc = p_ica_ecdsa_verify(ica_data->adapter_handle, + eckey, + (unsigned char *) in_data, + (unsigned int) in_data_len, + (unsigned char *) signature, signature_len); + switch (rc) { + case 0: + ret = CKR_OK; + break; + case EFAULT: + TRACE_ERROR("ica_ecdsa_verify() returned invalid signature, " + "rc = %d. \n", rc); + ret = CKR_SIGNATURE_INVALID; + break; + default: + TRACE_ERROR("ica_ecdsa_verify() returned internal error, " + "rc = %d. \n", rc); + ret = CKR_FUNCTION_FAILED; + break; + } + +end: + p_ica_ec_key_free(eckey); + + return ret; +} + +CK_RV token_specific_ecdh_pkcs_derive(STDLL_TokData_t *tokdata, + CK_BYTE *priv_bytes, + CK_ULONG priv_length, + CK_BYTE *pub_bytes, + CK_ULONG pub_length, + CK_BYTE *secret_value, + CK_ULONG *secret_value_len, + CK_BYTE *oid, CK_ULONG oid_length) +{ + ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; + CK_RV ret = CKR_OK; + ICA_EC_KEY *pubkey = NULL, *privkey = NULL; + unsigned int n, privlen, i; + unsigned char d_array[ICATOK_EC_MAX_D_LEN]; + unsigned char x_array[ICATOK_EC_MAX_D_LEN]; + unsigned char y_array[ICATOK_EC_MAX_D_LEN]; + int rc, nid; + CK_BYTE *ecpoint; + CK_ULONG ecpoint_len, field_len; + + UNUSED(tokdata); + + *secret_value_len = 0; + + if (!ica_data->ica_ec_support_available) { + TRACE_ERROR("ECC support is not available in Libica\n"); + return CKR_FUNCTION_NOT_SUPPORTED; + } + + /* Get nid from oid */ + nid = nid_from_oid(oid, oid_length); + if (nid < 0) { + TRACE_ERROR("curve not supported by icatoken.\n"); + return CKR_CURVE_NOT_SUPPORTED; + } + + /* Create ICA_EC_KEY object with public key */ + pubkey = p_ica_ec_key_new(nid, &privlen); + if (!pubkey) { + TRACE_ERROR("ica_ec_key_new() for curve %i failed.\n", nid); + return CKR_FUNCTION_FAILED; + } + + /* As per PKCS#11, a token MUST be able to accept this value encoded + * as a raw octet string (as per section A.5.2 of [ANSI X9.62]). + * A token MAY, in addition, support accepting this value as a + * DER-encoded ECPoint (as per section E.6 of [ANSI X9.62]) i.e. + * the same as a CKA_EC_POINT encoding. + */ + ret = ber_decode_OCTET_STRING(pub_bytes, &ecpoint, &ecpoint_len, + &field_len); + if (ret != CKR_OK || field_len != pub_length || + ecpoint_len > pub_length - 2) { + /* no valid BER OCTET STRING encoding, assume raw octet string */ + ecpoint = pub_bytes; + ecpoint_len = pub_length; + } + + /* Provide (X,Y), decompress key if necessary */ + ret = set_pubkey_coordinates(nid, ecpoint, ecpoint_len, + privlen, x_array, y_array); + if (ret != 0) { + TRACE_ERROR("Cannot determine public key coordinates\n"); + goto end; + } + + /* Format (D) as char array with leading nulls if necessary */ + n = privlen - priv_length; + for (i = 0; i < n; i++) + d_array[i] = 0x00; + memcpy(&(d_array[n]), priv_bytes, priv_length); + + /* Initialize ICA_EC_KEY with public key (X,Y) */ + rc = p_ica_ec_key_init(x_array, y_array, NULL, pubkey); + if (rc != 0) { + TRACE_ERROR("ica_ec_key_init() for public key failed with " + "rc = %d \n", rc); + ret = CKR_FUNCTION_FAILED; + goto end; + } + + /* Create ICA_EC_KEY object with private key */ + privkey = p_ica_ec_key_new(nid, &privlen); + if (!privkey) { + TRACE_ERROR("ica_ec_key_new() for curve %i failed. \n", nid); + ret = CKR_FUNCTION_FAILED; + goto end; + } + + /* Initialize ICA_EC_KEY with private key (D) */ + rc = p_ica_ec_key_init(NULL, NULL, d_array, privkey); + if (rc != 0) { + TRACE_ERROR("ica_ec_key_init() for private key failed with " + "rc = %d \n", rc); + ret = CKR_FUNCTION_FAILED; + goto end; + } + + /* Calculate shared secret z */ + rc = p_ica_ecdh_derive_secret(ica_data->adapter_handle, privkey, + pubkey, secret_value, privlen); + if (rc != 0) { + TRACE_ERROR("ica_ecdh_derive_secret() failed with rc = %d. \n", rc); + ret = CKR_FUNCTION_FAILED; + goto end; + } + + *secret_value_len = privlen; + ret = CKR_OK; + +end: + p_ica_ec_key_free(privkey); + p_ica_ec_key_free(pubkey); + + return ret; +} +#endif diff --git a/usr/lib/ica_s390_stdll/tok_struct.h b/usr/lib/ica_s390_stdll/tok_struct.h new file mode 100644 index 0000000..2b9f421 --- /dev/null +++ b/usr/lib/ica_s390_stdll/tok_struct.h @@ -0,0 +1,147 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2002-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 + */ + +// SAB FIXME need to figure out a better way... +// // to get the variant dependency out +#ifndef __TOK_STRUCT_H +#define __TOK_STRUCT_H +#include + +#include "tok_spec_struct.h" + +#ifndef LITE_CONFIG_PATH + +#ifndef CONFIG_PATH +#warning CONFIG_PATH not set, using default (/usr/local/var/lib/opencryptoki) +#define CONFIG_PATH "/usr/local/var/lib/opencryptoki" +#endif // #ifndef CONFIG_PATH + +#define LITE_CONFIG_PATH CONFIG_PATH "/lite" +#endif // #ifndef LITE_CONFIG_PATH + +token_spec_t token_specific = { + LITE_CONFIG_PATH, + "lite", + 0, // keysize + // Token data info: + { + FALSE, // Don't use per guest data store + TRUE, // Use master key + CKM_DES3_CBC, // Data store encryption + (CK_BYTE *)"12345678", // Default initialization vector for pins + (CK_BYTE *)"10293847", // Default initialization vector for objects + }, + NULL, // t_creatlock + NULL, // t_attach_shm + &token_specific_init, + NULL, // init_token_data + NULL, // load_token_data + NULL, // save_token_data + &token_specific_rng, + &token_specific_final, + NULL, // init_token + NULL, // login + NULL, // logout + NULL, // init_pin + NULL, // set_pin + // DES + &token_specific_des_key_gen, + &token_specific_des_ecb, + &token_specific_des_cbc, + // Triple DES + &token_specific_tdes_ecb, + &token_specific_tdes_cbc, + &token_specific_tdes_ofb, + &token_specific_tdes_cfb, + &token_specific_tdes_mac, + &token_specific_tdes_cmac, + // RSA + &token_specific_rsa_decrypt, + &token_specific_rsa_encrypt, + &token_specific_rsa_sign, + &token_specific_rsa_verify, + &token_specific_rsa_verify_recover, + &token_specific_rsa_x509_decrypt, + &token_specific_rsa_x509_encrypt, + &token_specific_rsa_x509_sign, + &token_specific_rsa_x509_verify, + &token_specific_rsa_x509_verify_recover, + &token_specific_rsa_oaep_decrypt, + &token_specific_rsa_oaep_encrypt, + &token_specific_rsa_pss_sign, + &token_specific_rsa_pss_verify, + &token_specific_rsa_generate_keypair, +#ifndef NO_EC + // Elliptic Curve + &token_specific_ec_sign, + &token_specific_ec_verify, + &token_specific_ec_generate_keypair, + &token_specific_ecdh_pkcs_derive, +#else + NULL, + NULL, + NULL, + NULL, +#endif + NULL, // dh_pkcs_derive + NULL, // dh_pkcs_key_pair_gen + // SHA + &token_specific_sha_init, + &token_specific_sha, + &token_specific_sha_update, + &token_specific_sha_final, + //HMAC + NULL, // hmac_sign_init + NULL, // hmac_sign + NULL, // hmac_sign_update + NULL, // hmac_sign_final + NULL, // hmac_verify_init + NULL, // hmac_verify + NULL, // hmac_verify_update + NULL, // hmac_verify_final + &token_specific_generic_secret_key_gen, + // AES +#ifndef NOAES + &token_specific_aes_key_gen, + &token_specific_aes_ecb, + &token_specific_aes_cbc, + &token_specific_aes_ctr, + &token_specific_aes_gcm_init, + &token_specific_aes_gcm, + &token_specific_aes_gcm_update, + &token_specific_aes_gcm_final, + &token_specific_aes_ofb, + &token_specific_aes_cfb, + &token_specific_aes_mac, + &token_specific_aes_cmac, +#else + NULL, // aes_key_gen, + NULL, // aes_ecb, + NULL, // aes_cbc, + NULL, // aes_ctr, + NULL, // aes_gcm_init, + NULL, // aes_gcm, + NULL, // aes_gcm_update, + NULL, // aes_gcm_final, + NULL, // aes_ofb, + NULL, // aes_cfb, + NULL, // aes_mac, + NULL, // aes_cmac +#endif + // DSA + NULL, // dsa_generate_keypair + NULL, // dsa_sign + NULL, // dsa_verify + &token_specific_get_mechanism_list, + &token_specific_get_mechanism_info, + NULL // object_add +}; + +#endif diff --git a/usr/lib/icsf_stdll/icsf.c b/usr/lib/icsf_stdll/icsf.c new file mode 100644 index 0000000..a3b8985 --- /dev/null +++ b/usr/lib/icsf_stdll/icsf.c @@ -0,0 +1,3471 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2012-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 + */ + +/* + * OpenCryptoki ICSF token - LDAP functions + * + * Author: Marcelo Cerri (mhcerri@br.ibm.com) + * Eduardo Otubo (eotubo@br.ibm.com) + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include "icsf.h" + +/* For logging functions: */ +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "trace.h" + +/* + * Note about ICSF callable services: + * + * Any ICSF service uses a base data structure containing some common fields. + * This base structure is described by the following ASN.1 definition: + * + * requestValue ::= SEQUENCE { + * version INTEGER, + * exitData OCTET STRING, + * handle OCTET STRING, + * ruleArraySeq RuleArraySeq, + * requestData CSFPInput + * } + * + * RuleArraySeq ::= SEQUENCE { + * ruleArrayCount INTEGER, + * ruleArray OCTET STRING + * } + * + * CSFPInput ::= CHOICE { + * IQF [CSFIQF] IQFInput, + * DMK [CSFPDMK] DMKInput, + * DVK [CSFPDVK] DVKInput, + * GAV [CSFPGAV] GAVInput, + * GKP [CSFPGKP] GKPInput, + * GSK [CSFPGSK] GSKInput, + * HMG [CSFPHMG] HMGInput, + * HMV [CSFPHMV] HMVInput, + * OWH [CSFPOWH] OWHInput, + * PKS [CSFPPKS] PKSInput, + * PKV [CSFPPKV] PKVInput, + * SAV [CSFPSAV] SAVInput, + * SKD [CSFPSKD] SKDInput, + * SKE [CSFPSKE] SKEInput, + * TRC [CSFPTRC] TRCInput, + * TRD [CSFPTRD] TRDInput, + * TRL [CSFPTRL] TRLInput, + * UWK [CSFPUWK] UWKInput, + * WPK [CSFPWPK] WPKInput, + * GLDTRD [GLDTRD] GLDTRDInput, + * IQA [CSFIQA] IQAInput + * } + * + * CSFPInput defines which service is being called. A different tag number + * and data structure is defined for each service. + * + * In the same way, the output is also based on a common data structure. + * + * responseValue ::= SEQUENCE { + * version INTEGER, + * ICSFRc INTEGER (0 .. MaxCSFPInteger), + * ICSFRsnCode INTEGER (0 .. MaxCSFPInteger), + * exitData OCTET STRING, + * handle OCTET STRING, + * responseData CSFPOutput + * } + * + * CSFPOutput ::= CHOICE { + * IQF [CSFIQF] IQFOutput, + * DMK [CSFPDMK] DMKOutput, + * DVK [CSFPDVK] DVKOutput, + * GAV [CSFPGAV] GAVOutput, + * GKP [CSFPGKP] GKPOutput, + * GSK [CSFPGSK] GSKOutput, + * HMG [CSFPHMG] HMGOutput, + * HMV [CSFPHMV] HMVOutput, + * OWH [CSFPOWH] OWHOutput, + * PKS [CSFPPKS] PKSOutput, + * PKV [CSFPPKV] PKVOutput, + * SAV [CSFPSAV] SAVOutput, + * SKD [CSFPSKD] SKDOutput, + * SKE [CSFPSKE] SKEOutput, + * TRC [CSFPTRC] TRCOutput, + * TRD [CSFPTRD] TRDOutput, + * TRL [CSFPTRL] TRLOutput, + * UWK [CSFPUWK] UWKOutput, + * WPK [CSFPWPK] WPKOutput, + * GLDTRD [GLDTRD] GLDTRDOutput, + * IQA [CSFIQA] IQAOutput + * } + * + * ICSFRc is the return code: 0 indicates success, 4 partial success and + * values greater than 4 indicates an error. ICSFRsnCode is the reason code + * that provides further details about an error. + */ + +/* Macros for argument checking */ +#define CHECK_ARG_NON_NULL(_arg) \ + if (_arg == NULL) { \ + TRACE_ERROR("Null argument \"%s\".\n", #_arg); \ + return -1; \ + } + +#define CHECK_ARG_MAX_LEN(_arg, _length) \ + if (_arg && (strlen(_arg) > _length)) { \ + TRACE_ERROR("String too long %s=\"%s\"\n", #_arg, _arg); \ + return -1; \ + } + +#define CHECK_ARG_NON_NULL_AND_MAX_LEN(_arg, _length) \ + CHECK_ARG_NON_NULL(_arg); \ + CHECK_ARG_MAX_LEN(_arg, _length); + +/* + * Copy a null terminated string from `orig` to the buffer `dest` of length + * `len` and fill the remaining bytes with `padding_char`. The result string is + * not null terminated. + */ +static void strpad(char *dest, const char *orig, size_t len, int padding_char) +{ + size_t str_len = strlen(orig); + + UNUSED(padding_char); + + if (str_len > len) + str_len = len; + + memcpy(dest, orig, str_len); + if ((len - str_len) > 0) + memset(dest + str_len, ' ', len - str_len); +} + +/* Copy a string `orig` of length `len` and padded with `padding_char` to a null + * terminated string `dest`. `dest` should be at least `len` + 1 bytes long. + */ +void strunpad(char *dest, const char *orig, size_t len, int padding_char) +{ + size_t i; + + for (i = len - 1; i; i--) + if (orig[i - 1] != padding_char) + break; + + memcpy(dest, orig, i); + dest[i] = '\0'; +} + +/* + * Build a token handle based on token name. + * + * `handle` must be at least ICSF_HANDLE_LEN long. + */ +static void token_name_to_handle(char *handle, const char *token_name) +{ + /* The first 32 bytes of `handle` specifies the token's name, the + * remaining bytes should be blank. + */ + strpad(handle, token_name, ICSF_TOKEN_NAME_LEN, ' '); + memset(handle + ICSF_TOKEN_NAME_LEN, ' ', + ICSF_HANDLE_LEN - ICSF_TOKEN_NAME_LEN); +} + +/* + * Parse a structure object record to a handle. + * + * `data` must be at least ICSF_HANDLE_LEN long. + */ +void object_record_to_handle(char *data, + const struct icsf_object_record *record) +{ + /* + * Object handle is composed by token name, sequence number + * converted to hexadecimal and ID padded with blanks. + */ + size_t offset = 0; + char hex_seq[ICSF_SEQUENCE_LEN + 1]; + + strpad(data + offset, record->token_name, ICSF_TOKEN_NAME_LEN, ' '); + offset += ICSF_TOKEN_NAME_LEN; + + snprintf(hex_seq, sizeof(hex_seq), "%0*lX", ICSF_SEQUENCE_LEN, + record->sequence); + memcpy(data + offset, hex_seq, ICSF_SEQUENCE_LEN); + offset += ICSF_SEQUENCE_LEN; + + memset(data + offset, ' ', ICSF_HANDLE_LEN - offset); + data[offset] = record->id; +} + +/* + * Parse a raw object handle into token name, sequence and object type. + */ +void handle_to_object_record(struct icsf_object_record *record, + const char *data) +{ + size_t offset = 0; + char hex_seq[ICSF_SEQUENCE_LEN + 1]; + + strunpad(record->token_name, data + offset, ICSF_TOKEN_NAME_LEN + 1, ' '); + offset += ICSF_TOKEN_NAME_LEN; + + memcpy(hex_seq, data + offset, ICSF_SEQUENCE_LEN); + hex_seq[ICSF_SEQUENCE_LEN] = '\0'; + sscanf(hex_seq, "%lx", &record->sequence); + offset += ICSF_SEQUENCE_LEN; + + record->id = data[offset]; +} + +/* + * Ensure that LDAPv3 is used. V3 is needed for extended operations. + */ +static int icsf_force_ldap_v3(LDAP * ld) +{ + int rc; + int version = 0; + + CHECK_ARG_NON_NULL(ld); + + rc = ldap_get_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version); + if (rc != LDAP_OPT_SUCCESS) { + TRACE_ERROR("Failed to get LDAP version: %s (%d)\n", + ldap_err2string(rc), rc); + return -1; + } + if (version < LDAP_VERSION3) { + TRACE_INFO("Changing version from %d to %d.\n", version, LDAP_VERSION3); + version = LDAP_VERSION3; + rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version); + if (rc != LDAP_OPT_SUCCESS) { + TRACE_ERROR("Failed to set LDAP version: %s (%d)\n", + ldap_err2string(rc), rc); + return -1; + } + } + + return 0; +} + +/* + * Perform a simple bind to `uri` using `dn` and `password` as credentials. + */ +int icsf_login(LDAP ** ld, const char *uri, const char *dn, + const char *password) +{ + int rc; + struct berval cred; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL(password); + + /* Handle empty and null string in the same way */ + uri = (uri && uri[0]) ? uri : NULL; + dn = (dn && dn[0]) ? dn : NULL; + + /* Connect to LDAP server */ + TRACE_DEVEL("Connecting to: %s\n", uri ? uri : "(null)"); + rc = ldap_initialize(ld, uri); + if (rc != LDAP_SUCCESS) { + TRACE_ERROR("Failed to connect to \"%s\": %s (%d)\n", + uri ? uri : "(null)", ldap_err2string(rc), rc); + return -1; + } + + if (icsf_force_ldap_v3(*ld)) + return -1; + + TRACE_DEVEL("Binding with DN: %s\n", dn ? dn : "(null)"); + cred.bv_len = strlen(password); + cred.bv_val = (char *) password; + rc = ldap_sasl_bind_s(*ld, dn, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL); + if (rc != LDAP_SUCCESS) { + TRACE_ERROR("LDAP bind failed: %s (%d)\n", ldap_err2string(rc), rc); + return -1; + } + + return 0; +} + +/* + * Set the paths for private key, certificate and CA, which are used for + * SASL authentication using external certificate. + * + * TODO: check why these options just work as globals (ld == NULL) + */ +static int icsf_set_sasl_params(LDAP * ld, const char *cert, const char *key, + const char *ca, const char *ca_dir) +{ + int rc; + + CHECK_ARG_NON_NULL(ld); + + TRACE_DEVEL("Preparing environment for TLS\n"); + if (cert && *cert) { + TRACE_DEVEL("Using certificate: %s\n", cert); + rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CERTFILE, cert); + if (rc != LDAP_SUCCESS) { + TRACE_ERROR("Failed to set certificate file for TLS: " + "%s (%d)\n", ldap_err2string(rc), rc); + return -1; + } + } + + if (key && *key) { + TRACE_DEVEL("Using private key: %s\n", key); + rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_KEYFILE, key); + if (rc != LDAP_SUCCESS) { + TRACE_ERROR("Failed to set key file for TLS: " + "%s (%d)\n", ldap_err2string(rc), rc); + return -1; + } + } + + if (ca && *ca) { + TRACE_DEVEL("Using CA certificate file: %s\n", ca); + rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ca); + if (rc != LDAP_SUCCESS) { + TRACE_ERROR("Failed to set CA certificate file for TLS:" + " %s (%d)\n", ldap_err2string(rc), rc); + return -1; + } + } + + if (ca_dir && *ca_dir) { + TRACE_DEVEL("Using CA certificate dir: %s\n", ca_dir); + rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTDIR, ca_dir); + if (rc != LDAP_SUCCESS) { + TRACE_ERROR("Failed to set CA certificate dir for TLS: " + "%s (%d)\n", ldap_err2string(rc), rc); + return -1; + } + } + + return 0; +} + +/* + * Perform a SASL bind to `uri` using the given certificate, private key + * and CA paths. + */ +int icsf_sasl_login(LDAP ** ld, const char *uri, const char *cert, + const char *key, const char *ca, const char *ca_dir) +{ + int rc; + + CHECK_ARG_NON_NULL(ld); + + /* Handle empty and null string in the same way */ + uri = (uri && uri[0]) ? uri : NULL; + + /* Connect to LDAP server */ + TRACE_DEVEL("Connecting to: %s\n", uri ? uri : "(null)"); + rc = ldap_initialize(ld, uri); + if (rc != LDAP_SUCCESS) { + TRACE_ERROR("Failed to connect to \"%s\": %s (%d)\n", + uri ? uri : "(null)", ldap_err2string(rc), rc); + return -1; + } + + if (icsf_force_ldap_v3(*ld)) + return -1; + + /* Initialize TLS */ + if (icsf_set_sasl_params(*ld, cert, key, ca, ca_dir)) + return -1; + + TRACE_DEVEL("Binding\n"); + rc = ldap_sasl_bind_s(*ld, NULL, "EXTERNAL", NULL, NULL, NULL, NULL); + if (rc != LDAP_SUCCESS) { + char *ext_msg = NULL; + ldap_get_option(*ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, &ext_msg); + TRACE_ERROR("LDAP bind failed: %s (%d)%s%s\n", + ldap_err2string(rc), rc, + ext_msg ? "\nDetailed message: " : "", + ext_msg ? ext_msg : ""); + if (ext_msg) + ldap_memfree(ext_msg); + return -1; + } + + return 0; +} + +/* + * Disconnect from the server. + */ +int icsf_logout(LDAP * ld) +{ + int rc; + + CHECK_ARG_NON_NULL(ld); + + rc = ldap_unbind_ext_s(ld, NULL, NULL); + if (rc != LDAP_SUCCESS) { + TRACE_ERROR("Failed to unbind: %s (%d)\n", ldap_err2string(rc), rc); + return -1; + } + + return 0; +} + +/* + * Check if the ICSF LDAP extension is supported by the server. + */ +int icsf_check_pkcs_extension(LDAP * ld) +{ + int rc = -1; + int ret; + LDAPMessage *res = NULL; + LDAPMessage *entry = NULL; + BerElement *ber = NULL; + char *attr = NULL; + char expected_attr[] = "supportedextension"; + char *attr_list[] = { expected_attr, NULL }; + const char *expected_oid = ICSF_REQ_OID; + + CHECK_ARG_NON_NULL(ld); + + /* Search root DSE. */ + ret = ldap_search_ext_s(ld, "", /* Base DN */ + LDAP_SCOPE_BASE, /* Scope */ + "(objectclass=*)", /* Filter */ + attr_list, /* Attribute list */ + 0, /* Attributes only */ + NULL, /* Server controls */ + NULL, /* Client controls */ + NULL, /* Timeout */ + 0, /* Size limit */ + &res); + if (ret) + goto cleanup; + + /* It should contain just one entry */ + entry = ldap_first_entry(ld, res); + if (entry == NULL) + goto cleanup; + + /* Loop through attributes */ + attr = ldap_first_attribute(ld, entry, &ber); + while (attr) { + if (!strcmp(expected_attr, attr)) { + /* Get the value for each attribute */ + struct berval **it; + struct berval **values = ldap_get_values_len(ld, entry, attr); + if (values == NULL) + goto cleanup; + + /* Print each value */ + for (it = values; *it; it++) + if (!strncmp(expected_oid, + (*it)->bv_val, + strlen(expected_oid))) { + /* It's supported */ + rc = 0; + } + + ldap_value_free_len(values); + + if (rc == 0) + goto cleanup; + } + + /* Get next attribute */ + ldap_memfree(attr); + attr = ldap_next_attribute(ld, entry, ber); + } + + /* Not supported. */ + rc = 1; + +cleanup: + if (attr) + ldap_memfree(attr); + if (ber) + ber_free(ber, 0); + if (res) + ldap_msgfree(res); + + return rc; +} + +/* + * `icsf_call` is a generic helper function for ICSF services. + * + * Every request message to an ICSF service has some common fields and a + * specific field that depends on the service that is called. The structure of + * this field differs for each service and it's also marked with a specific tag + * that identifies the service. + * + * `handle` identifies a token or object. It should be always 44 bytes long. + * + * `reason` returns the ICSF reason code. It's ignored when NULL. + * + * `rule_array` should be a sequence of 8 bytes strings padded with blanks. Each + * 8 bytes is an item and can change the behaviour of a call. + * + * `tag` identifies the ICSF service. + * + * `specific` is the service-specific field of the request message. A NULL value + * indicates an empty field. + * + * `result` points to the service-specific part of the response message. If a + * non-NULL value is given, the caller must free it. + */ +static int icsf_call(LDAP * ld, int *reason, char *handle, size_t handle_len, + const char *rule_array, size_t rule_array_len, + ber_tag_t tag, BerElement * specific, BerElement ** result) +{ + int rc; + BerElement *ber_req = NULL; + BerElement *ber_res = NULL; + struct berval *raw_req = NULL; + struct berval *raw_res = NULL; + struct berval *raw_specific = NULL; + char *response_oid = NULL; + + /* Variables used as input */ + int version = 1; + char *exit_data = ""; /* Ignored */ + int rule_array_count; + + /* Variables used as output */ + int return_code = 0; + int reason_code = 0; + struct berval *out_handle = NULL; + + /* Check sizes */ + if (handle_len != ICSF_HANDLE_LEN) { + TRACE_ERROR("Invalid handle length: %lu\n", handle_len); + return -1; + } + + if ((rule_array_len % ICSF_RULE_ITEM_LEN)) { + TRACE_ERROR("Invalid rule array length: %lu\n", rule_array_len); + return -1; + } + rule_array_count = rule_array_len / ICSF_RULE_ITEM_LEN; + + /* Allocate ber_req to encode message. */ + ber_req = ber_alloc_t(LBER_USE_DER); + if (ber_req == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = -1; + goto cleanup; + } + + if (specific) { + rc = ber_flatten(specific, &raw_specific); + if (rc) { + TRACE_ERROR("Failed to flatten specific data.\n"); + rc = -1; + goto cleanup; + } + } + + /* Encode message: + * + * requestValue ::= SEQUENCE { + * version INTEGER, + * exitData OCTET STRING, + * handle_len OCTET STRING, + * ruleArraySeq RuleArraySeq, + * requestData CSFPInput + * } + * + * RuleArraySeq ::= SEQUENCE { + * ruleArrayCount INTEGER, + * ruleArray OCTET STRING + * } + * + * CSFPInput ::= CHOICE { + * IQF [CSFIQF] IQFInput, + * DMK [CSFPDMK] DMKInput, + * DVK [CSFPDVK] DVKInput, + * GAV [CSFPGAV] GAVInput, + * GKP [CSFPGKP] GKPInput, + * GSK [CSFPGSK] GSKInput, + * HMG [CSFPHMG] HMGInput, + * HMV [CSFPHMV] HMVInput, + * OWH [CSFPOWH] OWHInput, + * PKS [CSFPPKS] PKSInput, + * PKV [CSFPPKV] PKVInput, + * SAV [CSFPSAV] SAVInput, + * SKD [CSFPSKD] SKDInput, + * SKE [CSFPSKE] SKEInput, + * TRC [CSFPTRC] TRCInput, + * TRD [CSFPTRD] TRDInput, + * TRL [CSFPTRL] TRLInput, + * UWK [CSFPUWK] UWKInput, + * WPK [CSFPWPK] WPKInput, + * GLDTRD [GLDTRD] GLDTRDInput, + * IQA [CSFIQA] IQAInput + * } + */ + tag |= LBER_CLASS_CONTEXT | LBER_CONSTRUCTED; + rc = ber_printf(ber_req, "{iso{io}to}", version, exit_data, handle, + handle_len, rule_array_count, rule_array, + rule_array_len, tag, + (raw_specific) ? raw_specific->bv_val : "", + (raw_specific) ? raw_specific->bv_len : 0); + if (rc < 0) { + TRACE_ERROR("Failed to encode message.\n"); + rc = -1; + goto cleanup; + } + + rc = ber_flatten(ber_req, &raw_req); + if (rc) { + TRACE_ERROR("Failed to flatten BER data.\n"); + rc = -1; + goto cleanup; + } + + /* Call ICSF service */ + rc = ldap_extended_operation_s(ld, ICSF_REQ_OID, raw_req, NULL, NULL, + &response_oid, &raw_res); + if (rc != LDAP_SUCCESS) { + char *ext_msg = NULL; + ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, &ext_msg); + TRACE_ERROR("ICSF call failed: %s (%d)%s%s\n", + ldap_err2string(rc), rc, + ext_msg ? "\nDetailed message: " : "", + ext_msg ? ext_msg : ""); + if (ext_msg) + ldap_memfree(ext_msg); + rc = -1; + goto cleanup; + } + + /* Decode result */ + ber_res = ber_init(raw_res); + if (ber_res == NULL) { + TRACE_ERROR("Failed to create a response buffer\n"); + rc = -1; + goto cleanup; + } + + /* Decode common response fields: */ + rc = ber_scanf(ber_res, "{iiixO", &version, &return_code, + &reason_code, &out_handle); + if (rc < 0) { + TRACE_ERROR("Failed to decode message.\n"); + rc = -1; + goto cleanup; + } + + /* Copy handle */ + if (out_handle == NULL) { + memset(handle, 0, handle_len); + } else { + size_t len = (handle_len < out_handle->bv_len) + ? handle_len : out_handle->bv_len; + memcpy(handle, out_handle->bv_val, len); + memset(handle + len, 0, handle_len - len); + } + + TRACE_DEVEL("ICSF call result: %d (%d)\n", return_code, reason_code); + + if (ICSF_RC_IS_ERROR(return_code)) { + TRACE_ERROR("ICSF call failed: %d (%d)\n", return_code, reason_code); + } + + rc = return_code; + +cleanup: + if (reason) + *reason = reason_code; + if (result) + *result = ber_res; + else if (ber_res) + ber_free(ber_res, 1); + if (ber_req) + ber_free(ber_req, 1); + if (raw_req) + ber_bvfree(raw_req); + if (raw_res) + ber_bvfree(raw_res); + if (response_oid) + ldap_memfree(response_oid); + if (out_handle) + ber_bvfree(out_handle); + if (raw_specific) + ber_bvfree(raw_specific); + + return rc; +} + +/* + * Create a new token. All parameters must be null terminated strings. + */ +int icsf_create_token(LDAP * ld, int *reason, const char *token_name, + const char *manufacturer, const char *model, + const char *serial) +{ + int rc = -1; + char handle[ICSF_HANDLE_LEN]; + char rule_array[2 * ICSF_RULE_ITEM_LEN]; + char attribute_list[68] = { 0, }; + BerElement *msg = NULL; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL_AND_MAX_LEN(token_name, ICSF_TOKEN_NAME_LEN); + CHECK_ARG_NON_NULL_AND_MAX_LEN(manufacturer, ICSF_MANUFACTURER_LEN); + CHECK_ARG_NON_NULL_AND_MAX_LEN(model, ICSF_MODEL_LEN); + CHECK_ARG_NON_NULL_AND_MAX_LEN(serial, ICSF_SERIAL_LEN); + + token_name_to_handle(handle, token_name); + + /* Should be 8 bytes padded. It's a token creation and if the token + * already exists it is recreated. + */ + strpad(rule_array, "TOKEN", ICSF_RULE_ITEM_LEN, ' '); + strpad(rule_array + ICSF_RULE_ITEM_LEN, "RECREATE", ICSF_RULE_ITEM_LEN, + ' '); + + /* For token creation, handle is composed by 32 bytes for manufacturer + * id, 16 bytes for model, 16 bytes for serial number, and 4 trailing + * bytes with zeros. + */ + strpad(attribute_list, manufacturer, ICSF_MANUFACTURER_LEN, ' '); + strpad(attribute_list + ICSF_MANUFACTURER_LEN, model, ICSF_MODEL_LEN, ' '); + strpad(attribute_list + ICSF_MANUFACTURER_LEN + ICSF_MODEL_LEN, serial, + ICSF_SERIAL_LEN, ' '); + + /* Allocate ber_req to encode message. */ + msg = ber_alloc_t(LBER_USE_DER); + if (msg == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto cleanup; + } + + /* Encode message: + * + * TRCInput ::= SEQUENCE { + * trcAttrs ::= CHOICE { + * tokenAttrString [0] OCTET STRING, + * } + * } + */ + rc = ber_printf(msg, "to", 0 | LBER_CLASS_CONTEXT, attribute_list, + sizeof(attribute_list)); + if (rc < 0) { + TRACE_ERROR("Failed to encode message.\n"); + goto cleanup; + } + + rc = icsf_call(ld, reason, handle, sizeof(handle), + rule_array, sizeof(rule_array), ICSF_TAG_CSFPTRC, msg, NULL); + +cleanup: + if (msg) + ber_free(msg, 1); + + return rc; +} + +/* + * Destroy a token. + */ +int icsf_destroy_token(LDAP * ld, int *reason, char *token_name) +{ + /* Variables used as input */ + char handle[ICSF_HANDLE_LEN]; + char rule_array[1 * ICSF_RULE_ITEM_LEN]; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL_AND_MAX_LEN(token_name, ICSF_TOKEN_NAME_LEN); + + token_name_to_handle(handle, token_name); + + /* Should be 8 bytes padded. */ + strpad(rule_array, "TOKEN", ICSF_RULE_ITEM_LEN, ' '); + + /* + * CSFPTRD service is used to destroy a token or an object. Handle + * indicates the token or object that must be destroyed and no + * additional data is needed. + */ + return icsf_call(ld, reason, handle, sizeof(handle), rule_array, + sizeof(rule_array), ICSF_TAG_CSFPTRD, NULL, NULL); +} + +/* + * Parse a sequence of bytes `data` returned by a CSFPTRL call containing the + * attributes of a token and store the parsed value in the structure `record`. + * + * The data is formated as the following: + * - 32 bytes for token name; + * - 32 bytes for manufacturer name; + * - 16 bytes for model identification; + * - 16 bytes for serial number; + * - 8 bytes for date in UTC of the last change encoded as a string in the + * format "yyyymmdd". + * - 8 bytes for time in UTC of the last change encoded as a string in the + * format "hhmmssth". + * - 4 bytes of flags (the first bit of the first byte indicate that the + * token is write protected). + */ +static void parse_token_record(struct icsf_token_record *record, + const char *data) +{ + size_t offset = 0; + + strunpad(record->name, data + offset, ICSF_TOKEN_NAME_LEN + 1, ' '); + offset += ICSF_TOKEN_NAME_LEN; + + strunpad(record->manufacturer, data + offset, ICSF_MANUFACTURER_LEN + 1, + ' '); + offset += ICSF_MANUFACTURER_LEN; + + strunpad(record->model, data + offset, ICSF_MODEL_LEN + 1, ' '); + offset += ICSF_MODEL_LEN; + + strunpad(record->serial, data + offset, ICSF_SERIAL_LEN + 1, ' '); + offset += ICSF_SERIAL_LEN; + + strunpad(record->date, data + offset, ICSF_DATE_LEN + 1, ' '); + offset += ICSF_DATE_LEN; + + strunpad(record->time, data + offset, ICSF_TIME_LEN + 1, ' '); + offset += ICSF_TIME_LEN; + + /* Flags are not a string, just a bunch of flags. So it doesn't need + * to be null terminated. + */ + memcpy(record->flags, data + offset, ICSF_FLAGS_LEN); +} + +/* helper function to determine if a specific keyword is in the rule array */ +int in_rulearray(const char *keyword, const char *rulearray, int count) +{ + int i = 0; + + while (count) { + if (memcmp(keyword, rulearray + i, 8) == 0) + return 1; + i += 8; + count--; + } + + return 0; +} + +/* + * This function indicates if an attribute should be BER encoded as a number or + * not, based on its type. + */ +static int is_numeric_attr(CK_ULONG type) +{ + switch (type) { + case CKA_CLASS: + case CKA_KEY_TYPE: + case CKA_CERTIFICATE_TYPE: + case CKA_KEY_GEN_MECHANISM: + case CKA_VALUE_LEN: + case CKA_MODULUS_BITS: + return 1; + } + return 0; +} + +/* + * This helper functions receives a list of attributes containing type, length + * and value and encode it in BER encoding. Numeric and non numeric attributes + * are encoded using different rules. + * + * The attributes are encoded following rules: + * + * Attributes ::= SEQUENCE OF SEQUENCE { + * attrName INTEGER, + * attrValue AttributeValue + * } + * + * AttributeValue ::= CHOICE { + * charValue [0] OCTET STRING, + * intValue [1] INTEGER + * } + * + */ +static int icsf_ber_put_attribute_list(BerElement * ber, CK_ATTRIBUTE * attrs, + CK_ULONG attrs_len) +{ + size_t i; + + for (i = 0; i < attrs_len; i++) { + if (!is_numeric_attr(attrs[i].type)) { + /* Non numeric attributes are encode as octet strings */ + if (ber_printf(ber, "{ito}", attrs[i].type, + 0 | LBER_CLASS_CONTEXT, attrs[i].pValue, + attrs[i].ulValueLen) < 0) { + goto encode_error; + } + } else { + long value; + unsigned long mask; + + /* `long` is used here to support any size of integer, + * however if the value is shorter than a `long` then + * just the significant bits should be used. + */ + if (attrs[i].ulValueLen > sizeof(long)) { + TRACE_ERROR("Integer value too long for attribute\n"); + goto encode_error; + } + + /* Calculate a mask to get just the bits in the range of + * the given length. + */ + mask = (1UL << (8 * attrs[i].ulValueLen)) - 1; + if (mask == 0) + mask = (unsigned long) -1; + + value = *((unsigned long *) attrs[i].pValue) & mask; + + /* Encode integer attribute. */ + if (ber_printf(ber, "{iti}", attrs[i].type, + 1 | LBER_CLASS_CONTEXT, value) < 0) { + goto encode_error; + } + } + } + + return 0; + +encode_error: + TRACE_ERROR("Failed to encode message.\n"); + + return -1; +} + +/* + * + * `icsf_list` is a helper function for CSFPTRL service, + * which is used for token and object listing. + * + * `handle` identifies the last token or object returned by a previous call of + * `icsf_list`. It should be always 44 bytes long and be in the following + * format: + * + * - For tokens: + * * 32 bytes containing the token name padded with blanks; + * * remaining bytes filled with blanks. + * + * - For objects: + * * 32 bytes containing the token name padded with blanks; + * * 8 bytes containing the object's sequence number encoded int + * hexadecimal. + * * 1 byte with the character 'T' for token objects or 'S' for session + * objects. + * * remaining bytes filled with blanks. + * + * `rule_array` should be a sequence of 8 bytes strings padded with blanks. + * It indicates if a list of tokens or a objects will be returned (please refer + * to `icsf_create_token` and `icsf_create_object` for details). + * + * `bv_list` is an output buffer for the raw data and should be freed by the + * caller. + * + * `list_len` is used as input to indicate the number of bytes of the buffer to + * be returned, and it's updated with the number of bytes returned. + * + * `list_count` indicates how many items should be returned. + */ +static int icsf_list(LDAP * ld, int *reason, char *handle, size_t handle_len, + CK_ULONG attrs_len, CK_ATTRIBUTE * attrs, + const char *rule_array, size_t rule_array_len, + struct berval **bv_list, size_t * list_len, + size_t list_count) +{ + int rc = -1; + BerElement *msg = NULL; + BerElement *result = NULL; + int out_list_len = 0; + int objectInRuleArray = 0; + + /* Allocate request message. */ + msg = ber_alloc_t(LBER_USE_DER); + if (msg == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto cleanup; + } + + /* Encode message: + * + * TRLInput ::= SEQUENCE { + * inListLen INTEGER (0 .. MaxCSFPInteger), + * maxHandleCount INTEGER (0 .. MaxCSFPInteger), + * searchTemplate [0] Attributes OPTIONAL + * } + * + */ + if (ber_printf(msg, "ii", *list_len, list_count) < 0) { + TRACE_ERROR("Failed to encode message.\n"); + goto cleanup; + } + + objectInRuleArray = in_rulearray("OBJECT ", rule_array, + rule_array_len / ICSF_RULE_ITEM_LEN); + + if ((objectInRuleArray) && (attrs != NULL)) { + if (ber_printf(msg, "t{", 0 | LBER_CLASS_CONTEXT | LBER_CONSTRUCTED) < + 0) { + TRACE_ERROR("Failed to flatten attribute list\n"); + goto cleanup; + } + + if (icsf_ber_put_attribute_list(msg, attrs, attrs_len) < 0) { + TRACE_ERROR("Failed to flatten attribute list\n"); + goto cleanup; + } + + if (ber_printf(msg, "}") < 0) { + TRACE_ERROR("Failed to encode message.\n"); + goto cleanup; + } + } + + rc = icsf_call(ld, reason, handle, handle_len, rule_array, + rule_array_len, ICSF_TAG_CSFPTRL, msg, &result); + if (ICSF_RC_IS_ERROR(rc)) + goto cleanup; + + /* Decode result: + * + * TRLOutput ::= SEQUENCE { + * outList CHOICE { + * tokenList [0] OCTET STRING, + * handleList [1] OCTET STRING + * }, + * outListLen INTEGER (0 .. MaxCSFPInteger) + * } + */ + if (ber_scanf(result, "{Oi}", bv_list, &out_list_len) == LBER_ERROR) { + TRACE_ERROR("Failed to decode message.\n"); + rc = -1; + goto cleanup; + } + + *list_len = out_list_len; + +cleanup: + if (msg) + ber_free(msg, 1); + if (result) + ber_free(result, 1); + + return rc; +} + +/* + * List tokens on the server. + * + * `previous` must point to the last token returned by a previous call of + * `icsf_list_tokens` or should be NULL for the first call. + * + * `records` must point to a buffer of token records with `records_len` + * elements. `records_len` is updated with the number of tokens returned + * and it's zero when there's no more records left. + */ +int icsf_list_tokens(LDAP * ld, int *reason, struct icsf_token_record *previous, + struct icsf_token_record *records, size_t * records_len) +{ + int rc = -1; + char handle[44]; + char rule_array[ICSF_RULE_ITEM_LEN]; + struct berval *bv_list = NULL; + size_t list_len; + size_t i; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL(records); + CHECK_ARG_NON_NULL(records_len); + + /* The first record that must be returned in `records` is the next one + * after `previous`, and for that the `previous` handle must be + * provided. When `previous` is null a blank handle should be used + * instead. + */ + if (previous) + token_name_to_handle(handle, previous->name); + else + memset(handle, ' ', sizeof(handle)); + + /* Should be 8 bytes padded. */ + strpad(rule_array, "TOKEN", ICSF_RULE_ITEM_LEN, ' '); + + list_len = ICSF_TOKEN_RECORD_LEN * *records_len; + rc = icsf_list(ld, reason, handle, sizeof(handle), 0, NULL, rule_array, + sizeof(rule_array), &bv_list, &list_len, *records_len); + if (ICSF_RC_IS_ERROR(rc)) + goto cleanup; + + /* Parse result */ + *records_len = list_len / ICSF_TOKEN_RECORD_LEN; + for (i = 0; i < *records_len; i++) { + size_t offset = i * ICSF_TOKEN_RECORD_LEN; + parse_token_record(&records[i], bv_list->bv_val + offset); + } + +cleanup: + if (bv_list) + ber_bvfree(bv_list); + + return rc; +} + +int icsf_copy_object(LDAP * ld, int *reason, + CK_ATTRIBUTE * attrs, CK_ULONG attrs_len, + struct icsf_object_record *src, + struct icsf_object_record *dst) +{ + int rc = -1; + char handle[ICSF_HANDLE_LEN]; + char rule_array[2 * ICSF_RULE_ITEM_LEN]; + BerElement *msg = NULL; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL(src); + CHECK_ARG_NON_NULL(attrs); + + object_record_to_handle(handle, src); + + /* Allocate ber_req to encode message. */ + msg = ber_alloc_t(LBER_USE_DER); + if (msg == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto cleanup; + } + + if (attrs_len != 0) { + rc = ber_printf(msg, "t{", 1 | LBER_CLASS_CONTEXT | LBER_CONSTRUCTED); + if (rc < 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + goto cleanup; + } + + if (icsf_ber_put_attribute_list(msg, attrs, attrs_len) < 0) { + TRACE_DEVEL("icsf_ber_put_attribute_list failed\n"); + goto cleanup; + } + + if (ber_printf(msg, "}") < 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + goto cleanup; + } + } else { + rc = ber_printf(msg, "tn", 1 | LBER_CLASS_CONTEXT | LBER_CONSTRUCTED); + if (rc < 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + goto cleanup; + } + } + + /* Should be 8 bytes padded. */ + strpad(rule_array, "OBJECT", ICSF_RULE_ITEM_LEN, ' '); + strpad(rule_array + ICSF_RULE_ITEM_LEN, "COPY", ICSF_RULE_ITEM_LEN, ' '); + + rc = icsf_call(ld, reason, handle, sizeof(handle), + rule_array, sizeof(rule_array), ICSF_TAG_CSFPTRC, msg, NULL); + + if (!rc && dst) + handle_to_object_record(dst, handle); + +cleanup: + if (msg) + ber_free(msg, 1); + + return rc; +} + +/* + * Create an object in the token defined by the given `token_name`. + * + * `attrs` is a list of attributes each one consisting in a type, a length and a + * value (a sequence of bytes). `attrs_len` indicates how many attributes the + * input list has. + * + * `obj_handle` is the buffer that will receive the handler for the new object. + * And it should be at least 44 bytes long (indicated by `obj_handle_len`). + */ +int icsf_create_object(LDAP * ld, int *reason, const char *token_name, + CK_ATTRIBUTE * attrs, CK_ULONG attrs_len, + struct icsf_object_record *object) +{ + int rc = -1; + char handle[ICSF_HANDLE_LEN]; + char rule_array[ICSF_RULE_ITEM_LEN]; + BerElement *msg = NULL; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL_AND_MAX_LEN(token_name, ICSF_TOKEN_NAME_LEN); + CHECK_ARG_NON_NULL(attrs); + + token_name_to_handle(handle, token_name); + + /* Should be 8 bytes padded. */ + strpad(rule_array, "OBJECT", sizeof(rule_array), ' '); + + /* Allocate ber_req to encode message. */ + msg = ber_alloc_t(LBER_USE_DER); + if (msg == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto cleanup; + } + + /* Encode message: + * + * TRCInput ::= SEQUENCE { + * trcAttrs ::= CHOICE { + * objectAttrList [1] Attributes + * } + * } + * + * Attributes ::= SEQUENCE OF SEQUENCE { + * attrName INTEGER, + * attrValue AttributeValue + * } + * + * AttributeValue ::= CHOICE { + * charValue [0] OCTET STRING, + * intValue [1] INTEGER + * } + * + */ + if (ber_printf(msg, "t{", 1 | LBER_CLASS_CONTEXT | LBER_CONSTRUCTED) < 0) { + TRACE_ERROR("Failed to encode message.\n"); + goto cleanup; + } + + if (icsf_ber_put_attribute_list(msg, attrs, attrs_len) < 0) { + TRACE_ERROR("Failed to flatten attribute list\n"); + goto cleanup; + } + + if (ber_printf(msg, "}") < 0) { + TRACE_ERROR("Failed to encode message.\n"); + goto cleanup; + } + + rc = icsf_call(ld, reason, handle, sizeof(handle), + rule_array, sizeof(rule_array), ICSF_TAG_CSFPTRC, msg, NULL); + +cleanup: + if (msg) + ber_free(msg, 1); + + if (!rc && object) + handle_to_object_record(object, handle); + + return rc; +} + +/* + * List objects for a token indicated by `token_name`. + * + * `previous` must point to the last object returned by a previous call of + * `icsf_list_objects` or should be NULL for the first call. + * + * `records` must point to a buffer of object records with `records_len` + * elements. `records_len` is updated with the number of objects returned + * and it's zero when there's no more records left. + */ +int icsf_list_objects(LDAP * ld, int *reason, const char *token_name, + CK_ULONG attrs_len, CK_ATTRIBUTE * attrs, + struct icsf_object_record *previous, + struct icsf_object_record *records, size_t * records_len, + int all) +{ + int rc = -1; + char handle[ICSF_HANDLE_LEN]; + char rule_array[2 * ICSF_RULE_ITEM_LEN]; + size_t rule_array_count = 1; + struct berval *bv_list = NULL; + size_t list_len; + size_t i; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL_AND_MAX_LEN(token_name, ICSF_TOKEN_NAME_LEN); + CHECK_ARG_NON_NULL(records); + CHECK_ARG_NON_NULL(records_len); + + /* The first record that must be returned in `records` is the next one + * after `previous`, and for that the `previous` handle must be + * provided. When `previous` is null, the token handle should be used + * instead. + */ + if (previous) + object_record_to_handle(handle, previous); + else + token_name_to_handle(handle, token_name); + + /* Should be 8 bytes padded. */ + strpad(rule_array, "OBJECT", ICSF_RULE_ITEM_LEN, ' '); + if (all) { + strpad(rule_array + ICSF_RULE_ITEM_LEN, "ALL", ICSF_RULE_ITEM_LEN, ' '); + rule_array_count += 1; + } + + list_len = ICSF_HANDLE_LEN * *records_len; + rc = icsf_list(ld, reason, handle, sizeof(handle), attrs_len, attrs, + rule_array, rule_array_count * ICSF_RULE_ITEM_LEN, &bv_list, + &list_len, *records_len); + if (ICSF_RC_IS_ERROR(rc)) + goto cleanup; + + /* Parse result */ + *records_len = list_len / ICSF_HANDLE_LEN; + for (i = 0; i < *records_len; i++) { + size_t offset = i * ICSF_HANDLE_LEN; + handle_to_object_record(&records[i], bv_list->bv_val + offset); + } + +cleanup: + if (bv_list) + ber_bvfree(bv_list); + + return rc; +} + +/* + * Destroy an object. + */ +int icsf_destroy_object(LDAP * ld, int *reason, struct icsf_object_record *obj) +{ + /* Variables used as input */ + char handle[ICSF_HANDLE_LEN]; + char rule_array[1 * ICSF_RULE_ITEM_LEN]; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL(obj); + + object_record_to_handle(handle, obj); + + /* Should be 8 bytes padded. */ + strpad(rule_array, "OBJECT", ICSF_RULE_ITEM_LEN, ' '); + + /* + * CSFPTRD service is used to destroy a token or an object. Handle + * indicates the token or object that must be destroyed and no + * additional data is needed. + */ + return icsf_call(ld, reason, handle, sizeof(handle), rule_array, + sizeof(rule_array), ICSF_TAG_CSFPTRD, NULL, NULL); +} + +/* + * Generate an asymmetric key pair. + */ +int icsf_generate_key_pair(LDAP * ld, int *reason, const char *token_name, + CK_ATTRIBUTE * pub_attrs, CK_ULONG pub_attrs_len, + CK_ATTRIBUTE * priv_attrs, CK_ULONG priv_attrs_len, + struct icsf_object_record *pub_key_object, + struct icsf_object_record *priv_key_object) +{ + int rc = -1; + char handle[ICSF_HANDLE_LEN]; + BerElement *msg = NULL; + BerElement *result = NULL; + struct berval bv_priv_handle = { 0, NULL }; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL_AND_MAX_LEN(token_name, ICSF_TOKEN_NAME_LEN); + CHECK_ARG_NON_NULL(pub_attrs); + CHECK_ARG_NON_NULL(priv_attrs); + CHECK_ARG_NON_NULL(pub_key_object); + CHECK_ARG_NON_NULL(priv_key_object); + + token_name_to_handle(handle, token_name); + + if (!(msg = ber_alloc_t(LBER_USE_DER))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return rc; + } + + /* Encode message: + * + * GKPInput ::= SEQUENCE { + * publicKeyAttrList Attributes, + * privateKeyAttrList Attributes + * } + * + * Attribute lists are built by icsf_ber_put_attribute_list() + */ + if (ber_printf(msg, "{") < 0 || + icsf_ber_put_attribute_list(msg, pub_attrs, pub_attrs_len) < 0 || + ber_printf(msg, "}{") < 0 || + icsf_ber_put_attribute_list(msg, priv_attrs, priv_attrs_len) < 0 || + ber_printf(msg, "}") < 0) { + TRACE_ERROR("Failed to encode message.\n"); + goto cleanup; + } + + rc = icsf_call(ld, reason, handle, sizeof(handle), "", 0, + ICSF_TAG_CSFPGKP, msg, &result); + if (rc) + goto cleanup; + + /* Get private key handle from GKP response */ + if (ber_scanf(result, "m", &bv_priv_handle) == LBER_ERROR) { + TRACE_ERROR("Failed to decode the response.\n"); + rc = -1; + goto cleanup; + } + if (bv_priv_handle.bv_len != ICSF_HANDLE_LEN) { + TRACE_ERROR("Invalid length for handle: %lu\n", + (unsigned long) bv_priv_handle.bv_len); + rc = -1; + goto cleanup; + } + handle_to_object_record(priv_key_object, bv_priv_handle.bv_val); + + /* Get public key handle from common ICSF header */ + handle_to_object_record(pub_key_object, handle); + +cleanup: + if (result) + ber_free(result, 1); + if (msg) + ber_free(msg, 1); + + return rc; +} + +/* + * Generate a symmetric key. + */ +int icsf_generate_secret_key(LDAP * ld, int *reason, const char *token_name, + CK_MECHANISM_PTR mech, + CK_ATTRIBUTE * attrs, CK_ULONG attrs_len, + struct icsf_object_record *object) +{ + int rc = -1; + char handle[ICSF_HANDLE_LEN]; + char rule_array[1 * ICSF_RULE_ITEM_LEN]; + char param[2]; + size_t param_len; + CK_VERSION_PTR version; + BerElement *msg = NULL; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL_AND_MAX_LEN(token_name, ICSF_TOKEN_NAME_LEN); + CHECK_ARG_NON_NULL(mech); + CHECK_ARG_NON_NULL(attrs); + + token_name_to_handle(handle, token_name); + + /* Map mechanism into the rule array */ + switch (mech->mechanism) { + case CKM_TLS_PRE_MASTER_KEY_GEN: + strpad(rule_array, "TLS", sizeof(rule_array), ' '); + break; + case CKM_SSL3_PRE_MASTER_KEY_GEN: + strpad(rule_array, "SSL", sizeof(rule_array), ' '); + break; + case CKM_DSA_PARAMETER_GEN: + case CKM_DH_PKCS_PARAMETER_GEN: + strpad(rule_array, "PARMS", sizeof(rule_array), ' '); + break; + default: + strpad(rule_array, "KEY", sizeof(rule_array), ' '); + } + + /* Fill parameters if necessary */ + switch (mech->mechanism) { + case CKM_TLS_PRE_MASTER_KEY_GEN: + case CKM_SSL3_PRE_MASTER_KEY_GEN: + /* Check expected length */ + if (mech->ulParameterLen != sizeof(*version)) { + TRACE_ERROR("Invalid mechanism parameter length: " + "%lu\n", (unsigned long) mech->ulParameterLen); + return -1; + } + + /* Fill parameter with version numbers */ + version = (CK_VERSION_PTR) mech->pParameter; + param[0] = version->major; + param[1] = version->minor; + param_len = 2; + + break; + default: + /* Parameter should be empty */ + param_len = 0; + } + + if (!(msg = ber_alloc_t(LBER_USE_DER))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return rc; + } + + /* Encode message: + * + * GSKInput ::= SEQUENCE { + * attrList Attributes, + * parmsList OCTET STRING + * } + * + * attrList is built by icsf_ber_put_attribute_list() + */ + if (ber_printf(msg, "{") < 0) { + TRACE_ERROR("Failed to encode message.\n"); + goto cleanup; + } + + if (icsf_ber_put_attribute_list(msg, attrs, attrs_len) < 0 || + ber_printf(msg, "}o", param, param_len) < 0) { + TRACE_ERROR("Failed to encode message.\n"); + goto cleanup; + } + + rc = icsf_call(ld, reason, handle, sizeof(handle), rule_array, + sizeof(rule_array), ICSF_TAG_CSFPGSK, msg, NULL); + if (!rc) + handle_to_object_record(object, handle); + +cleanup: + if (msg) + ber_free(msg, 1); + + return rc; +} + +/* + * Return the rule array element for the given mechanism. + */ +static const char *get_algorithm_rule(CK_MECHANISM_PTR mech, int arg) +{ + switch (mech->mechanism) { + case CKM_DES_ECB: + case CKM_DES_CBC: + case CKM_DES_CBC_PAD: + return "DES"; + case CKM_DES3_ECB: + case CKM_DES3_CBC: + case CKM_DES3_CBC_PAD: + return "DES3"; + case CKM_AES_ECB: + case CKM_AES_CBC: + case CKM_AES_CBC_PAD: + case CKM_AES_CTR: + return "AES"; + case CKM_DSA: + return "DSA"; + case CKM_ECDSA: + return "ECDSA"; + case CKM_RSA_X_509: + return "RSA-ZERO"; + case CKM_RSA_PKCS: + return "RSA-PKCS"; + case CKM_SHA_1_HMAC: + return "SHA-1"; + case CKM_SHA256_HMAC: + return "SHA-256"; + case CKM_SHA384_HMAC: + return "SHA-384"; + case CKM_SHA512_HMAC: + return "SHA-512"; + case CKM_MD5_HMAC: + return "MD5"; + case CKM_SSL3_MD5_MAC: + return "SSL3-MD5"; + case CKM_SSL3_SHA1_MAC: + return "SSL3-SHA"; + case CKM_SHA1_RSA_PKCS: + if (arg) + return "SHA-1 VER-RSA"; + else + return "SHA-1 SIGN-RSA"; + case CKM_SHA256_RSA_PKCS: + if (arg) + return "SHA-256 VER-RSA"; + else + return "SHA-256 SIGN-RSA"; + case CKM_SHA384_RSA_PKCS: + if (arg) + return "SHA-384 VER-RSA"; + else + return "SHA-384 SIGN-RSA"; + case CKM_SHA512_RSA_PKCS: + if (arg) + return "SHA-512 VER-RSA"; + else + return "SHA-512 SIGN-RSA"; + case CKM_MD5_RSA_PKCS: + if (arg) + return "MD5 VER-RSA"; + else + return "MD5 SIGN-RSA"; + case CKM_DSA_SHA1: + if (arg) + return "SHA-1 VER-DSA"; + else + return "SHA-1 SIGN-DSA"; + case CKM_ECDSA_SHA1: + if (arg) + return "SHA-1 VER-EC"; + else + return "SHA-1 SIGN-EC"; + case CKM_SSL3_KEY_AND_MAC_DERIVE: + return "SSL-KM"; + case CKM_TLS_KEY_AND_MAC_DERIVE: + return "TLS-KM"; + } + + return NULL; +} + +/* + * Return the rule array element for the cipher mode based on the given + * mechanism. + */ +static const char *get_cipher_mode(CK_MECHANISM_PTR mech) +{ + switch (mech->mechanism) { + case CKM_DES_ECB: + case CKM_DES3_ECB: + case CKM_AES_ECB: + return "ECB"; + case CKM_DES_CBC: + case CKM_DES3_CBC: + case CKM_AES_CBC: + return "CBC"; + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC_PAD: + case CKM_AES_CBC_PAD: + return "CBC-PAD"; + } + + return NULL; +} + +/* + * Get the block size of supported algorithms/mechanism. + */ +CK_RV icsf_block_size(CK_MECHANISM_TYPE mech_type, CK_ULONG_PTR p_block_size) +{ + CK_ULONG block_size; + + switch (mech_type) { + case CKM_DES_CBC: + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC: + case CKM_DES3_CBC_PAD: + case CKM_DES_ECB: + case CKM_DES3_ECB: + block_size = DES_BLOCK_SIZE; + break; + case CKM_AES_CBC: + case CKM_AES_CBC_PAD: + case CKM_AES_ECB: + block_size = AES_BLOCK_SIZE; + break; + case CKM_MD5_RSA_PKCS: + block_size = MD5_BLOCK_SIZE; + break; + case CKM_SHA1_RSA_PKCS: + case CKM_SHA256_RSA_PKCS: + case CKM_DSA_SHA1: + case CKM_ECDSA_SHA1: + block_size = SHA1_BLOCK_SIZE; + break; + case CKM_SHA384_RSA_PKCS: + case CKM_SHA512_RSA_PKCS: + block_size = SHA384_BLOCK_SIZE; + break; + default: + return CKR_MECHANISM_INVALID; + } + + if (p_block_size) + *p_block_size = block_size; + + return CKR_OK; +} + +/* + * Extract and check the initialization vector contained in the given mechanism. + */ +static CK_RV icsf_encrypt_initial_vector(CK_MECHANISM_PTR mech, char *iv, + size_t * iv_len) +{ + CK_RV rc; + int use_iv = 0; + size_t expected_iv_len = 0; + + if ((rc = icsf_block_size(mech->mechanism, &expected_iv_len))) + return rc; + + switch (mech->mechanism) { + case CKM_DES_CBC: + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC: + case CKM_DES3_CBC_PAD: + case CKM_AES_CBC: + case CKM_AES_CBC_PAD: + use_iv = 1; + } + + if (iv_len && *iv_len < expected_iv_len) { + TRACE_ERROR("IV too small.\n"); + return CKR_FUNCTION_FAILED; + } + + /* Set the Initialization vector */ + if (iv) + memset(iv, 0, expected_iv_len); + if (use_iv) { + /* + * Otherwise use the mechanism parameter as the IV. + */ + if (mech->ulParameterLen != expected_iv_len) { + TRACE_ERROR("Invalid mechanism parameter length: %lu " + "(expected %lu)\n", + (unsigned long) mech->ulParameterLen, + (unsigned long) expected_iv_len); + return CKR_MECHANISM_PARAM_INVALID; + } + if (iv) + memcpy(iv, mech->pParameter, expected_iv_len); + } + if (iv_len) + *iv_len = expected_iv_len; + + return 0; +} + +/* + * Symmetric key encrypt. + */ +int icsf_secret_key_encrypt(LDAP * ld, int *p_reason, + struct icsf_object_record *key, + CK_MECHANISM_PTR mech, int chaining, + const char *clear_text, size_t clear_text_len, + char *cipher_text, size_t * p_cipher_text_len, + char *chaining_data, size_t * p_chaining_data_len) +{ + int rc = 0; + char handle[ICSF_HANDLE_LEN]; + char rule_array[3 * ICSF_RULE_ITEM_LEN]; + BerElement *msg = NULL; + BerElement *result = NULL; + char init_vector[32]; + size_t init_vector_len = sizeof(init_vector); + struct berval bv_cipher_data = { 0UL, NULL }; + struct berval bv_chaining_data = { 0UL, NULL }; + const char *rule_alg, *rule_cipher; + int reason = 0, length = 0; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL(key); + CHECK_ARG_NON_NULL(mech); + CHECK_ARG_NON_NULL(clear_text); + CHECK_ARG_NON_NULL(p_cipher_text_len); + + if (!ICSF_CHAINING_IS_VALID(chaining)) { + TRACE_ERROR("Invalid value for chaining: %d\n", chaining); + return -1; + } + + object_record_to_handle(handle, key); + + /* + * Add to rule array the algorithm, the cipher mode and the + * chaining mode. + */ + if (!(rule_alg = get_algorithm_rule(mech, 0))) { + TRACE_ERROR("Invalid algorithm: %lu\n", + (unsigned long) mech->mechanism); + return -1; + } + + if (!(rule_cipher = get_cipher_mode(mech))) { + TRACE_ERROR("Invalid cipher mode: %lu\n", + (unsigned long) mech->mechanism); + return -1; + } + + strpad(rule_array + 0 * ICSF_RULE_ITEM_LEN, rule_alg, + ICSF_RULE_ITEM_LEN, ' '); + strpad(rule_array + 1 * ICSF_RULE_ITEM_LEN, rule_cipher, + ICSF_RULE_ITEM_LEN, ' '); + strpad(rule_array + 2 * ICSF_RULE_ITEM_LEN, ICSF_CHAINING(chaining), + ICSF_RULE_ITEM_LEN, ' '); + + /* Set the IV based on the given mechanism */ + if (chaining != ICSF_CHAINING_INITIAL && chaining != ICSF_CHAINING_ONLY) { + rc = icsf_encrypt_initial_vector(mech, NULL, NULL); + memset(init_vector, 0, init_vector_len); + } else { + rc = icsf_encrypt_initial_vector(mech, init_vector, &init_vector_len); + } + if (rc) + return -1; + + /* Build request */ + if (!(msg = ber_alloc_t(LBER_USE_DER))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return -1; + } + + if (ber_printf(msg, "toooi", + 0 | LBER_CLASS_CONTEXT, init_vector, init_vector_len, + (chaining_data) ? chaining_data : "", + (p_chaining_data_len) ? *p_chaining_data_len : 0UL, + clear_text, clear_text_len, + (cipher_text) ? *p_cipher_text_len : 0UL) < 0) { + rc = -1; + TRACE_ERROR("Failed to encode message: %d.\n", rc); + goto done; + } + + /* Call service */ + rc = icsf_call(ld, &reason, handle, sizeof(handle), + rule_array, sizeof(rule_array), + ICSF_TAG_CSFPSKE, msg, &result); + if (p_reason) + *p_reason = reason; + if (ICSF_RC_IS_ERROR(rc) + && reason != ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT) + goto done; + + /* Parse response */ + if (ber_scanf(result, "{mmi", &bv_chaining_data, &bv_cipher_data, + &length) == LBER_ERROR) { + rc = -1; + TRACE_ERROR("Failed to decode the response.\n"); + goto done; + } + + *p_cipher_text_len = length; + /* Copy encrypted data */ + if (bv_cipher_data.bv_len > *p_cipher_text_len) { + TRACE_ERROR("Cipher data longer than expected: %lu " + "(expected %lu)\n", + (unsigned long) bv_cipher_data.bv_len, + (unsigned long) *p_cipher_text_len); + rc = -1; + goto done; + } + if (cipher_text) + memcpy(cipher_text, bv_cipher_data.bv_val, bv_cipher_data.bv_len); + + /* Copy chaining data */ + if (p_chaining_data_len) { + if (bv_chaining_data.bv_len > *p_chaining_data_len) { + TRACE_ERROR("Chaining data longer than expected: %lu " + "(expected %lu)\n", + (unsigned long) bv_chaining_data.bv_len, + (unsigned long) *p_chaining_data_len); + rc = -1; + goto done; + } + *p_chaining_data_len = bv_chaining_data.bv_len; + if (chaining_data) { + memcpy(chaining_data, bv_chaining_data.bv_val, + *p_chaining_data_len); + } + } + +done: + if (result) + ber_free(result, 1); + if (msg) + ber_free(msg, 1); + + return rc; +} + +/* + * Symmetric key decrypt. + */ +int icsf_secret_key_decrypt(LDAP * ld, int *p_reason, + struct icsf_object_record *key, + CK_MECHANISM_PTR mech, int chaining, + const char *cipher_text, size_t cipher_text_len, + char *clear_text, size_t * p_clear_text_len, + char *chaining_data, size_t * p_chaining_data_len) +{ + int rc = 0; + char handle[ICSF_HANDLE_LEN]; + char rule_array[3 * ICSF_RULE_ITEM_LEN]; + BerElement *msg = NULL; + BerElement *result = NULL; + char init_vector[32]; + size_t init_vector_len = sizeof(init_vector); + struct berval bv_clear_data = { 0UL, NULL }; + struct berval bv_chaining_data = { 0UL, NULL }; + const char *rule_alg, *rule_cipher; + int reason = 0, length = 0; + size_t clear_len; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL(key); + CHECK_ARG_NON_NULL(mech); + CHECK_ARG_NON_NULL(cipher_text); + CHECK_ARG_NON_NULL(p_clear_text_len); + + if (!ICSF_CHAINING_IS_VALID(chaining)) { + TRACE_ERROR("Invalid value for chaining: %d\n", chaining); + return -1; + } + + object_record_to_handle(handle, key); + + /* + * Add to rule array the algorithm, the cipher mode and the + * chaining mode. + */ + if (!(rule_alg = get_algorithm_rule(mech, 0))) { + TRACE_ERROR("Invalid algorithm: %lu\n", + (unsigned long) mech->mechanism); + return -1; + } + + if (!(rule_cipher = get_cipher_mode(mech))) { + TRACE_ERROR("Invalid cipher mode: %lu\n", + (unsigned long) mech->mechanism); + return -1; + } + + strpad(rule_array + 0 * ICSF_RULE_ITEM_LEN, rule_alg, + ICSF_RULE_ITEM_LEN, ' '); + strpad(rule_array + 1 * ICSF_RULE_ITEM_LEN, rule_cipher, + ICSF_RULE_ITEM_LEN, ' '); + strpad(rule_array + 2 * ICSF_RULE_ITEM_LEN, ICSF_CHAINING(chaining), + ICSF_RULE_ITEM_LEN, ' '); + + /* Set the IV based on the given mechanism */ + if (chaining != ICSF_CHAINING_INITIAL && chaining != ICSF_CHAINING_ONLY) { + rc = icsf_encrypt_initial_vector(mech, NULL, NULL); + memset(init_vector, 0, init_vector_len); + } else { + rc = icsf_encrypt_initial_vector(mech, init_vector, &init_vector_len); + } + if (rc) + return -1; + + /* Build request */ + if (!(msg = ber_alloc_t(LBER_USE_DER))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return -1; + } + + /* + * For mechs with CBC padding (CKM_*_CBC_PAD), we need to specify the clear + * text length at least as large as the cipher text length. The padding is + * removed, but the call still wants the output size to be that large, + * otherwise it returns an ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT error, + * although the resulting (un-padded) clear text fits into the user + * supplied buffer. + */ + clear_len = *p_clear_text_len; + switch (mech->mechanism) { + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC_PAD: + case CKM_AES_CBC_PAD: + if (clear_len < cipher_text_len) + clear_len = cipher_text_len; + break; + default: + break; + } + + if (ber_printf(msg, "totototi", + 0 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE, + init_vector, init_vector_len, + 2 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE, + (chaining_data) ? chaining_data : "", + (p_chaining_data_len) ? *p_chaining_data_len : 0UL, + 3 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE, + cipher_text, cipher_text_len, + 4 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE, + (clear_text) ? clear_len : 0UL) < 0) { + rc = -1; + TRACE_ERROR("Failed to encode message: %d.\n", rc); + goto done; + } + + /* Call service */ + rc = icsf_call(ld, &reason, handle, sizeof(handle), + rule_array, sizeof(rule_array), + ICSF_TAG_CSFPSKD, msg, &result); + if (p_reason) + *p_reason = reason; + if (ICSF_RC_IS_ERROR(rc) && + reason != ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT) + goto done; + + /* Parse response */ + if (ber_scanf(result, "{mmi", &bv_chaining_data, &bv_clear_data, + &length) == LBER_ERROR) { + rc = -1; + TRACE_ERROR("Failed to decode the response.\n"); + goto done; + } + + *p_clear_text_len = length; + /* Copy encrypted data */ + if (bv_clear_data.bv_len > *p_clear_text_len) { + TRACE_ERROR("Clear data longer than expected: %lu " + "(expected %lu)\n", + (unsigned long) bv_clear_data.bv_len, + (unsigned long) *p_clear_text_len); + rc = -1; + goto done; + } + if (clear_text) + memcpy(clear_text, bv_clear_data.bv_val, bv_clear_data.bv_len); + + /* Copy chaining data */ + if (p_chaining_data_len) { + if (bv_chaining_data.bv_len > *p_chaining_data_len) { + TRACE_ERROR("Chaining data longer than expected: %lu " + "(expected %lu)\n", + (unsigned long) bv_chaining_data.bv_len, + (unsigned long) *p_chaining_data_len); + rc = -1; + goto done; + } + *p_chaining_data_len = bv_chaining_data.bv_len; + if (chaining_data) { + memcpy(chaining_data, bv_chaining_data.bv_val, + *p_chaining_data_len); + } + } + +done: + if (result) + ber_free(result, 1); + if (msg) + ber_free(msg, 1); + + return rc; +} + +static int icsf_ber_decode_get_attribute_list(BerElement * berbuf, + CK_ATTRIBUTE * attrs, + CK_ULONG attrs_len) +{ + int attrtype; + struct berval attrbval = { 0, NULL }; + ber_int_t intval; + unsigned int i; + CK_ULONG found = 0; + ber_tag_t tag; + CK_RV rc = CKR_OK; + + if (ber_scanf(berbuf, "{{") == LBER_ERROR) + goto decode_error; + + while (1) { + + /* get tag preceding sequence */ + if (ber_scanf(berbuf, "t", &tag) == LBER_ERROR) + goto decode_error; + + /* is it a sequence (thus attribute) */ + if (tag != (LBER_CLASS_UNIVERSAL | LBER_CONSTRUCTED | LBER_SEQUENCE)) + break; + + /* sequence, so get attribute info */ + if (ber_scanf(berbuf, "{it", &attrtype, &tag) == LBER_ERROR) + goto decode_error; + if ((tag & LBER_BIG_TAG_MASK) == 0) { + if (ber_scanf(berbuf, "o}", &attrbval) == LBER_ERROR) + goto decode_error; + } else { + if (ber_scanf(berbuf, "i}", &intval) == LBER_ERROR) + goto decode_error; + attrbval.bv_len = sizeof(CK_ULONG); + } + + /* see if this type matches any that we need to + * get value for. if so, then get the value, otherwise + * continue until we have found all of them or there + * are no more attributes to search + */ + for (i = 0; i < attrs_len; i++) { + if (attrs[i].type != (CK_ATTRIBUTE_TYPE)attrtype) + continue; + + /* we have decoded attribute, now add the values */ + if (attrs[i].pValue == NULL) { + attrs[i].ulValueLen = attrbval.bv_len; + } else if (attrs[i].ulValueLen >= attrbval.bv_len) { + if ((tag & LBER_BIG_TAG_MASK) == 0) { + memcpy(attrs[i].pValue, attrbval.bv_val, attrbval.bv_len); + } else { + *((CK_ULONG *) attrs[i].pValue) = intval; + } + attrs[i].ulValueLen = attrbval.bv_len; + } else { + rc = CKR_BUFFER_TOO_SMALL; + attrs[i].ulValueLen = -1; + goto decode_error; + } + + /* keep count of how many are found. */ + found++; + } + + /* if we have found all the values for our list, then + * we are done. + */ + if (found == attrs_len) + break; + } + + /* if we have gone through the entire loop and could not find + * all of the attributes in our list, mark this as an error. + */ + if (found < attrs_len) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_TYPE_INVALID)); + rc = CKR_ATTRIBUTE_TYPE_INVALID; + goto decode_error; + } + + return rc; + +decode_error: + TRACE_ERROR("Failed to decode message.\n"); + + if (!rc) + rc = CKR_FUNCTION_FAILED; + + return rc; +} + +int icsf_get_attribute(LDAP * ld, int *reason, + struct icsf_object_record *object, CK_ATTRIBUTE * attrs, + CK_ULONG attrs_len) +{ + + char handle[ICSF_HANDLE_LEN]; + BerElement *msg = NULL; + BerElement *result = NULL; + unsigned int i; + int rc = 0; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL(attrs); + CHECK_ARG_NON_NULL(object); + + object_record_to_handle(handle, object); + + if (!(msg = ber_alloc_t(LBER_USE_DER))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + /* Encode message: + * + * GAVInput ::= attrListLen + * + * attrListLen ::= INTEGER (0 .. MaxCSFPInteger) + * + */ + + rc = ber_printf(msg, "i", attrs_len); + if (rc < 0) + goto cleanup; + + rc = icsf_call(ld, reason, handle, sizeof(handle), "", 0, + ICSF_TAG_CSFPGAV, msg, &result); + if (rc != 0) { + TRACE_DEVEL("icsf_call failed.\n"); + goto cleanup; + } + + /* Before decoding the result, initialize the attribute values length. + * This will help to indicate which attributes were not found + * or not enough storage was allocated for the value. + */ + for (i = 0; i < attrs_len; i++) + attrs[i].ulValueLen = (CK_ULONG) - 1; + + /* Decode the result: + * + * GAVOutput ::= SEQUENCE { + * attrList Attributes, + * attrListLen INTEGER (0 .. MaxCSFPInteger) + * } + * + * asn.1 {{{ito|i} {ito|i} ...}i} + */ + rc = icsf_ber_decode_get_attribute_list(result, attrs, attrs_len); + if (rc < 0) { + TRACE_ERROR("Failed to decode message.\n"); + goto cleanup; + } + +cleanup: + if (msg) + ber_free(msg, 1); + + if (result) + ber_free(result, 1); + + return rc; +} + +int icsf_set_attribute(LDAP * ld, int *reason, + struct icsf_object_record *object, CK_ATTRIBUTE * attrs, + CK_ULONG attrs_len) +{ + int rc = -1; + char handle[ICSF_HANDLE_LEN]; + BerElement *msg = NULL; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL(attrs); + + object_record_to_handle(handle, object); + + if (!(msg = ber_alloc_t(LBER_USE_DER))) { + return rc; + } + + /* Encode message: + * + * SAVInput ::= Attributes + * + * attrList is built by icsf_ber_put_attribute_list() + */ + if (icsf_ber_put_attribute_list(msg, attrs, attrs_len) < 0) { + TRACE_ERROR("Failed to encode message.\n"); + goto cleanup; + } + + rc = icsf_call(ld, reason, handle, sizeof(handle), "", 0, + ICSF_TAG_CSFPSAV, msg, NULL); + if (rc < 0) { + TRACE_ERROR("icsf_call failed.\n"); + goto cleanup; + } + + /* Decode message: + * + * SAVOutput ::= NULL + * + */ + +cleanup: + if (msg) + ber_free(msg, 1); + + + return rc; +} + +/* + * Sign or decrypt data using a private key. + */ +int icsf_private_key_sign(LDAP * ld, int *p_reason, int decrypt, + struct icsf_object_record *key, CK_MECHANISM_PTR mech, + const char *cipher_text, size_t cipher_text_len, + char *clear_text, size_t * p_clear_text_len) +{ + int rc; + int reason = 0; + char handle[ICSF_HANDLE_LEN]; + char rule_array[2 * ICSF_RULE_ITEM_LEN]; + size_t rule_array_count = 0; + const char *rule_alg; + BerElement *msg = NULL; + BerElement *result = NULL; + struct berval bv_clear_text = { 0, NULL }; + int length = 0; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL(key); + CHECK_ARG_NON_NULL(mech); + CHECK_ARG_NON_NULL(cipher_text); + CHECK_ARG_NON_NULL(p_clear_text_len); + + object_record_to_handle(handle, key); + + /* Build rule array based on mechanism */ + if (!(rule_alg = get_algorithm_rule(mech, 0))) { + TRACE_ERROR("Invalid algorithm: %lu\n", + (unsigned long) mech->mechanism); + return -1; + } + + strpad(rule_array, rule_alg, ICSF_RULE_ITEM_LEN, ' '); + rule_array_count += 1; + if (decrypt) { + strpad(rule_array + (rule_array_count * ICSF_RULE_ITEM_LEN), + "DECRYPT", ICSF_RULE_ITEM_LEN, ' '); + rule_array_count += 1; + } + + /* Build request */ + if (!(msg = ber_alloc_t(LBER_USE_DER))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return -1; + } + + if (ber_printf(msg, "oi", cipher_text, (ber_int_t) cipher_text_len, + (!clear_text) ? 0 : ((ber_int_t) * p_clear_text_len)) < 0) { + rc = -1; + TRACE_ERROR("Failed to encode message: %d.\n", rc); + goto done; + } + + /* Call service */ + rc = icsf_call(ld, &reason, handle, sizeof(handle), rule_array, + rule_array_count * ICSF_RULE_ITEM_LEN, ICSF_TAG_CSFPPKS, + msg, &result); + if (p_reason) + *p_reason = reason; + if (ICSF_RC_IS_ERROR(rc) + && reason != ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT) + goto done; + + if (ber_scanf(result, "{mi}", &bv_clear_text, &length) == LBER_ERROR) { + rc = -1; + TRACE_ERROR("Failed to decode the response.\n"); + goto done; + } + + /* Copy clear data */ + *p_clear_text_len = length; + if (bv_clear_text.bv_len > *p_clear_text_len) { + TRACE_ERROR("Clear data longer than expected: %lu " + "(expected %lu)\n", + (unsigned long) bv_clear_text.bv_len, + (unsigned long) *p_clear_text_len); + rc = -1; + goto done; + } + if (clear_text) + memcpy(clear_text, bv_clear_text.bv_val, *p_clear_text_len); + +done: + if (result) + ber_free(result, 1); + if (msg) + ber_free(msg, 1); + return rc; +} + +/* + * Verify or encrypt using a public. key. + */ +int icsf_public_key_verify(LDAP * ld, int *p_reason, int encrypt, + struct icsf_object_record *key, + CK_MECHANISM_PTR mech, const char *clear_text, + size_t clear_text_len, char *cipher_text, + size_t * p_cipher_text_len) +{ + int rc; + int reason = 0; + char handle[ICSF_HANDLE_LEN]; + char rule_array[2 * ICSF_RULE_ITEM_LEN]; + size_t rule_array_count = 0; + const char *rule_alg; + BerElement *msg = NULL; + BerElement *result = NULL; + struct berval bv_cipher_text = { 0, NULL }; + int length = 0; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL(key); + CHECK_ARG_NON_NULL(mech); + CHECK_ARG_NON_NULL(clear_text); + CHECK_ARG_NON_NULL(p_cipher_text_len); + + object_record_to_handle(handle, key); + + /* Build rule array based on mechanism */ + if (!(rule_alg = get_algorithm_rule(mech, 0))) { + TRACE_ERROR("Invalid algorithm: %lu\n", + (unsigned long) mech->mechanism); + return -1; + } + + strpad(rule_array, rule_alg, ICSF_RULE_ITEM_LEN, ' '); + rule_array_count += 1; + if (encrypt) { + strpad(rule_array + (rule_array_count * ICSF_RULE_ITEM_LEN), + "ENCRYPT", ICSF_RULE_ITEM_LEN, ' '); + rule_array_count += 1; + } + + /* Build request */ + if (!(msg = ber_alloc_t(LBER_USE_DER))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return -1; + } + + if (encrypt) { + rc = ber_printf(msg, "oti", clear_text, clear_text_len, + 0 | LBER_CLASS_CONTEXT, *p_cipher_text_len); + } else { + rc = ber_printf(msg, "oto", cipher_text, *p_cipher_text_len, + 1 | LBER_CLASS_CONTEXT, clear_text, clear_text_len); + } + if (rc < 0) { + rc = -1; + TRACE_ERROR("Failed to encode message: %d.\n", rc); + goto done; + } + + /* Call request */ + rc = icsf_call(ld, &reason, handle, sizeof(handle), rule_array, + rule_array_count * ICSF_RULE_ITEM_LEN, ICSF_TAG_CSFPPKV, + msg, &result); + if (p_reason) + *p_reason = reason; + if (ICSF_RC_IS_ERROR(rc) + && reason != ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT) + goto done; + + /* There's no output data when verifying */ + if (!encrypt) + goto done; + + if (ber_scanf(result, "{mi}", &bv_cipher_text, &length) == LBER_ERROR) { + rc = -1; + TRACE_ERROR("Failed to decode the response.\n"); + goto done; + } + + /* Copy clear data */ + *p_cipher_text_len = length; + if (bv_cipher_text.bv_len != *p_cipher_text_len) { + TRACE_ERROR("Cipher data length different that expected: %lu " + "(expected %lu)\n", + (unsigned long) bv_cipher_text.bv_len, + (unsigned long) *p_cipher_text_len); + rc = -1; + goto done; + } + if (cipher_text) + memcpy(cipher_text, bv_cipher_text.bv_val, *p_cipher_text_len); + +done: + if (result) + ber_free(result, 1); + if (msg) + ber_free(msg, 1); + + return rc; +} + +int icsf_hmac_sign(LDAP * ld, int *reason, struct icsf_object_record *key, + CK_MECHANISM_PTR mech, const char *chain_rule, + const char *clear_text, size_t clear_text_len, char *hmac, + size_t * hmac_len, char *chain_data, size_t * chain_data_len) +{ + int rc = 0; + char handle[ICSF_HANDLE_LEN]; + char rule_array[2 * ICSF_RULE_ITEM_LEN]; + BerElement *msg = NULL; + BerElement *result = NULL; + struct berval bvHmac = { 0, NULL }; + struct berval bvChain = { 0, NULL }; + int hmac_length; + const char *rule_alg; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL(key); + CHECK_ARG_NON_NULL(mech); + + object_record_to_handle(handle, key); + + /* Add to rule array, the algorithm and chaining mode */ + + if (!(rule_alg = get_algorithm_rule(mech, 0))) { + TRACE_ERROR("Invalid algorithm: %lu\n", + (unsigned long) mech->mechanism); + return -1; + } + + strpad(rule_array + 0 * ICSF_RULE_ITEM_LEN, rule_alg, + ICSF_RULE_ITEM_LEN, ' '); + strpad(rule_array + 1 * ICSF_RULE_ITEM_LEN, chain_rule, + ICSF_RULE_ITEM_LEN, ' '); + + /* Build the request */ + if (!(msg = ber_alloc_t(LBER_USE_DER))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return -1; + } + + /* Input ASN.1 for CSFPHMG. + * HMGInput ::= SEQUENCE { + * text OCTET STRING, + * chainData OCTET STRING, + * hmacLength INTEGER (0 .. MaxCSFPInteger) + * } + */ + + if (ber_printf(msg, "ooi", (clear_text) ? clear_text : "", + clear_text_len, chain_data, *chain_data_len, + *hmac_len) < 0) { + rc = -1; + TRACE_ERROR("Failed to encode message: %d.\n", rc); + goto done; + } + + /* Call service */ + rc = icsf_call(ld, reason, handle, sizeof(handle), rule_array, + sizeof(rule_array), ICSF_TAG_CSFPHMG, msg, &result); + + if (ICSF_RC_IS_ERROR(rc)) { + TRACE_DEVEL("icsf_call failed\n"); + goto done; + } + + /* Parse the response. + * HMGOutput ::= SEQUENCE { + * chainData OCTET STRING, + * hmac OCTET STRING, + * hmacLength INTEGER (0 .. MaxCSFPInteger) + * } + * + * Where, + * chainData - A string that specifies the chaining data returned + * during multi-part HMAC hashing in the CSFPHMG callable service. + * This chainData must be specified on subsequent calls to + * the CSFPHMG callable service. + * hmac - A string containing the HMAC value + * hmacLength - ignored by ICSF + * + * NOTE: + * - chainData is always blindly returned, whether it is pertinent + * or not. + * - For a FIRST or MIDDLE request, hmac is returned as a zero length + * string. + * - For a LAST or ONLY request, hmac is returned as a string of + * appropriate length based on the mechanism. The validity of the hmac + * contents are subject to ICSF behavior, based on the ICSF return + * code and ICSF reason code. + * - The hmacLength is ignored by ICSF and has no affect on how we + * encode the returned hmac. The hmacLength is passed along through + * the BER encoded messages and in and out of the ICSF call in case + * this changes in the future. + */ + + if (ber_scanf(result, "{ooi}", &bvChain, &bvHmac, &hmac_length) + == LBER_ERROR) { + rc = -1; + TRACE_ERROR("Failed to decode the response.\n"); + goto done; + } + + /* copy the chained data even if not using it */ + *chain_data_len = bvChain.bv_len; + memcpy(chain_data, bvChain.bv_val, bvChain.bv_len); + + /* copy the hmac when needed */ + if (*hmac_len) { + if (*hmac_len >= bvHmac.bv_len) { + memcpy(hmac, bvHmac.bv_val, bvHmac.bv_len); + *hmac_len = bvHmac.bv_len; + } else { + /* supplied buffer is too small */ + *reason = 3003; + } + } +done: + if (result) + ber_free(result, 1); + + if (msg) + ber_free(msg, 1); + if (bvHmac.bv_val) + ber_memfree(bvHmac.bv_val); + if (bvChain.bv_val) + ber_memfree(bvChain.bv_val); + + return rc; +} + +int icsf_hmac_verify(LDAP * ld, int *reason, struct icsf_object_record *key, + CK_MECHANISM_PTR mech, const char *chain_rule, + const char *clear_text, size_t clear_text_len, + char *hmac, size_t hmac_len, char *chain_data, + size_t * chain_data_len) +{ + int rc = 0; + char handle[ICSF_HANDLE_LEN]; + char rule_array[2 * ICSF_RULE_ITEM_LEN]; + BerElement *msg = NULL; + BerElement *result = NULL; + struct berval bvChain = { 0UL, NULL }; + const char *rule_alg; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL(key); + CHECK_ARG_NON_NULL(mech); + + object_record_to_handle(handle, key); + + /* Add to rule array, the algorithm and chaining mode */ + + if (!(rule_alg = get_algorithm_rule(mech, 0))) { + TRACE_ERROR("Invalid algorithm: %lu\n", + (unsigned long) mech->mechanism); + return -1; + } + + strpad(rule_array + 0 * ICSF_RULE_ITEM_LEN, rule_alg, + ICSF_RULE_ITEM_LEN, ' '); + strpad(rule_array + 1 * ICSF_RULE_ITEM_LEN, chain_rule, + ICSF_RULE_ITEM_LEN, ' '); + + /* Build the request */ + if (!(msg = ber_alloc_t(LBER_USE_DER))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return -1; + } + + /* + * Input ASN.1 for CSFPHMV. + * HMVInput ::= SEQUENCE { + * text OCTET STRING, + * chainData OCTET STRING, + * hmac OCTET STRING + * } + * + * Where, + * text - A string that identifies the text to test an HMAC hash + * in the CSFPHMV callable service. + * chainData - A string that specifies the chaining data maintained + * during multi-part HMAC hashing in the CSFPHMV callable + * service. + * hmac - A string that identifies the HMAC hash to verify + * against the text in the CSFPHMV callable service. + * NOTE: + * - chainData is always required, even on a FIRST call (where it is + * not really an input) and even on an ONLY call (where there is no + * chaining). An HMV ONLY call fails with reason_code=11000 when + * chain_data_length is 0. + * - For an ONLY call or LAST call, hmac MUST be at least as + * many bytes in length as required based on the mechanism. + * - For a FIRST or MIDDLE call, hmac is ignored. + */ + if (ber_printf(msg, "ooo", (clear_text) ? clear_text : "", + clear_text_len, chain_data, *chain_data_len, + hmac, hmac_len) < 0) { + rc = -1; + TRACE_ERROR("Failed to encode message: %d.\n", rc); + goto done; + } + + /* Call service */ + rc = icsf_call(ld, reason, handle, sizeof(handle), rule_array, + sizeof(rule_array), ICSF_TAG_CSFPHMV, msg, &result); + + if (ICSF_RC_IS_ERROR(rc)) { + TRACE_DEVEL("icsf_call failed\n"); + goto done; + } + + /* Parse the response. + * HMVOutput ::= chainData OCTET STRING + * + * Where, + * chainData - A string that specifies the chaining data returned + * during multi-part HMAC hashing in the CSFPHMV callable service. + * This chainData must be specified on subsequent calls to + * the CSFPHMV callable service. + * + * NOTE: + * - chainData is always blindly returned, whether it is pertinent + * or not. + */ + if (ber_scanf(result, "m", &bvChain) == LBER_ERROR) { + rc = -1; + TRACE_ERROR("Failed to decode the response.\n"); + goto done; + } + + /* if chaining, copy the chained data */ + *chain_data_len = bvChain.bv_len; + memcpy(chain_data, bvChain.bv_val, bvChain.bv_len); + +done: + if (result) + ber_free(result, 1); + + if (msg) + ber_free(msg, 1); + + return rc; +} + +/* + * Wrap a key. + */ +int icsf_wrap_key(LDAP * ld, int *p_reason, CK_MECHANISM_PTR mech, + struct icsf_object_record *wrapping_key, + struct icsf_object_record *key, CK_BYTE_PTR wrapped_key, + CK_ULONG_PTR p_wrapped_key_len) +{ + int rc = 0; + int reason = 0; + char handle[ICSF_HANDLE_LEN]; + char wrapping_handle[ICSF_HANDLE_LEN]; + char rule_array[2 * ICSF_RULE_ITEM_LEN]; + size_t rule_array_count = 0; + const char *rule_fmt = NULL; + const char *rule_alg = NULL; + BerElement *msg = NULL; + BerElement *result = NULL; + struct berval bv_wrapped_key = { 0, NULL }; + ber_int_t wrapped_key_len = 0; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL(mech); + CHECK_ARG_NON_NULL(wrapping_key); + CHECK_ARG_NON_NULL(key); + CHECK_ARG_NON_NULL(p_wrapped_key_len); + + object_record_to_handle(handle, key); + object_record_to_handle(wrapping_handle, wrapping_key); + + /* Build rule array based on mechanism */ + switch (mech->mechanism) { + case CKM_RSA_PKCS: + rule_fmt = "PKCS-1.2"; + break; + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC_PAD: + case CKM_AES_CBC_PAD: + rule_fmt = "PKCS-8"; + if (!(rule_alg = get_algorithm_rule(mech, 0))) { + TRACE_ERROR("Invalid algorithm: %lu\n", + (unsigned long) mech->mechanism); + return -1; + } + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return -1; + } + + strpad(rule_array, rule_fmt, ICSF_RULE_ITEM_LEN, ' '); + rule_array_count += 1; + if (rule_alg) { + strpad(rule_array + (rule_array_count * ICSF_RULE_ITEM_LEN), + rule_alg, ICSF_RULE_ITEM_LEN, ' '); + rule_array_count += 1; + } + + /* Build request */ + if (!(msg = ber_alloc_t(LBER_USE_DER))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return -1; + } + + /* Encode message: + * + * WPKInput ::= SEQUENCE { + * wrappingHandle OCTET STRING, + * wrappedKeyMaxLen INTEGER (0 .. MaxCSFPInteger), + * initialValue OCTET STRING + * } + * For a size query (wrapped_key is NULL), we set wrappedKeyMaxLen to + * USHRT_MAX (65535), which is hopefully large enough. + */ + rc = ber_printf(msg, "ois", wrapping_handle, sizeof(wrapping_handle), + wrapped_key != NULL ? (ber_int_t)*p_wrapped_key_len : USHRT_MAX, ""); + if (rc < 0) { + rc = -1; + TRACE_ERROR("Failed to encode message: %d.\n", rc); + goto done; + } + + /* Call request */ + rc = icsf_call(ld, &reason, handle, sizeof(handle), rule_array, + rule_array_count * ICSF_RULE_ITEM_LEN, ICSF_TAG_CSFPWPK, + msg, &result); + if (p_reason) + *p_reason = reason; + if (ICSF_RC_IS_ERROR(rc) + && reason != ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT) + goto done; + + /* Decode message: + * + * WPKOutput ::= SEQUENCE { + * wrappedKey OCTET STRING, + * wrappedKeyLen INTEGER + * } + */ + if (ber_scanf(result, "{mi}", &bv_wrapped_key, &wrapped_key_len) + == LBER_ERROR) { + rc = -1; + TRACE_ERROR("Failed to decode the response.\n"); + goto done; + } + *p_wrapped_key_len = wrapped_key_len; + + /* Copy wrapped key */ + if (bv_wrapped_key.bv_len > *p_wrapped_key_len) { + TRACE_ERROR("Wrapped key length different that expected: %lu " + "(expected %lu)\n", + (unsigned long) bv_wrapped_key.bv_len, + (unsigned long) *p_wrapped_key_len); + rc = -1; + goto done; + } + if (wrapped_key) + memcpy(wrapped_key, bv_wrapped_key.bv_val, *p_wrapped_key_len); + +done: + if (result) + ber_free(result, 1); + if (msg) + ber_free(msg, 1); + + return rc; +} + +/* + * Unwrap a key. + */ +int icsf_unwrap_key(LDAP * ld, int *p_reason, CK_MECHANISM_PTR mech, + struct icsf_object_record *unwrapping_key, + CK_BYTE_PTR wrapped_key, CK_ULONG wrapped_key_len, + CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, + struct icsf_object_record *key) +{ + int rc = 0; + int reason = 0; + char handle[ICSF_HANDLE_LEN]; + char rule_array[2 * ICSF_RULE_ITEM_LEN]; + size_t rule_array_count = 0; + const char *rule_fmt = NULL; + const char *rule_alg = NULL; + BerElement *msg = NULL; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL(mech); + CHECK_ARG_NON_NULL(unwrapping_key); + CHECK_ARG_NON_NULL(wrapped_key); + CHECK_ARG_NON_NULL(key); + + object_record_to_handle(handle, unwrapping_key); + + /* Build rule array based on mechanism */ + switch (mech->mechanism) { + case CKM_RSA_PKCS: + rule_fmt = "PKCS-1.2"; + break; + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC_PAD: + case CKM_AES_CBC_PAD: + rule_fmt = "PKCS-8"; + if (!(rule_alg = get_algorithm_rule(mech, 0))) { + TRACE_ERROR("Invalid algorithm: %lu\n", + (unsigned long) mech->mechanism); + return -1; + } + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return -1; + } + + strpad(rule_array, rule_fmt, ICSF_RULE_ITEM_LEN, ' '); + rule_array_count += 1; + if (rule_alg) { + strpad(rule_array + (rule_array_count * ICSF_RULE_ITEM_LEN), + rule_alg, ICSF_RULE_ITEM_LEN, ' '); + rule_array_count += 1; + } + + /* Build request */ + if (!(msg = ber_alloc_t(LBER_USE_DER))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return -1; + } + + /* Encode message: + * + * UWKInput ::= SEQUENCE { + * wrappedKey OCTET STRING, + * initialValue OCTET STRING, + * attrList Attributes + * } + */ + if (ber_printf(msg, "os", wrapped_key, wrapped_key_len, "") < 0 || + ber_printf(msg, "{") < 0 || + icsf_ber_put_attribute_list(msg, attrs, attrs_len) || + ber_printf(msg, "}") < 0) { + rc = -1; + TRACE_ERROR("Failed to encode message: %d.\n", rc); + goto done; + } + + /* Call request */ + rc = icsf_call(ld, &reason, handle, sizeof(handle), rule_array, + rule_array_count * ICSF_RULE_ITEM_LEN, ICSF_TAG_CSFPUWK, + msg, NULL); + if (p_reason) + *p_reason = reason; + if (ICSF_RC_IS_ERROR(rc)) + goto done; + + handle_to_object_record(key, handle); + +done: + if (msg) + ber_free(msg, 1); + + return rc; +} + +int icsf_hash_signverify(LDAP * ld, int *reason, struct icsf_object_record *key, + CK_MECHANISM_PTR mech, const char *chain_rule, + const char *clear_text, unsigned long clear_text_len, + char *sig, unsigned long *sig_len, char *chain_data, + size_t * chain_data_len, int verify) +{ + int rc = 0; + char handle[ICSF_HANDLE_LEN]; + char rule_array[3 * ICSF_RULE_ITEM_LEN]; + BerElement *msg = NULL; + BerElement *result = NULL; + struct berval bvSig = { 0, NULL }; + struct berval bvChain = { 0, NULL }; + int length, reason_code; + const char *rule_alg; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL(key); + CHECK_ARG_NON_NULL(mech); + + object_record_to_handle(handle, key); + + /* Add to rule array, the algorithm and chaining mode */ + if (!(rule_alg = get_algorithm_rule(mech, verify))) { + TRACE_ERROR("Invalid algorithm: %lu\n", + (unsigned long) mech->mechanism); + return -1; + } + + strpad(rule_array + 0 * ICSF_RULE_ITEM_LEN, rule_alg, + 2 * ICSF_RULE_ITEM_LEN, ' '); + strpad(rule_array + 2 * ICSF_RULE_ITEM_LEN, chain_rule, + ICSF_RULE_ITEM_LEN, ' '); + + /* Build the request */ + if (!(msg = ber_alloc_t(LBER_USE_DER))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return -1; + } + + if (ber_printf(msg, "ooo", (clear_text) ? clear_text : "", + clear_text_len, (chain_data) ? chain_data : "", + (chain_data_len) ? *chain_data_len : 0UL, + (sig) ? sig : "", (sig_len) ? *sig_len : 0) < 0) { + rc = -1; + TRACE_ERROR("Failed to encode message: %d.\n", rc); + goto done; + } + + /* Call service */ + rc = icsf_call(ld, &reason_code, handle, sizeof(handle), rule_array, + sizeof(rule_array), ICSF_TAG_CSFPOWH, msg, &result); + + if (reason) + *reason = reason_code; + + /* If there was an error related to buffer being too small, + * don't exit until you get the max required length from response. + */ + if (ICSF_RC_IS_ERROR(rc) && (reason_code != 3003)) + goto done; + else if ((reason_code == 8000) || (reason_code == 11000)) + goto done; + + /* Parse the response. */ + if (ber_scanf(result, "{ooi}", &bvChain, &bvSig, &length) == LBER_ERROR) { + rc = -1; + TRACE_ERROR("Failed to decode the response.\n"); + goto done; + } + + /* Only need to return the length for signing */ + if (sig_len && !verify) + *sig_len = length; + + /* leave if just returning the length. */ + if (!verify && *reason == 3003) + goto done; + + /* copy the chained data when required */ + if (chain_data) + memcpy(chain_data, bvChain.bv_val, bvChain.bv_len); + + /* copy signature when signing */ + if (!verify) + memcpy(sig, bvSig.bv_val, bvSig.bv_len); + +done: + if (result) + ber_free(result, 1); + if (msg) + ber_free(msg, 1); + if (bvSig.bv_val) + ber_memfree(bvSig.bv_val); + if (bvChain.bv_val) + ber_memfree(bvChain.bv_val); + + return rc; +} + +/* + * Derive a symmetric key. + */ +int icsf_derive_key(LDAP * ld, int *reason, CK_MECHANISM_PTR mech, + struct icsf_object_record *baseKey, + struct icsf_object_record *object, + CK_ATTRIBUTE * attrs, CK_ULONG attrs_len) +{ + int rc = -1; + char handle[ICSF_HANDLE_LEN]; + char rule_array[1 * ICSF_RULE_ITEM_LEN]; + BerElement *msg = NULL; + BerElement *result = NULL; + CK_VERSION_PTR version = NULL; + CK_SSL3_MASTER_KEY_DERIVE_PARAMS *params = NULL; + CK_SSL3_RANDOM_DATA *random_data = NULL; + struct berval clientData = { 0, NULL }, serverData = { + 0, NULL}; + struct berval publicValue = { 0, NULL }, bvParam = { + 0, NULL}; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL(mech); + + object_record_to_handle(handle, baseKey); + + /* Map mechanism into the rule array */ + switch (mech->mechanism) { + case CKM_SSL3_MASTER_KEY_DERIVE: + strpad(rule_array, "SSL-MS", ICSF_RULE_ITEM_LEN, ' '); + break; + case CKM_DH_PKCS_DERIVE: + strpad(rule_array, "PKCS-DH", ICSF_RULE_ITEM_LEN, ' '); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return -1; + } + + if (!(msg = ber_alloc_t(LBER_USE_DER))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return rc; + } + + /* Encode message: + * + * DVKInput ::= SEQUENCE { + * attrList Attributes, + * parmsListChoice DVKInputParmsList + * } + * + * DVKInputParmsList ::= CHOICE { + * PKCS-DH_publicValue [0] OCTET STRING, + * SSL-TLS [1] SSL-TLS_DVKInputParmsList, + * EC-DH [2] EC-DH_DVKInputParmsList + * } + * + * SSL-TLS_DVKInputParmsList ::= SEQUENCE { + * clientRandomData OCTET STRING, + * serverRandomData OCTET STRING + * } + * + * EC-DH is not supported + * + * attrList is built by icsf_ber_put_attribute_list() + */ + if (ber_printf(msg, "{") < 0) { + TRACE_ERROR("Failed to encode message.\n"); + goto cleanup; + } + + if (icsf_ber_put_attribute_list(msg, attrs, attrs_len) < 0) { + TRACE_DEVEL("Failed to encode message.\n"); + goto cleanup; + } + + if (ber_printf(msg, "}") < 0) { + TRACE_ERROR("Failed to encode message.\n"); + goto cleanup; + } + + /* Attribute list depends on type of mechanism */ + switch (mech->mechanism) { + case CKM_DH_PKCS_DERIVE: + if ((!mech->pParameter) || ((mech->ulParameterLen < 64) || + (mech->ulParameterLen > 256))) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + publicValue.bv_val = mech->pParameter; + publicValue.bv_len = mech->ulParameterLen; + if (ber_printf + (msg, "tO", 0 | LBER_PRIMITIVE | LBER_CLASS_CONTEXT, + &publicValue) < 0) { + TRACE_ERROR("Failed to encode message.\n"); + goto cleanup; + } + break; + case CKM_SSL3_MASTER_KEY_DERIVE: + params = (CK_SSL3_MASTER_KEY_DERIVE_PARAMS *) mech->pParameter; + random_data = (CK_SSL3_RANDOM_DATA *) (¶ms->RandomInfo); + + clientData.bv_len = random_data->ulClientRandomLen; + clientData.bv_val = (char *)random_data->pClientRandom; + serverData.bv_len = random_data->ulServerRandomLen; + serverData.bv_val = (char *)random_data->pServerRandom; + + if (ber_printf(msg, "t{OO}", 1 | LBER_CLASS_CONTEXT | LBER_CONSTRUCTED, + &clientData, &serverData) < 0) { + TRACE_ERROR("Failed to encode message.\n"); + goto cleanup; + } + break; + default: + TRACE_ERROR("Mechanism not supported.\n"); + return -1; + } + + rc = icsf_call(ld, reason, handle, sizeof(handle), rule_array, + sizeof(rule_array), ICSF_TAG_CSFPDVK, msg, &result); + if (!rc) { + handle_to_object_record(object, handle); + + /* Decode the result: + * + * DVKOutput ::= SEQUENCE { + * parmsListChoice DVKOutputParmsList + * } + * + * DVKOutputParmsList ::= CHOICE { + * PKCS-DH_Output [0] NULL, + * SSL-TLS_Output [1] OCTET STRING, + * EC-DH_Output [2] NULL (not supported) + * } + */ + if (mech->mechanism == CKM_SSL3_MASTER_KEY_DERIVE) { + if (ber_scanf(result, "o", &bvParam) == LBER_ERROR) { + TRACE_ERROR("Failed to Derive Key\n"); + rc = -1; + goto cleanup; + } + + params = (CK_SSL3_MASTER_KEY_DERIVE_PARAMS *) mech->pParameter; + version = (CK_VERSION_PTR) (¶ms->pVersion); + version->major = bvParam.bv_val[0]; + version->minor = bvParam.bv_val[1]; + } + } + + rc = 0; + +cleanup: + if (msg) + ber_free(msg, 1); + if (result) + ber_free(result, 1); + + return rc; +} + +/* + * Devive multiple keys at once. + */ +int icsf_derive_multiple_keys(LDAP * ld, int *p_reason, CK_MECHANISM_PTR mech, + struct icsf_object_record *key, + CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, + struct icsf_object_record *client_mac_handle, + struct icsf_object_record *server_mac_handle, + struct icsf_object_record *client_key_handle, + struct icsf_object_record *server_key_handle, + unsigned char *client_iv, + unsigned char *server_iv) +{ + int rc = 0; + const char *rule_alg; + char handle[ICSF_HANDLE_LEN]; + char rule_array[ICSF_RULE_ITEM_LEN]; + BerElement *msg = NULL; + BerElement *result = NULL; + ber_tag_t tag; + CK_SSL3_KEY_MAT_PARAMS *params; + struct berval bv_client_random_data; + struct berval bv_server_random_data; + struct berval bv_client_mac_handle = { 0, NULL }; + struct berval bv_server_mac_handle = { 0, NULL }; + struct berval bv_client_key_handle = { 0, NULL }; + struct berval bv_server_key_handle = { 0, NULL }; + struct berval bv_client_iv = { 0, NULL }; + struct berval bv_server_iv = { 0, NULL }; + + UNUSED(client_iv); + UNUSED(server_iv); + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL(mech); + CHECK_ARG_NON_NULL(key); + + object_record_to_handle(handle, key); + + /* Build rule array based on mechanism */ + if (!(rule_alg = get_algorithm_rule(mech, 0))) { + TRACE_ERROR("Invalid algorithm: %lu\n", + (unsigned long) mech->mechanism); + return -1; + } + + strpad(rule_array, rule_alg, ICSF_RULE_ITEM_LEN, ' '); + + /* Build request */ + if (!(msg = ber_alloc_t(LBER_USE_DER))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return -1; + } + + /* + * DMKInput sequence. + * + * DMKInput ::= SEQUENCE { + * attrList Attributes, + * parmsListChoice DMKInputParmsList + * } + * + * DMKInputParmsList ::= CHOICE { + * SSL-KM_TLS-KM [0] SSL_TLS_DMKInputParmsList + * } + * + * SSL_TLS_DMKInputParmsList ::= SEQUENCE { + * export BOOLEAN, + * macSize INTEGER, + * keySize INTEGER, + * ivSize INTEGER, + * clientRandomData OCTET STRING, + * serverRandomData OCTET STRING + * } + */ + params = (CK_SSL3_KEY_MAT_PARAMS *) mech->pParameter; + if (!params) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + rc = ber_printf(msg, "{"); + if (rc < 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + goto done; + } + + if (icsf_ber_put_attribute_list(msg, attrs, attrs_len) < 0) { + TRACE_ERROR("icsf_ber_put_attribute_list failed\n"); + goto done; + } + + if (ber_printf(msg, "}") < 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + goto done; + } + + tag = 0 | LBER_CLASS_CONTEXT | LBER_CONSTRUCTED; + bv_client_random_data.bv_len = params->RandomInfo.ulClientRandomLen; + bv_client_random_data.bv_val = (char *)params->RandomInfo.pClientRandom; + bv_server_random_data.bv_len = params->RandomInfo.ulServerRandomLen; + bv_server_random_data.bv_val = (char *)params->RandomInfo.pServerRandom; + + rc = ber_printf(msg, "t{biiiOO}", tag, + (ber_int_t) params->bIsExport, + (ber_int_t) params->ulMacSizeInBits, + (ber_int_t) params->ulKeySizeInBits, + (ber_int_t) params->ulIVSizeInBits, + &bv_client_random_data, &bv_server_random_data); + if (rc < 0) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + goto done; + } + + /* Call request */ + rc = icsf_call(ld, p_reason, handle, sizeof(handle), rule_array, + sizeof(rule_array), ICSF_TAG_CSFPDMK, msg, &result); + if (ICSF_RC_IS_ERROR(rc)) + goto done; + + /* + * DMKOutput ::= SEQUENCE { + * parmsListChoice DMKOutputParmsList + * } + * + * DMKOutputParmsList ::= CHOICE { + * SSL-KM_TLS-KM [0] SSL_TLS_DMKOutputParmsList + * } + * + * SSL_TLS_DMKOutputParmsList ::= SEQUENCE { + * clientMACHandle OCTET STRING, + * clientMACHandle OCTET STRING, + * clientKeyHandle OCTET STRING, + * serverKeyHandle OCTET STRING, + * clientIV OCTET STRING, + * serverIV OCTET STRING + * } + */ + + /* + * Since we are copying the values after all, "m" has the advantage of + * not needing to free the returned values... + */ + if (ber_scanf(result, "{t{mmmmmm}}", &tag, &bv_client_mac_handle, + &bv_server_mac_handle, &bv_client_key_handle, + &bv_server_key_handle, &bv_client_iv, &bv_server_iv) + == LBER_ERROR) { + rc = -1; + TRACE_ERROR("Failed to decode the response.\n"); + goto done; + } + + /* Copy key handles */ + if (bv_client_mac_handle.bv_len != ICSF_HANDLE_LEN || + bv_server_mac_handle.bv_len != ICSF_HANDLE_LEN || + bv_client_key_handle.bv_len != ICSF_HANDLE_LEN || + bv_server_key_handle.bv_len != ICSF_HANDLE_LEN) { + TRACE_ERROR("Invalid key handle size: %lu/%lu/%lu/%lu\n", + (unsigned long) bv_client_mac_handle.bv_len, + (unsigned long) bv_server_mac_handle.bv_len, + (unsigned long) bv_client_key_handle.bv_len, + (unsigned long) bv_server_key_handle.bv_len); + rc = CKR_FUNCTION_FAILED; + goto done; + } + handle_to_object_record(client_mac_handle, bv_client_mac_handle.bv_val); + handle_to_object_record(server_mac_handle, bv_server_mac_handle.bv_val); + handle_to_object_record(client_key_handle, bv_client_key_handle.bv_val); + handle_to_object_record(server_key_handle, bv_server_key_handle.bv_val); + + /* Copy IVs */ + if (params->ulIVSizeInBits) { + if (8 * bv_client_iv.bv_len != params->ulIVSizeInBits) { + TRACE_ERROR("Invalid client IV size: %lu\n", + (unsigned long) bv_client_iv.bv_len); + rc = CKR_FUNCTION_FAILED; + goto done; + } + memcpy(params->pReturnedKeyMaterial->pIVClient, + bv_client_iv.bv_val, bv_client_iv.bv_len); + + if (8 * bv_server_iv.bv_len != params->ulIVSizeInBits) { + TRACE_ERROR("Invalid server IV size: %lu\n", + (unsigned long) bv_server_iv.bv_len); + rc = CKR_FUNCTION_FAILED; + goto done; + } + memcpy(params->pReturnedKeyMaterial->pIVServer, + bv_server_iv.bv_val, bv_server_iv.bv_len); + } + +done: + if (result) + ber_free(result, 1); + if (msg) + ber_free(msg, 1); + + return rc; +} + +/** get size of an icsf object */ +int icsf_get_object_size(LDAP * ld, int *reason, + struct icsf_object_record *object, CK_ULONG attrs_len, + CK_ULONG * obj_size) +{ + + char handle[ICSF_HANDLE_LEN]; + BerElement *msg = NULL; + BerElement *result = NULL; + int rc = 0; + int size = 0; + + CHECK_ARG_NON_NULL(ld); + CHECK_ARG_NON_NULL(object); + + object_record_to_handle(handle, object); + + if (!(msg = ber_alloc_t(LBER_USE_DER))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + /* Encode message: + * + * GAVInput ::= attrListLen + * + * attrListLen ::= INTEGER (0 .. MaxCSFPInteger) + * + */ + + rc = ber_printf(msg, "i", attrs_len); + if (rc < 0) + goto cleanup; + + rc = icsf_call(ld, reason, handle, sizeof(handle), "", 0, + ICSF_TAG_CSFPGAV, msg, &result); + if (rc != 0) { + TRACE_DEVEL("icsf_call failed. rc=%d, reason=%d", rc, *reason); + goto cleanup; + } + + /* Decode the result: + * + * GAVOutput ::= SEQUENCE { + * attrList Attributes, + * attrListLen INTEGER (0 .. MaxCSFPInteger) + * } + * + * asn.1 {{{ito|i} {ito|i} ...}i} + */ + + if (ber_scanf(result, "{") == LBER_ERROR) { + TRACE_ERROR("Failed to decode message - icsf_get_object_size"); + goto cleanup; + } + //interested only in the list length which will be the size of the object in + //bytes + if (ber_scanf(result, "xi}", &size) == LBER_ERROR) { + TRACE_ERROR("Failed to decode message - icsf_get_object_size"); + goto cleanup; + } + TRACE_INFO("icsf_get_object_size - size = %d\n", size); + + *obj_size = size; + +cleanup: + if (msg) + ber_free(msg, 1); + + if (result) + ber_free(result, 1); + + return rc; +} diff --git a/usr/lib/icsf_stdll/icsf.h b/usr/lib/icsf_stdll/icsf.h new file mode 100644 index 0000000..6046d24 --- /dev/null +++ b/usr/lib/icsf_stdll/icsf.h @@ -0,0 +1,260 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2012-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 + */ + +/* + * OpenCryptoki ICSF token - LDAP functions + * + * Author: Marcelo Cerri (mhcerri@br.ibm.com) + * + */ + +#ifndef ICSF_H +#define ICSF_H + +#include +#include +#include "pkcs11types.h" + +/* OIDs used for PKCS extension */ +#define ICSF_REQ_OID "1.3.18.0.2.12.83" +#define ICSF_RES_OID "1.3.18.0.2.12.84" + +/* + * Tag numbers for each ICSF call. + * + * ICSF message is composed by some fields that are common to all services and + * a service-specific field. The tag number of this field identifies the + * service that is called. + */ +#define ICSF_TAG_CSFPDMK 1 // Derive Multiple Keys +#define ICSF_TAG_CSFPDVK 2 // Derive Key +#define ICSF_TAG_CSFPGAV 3 +#define ICSF_TAG_CSFPGKP 4 +#define ICSF_TAG_CSFPGSK 5 +#define ICSF_TAG_CSFPHMG 6 +#define ICSF_TAG_CSFPHMV 7 +#define ICSF_TAG_CSFPOWH 8 +#define ICSF_TAG_CSFPPKS 9 +#define ICSF_TAG_CSFPPKV 10 +#define ICSF_TAG_CSFPSAV 11 +#define ICSF_TAG_CSFPSKD 12 +#define ICSF_TAG_CSFPSKE 13 +#define ICSF_TAG_CSFPTRC 14 +#define ICSF_TAG_CSFPTRD 15 +#define ICSF_TAG_CSFPTRL 16 +#define ICSF_TAG_CSFPUWK 17 +#define ICSF_TAG_CSFPWPK 18 + +/* Return codes */ +#define ICSF_RC_SUCCESS 0 +#define ICSF_RC_PARTIAL_SUCCESS 4 +#define ICSF_RC_ERROR 8 +#define ICSF_RC_FATAL 12 +#define ICSF_RC_IS_ERROR(rc) \ + ((rc) > ICSF_RC_PARTIAL_SUCCESS || (rc) < 0) + +/* Reason codes */ +#define ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT 3003 + +/* Default lengths */ +#define ICSF_HANDLE_LEN 44 +#define ICSF_TOKEN_RECORD_LEN 116 +#define ICSF_TOKEN_NAME_LEN 32 +#define ICSF_SEQUENCE_LEN 8 +#define ICSF_MANUFACTURER_LEN 32 +#define ICSF_MODEL_LEN 16 +#define ICSF_SERIAL_LEN 16 +#define ICSF_DATE_LEN 8 +#define ICSF_TIME_LEN 8 +#define ICSF_FLAGS_LEN 4 +#define ICSF_RULE_ITEM_LEN 8 + +#define MAX_RECORDS 10 + +/* Object types */ +#define ICSF_SESSION_OBJECT 'S' +#define ICSF_TOKEN_OBJECT 'T' +#define ICSF_IS_VALID_OBJECT_TYPE(_type) \ + (_type == ICSF_SESSION_OBJECT || \ + _type == ICSF_TOKEN_OBJECT) + +/* Chaining types */ +#define ICSF_CHAINING_INITIAL 1 +#define ICSF_CHAINING_CONTINUE 2 +#define ICSF_CHAINING_FINAL 3 +#define ICSF_CHAINING_ONLY 4 + +#define ICSF_CHAINING_IS_VALID(_type) \ + (((_type) == ICSF_CHAINING_INITIAL) || \ + ((_type) == ICSF_CHAINING_CONTINUE) || \ + ((_type) == ICSF_CHAINING_FINAL) || \ + ((_type) == ICSF_CHAINING_ONLY)) + +#define ICSF_CHAINING(_type) \ + (((_type) == ICSF_CHAINING_INITIAL) ? "INITIAL" : \ + ((_type) == ICSF_CHAINING_CONTINUE) ? "CONTINUE" : \ + ((_type) == ICSF_CHAINING_FINAL) ? "FINAL" : \ + ((_type) == ICSF_CHAINING_ONLY) ? "ONLY" : \ + NULL) + +#define ICSF_CHAINING_DATA_LEN (128) + +/* Macros for testing flags. */ +#define ICSF_IS_TOKEN_READ_ONLY(_flags) \ + (_flags[0] & (1 << 7)) + +struct icsf_token_record { + char name[ICSF_TOKEN_NAME_LEN + 1]; + char manufacturer[ICSF_MANUFACTURER_LEN + 1]; + char model[ICSF_MODEL_LEN + 1]; + char serial[ICSF_SERIAL_LEN + 1]; + char date[ICSF_DATE_LEN + 1]; + char time[ICSF_TIME_LEN + 1]; + char flags[ICSF_FLAGS_LEN]; +}; + +struct icsf_object_record { + char token_name[ICSF_TOKEN_NAME_LEN + 1]; + unsigned long sequence; + char id; +}; + +int icsf_login(LDAP ** ld, const char *uri, const char *dn, + const char *password); + +int icsf_sasl_login(LDAP ** ld, const char *uri, const char *cert, + const char *key, const char *ca, const char *ca_dir); + +int icsf_logout(LDAP * ld); + +int icsf_check_pkcs_extension(LDAP * ld); + +int icsf_create_token(LDAP * ld, int *reason, const char *token_name, + const char *manufacturer_id, const char *model, + const char *serial_number); + +int icsf_destroy_token(LDAP * ld, int *reason, char *token_name); + +int icsf_list_tokens(LDAP * ld, int *reason, struct icsf_token_record *first, + struct icsf_token_record *records, size_t * records_len); + +int icsf_copy_object(LDAP * ld, int *reason, + CK_ATTRIBUTE * attrs, CK_ULONG attrs_len, + struct icsf_object_record *src, + struct icsf_object_record *dst); + +int icsf_create_object(LDAP * ld, int *reason, const char *token_name, + CK_ATTRIBUTE * attrs, CK_ULONG attrs_len, + struct icsf_object_record *object); + +int icsf_list_objects(LDAP * ld, int *reason, const char *token_name, + CK_ULONG attrs_len, CK_ATTRIBUTE * attrs, + struct icsf_object_record *previous, + struct icsf_object_record *records, size_t * records_len, + int all); + +int icsf_destroy_object(LDAP * ld, int *reason, struct icsf_object_record *obj); + +int icsf_generate_secret_key(LDAP * ld, int *reason, const char *token_name, + CK_MECHANISM_PTR mech, + CK_ATTRIBUTE * attrs, CK_ULONG attrs_len, + struct icsf_object_record *object); + +int icsf_derive_key(LDAP * ld, int *reason, CK_MECHANISM_PTR mech, + struct icsf_object_record *baseKey, + struct icsf_object_record *object, + CK_ATTRIBUTE * attrs, CK_ULONG attrs_len); + +int icsf_generate_key_pair(LDAP * ld, int *reason, const char *token_name, + CK_ATTRIBUTE * pub_attrs, CK_ULONG pub_attrs_len, + CK_ATTRIBUTE * priv_attrs, CK_ULONG priv_attrs_len, + struct icsf_object_record *pub_key_object, + struct icsf_object_record *priv_key_object); + +CK_RV icsf_block_size(CK_MECHANISM_TYPE mech_type, CK_ULONG_PTR p_block_size); + +int icsf_get_attribute(LDAP * ld, int *reason, + struct icsf_object_record *object, CK_ATTRIBUTE * attrs, + CK_ULONG attrs_len); + +int icsf_set_attribute(LDAP * ld, int *reason, + struct icsf_object_record *object, CK_ATTRIBUTE * attrs, + CK_ULONG attrs_len); + +int icsf_secret_key_encrypt(LDAP * ld, int *reason, + struct icsf_object_record *key, + CK_MECHANISM_PTR mech, int chaining, + const char *clear_text, size_t clear_text_len, + char *cipher_text, size_t * p_cipher_text_len, + char *chaining_data, size_t * p_chaining_data_len); + +int icsf_secret_key_decrypt(LDAP * ld, int *reason, + struct icsf_object_record *key, + CK_MECHANISM_PTR mech, int chaining, + const char *cipher_text, size_t cipher_text_len, + char *clear_text, size_t * p_clear_text_len, + char *chaining_data, size_t * p_chaining_data_len); + +int icsf_private_key_sign(LDAP * ld, int *p_reason, int decrypt, + struct icsf_object_record *key, CK_MECHANISM_PTR mech, + const char *cipher_text, size_t cipher_text_len, + char *clear_text, size_t * p_clear_text_len); + +int icsf_public_key_verify(LDAP * ld, int *p_reason, int encrypt, + struct icsf_object_record *key, + CK_MECHANISM_PTR mech, const char *clear_text, + size_t clear_text_len, char *cipher_text, + size_t * p_cipher_text_len); + +int icsf_hmac_sign(LDAP * ld, int *reason, struct icsf_object_record *key, + CK_MECHANISM_PTR mech, const char *chain_rule, + const char *clear_text, size_t clear_text_len, char *hmac, + size_t * hmac_len, char *chain_data, + size_t * chain_data_len); + +int icsf_hmac_verify(LDAP * ld, int *reason, struct icsf_object_record *key, + CK_MECHANISM_PTR mech, const char *chain_rule, + const char *clear_text, size_t clear_text_len, + char *hmac, size_t hmac_len, char *chain_data, + size_t * chain_data_len); + +int icsf_wrap_key(LDAP * ld, int *p_reason, CK_MECHANISM_PTR mech, + struct icsf_object_record *wrapping_key, + struct icsf_object_record *key, CK_BYTE_PTR wrapped_key, + CK_ULONG_PTR p_wrapped_key_len); + +int icsf_unwrap_key(LDAP * ld, int *p_reason, CK_MECHANISM_PTR mech, + struct icsf_object_record *unwrapping_key, + CK_BYTE_PTR wrapped_key, CK_ULONG wrapped_key_len, + CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, + struct icsf_object_record *key); + +int icsf_hash_signverify(LDAP * ld, int *reason, struct icsf_object_record *key, + CK_MECHANISM_PTR mech, const char *chain_rule, + const char *clear_text, unsigned long clear_text_len, + char *sig, unsigned long *sig_len, char *chain_data, + size_t * chain_data_len, int verify); + +int icsf_derive_multiple_keys(LDAP * ld, int *p_reason, CK_MECHANISM_PTR mech, + struct icsf_object_record *key, + CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, + struct icsf_object_record *client_mac_handle, + struct icsf_object_record *server_mac_handle, + struct icsf_object_record *client_key_handle, + struct icsf_object_record *server_key_handle, + unsigned char *client_iv, + unsigned char *server_iv); + +int icsf_get_object_size(LDAP * ld, int *reason, + struct icsf_object_record *object, CK_ULONG attrs_len, + CK_ULONG * obj_size); + +void strunpad(char *dest, const char *orig, size_t len, int padding_char); +#endif diff --git a/usr/lib/icsf_stdll/icsf_config.h b/usr/lib/icsf_stdll/icsf_config.h new file mode 100644 index 0000000..87ccf5c --- /dev/null +++ b/usr/lib/icsf_stdll/icsf_config.h @@ -0,0 +1,38 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2013-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 + */ + +#ifndef ICSF_CONFIG_H +#define ICSF_CONFIG_H + +#include +#include "pkcs11types.h" +#include "icsf.h" + +#define ICSF_CFG_MECH_SIMPLE 0 +#define ICSF_CFG_MECH_SASL 1 + +/* ICSF specific slot data */ +struct icsf_config { + char name[ICSF_TOKEN_NAME_LEN + 1]; + char manuf[ICSF_MANUFACTURER_LEN + 1]; + char model[ICSF_MODEL_LEN + 1]; + char serial[ICSF_SERIAL_LEN + 1]; + char uri[PATH_MAX + 1]; + char dn[NAME_MAX + 1]; + char ca_file[PATH_MAX + 1]; + char cert_file[PATH_MAX + 1]; + char key_file[PATH_MAX + 1]; + int mech; +}; + +CK_RV parse_config_file(const char *conf_name, CK_SLOT_ID slot_id, + struct icsf_config *data); + +#endif diff --git a/usr/lib/icsf_stdll/icsf_config_lexer.l b/usr/lib/icsf_stdll/icsf_config_lexer.l new file mode 100644 index 0000000..62bdf5b --- /dev/null +++ b/usr/lib/icsf_stdll/icsf_config_lexer.l @@ -0,0 +1,81 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2013-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 + */ + +%{ +#include +#include "icsf_config_parse.h" + +/* Ignore -Wsign-compare for autogenerated code. */ +#pragma GCC diagnostic ignored "-Wsign-compare" + +extern void yyerror(const char *s); + +%} + +%option noyywrap +%option nounput +%option noinput + +%% + +[\t\n ]+ { + /* Ignore spaces */ +} + +#.*\n { + /* Comment */ +} + +slot { + /* Identify a definition */ + return SLOT; +} + +[0-9]+ { + /* Number */ + yylval.num = strtoul(yytext, NULL, 10); + return INTEGER; +} + +\{ { + /* Open definition */ + return BEGIN_DEF; +} + +\} { + /* Close definition */ + return END_DEF; +} + += { + /* Assignment */ + return EQUAL; +} + +[^\"= \t\n]+ { + /* String */ + yylval.str = strdup(yytext); + return STRING; +} + +\"[^\"\n]*\" { + /* Quoted string */ + yylval.str = strdup(yytext + 1); + if (yylval.str && yylval.str[0]) + yylval.str[strlen(yylval.str) - 1] = '\0'; + return STRING; +} + +. { + /* Default */ + yyerror(yytext); +} + +%% diff --git a/usr/lib/icsf_stdll/icsf_config_parse.y b/usr/lib/icsf_stdll/icsf_config_parse.y new file mode 100644 index 0000000..cd85d53 --- /dev/null +++ b/usr/lib/icsf_stdll/icsf_config_parse.y @@ -0,0 +1,229 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2013-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 + */ + +%{ +#include +#include +#include +#include +#include +#include +#include +#include +#include "pkcs11types.h" +#include "icsf_config.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "trace.h" + +/* Global vars used as parameter to bison/flex parser. */ +extern FILE *yyin; +CK_SLOT_ID in_slot_id; +int expected_slot; +struct icsf_config out_config; +char out_str_mech[64] = ""; +int out_rc; + +/* Function used to report error. */ +void yyerror(const char *str); + +extern int yylex(); + +/* */ +struct ref { + char *key; + char *addr; + size_t len; + int required; +}; +struct ref refs[] = { + { "token_name", out_config.name, sizeof(out_config.name), 1 }, + { "token_manufacture", out_config.manuf, sizeof(out_config.manuf), 1 }, + { "token_model", out_config.model, sizeof(out_config.model), 1 }, + { "token_serial", out_config.serial, sizeof(out_config.serial), 1 }, + { "mech", out_str_mech, sizeof(out_str_mech), 1 }, + { "uri", out_config.uri, sizeof(out_config.uri), 0 }, + { "binddn", out_config.dn, sizeof(out_config.dn), 0 }, + { "cacert", out_config.ca_file, sizeof(out_config.ca_file), 0 }, + { "cert", out_config.cert_file, sizeof(out_config.cert_file), 0 }, + { "key", out_config.key_file, sizeof(out_config.key_file), 0 }, +}; +size_t refs_len = sizeof(refs)/sizeof(*refs); +%} + +%union { + unsigned int num; + char *str; +}; + +%token STRING +%token INTEGER +%token SLOT +%token BEGIN_DEF +%token END_DEF +%token EQUAL + +%% + +slots: + slots slot + | + ; + +slot: + SLOT INTEGER + { + expected_slot = ($2 == in_slot_id); + } + BEGIN_DEF key_values END_DEF + ; + +key_values: + key_values key_value + | + ; + +key_value: + STRING EQUAL STRING + { + char *key = $1; + char *value = $3; + size_t i; + + /* Check if this keyword belongs to the expected slot. */ + if (!expected_slot || out_rc) + goto done; + + /* Check key and value */ + if (!key || !value) { + out_rc = 1; + TRACE_ERROR("Null %s found.\n", (!key) ? "key" : "value"); + goto done; + } + + /* Check if this keyword is expected. */ + for (i = 0; i < strlen(key); i++) + key[i] = tolower(key[i]); + + for(i = 0; i < refs_len; i++) { + if (!strcmp(refs[i].key, key)) { + strncpy(refs[i].addr, value, refs[i].len); + refs[i].addr[refs[i].len - 1] = '\0'; + goto done; + } + } + + out_rc = 1; + TRACE_ERROR("Invalid keyword: %s\n", key); + + done: + if (key) + free(key); + if (value) + free(value); + } + ; + +%% + +void +yyerror(const char *str) +{ + out_rc = 1; + fprintf(stderr,"Error: %s\n", str); + TRACE_DEBUG("Failed to parse config file. %s\n", str); +} + +static int +check_keys(const char *conf_name) +{ + size_t i; + + for (i = 0; i < refs_len; i++) { + if (refs[i].required && *refs[i].addr == '\0') { + TRACE_ERROR("Missing required key \"%s\" in \"%s\".\n", + refs[i].key, conf_name); + return -1; + } + } + + return 0; +} + +/* + * Parse config file using yacc. + */ +CK_RV +parse_config_file(const char *conf_name, CK_SLOT_ID slot_id, + struct icsf_config *data) +{ + CK_RV rc; + struct stat stat_info; + + /* Check is file exists. */ + if (stat(conf_name, &stat_info) || !S_ISREG(stat_info.st_mode)) { + TRACE_ERROR("File \"%s\" does not exist or is invalid.\n", + conf_name); + return CKR_FUNCTION_FAILED; + } + + /* Set parameters used by the parser */ + in_slot_id = slot_id; + out_rc = 0; + memset(&out_config, 0, sizeof(*data)); + expected_slot = FALSE; + + /* Open config file */ + yyin = fopen(conf_name, "r"); + if (yyin == NULL) { + TRACE_ERROR("Failed to open \"%s\".\n", conf_name); + return CKR_FUNCTION_FAILED; + } + + /* Parse config file */ + rc = yyparse(); + fclose(yyin); + if (rc || out_rc) { + TRACE_ERROR("Failed to parser file \"%s\" (%lu:%d).\n", + conf_name, rc, out_rc); + return CKR_FUNCTION_FAILED; + } + + /* Check required keys*/ + if (check_keys(conf_name)) + return CKR_FUNCTION_FAILED; + + /* Parse mechanism type */ + if (!strcmp(out_str_mech, "SIMPLE")) { + out_config.mech = ICSF_CFG_MECH_SIMPLE; + } else if (!strcmp(out_str_mech, "SASL")) { + out_config.mech = ICSF_CFG_MECH_SASL; + } else { + TRACE_ERROR("Unknown mechanism type found: %s\n", out_str_mech); + return CKR_FUNCTION_FAILED; + } + + /* Copy output data. */ + memcpy(data, &out_config, sizeof(*data)); + + #if DEBUG + { + size_t i; + TRACE_DEVEL("ICSF configs for slot %lu.\n", slot_id); + for (i = 0; i < refs_len; i++) { + TRACE_DEVEL(" %s = \"%s\"\n", refs[i].key, + refs[i].addr); + } + } + #endif + + return CKR_OK; +} diff --git a/usr/lib/icsf_stdll/icsf_specific.c b/usr/lib/icsf_stdll/icsf_specific.c new file mode 100644 index 0000000..8ad02e0 --- /dev/null +++ b/usr/lib/icsf_stdll/icsf_specific.c @@ -0,0 +1,4963 @@ +/* + * 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 + */ + +/* + * openCryptoki ICSF token + * + * Author: Marcelo Cerri (mhcerri@br.ibm.com) + * + * Based on CCC token. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "pbkdf.h" +#include "h_extern.h" +#include "tok_specific.h" +#include "tok_struct.h" +#include "icsf_config.h" +#include "icsf_specific.h" +#include "pbkdf.h" +#include "list.h" +#include "attributes.h" +#include "../api/apiproto.h" +#include "trace.h" +#include "shared_memory.h" +#include "slotmgr.h" + +/* Default token attributes */ +const char manuf[] = "IBM"; +const char model[] = "ICSF"; +const char descr[] = "IBM ICSF token"; +const char label[] = "icsftok"; + +/* mechanisms provided by this token */ +static const MECH_LIST_ELEMENT icsf_mech_list[] = { + {CKM_DES_KEY_GEN, {8, 8, CKF_HW | CKF_GENERATE}}, + {CKM_DES_ECB, {0, 0, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, + {CKM_DES_CBC, {0, 0, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, + {CKM_DES_CBC_PAD, + {0, 0, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {CKM_DES3_ECB, {0, 0, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, + {CKM_DES3_CBC, {0, 0, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, + {CKM_DES3_CBC_PAD, + {0, 0, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {CKM_DES3_KEY_GEN, {24, 24, CKF_HW | CKF_GENERATE}}, + {CKM_DES2_KEY_GEN, {24, 24, CKF_HW | CKF_GENERATE}}, + {CKM_RSA_PKCS_KEY_PAIR_GEN, {512, 4096, CKF_HW | CKF_GENERATE_KEY_PAIR}}, + {CKM_RSA_PKCS, + {512, 4096, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP | + CKF_SIGN | CKF_VERIFY }}, + {CKM_RSA_X_509, + {512, 4096, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_SIGN | CKF_VERIFY }}, + {CKM_MD5_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA1_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA256_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA384_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA512_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA_1, {0, 0, CKF_HW | CKF_DIGEST}}, + {CKM_SHA_1_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA256_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA384_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA512_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {CKM_MD5, {0, 0, CKF_DIGEST}}, + {CKM_MD5_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}}, + {CKM_AES_KEY_GEN, {16, 32, CKF_HW | CKF_GENERATE}}, + {CKM_AES_ECB, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, + {CKM_AES_CBC, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, + {CKM_AES_CBC_PAD, + {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {CKM_DH_PKCS_KEY_PAIR_GEN, {512, 2048, CKF_GENERATE_KEY_PAIR}}, + {CKM_DH_PKCS_DERIVE, {512, 2048, CKF_DERIVE}}, + {CKM_DSA_KEY_PAIR_GEN, {512, 2048, CKF_HW | CKF_GENERATE_KEY_PAIR}}, + {CKM_DSA_SHA1, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {CKM_DSA, {512, 2048, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {CKM_ECDSA_SHA1, + {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_F_P | + CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS}}, + {CKM_ECDSA, + {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_F_P | + CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS}}, + {CKM_EC_KEY_PAIR_GEN, + {160, 521, CKF_HW | CKF_GENERATE_KEY_PAIR | CKF_EC_F_P | + CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS}}, + {CKM_SSL3_PRE_MASTER_KEY_GEN, {48, 48, CKF_HW | CKF_GENERATE}}, + {CKM_SSL3_MD5_MAC, {384, 384, CKF_SIGN | CKF_VERIFY}}, + {CKM_SSL3_SHA1_MAC, {384, 384, CKF_SIGN | CKF_VERIFY}}, + {CKM_SSL3_MASTER_KEY_DERIVE, {48, 48, CKF_DERIVE}}, + {CKM_SSL3_KEY_AND_MAC_DERIVE, {48, 48, CKF_DERIVE}}, + {CKM_TLS_KEY_AND_MAC_DERIVE, {48, 48, CKF_DERIVE}}, + {CKM_GENERIC_SECRET_KEY_GEN, {80, 2048, CKF_HW | CKF_GENERATE}}, +}; + +static const CK_ULONG icsf_mech_list_len = + (sizeof(icsf_mech_list) / sizeof(MECH_LIST_ELEMENT)); + +/* Each element of the list sessions should have this type: */ +struct session_state { + CK_SESSION_HANDLE session_id; + LDAP *ld; + + /* List element */ + list_entry_t sessions; +}; + + +/* Each element of the btree objects should have this type: */ +struct icsf_object_mapping { + struct bt_ref_hdr hdr; + CK_SESSION_HANDLE session_id; + struct icsf_object_record icsf_object; +}; + +/* + * Structure used to keep track of data used in multi-part operations. + */ +struct icsf_multi_part_context { + int initiated; + char chain_data[ICSF_CHAINING_DATA_LEN]; + char *data; + size_t data_len; + size_t used_data_len; +}; + +/* + * Get the session specific structure. + */ +static struct session_state *get_session_state(STDLL_TokData_t * tokdata, + CK_SESSION_HANDLE session_id) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + struct session_state *found = NULL; + struct session_state *s; + + /* Lock sessions list */ + if (pthread_mutex_lock(&icsf_data->sess_list_mutex)) { + TRACE_ERROR("Failed to lock mutex.\n"); + return NULL; + } + + for_each_list_entry(&icsf_data->sessions, struct session_state, s, sessions) { + if (s->session_id == session_id) { + found = s; + goto done; + } + } + +done: + /* Unlock */ + if (pthread_mutex_unlock(&icsf_data->sess_list_mutex)) { + TRACE_ERROR("Mutex Unlock failed.\n"); + return NULL; + } + + return found; +} + +static void purge_object_mapping_cb(STDLL_TokData_t * tokdata, void *value, + unsigned long node_num, void *p3) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + + UNUSED(value); + UNUSED(p3); + + /* Remove the object */ + bt_node_free(&icsf_data->objects, node_num, TRUE); +} + +/* + * Remove all mapped objects. + */ +static CK_RV purge_object_mapping(STDLL_TokData_t * tokdata) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + + bt_for_each_node(tokdata, &icsf_data->objects, purge_object_mapping_cb, + NULL); + + return CKR_OK; +} + +/* Store ICSF specific data for each slot*/ +struct slot_data { + int initialized; + char conf_name[PATH_MAX + 1]; + char uri[PATH_MAX + 1]; + char dn[NAME_MAX + 1]; + char ca_file[PATH_MAX + 1]; + char cert_file[PATH_MAX + 1]; + char key_file[PATH_MAX + 1]; + int mech; +}; +struct slot_data *slot_data[NUMBER_SLOTS_MANAGED]; + +/* + * Converts an ICSF reason code to an ock error code + */ +int icsf_to_ock_err(int icsf_return_code, int icsf_reason_code) +{ + switch (icsf_return_code) { + case 0: + return CKR_OK; + case 4: + switch (icsf_reason_code) { + case 8000: + case 11000: + return CKR_SIGNATURE_INVALID; + } + break; + case 8: + switch (icsf_reason_code) { + case 2154: + return CKR_KEY_TYPE_INCONSISTENT; + case 2028: + return CKR_WRAPPED_KEY_INVALID; + case 3003: + return CKR_BUFFER_TOO_SMALL; + case 3019: + return CKR_SESSION_HANDLE_INVALID; + case 3027: + return CKR_SESSION_HANDLE_INVALID; + case 3029: + return CKR_ATTRIBUTE_TYPE_INVALID; + case 3030: + return CKR_ATTRIBUTE_VALUE_INVALID; + case 3033: + return CKR_TEMPLATE_INCOMPLETE; + case 3034: + case 3035: + return CKR_ATTRIBUTE_READ_ONLY; + case 3038: + return CKR_KEY_FUNCTION_NOT_PERMITTED; + case 3039: + return CKR_KEY_TYPE_INCONSISTENT; + case 3041: + return CKR_KEY_NOT_WRAPPABLE; + case 3043: + return CKR_KEY_HANDLE_INVALID; + case 3045: + return CKR_KEY_UNEXTRACTABLE; + case 72: + case 11000: + return CKR_DATA_LEN_RANGE; + case 11028: + return CKR_SIGNATURE_INVALID; + } + break; + } + return CKR_FUNCTION_FAILED; +} + +/* + * Called during C_Initialize. + */ +CK_RV icsftok_init(STDLL_TokData_t * tokdata, CK_SLOT_ID slot_id, + char *conf_name) +{ + CK_RV rc; + struct slot_data *data; + icsf_private_data_t *icsf_data; + + TRACE_INFO("icsf %s slot=%lu running\n", __func__, slot_id); + + /* Check Slot ID */ + if (slot_id >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("Invalid slot ID: %lu\n", slot_id); + return CKR_FUNCTION_FAILED; + } + + tokdata->mech_list = (MECH_LIST_ELEMENT *)icsf_mech_list; + tokdata->mech_list_len = icsf_mech_list_len; + + icsf_data = calloc(1, sizeof(icsf_private_data_t)); + 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); + tokdata->private_data = icsf_data; + + rc = XProcLock(tokdata); + if (rc != CKR_OK) + return CKR_FUNCTION_FAILED; + + if (slot_data[slot_id] == NULL) { + TRACE_ERROR("ICSF slot data not initialized.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + data = slot_data[slot_id]; + data->initialized = 0; + strncpy(data->conf_name, conf_name, sizeof(data->conf_name) - 1); + data->conf_name[sizeof(data->conf_name) - 1] = '\0'; + +done: + if (rc == CKR_OK) + rc = XProcUnLock(tokdata); + else + XProcUnLock(tokdata); + + return rc; +} + +CK_RV token_specific_init_token_data(STDLL_TokData_t * tokdata, + CK_SLOT_ID slot_id) +{ + CK_RV rc = CKR_OK; + const char *conf_name = NULL; + struct icsf_config config; + + /* Check Slot ID */ + if (slot_id >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("Invalid slot ID: %lu\n", slot_id); + return CKR_FUNCTION_FAILED; + } + + rc = XProcLock(tokdata); + if (rc != CKR_OK) + return CKR_FUNCTION_FAILED; + + if (slot_data[slot_id] == NULL) { + TRACE_ERROR("ICSF slot data not initialized.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Check if data needs to be retrieved for this slot */ + if (slot_data[slot_id]->initialized) { + TRACE_DEVEL("Slot data already initialized for slot %lu. " + "Skipping it\n", slot_id); + goto done; + } + + /* Check config file */ + conf_name = slot_data[slot_id]->conf_name; + if (!conf_name || !conf_name[0]) { + TRACE_ERROR("Missing config for slot %lu.\n", slot_id); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + TRACE_DEVEL("DEBUG: conf_name=\"%s\".\n", conf_name); + if (parse_config_file(conf_name, slot_id, &config)) { + TRACE_ERROR("Failed to parse file \"%s\" for slot %lu.\n", + conf_name, slot_id); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Copy general info */ + memcpy(tokdata->nv_token_data->token_info.label, config.name, + strlen(config.name)); + memcpy(tokdata->nv_token_data->token_info.manufacturerID, config.manuf, + strlen(config.manuf)); + memcpy(tokdata->nv_token_data->token_info.model, config.model, + strlen(config.model)); + memcpy(tokdata->nv_token_data->token_info.serialNumber, config.serial, + strlen(config.serial)); + + /* Copy ICSF specific info */ + strcpy(slot_data[slot_id]->uri, config.uri); + strcpy(slot_data[slot_id]->dn, config.dn); + strcpy(slot_data[slot_id]->ca_file, config.ca_file); + strcpy(slot_data[slot_id]->cert_file, config.cert_file); + strcpy(slot_data[slot_id]->key_file, config.key_file); + slot_data[slot_id]->initialized = 1; + slot_data[slot_id]->mech = config.mech; + +done: + if (rc == CKR_OK) + rc = XProcUnLock(tokdata); + else + XProcUnLock(tokdata); + + return rc; +} + +CK_RV token_specific_load_token_data(STDLL_TokData_t * tokdata, + CK_SLOT_ID slot_id, FILE * fh) +{ + CK_RV rc; + struct slot_data data; + + /* Check Slot ID */ + if (slot_id >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("Invalid slot ID: %lu\n", slot_id); + return CKR_FUNCTION_FAILED; + } + + if (!fread(&data, sizeof(data), 1, fh)) { + TRACE_ERROR("Failed to read ICSF slot data.\n"); + return CKR_FUNCTION_FAILED; + } + + rc = XProcLock(tokdata); + if (rc != CKR_OK) + return CKR_FUNCTION_FAILED; + + if (slot_data[slot_id] == NULL) { + TRACE_ERROR("ICSF slot data not initialized.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + memcpy(slot_data[slot_id], &data, sizeof(data)); + +done: + if (rc == CKR_OK) + rc = XProcUnLock(tokdata); + else + XProcUnLock(tokdata); + + return rc; +} + +CK_RV token_specific_save_token_data(STDLL_TokData_t * tokdata, + CK_SLOT_ID slot_id, FILE * fh) +{ + CK_RV rc; + + /* Check Slot ID */ + if (slot_id >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("Invalid slot ID: %lu\n", slot_id); + return CKR_FUNCTION_FAILED; + } + + rc = XProcLock(tokdata); + if (rc != CKR_OK) + return CKR_FUNCTION_FAILED; + + if (slot_data[slot_id] == NULL) { + TRACE_ERROR("ICSF slot data not initialized.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (!fwrite(slot_data[slot_id], sizeof(**slot_data), 1, fh)) { + TRACE_ERROR("Failed to write ICSF slot data.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + +done: + if (rc == CKR_OK) + rc = XProcUnLock(tokdata); + else + XProcUnLock(tokdata); + + return rc; +} + +/* + * Initialize the shared memory region. ICSF has to use a custom method for + * this because it uses additional data in the shared memory and in the future + * multiple slots should be supported for ICSF. + */ +CK_RV token_specific_attach_shm(STDLL_TokData_t * tokdata, CK_SLOT_ID slot_id) +{ + CK_RV rc; + int ret; + void *ptr; + LW_SHM_TYPE **shm = &tokdata->global_shm; + size_t len = sizeof(**shm) + sizeof(**slot_data); + char *shm_id = NULL; + + if (slot_id >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("Invalid slot ID: %lu\n", slot_id); + return CKR_FUNCTION_FAILED; + } + + if (asprintf(&shm_id, "/icsf-%lu", slot_id) < 0) { + TRACE_ERROR("Failed to allocate shared memory id " + "for slot %lu.\n", slot_id); + return CKR_HOST_MEMORY; + } + TRACE_DEVEL("Attaching to shared memory \"%s\".\n", shm_id); + + rc = XProcLock(tokdata); + if (rc != CKR_OK) + return CKR_FUNCTION_FAILED; + + /* + * Attach to an existing shared memory region or create it if it doesn't + * exists. When the it's created (ret=0) the region is initialized with + * zeroes. + */ + ret = sm_open(shm_id, 0666, (void **) &ptr, len, 1); + if (ret < 0) { + TRACE_ERROR("Failed to open shared memory \"%s\".\n", shm_id); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + *shm = ptr; + slot_data[slot_id] = (struct slot_data *)((unsigned char *)ptr + + sizeof(**shm)); + +done: + if (rc == CKR_OK) + rc = XProcUnLock(tokdata); + else + XProcUnLock(tokdata); + + if (shm_id) + free(shm_id); + + return rc; +} + +CK_RV login(STDLL_TokData_t * tokdata, LDAP ** ld, CK_SLOT_ID slot_id, + CK_BYTE * pin, CK_ULONG pin_len, const char *pass_file_type) +{ + CK_RV rc; + struct slot_data data; + LDAP *ldapd = NULL; + int ret; + + UNUSED(pass_file_type); + + /* Check Slot ID */ + if (slot_id >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("Invalid slot ID: %lu\n", slot_id); + return CKR_FUNCTION_FAILED; + } + + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get process lock.\n"); + goto done; + } + + /* Check slot data */ + if (slot_data[slot_id] == NULL || !slot_data[slot_id]->initialized) { + TRACE_ERROR("ICSF slot data not initialized.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + memcpy(&data, slot_data[slot_id], sizeof(data)); + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release process lock.\n"); + goto done; + } + + if (data.mech == ICSF_CFG_MECH_SIMPLE) { + CK_BYTE mk[MAX_KEY_SIZE]; + CK_BYTE racf_pass[PIN_SIZE]; + int mk_len = sizeof(mk); + int racf_pass_len = sizeof(racf_pass); + char pk_dir_buf[PATH_MAX]; + char fname[PATH_MAX]; + + /* Load master key */ + sprintf(fname, "%s/MK_SO", get_pk_dir(tokdata, pk_dir_buf)); + if (get_masterkey(pin, pin_len, fname, mk, &mk_len)) { + TRACE_DEVEL("Failed to get masterkey \"%s\".\n", fname); + return CKR_FUNCTION_FAILED; + } + + /* Load RACF password */ + if (get_racf(mk, mk_len, racf_pass, &racf_pass_len)) { + TRACE_DEVEL("Failed to get RACF password.\n"); + return CKR_FUNCTION_FAILED; + } + + /* Simple bind */ + ret = icsf_login(&ldapd, data.uri, data.dn, (char *)racf_pass); + } else { + /* SASL bind */ + ret = icsf_sasl_login(&ldapd, data.uri, data.cert_file, + data.key_file, data.ca_file, NULL); + } + + if (ret) { + TRACE_DEVEL("Failed to bind to %s\n", data.uri); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + if (icsf_check_pkcs_extension(ldapd)) { + TRACE_ERROR("ICSF LDAP externsion not supported.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + +done: + if (rc == CKR_OK && ld) + *ld = ldapd; + + return rc; +} + +CK_RV reset_token_data(STDLL_TokData_t * tokdata, CK_SLOT_ID slot_id, + CK_CHAR_PTR pin, CK_ULONG pin_len) +{ + CK_BYTE mk[MAX_KEY_SIZE]; + CK_BYTE racf_pass[PIN_SIZE]; + int mk_len = sizeof(mk); + int racf_pass_len = sizeof(racf_pass); + char pk_dir_buf[PATH_MAX]; + char fname[PATH_MAX]; + + /* Remove user's masterkey */ + if (slot_data[slot_id]->mech == ICSF_CFG_MECH_SIMPLE) { + sprintf(fname, "%s/MK_USER", get_pk_dir(tokdata, pk_dir_buf)); + if (unlink(fname) && errno == ENOENT) + TRACE_WARNING("Failed to remove \"%s\".\n", fname); + + /* Load master key */ + sprintf(fname, "%s/MK_SO", get_pk_dir(tokdata, pk_dir_buf)); + if (get_masterkey(pin, pin_len, fname, mk, &mk_len)) { + TRACE_DEVEL("Failed to load masterkey \"%s\".\n", fname); + return CKR_FUNCTION_FAILED; + } + + /* Load RACF password */ + if (get_racf(mk, mk_len, racf_pass, &racf_pass_len)) { + TRACE_DEVEL("Failed to get RACF password.\n"); + return CKR_FUNCTION_FAILED; + } + + /* Generate new key */ + if (get_randombytes(mk, mk_len)) { + TRACE_DEVEL("Failed to generate new master key.\n"); + return CKR_FUNCTION_FAILED; + } + + /* Save racf password using the new master key */ + if (secure_racf(racf_pass, racf_pass_len, mk, mk_len)) { + TRACE_DEVEL("Failed to save racf password.\n"); + return CKR_FUNCTION_FAILED; + } + } + + /* Reset token data and keep token name */ + slot_data[slot_id]->initialized = 0; + load_token_data(tokdata, slot_id); + init_slotInfo(&tokdata->slot_info); + tokdata->nv_token_data->token_info.flags |= CKF_TOKEN_INITIALIZED; + + if (slot_data[slot_id]->mech == ICSF_CFG_MECH_SIMPLE) { + /* Save master key */ + if (secure_masterkey(mk, mk_len, pin, pin_len, fname)) { + TRACE_DEVEL("Failed to save the new master key.\n"); + return CKR_FUNCTION_FAILED; + } + } + + if (save_token_data(tokdata, slot_id)) { + TRACE_DEVEL("Failed to save token data.\n"); + return CKR_FUNCTION_FAILED; + } + + return CKR_OK; +} + +CK_RV destroy_objects(STDLL_TokData_t * tokdata, CK_SLOT_ID slot_id, + CK_CHAR_PTR token_name, CK_CHAR_PTR pin, CK_ULONG pin_len) +{ + CK_RV rv = CKR_OK; + LDAP *ld = NULL; + struct icsf_object_record records[16]; + struct icsf_object_record *previous = NULL; + size_t i, records_len; + int reason = 0; + int rc; + + if (login(tokdata, &ld, slot_id, pin, pin_len, RACFFILE)) + return CKR_FUNCTION_FAILED; + + TRACE_DEVEL("Destroying objects in slot %lu.\n", slot_id); + do { + records_len = sizeof(records) / sizeof(records[0]); + + rc = icsf_list_objects(ld, NULL, (char *)token_name, 0, NULL, + previous, records, &records_len, 0); + if (ICSF_RC_IS_ERROR(rc)) { + TRACE_DEVEL("Failed to list objects for slot %lu.\n", slot_id); + rv = CKR_FUNCTION_FAILED; + goto done; + } + + for (i = 0; i < records_len; i++) { + if ((rc = icsf_destroy_object(ld, &reason, &records[i]))) { + TRACE_DEVEL("Failed to destroy object " + "%s/%lu/%c in slot %lu.\n", + records[i].token_name, + records[i].sequence, records[i].id, slot_id); + rv = icsf_to_ock_err(rc, reason); + goto done; + } + } + + if (records_len) + previous = &records[records_len - 1]; + } while (records_len); + +done: + if (icsf_logout(ld) && rv == CKR_OK) + rv = CKR_FUNCTION_FAILED; + + return rv; +} + +/* + * Initialize token. + */ +CK_RV icsftok_init_token(STDLL_TokData_t * tokdata, CK_SLOT_ID slot_id, + CK_CHAR_PTR pin, CK_ULONG pin_len, CK_CHAR_PTR label) +{ + CK_RV rc = CKR_OK; + CK_BYTE hash_sha[SHA1_HASH_SIZE]; + CK_CHAR token_name[sizeof(tokdata->nv_token_data->token_info.label) + 1]; + + UNUSED(label); + + /* Check pin */ + rc = compute_sha1(tokdata, pin, pin_len, hash_sha); + if (memcmp(tokdata->nv_token_data->so_pin_sha, hash_sha, + SHA1_HASH_SIZE) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + + if ((rc = reset_token_data(tokdata, slot_id, pin, pin_len))) + goto done; + + strunpad((char *)token_name, + (const char *)tokdata->nv_token_data->token_info.label, + sizeof(tokdata->nv_token_data->token_info.label), ' '); + + if ((rc = destroy_objects(tokdata, slot_id, token_name, pin, pin_len))) + goto done; + + /* purge the object btree */ + if (purge_object_mapping(tokdata)) { + TRACE_DEVEL("Failed to purge objects.\n"); + rc = CKR_FUNCTION_FAILED; + } + +done: + return rc; +} + +CK_RV icsftok_init_pin(STDLL_TokData_t * tokdata, SESSION * sess, + CK_CHAR_PTR pPin, CK_ULONG ulPinLen) +{ + CK_RV rc = CKR_OK; + CK_BYTE hash_sha[SHA1_HASH_SIZE]; + CK_SLOT_ID sid; + char fname[PATH_MAX]; + char pk_dir_buf[PATH_MAX]; + + /* get slot id */ + sid = sess->session_info.slotID; + + /* compute the SHA of the user pin */ + rc = compute_sha1(tokdata, pPin, ulPinLen, hash_sha); + if (rc != CKR_OK) { + TRACE_ERROR("Hash Computation Failed.\n"); + return rc; + } + + /* encrypt the masterkey and store in MK_USER if using SIMPLE AUTH + * to authenticate to ldao server. The masterkey protects the + * racf passwd. + */ + if (slot_data[sid]->mech == ICSF_CFG_MECH_SIMPLE) { + sprintf(fname, "%s/MK_USER", get_pk_dir(tokdata, pk_dir_buf)); + + rc = secure_masterkey(tokdata->master_key, + AES_KEY_SIZE_256, pPin, ulPinLen, fname); + if (rc != CKR_OK) { + TRACE_DEVEL("Could not create MK_USER.\n"); + return rc; + } + } + + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get process lock.\n"); + return rc; + } + + memcpy(tokdata->nv_token_data->user_pin_sha, hash_sha, SHA1_HASH_SIZE); + tokdata->nv_token_data->token_info.flags |= CKF_USER_PIN_INITIALIZED; + tokdata->nv_token_data->token_info.flags &= ~(CKF_USER_PIN_TO_BE_CHANGED); + tokdata->nv_token_data->token_info.flags &= ~(CKF_USER_PIN_LOCKED); + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Process Lock Failed.\n"); + return rc; + } + + return rc; +} + +CK_RV icsftok_set_pin(STDLL_TokData_t * tokdata, SESSION * sess, + CK_CHAR_PTR pOldPin, CK_ULONG ulOldLen, + CK_CHAR_PTR pNewPin, CK_ULONG ulNewLen) +{ + CK_RV rc = CKR_OK; + CK_BYTE new_hash_sha[SHA1_HASH_SIZE]; + CK_BYTE old_hash_sha[SHA1_HASH_SIZE]; + CK_SLOT_ID sid; + char fname[PATH_MAX]; + char pk_dir_buf[PATH_MAX]; + + /* get slot id */ + sid = sess->session_info.slotID; + + rc = compute_sha1(tokdata, pNewPin, ulNewLen, new_hash_sha); + rc |= compute_sha1(tokdata, pOldPin, ulOldLen, old_hash_sha); + if (rc != CKR_OK) { + TRACE_ERROR("Hash Computation Failed.\n"); + return rc; + } + + /* check that the old pin and new pin are not the same. */ + if (memcmp(old_hash_sha, new_hash_sha, SHA1_HASH_SIZE) == 0) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INVALID)); + return CKR_PIN_INVALID; + } + + /* check the length requirements */ + if ((ulNewLen < MIN_PIN_LEN) || (ulNewLen > MAX_PIN_LEN)) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LEN_RANGE)); + return CKR_PIN_LEN_RANGE; + } + + if ((sess->session_info.state == CKS_RW_USER_FUNCTIONS) || + (sess->session_info.state == CKS_RW_PUBLIC_SESSION)) { + /* check that old pin matches what is in NVTOK.DAT */ + if (memcmp + (tokdata->nv_token_data->user_pin_sha, old_hash_sha, + SHA1_HASH_SIZE) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + return CKR_PIN_INCORRECT; + } + /* if using simple auth, encrypt masterkey with new pin */ + if (slot_data[sid]->mech == ICSF_CFG_MECH_SIMPLE) { + sprintf(fname, "%s/MK_USER", get_pk_dir(tokdata, pk_dir_buf)); + rc = secure_masterkey(tokdata->master_key, + AES_KEY_SIZE_256, pNewPin, ulNewLen, fname); + if (rc != CKR_OK) { + TRACE_ERROR("Save Master Key Failed.\n"); + return rc; + } + } + + /* grab lock and change shared memory */ + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Process Lock Failed.\n"); + return rc; + } + + memcpy(tokdata->nv_token_data->user_pin_sha, new_hash_sha, + SHA1_HASH_SIZE); + tokdata->nv_token_data->token_info.flags &= + ~(CKF_USER_PIN_TO_BE_CHANGED); + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Process Lock Failed.\n"); + return rc; + } + + } else if (sess->session_info.state == CKS_RW_SO_FUNCTIONS) { + + /* check that old pin matches what is in NVTOK.DAT */ + if (memcmp + (tokdata->nv_token_data->so_pin_sha, old_hash_sha, + SHA1_HASH_SIZE) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + return CKR_PIN_INCORRECT; + } + + /* check that new pin is not the default */ + if (memcmp(new_hash_sha, default_so_pin_sha, SHA1_HASH_SIZE) == 0) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INVALID)); + return CKR_PIN_INVALID; + } + + if (slot_data[sid]->mech == ICSF_CFG_MECH_SIMPLE) { + /* + * if using simle auth, encrypt masterkey with new pin + */ + sprintf(fname, "%s/MK_SO", get_pk_dir(tokdata, pk_dir_buf)); + rc = secure_masterkey(tokdata->master_key, + AES_KEY_SIZE_256, pNewPin, ulNewLen, fname); + if (rc != CKR_OK) { + TRACE_ERROR("Save Master Key Failed.\n"); + return rc; + } + } + + /* grab lock and change shared memory */ + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Process Lock Failed.\n"); + return rc; + } + + memcpy(tokdata->nv_token_data->so_pin_sha, new_hash_sha, + SHA1_HASH_SIZE); + tokdata->nv_token_data->token_info.flags &= ~(CKF_SO_PIN_TO_BE_CHANGED); + + XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Process Lock Failed.\n"); + return rc; + } + } else { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY)); + return CKR_SESSION_READ_ONLY; + } + + rc = save_token_data(tokdata, sid); + if (rc != CKR_OK) { + TRACE_ERROR("Save Token Failed.\n"); + return rc; + } + + return rc; +} + +LDAP *getLDAPhandle(STDLL_TokData_t * tokdata, CK_SLOT_ID slot_id) +{ + CK_BYTE racfpwd[PIN_SIZE]; + int racflen; + char *ca_dir = NULL; + LDAP *new_ld = NULL; + CK_RV rc = CKR_OK; + + if (slot_data[slot_id] == NULL) { + TRACE_ERROR("ICSF slot data not initialized.\n"); + return NULL; + } + /* Check if using sasl or simple auth */ + if (slot_data[slot_id]->mech == ICSF_CFG_MECH_SIMPLE) { + TRACE_INFO("Using SIMPLE auth with slot ID: %lu\n", slot_id); + /* get racf passwd */ + rc = get_racf(tokdata->master_key, AES_KEY_SIZE_256, racfpwd, &racflen); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to get racf passwd.\n"); + return NULL; + } + + /* ok got the passwd, perform simple ldap bind call */ + rc = icsf_login(&new_ld, slot_data[slot_id]->uri, + slot_data[slot_id]->dn, (char *)racfpwd); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to bind to ldap server.\n"); + return NULL; + } + } else { + TRACE_INFO("Using SASL auth with slot ID: %lu\n", slot_id); + rc = icsf_sasl_login(&new_ld, slot_data[slot_id]->uri, + slot_data[slot_id]->cert_file, + slot_data[slot_id]->key_file, + slot_data[slot_id]->ca_file, ca_dir); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to bind to ldap server.\n"); + return NULL; + } + } + + return new_ld; +} + +CK_RV icsf_get_handles(STDLL_TokData_t * tokdata, CK_SLOT_ID slot_id) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + struct session_state *s; + + /* Any prior sessions without an ldap descriptor, can now get one. */ + /* Lock sessions list */ + if (pthread_mutex_lock(&icsf_data->sess_list_mutex)) { + TRACE_ERROR("Failed to lock mutex.\n"); + return CKR_FUNCTION_FAILED; + } + + for_each_list_entry(&icsf_data->sessions, struct session_state, s, + sessions) { + if (s->ld == NULL) + s->ld = getLDAPhandle(tokdata, slot_id); + } + + if (pthread_mutex_unlock(&icsf_data->sess_list_mutex)) { + TRACE_ERROR("Mutex Unlock failed.\n"); + return CKR_FUNCTION_FAILED; + } + + return CKR_OK; +} + +CK_RV icsftok_open_session(STDLL_TokData_t * tokdata, SESSION * sess) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + CK_RV rc = CKR_OK; + LDAP *ld; + struct session_state *session_state; + + /* Sanity */ + if (sess == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_FUNCTION_FAILED; + } + + /* Add session to list */ + session_state = malloc(sizeof(struct session_state)); + if (!session_state) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_FUNCTION_FAILED; + } + session_state->session_id = sess->handle; + session_state->ld = NULL; + + if (pthread_mutex_lock(&icsf_data->sess_list_mutex)) { + TRACE_ERROR("Failed to lock mutex.\n"); + free(session_state); + return CKR_FUNCTION_FAILED; + } + /* see if user has logged in to acquire ldap handle for session. + * pkcs#11v2.2 states that all sessions within a process have + * same login state. + */ + if (session_mgr_user_session_exists(tokdata)) { + ld = getLDAPhandle(tokdata, sess->session_info.slotID); + if (ld == NULL) { + TRACE_DEVEL("Failed to get LDAP handle for session.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + /* put the new ldap handle into the session state. */ + session_state->ld = ld; + } + + /* put new session_state into the list */ + list_insert_head(&icsf_data->sessions, &session_state->sessions); + +done: + /* Unlock */ + if (pthread_mutex_unlock(&icsf_data->sess_list_mutex)) { + TRACE_ERROR("Mutex Unlock Failed.\n"); + rc = CKR_FUNCTION_FAILED; + } + + if (rc != CKR_OK) + free(session_state); + + return rc; +} + +/* + * Close a session. + * + * Must be called with sess_list_mutex locked. + */ +static CK_RV close_session(STDLL_TokData_t * tokdata, + struct session_state *session_state, + CK_BBOOL in_fork_initializer) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + CK_RV rc = CKR_OK; + unsigned long i; + int reason = 0; + + /* Remove each session object */ + for (i = 1; i <= icsf_data->objects.size; i++) { + struct icsf_object_mapping *mapping; + + /* Skip missing ids */ + if (!(mapping = bt_get_node_value(&icsf_data->objects, i))) + continue; + + /* Skip object from other sessions */ + if (mapping->session_id != session_state->session_id) { + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + continue; + } + + /* Skip token objects */ + if (mapping->icsf_object.id != ICSF_SESSION_OBJECT) { + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + continue; + } + + if ((rc = icsf_destroy_object(session_state->ld, &reason, + &mapping->icsf_object))) { + /* Log error */ + TRACE_DEBUG("Failed to remove icsf object: %s/%lu/%c", + mapping->icsf_object.token_name, + mapping->icsf_object.sequence, mapping->icsf_object.id); + rc = icsf_to_ock_err(rc, reason); + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + break; + } + + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + + /* Remove object from object list */ + bt_node_free(&icsf_data->objects, i, TRUE); + } + if (rc) + return rc; + + /* Log off from LDAP server */ + if (session_state->ld) { + if (!in_fork_initializer && icsf_logout(session_state->ld)) { + TRACE_DEVEL("Failed to disconnect from LDAP server.\n"); + return CKR_FUNCTION_FAILED; + } + session_state->ld = NULL; + } + + /* Remove session */ + list_remove(&session_state->sessions); + if (list_is_empty(&icsf_data->sessions)) { + if (purge_object_mapping(tokdata)) { + TRACE_DEVEL("Failed to purge objects.\n"); + rc = CKR_FUNCTION_FAILED; + } + } + free(session_state); + + return rc; +} + +/* + * Called during C_CloseSession. + */ +CK_RV icsftok_close_session(STDLL_TokData_t * tokdata, SESSION * session, + CK_BBOOL in_fork_initializer) +{ + CK_RV rc; + struct session_state *session_state; + + /* Get the related session_state */ + if (session == NULL + || !(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + return CKR_SESSION_HANDLE_INVALID; + } + + if ((rc = close_session(tokdata, session_state, in_fork_initializer))) + TRACE_ERROR("close_session failed\n"); + + return rc; +} + +/* + * Called during C_Finalize and C_CloseAllSessions + */ +CK_RV icsftok_final(STDLL_TokData_t * tokdata, CK_BBOOL finalize, + CK_BBOOL in_fork_initializer) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + CK_RV rc = CKR_OK; + struct session_state *session_state; + list_entry_t *e; + + /* Lock to add a new session in the list */ + if (pthread_mutex_lock(&icsf_data->sess_list_mutex)) { + TRACE_ERROR("Failed to lock mutex.\n"); + return CKR_FUNCTION_FAILED; + } + + for_each_list_entry_safe(&icsf_data->sessions, struct session_state, + session_state, sessions, e) { + if ((rc = close_session(tokdata, session_state, in_fork_initializer))) + break; + } + + /* Unlock */ + if (pthread_mutex_unlock(&icsf_data->sess_list_mutex)) { + TRACE_ERROR("Mutex Unlock Failed.\n"); + return CKR_FUNCTION_FAILED; + } + + if (finalize) { + bt_destroy(&icsf_data->objects); + pthread_mutex_destroy(&icsf_data->sess_list_mutex); + free(icsf_data); + tokdata->private_data = NULL; + } + + return rc; +} + +CK_RV icsftok_login(STDLL_TokData_t * tokdata, SESSION * sess, + CK_USER_TYPE userType, CK_CHAR_PTR pPin, CK_ULONG ulPinLen) +{ + CK_RV rc = CKR_OK; + char fname[PATH_MAX]; + CK_BYTE hash_sha[SHA1_HASH_SIZE]; + int mklen; + char pk_dir_buf[PATH_MAX]; + CK_SLOT_ID slot_id = sess->session_info.slotID; + + /* Check Slot ID */ + if (slot_id >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("Invalid slot ID: %lu\n", slot_id); + return CKR_FUNCTION_FAILED; + } + + /* compute the sha of the pin. */ + rc = compute_sha1(tokdata, pPin, ulPinLen, hash_sha); + if (rc != CKR_OK) { + TRACE_ERROR("Hash Computation Failed.\n"); + return rc; + } + + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Process Lock Failed.\n"); + return rc; + } + + if (userType == CKU_USER) { + /* check if pin initialized */ + if (memcmp(tokdata->nv_token_data->user_pin_sha, + "00000000000000000000", SHA1_HASH_SIZE) == 0) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_PIN_NOT_INITIALIZED)); + rc = CKR_USER_PIN_NOT_INITIALIZED; + goto done; + } + + /* check that pin is the same as the one in NVTOK.DAT */ + if (memcmp(tokdata->nv_token_data->user_pin_sha, hash_sha, + SHA1_HASH_SIZE) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + + /* now load the master key */ + if (slot_data[slot_id]->mech == ICSF_CFG_MECH_SIMPLE) { + sprintf(fname, "%s/MK_USER", get_pk_dir(tokdata, pk_dir_buf)); + rc = get_masterkey(pPin, ulPinLen, fname, + tokdata->master_key, &mklen); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to load master key.\n"); + goto done; + } + } + } else { + /* if SO ... */ + + /* check that pin is the same as the one in NVTOK.DAT */ + if (memcmp(tokdata->nv_token_data->so_pin_sha, hash_sha, + SHA1_HASH_SIZE) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + + if (slot_data[slot_id]->mech == ICSF_CFG_MECH_SIMPLE) { + /* now load the master key */ + sprintf(fname, "%s/MK_SO", get_pk_dir(tokdata, pk_dir_buf)); + rc = get_masterkey(pPin, ulPinLen, fname, + tokdata->master_key, &mklen); + if (rc != CKR_OK) { + TRACE_DEVEL("Failed to load master key.\n"); + goto done; + } + } + } + /* Now that user is authenticated, can get racf passwd and + * establish ldap handle for session. This will get done + * when we call icsf_get_handles() in SC_Login(). + */ +done: + if (rc == CKR_OK) + rc = XProcUnLock(tokdata); + else + XProcUnLock(tokdata); + + return rc; +} + +static CK_RV check_session_permissions(SESSION * sess, CK_ATTRIBUTE * attrs, + CK_ULONG attrs_len) +{ + CK_RV rc = CKR_OK; + /* PKCS#11 default value for CKA_TOKEN is FALSE */ + CK_BBOOL is_token_obj = FALSE; + /* ICSF default value for CKA_PRIVATE is TRUE */ + CK_BBOOL is_priv_obj = TRUE; + + /* Get attributes values */ + find_bbool_attribute(attrs, attrs_len, CKA_TOKEN, &is_token_obj); + find_bbool_attribute(attrs, attrs_len, CKA_PRIVATE, &is_priv_obj); + + /* + * Check whether session has permissions to create the object, etc + * + * Object R/O R/W R/O R/W R/W + * Type Public Public User User SO + * ------------------------------------------------------------- + * Public session R/W R/W R/W R/W R/W + * Private session R/W R/W + * Public token R/O R/W R/O R/W R/W + * Private token R/O R/W + */ + + if (sess->session_info.state == CKS_RO_PUBLIC_SESSION) { + if (is_priv_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + if (is_token_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY)); + rc = CKR_SESSION_READ_ONLY; + goto done; + } + } + + if (sess->session_info.state == CKS_RO_USER_FUNCTIONS) { + if (is_token_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY)); + rc = CKR_SESSION_READ_ONLY; + goto done; + } + } + + if (sess->session_info.state == CKS_RW_PUBLIC_SESSION) { + if (is_priv_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + } + + if (sess->session_info.state == CKS_RW_SO_FUNCTIONS) { + if (is_priv_obj) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + } + +done: + return rc; +} + +/* + * Copy an existing object. + */ +CK_RV icsftok_copy_object(STDLL_TokData_t * tokdata, + SESSION * session, CK_ATTRIBUTE_PTR attrs, + CK_ULONG attrs_len, CK_OBJECT_HANDLE src, + CK_OBJECT_HANDLE_PTR dst) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + CK_RV rc = CKR_OK; + struct session_state *session_state; + struct icsf_object_mapping *mapping_dst = NULL; + struct icsf_object_mapping *mapping_src = NULL; + CK_ULONG node_number; + int reason = 0; + + CK_BBOOL is_priv; + CK_BBOOL is_token; + CK_RV rc_permission = CKR_OK; + + CK_ATTRIBUTE priv_attrs[] = { + {CKA_PRIVATE, &is_priv, sizeof(is_priv)} + , + {CKA_TOKEN, &is_token, sizeof(is_token)} + , + }; + + CK_ATTRIBUTE_PTR temp_attrs; + + /* Get session state */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Allocate structure for new object */ + if (!(mapping_dst = malloc(sizeof(*mapping_dst)))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + + mapping_src = bt_get_node_value(&icsf_data->objects, src); + if (!mapping_src) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_OBJECT_HANDLE_INVALID; + goto done; + } + + rc = icsf_get_attribute(session_state->ld, &reason, + &mapping_src->icsf_object, priv_attrs, 2); + if (rc != CKR_OK) { + TRACE_ERROR("icsf_get_attribute failed\n"); + goto done; + } + + if (attrs_len != 0) { + /* looking for CKA_PRIVATE */ + temp_attrs = get_attribute_by_type(attrs, attrs_len, CKA_PRIVATE); + if (temp_attrs != NULL) { + priv_attrs[0].pValue = temp_attrs->pValue; + priv_attrs[0].ulValueLen = temp_attrs->ulValueLen; + } + + /* looking for CKA_TOKEN */ + temp_attrs = get_attribute_by_type(attrs, attrs_len, CKA_TOKEN); + if (temp_attrs != NULL) { + priv_attrs[1].pValue = temp_attrs->pValue; + priv_attrs[1].ulValueLen = attrs->ulValueLen; + } + } + + /* Check permissions based on attributes and session */ + rc = check_session_permissions(session, priv_attrs, 2); + if (rc_permission != CKR_OK) { + TRACE_DEVEL("check_session_permissions failed\n"); + goto done; + } + + /* Call ICSF service */ + rc = icsf_copy_object(session_state->ld, &reason, attrs, attrs_len, + &mapping_src->icsf_object, &mapping_dst->icsf_object); + if (rc != 0) { + TRACE_DEVEL("Failed to Copy object.\n"); + rc = icsf_to_ock_err(rc, reason); + goto done; + } + + /* Add info about object into session */ + if (!(node_number = bt_node_add(&icsf_data->objects, mapping_dst))) { + TRACE_ERROR("Failed to add object to binary tree.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Use node number as handle */ + *dst = node_number; + +done: + if (mapping_src) { + bt_put_node_value(&icsf_data->objects, mapping_src); + mapping_src = NULL; + } + + /* If allocated, object must be freed in case of failure */ + if (rc && mapping_dst) + free(mapping_dst); + + return rc; +} + +/* + * Create a new object. + */ +CK_RV icsftok_create_object(STDLL_TokData_t * tokdata, SESSION * session, + CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, + CK_OBJECT_HANDLE_PTR handle) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + CK_RV rc = CKR_OK; + struct session_state *session_state; + struct icsf_object_mapping *mapping; + CK_ULONG node_number; + char token_name[sizeof(tokdata->nv_token_data->token_info.label) + 1]; + int reason = 0; + + /* Check permissions based on attributes and session */ + rc = check_session_permissions(session, attrs, attrs_len); + if (rc != CKR_OK) + return rc; + + /* Copy token name from shared memory */ + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get process lock.\n"); + return rc; + } + + strunpad(token_name, (const char *)tokdata->nv_token_data->token_info.label, + sizeof(tokdata->nv_token_data->token_info.label), ' '); + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release process lock.\n"); + return rc; + } + + /* Allocate structure to keep ICSF object information */ + if (!(mapping = malloc(sizeof(*mapping)))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + memset(mapping, 0, sizeof(struct icsf_object_mapping)); + mapping->session_id = session->handle; + + /* Get session state */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Call ICSF service */ + if ((rc = icsf_create_object(session_state->ld, &reason, token_name, + attrs, attrs_len, &mapping->icsf_object))) { + TRACE_DEVEL("icsf_create_object failed\n"); + rc = icsf_to_ock_err(rc, reason); + goto done; + } + + /* Add info about object into session */ + if (!(node_number = bt_node_add(&icsf_data->objects, mapping))) { + TRACE_ERROR("Failed to add object to binary tree.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Use node number as handle */ + *handle = node_number; + +done: + /* If allocated, object must be freed in case of failure */ + if (rc && mapping) + free(mapping); + + return rc; +} + +/* + * Check if attribute values are valid and add default values for missing ones. + * + * It returns a new allocated array that must be freed with + * free_attribute_array(). + */ +static CK_RV check_key_attributes(CK_ULONG class, CK_ULONG key_type, + CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, + CK_ATTRIBUTE_PTR * p_attrs, + CK_ULONG * p_attrs_len) +{ + + CK_RV rc; + CK_ULONG i; + CK_ULONG check_types[] = { CKA_CLASS, CKA_KEY_TYPE }; + CK_ULONG *check_values[] = { &class, &key_type }; + + if ((rc = dup_attribute_array(attrs, attrs_len, p_attrs, p_attrs_len))) + return rc; + + for (i = 0; i < sizeof(check_types) / sizeof(*check_types); i++) { + /* Search for the attribute */ + CK_ATTRIBUTE_PTR attr = get_attribute_by_type(*p_attrs, + *p_attrs_len, + check_types[i]); + if (attr) { + /* Check the expected value */ + if (*((CK_ULONG *) attr->pValue) != *check_values[i]) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + rc = CKR_ATTRIBUTE_VALUE_INVALID; + goto cleanup; + } + } else { + /* Add default value */ + rc = add_to_attribute_array(p_attrs, p_attrs_len, + check_types[i], + (CK_BYTE *) check_values[i], + sizeof(*check_values[i])); + if (rc) + goto cleanup; + } + } + + rc = CKR_OK; + +cleanup: + if (rc) { + free_attribute_array(*p_attrs, *p_attrs_len); + *p_attrs = NULL; + *p_attrs_len = 0; + } + + return rc; +} + +/* + * Get the type of the key that must be generated based on given mechanism. + * + * This functions is used by both symmetric and asymmetric key generation + * functions. + */ +static CK_ULONG get_generate_key_type(CK_MECHANISM_PTR mech) +{ + switch (mech->mechanism) { + /* Symmetric keys */ + case CKM_AES_KEY_GEN: + return CKK_AES; + case CKM_DES_KEY_GEN: + return CKK_DES; + case CKM_DES2_KEY_GEN: + return CKK_DES2; + case CKM_DES3_KEY_GEN: + return CKK_DES3; + case CKM_SSL3_PRE_MASTER_KEY_GEN: + return CKK_GENERIC_SECRET; + /* Asymmetric keys */ + case CKM_RSA_PKCS_KEY_PAIR_GEN: + return CKK_RSA; + case CKM_DSA_KEY_PAIR_GEN: + return CKK_DSA; + case CKM_DH_PKCS_KEY_PAIR_GEN: + case CKM_DH_PKCS_DERIVE: + return CKK_DH; + case CKM_EC_KEY_PAIR_GEN: + return CKK_EC; + case CKM_SSL3_MASTER_KEY_DERIVE: + case CKM_SSL3_KEY_AND_MAC_DERIVE: + case CKM_TLS_KEY_AND_MAC_DERIVE: + case CKM_GENERIC_SECRET_KEY_GEN: + return CKK_GENERIC_SECRET; + } + + return -1; +} + +/* + * Generate a key pair. + */ +CK_RV icsftok_generate_key_pair(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM_PTR mech, + CK_ATTRIBUTE_PTR pub_attrs, + CK_ULONG pub_attrs_len, + CK_ATTRIBUTE_PTR priv_attrs, + CK_ULONG priv_attrs_len, + CK_OBJECT_HANDLE_PTR p_pub_key, + CK_OBJECT_HANDLE_PTR p_priv_key) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + CK_RV rc; + char token_name[sizeof(tokdata->nv_token_data->token_info.label) + 1]; + struct session_state *session_state; + struct icsf_object_mapping *pub_key_mapping = NULL; + struct icsf_object_mapping *priv_key_mapping = NULL; + int reason = 0; + int pub_node_number, priv_node_number; + CK_ATTRIBUTE_PTR new_pub_attrs = NULL; + CK_ULONG new_pub_attrs_len = 0; + CK_ATTRIBUTE_PTR new_priv_attrs = NULL; + CK_ULONG new_priv_attrs_len = 0; + CK_ULONG key_type; + + /* Check and set default attributes based on mech */ + if ((key_type = get_generate_key_type(mech)) == (CK_ULONG)-1) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + rc = check_key_attributes(CKO_PUBLIC_KEY, key_type, pub_attrs, + pub_attrs_len, &new_pub_attrs, + &new_pub_attrs_len); + if (rc != CKR_OK) + goto done; + + rc = check_key_attributes(CKO_PRIVATE_KEY, key_type, priv_attrs, + priv_attrs_len, &new_priv_attrs, + &new_priv_attrs_len); + if (rc != CKR_OK) + goto done; + + /* Check permissions based on attributes and session */ + rc = check_session_permissions(session, new_pub_attrs, new_pub_attrs_len); + if (rc != CKR_OK) + goto done; + rc = check_session_permissions(session, new_priv_attrs, new_priv_attrs_len); + if (rc != CKR_OK) + goto done; + + /* Get session state */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Copy token name from shared memory */ + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get process lock.\n"); + goto done; + } + + strunpad(token_name, (const char *)tokdata->nv_token_data->token_info.label, + sizeof(tokdata->nv_token_data->token_info.label), ' '); + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release process lock.\n"); + goto done; + } + + /* Allocate structure to keep ICSF objects information */ + if (!(pub_key_mapping = malloc(sizeof(*pub_key_mapping))) || + !(priv_key_mapping = malloc(sizeof(*priv_key_mapping)))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + + /* Call ICSF service */ + if ((rc = icsf_generate_key_pair(session_state->ld, &reason, token_name, + new_pub_attrs, new_pub_attrs_len, + new_priv_attrs, new_priv_attrs_len, + &pub_key_mapping->icsf_object, + &priv_key_mapping->icsf_object))) { + TRACE_DEVEL("icsf_generate_key_pair failed\n"); + rc = icsf_to_ock_err(rc, reason); + goto done; + } + + /* Add info about objects into session */ + if (!(pub_node_number = bt_node_add(&icsf_data->objects, pub_key_mapping)) || + !(priv_node_number = bt_node_add(&icsf_data->objects, priv_key_mapping))) { + TRACE_ERROR("Failed to add object to binary tree.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Use node numbers as handles */ + *p_pub_key = pub_node_number; + *p_priv_key = priv_node_number; + +done: + free_attribute_array(new_pub_attrs, new_pub_attrs_len); + free_attribute_array(new_priv_attrs, new_priv_attrs_len); + + /* Object mappings must be freed in case of failure */ + if (rc && pub_key_mapping) + free(pub_key_mapping); + if (rc && priv_key_mapping) + free(priv_key_mapping); + + return rc; +} + +/* + * Generate a symmetric key. + */ +CK_RV icsftok_generate_key(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM_PTR mech, CK_ATTRIBUTE_PTR attrs, + CK_ULONG attrs_len, CK_OBJECT_HANDLE_PTR handle) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + CK_RV rc = CKR_OK; + struct session_state *session_state; + struct icsf_object_mapping *mapping = NULL; + CK_ULONG node_number; + char token_name[sizeof(tokdata->nv_token_data->token_info.label) + 1]; + CK_ATTRIBUTE_PTR new_attrs = NULL; + CK_ULONG new_attrs_len = 0; + CK_ULONG class = CKO_SECRET_KEY; + CK_ULONG key_type = 0; + int reason = 0; + + /* Check attributes */ + if ((key_type = get_generate_key_type(mech)) == (CK_ULONG)-1) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + rc = check_key_attributes(class, key_type, attrs, attrs_len, &new_attrs, + &new_attrs_len); + if (rc != CKR_OK) + goto done; + + /* Check permissions based on attributes and session */ + rc = check_session_permissions(session, new_attrs, new_attrs_len); + if (rc != CKR_OK) + goto done; + + /* Copy token name from shared memory */ + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get process lock.\n"); + goto done; + } + + strunpad(token_name, (const char *)tokdata->nv_token_data->token_info.label, + sizeof(tokdata->nv_token_data->token_info.label), ' '); + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release process lock.\n"); + goto done; + } + + /* Allocate structure to keep ICSF object information */ + if (!(mapping = malloc(sizeof(*mapping)))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + goto done; + } + memset(mapping, 0, sizeof(struct icsf_object_mapping)); + mapping->session_id = session->handle; + + /* Get session state */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Call ICSF service */ + if ((rc = icsf_generate_secret_key(session_state->ld, &reason, token_name, + mech, new_attrs, new_attrs_len, + &mapping->icsf_object))) { + TRACE_DEVEL("icsf_generate_secret_key failed\n"); + rc = icsf_to_ock_err(rc, reason); + goto done; + } + + /* Add info about object into session */ + if (!(node_number = bt_node_add(&icsf_data->objects, mapping))) { + TRACE_ERROR("Failed to add object to binary tree.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Use node number as handle */ + *handle = node_number; + +done: + if (new_attrs) + free_attribute_array(new_attrs, new_attrs_len); + + /* If allocated, object must be freed in case of failure */ + if (rc && mapping) + free(mapping); + + return rc; +} + +/* + * Free all data pointed by an encryption context and set everything to zero. + */ +static void free_encr_ctx(ENCR_DECR_CONTEXT * encr_ctx) +{ + struct icsf_multi_part_context *multi_part_ctx; + + if (!encr_ctx) + return; + + /* Initialize encryption context */ + multi_part_ctx = (struct icsf_multi_part_context *) encr_ctx->context; + if (multi_part_ctx) { + if (multi_part_ctx->data) + free(multi_part_ctx->data); + free(multi_part_ctx); + } + if (encr_ctx->mech.pParameter) + free(encr_ctx->mech.pParameter); + memset(encr_ctx, 0, sizeof(*encr_ctx)); +} + +/* + * Return if the algorithm used by a mechanism is asymmetric or symmetric. + */ +static CK_RV get_crypt_type(CK_MECHANISM_PTR mech, int *p_symmetric) +{ + switch (mech->mechanism) { + case CKM_AES_ECB: + case CKM_AES_CBC: + case CKM_AES_CBC_PAD: + case CKM_DES_ECB: + case CKM_DES_CBC: + case CKM_DES_CBC_PAD: + case CKM_DES3_ECB: + case CKM_DES3_CBC: + case CKM_DES3_CBC_PAD: + *p_symmetric = 1; + break; + case CKM_RSA_PKCS: + case CKM_RSA_X_509: + *p_symmetric = 0; + break; + default: + return CKR_MECHANISM_INVALID; + } + + return CKR_OK; +} + +/** + * Validate mechanism parameter length here for the applicable + * encryption/decryption mechanisms supported by icsf token + */ +static CK_RV validate_mech_parameters(CK_MECHANISM_PTR mech) +{ + CK_RV rc = CKR_OK; + size_t expected_block_size = 0; + + /* Verify the mechanisms that has a parameter length + * specification per pkcs11#v2.2 spec + * */ + switch (mech->mechanism) { + case CKM_DES_CBC: + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC: + case CKM_DES3_CBC_PAD: + case CKM_AES_CBC: + case CKM_AES_CBC_PAD: + /* Get the expected block size. This check needs to be here as + * CKM_RSA_X_509 and CKM_RSA_PKCS does not have a block size */ + if ((rc = icsf_block_size(mech->mechanism, &expected_block_size))) + return rc; + + if (mech->ulParameterLen != expected_block_size) { + TRACE_ERROR("Invalid mechanism parameter length: %lu " + "(expected %lu)\n", + (unsigned long) mech->ulParameterLen, + (unsigned long) expected_block_size); + return CKR_MECHANISM_PARAM_INVALID; + } + break; + case CKM_DES_ECB: + case CKM_DES3_ECB: + case CKM_RSA_X_509: + case CKM_RSA_PKCS: + case CKM_AES_ECB: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + break; + default: + /** Encryption/decryption mechanism not supported by icsf token */ + TRACE_ERROR("icsf invalid mechanism %lu\n", mech->mechanism); + return CKR_MECHANISM_INVALID; + } + + return rc; +} + + +/* + * Initialize an encryption operation. + */ +CK_RV icsftok_encrypt_init(STDLL_TokData_t * tokdata, + SESSION * session, CK_MECHANISM_PTR mech, + CK_OBJECT_HANDLE key) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + CK_RV rc = CKR_OK; + ENCR_DECR_CONTEXT *encr_ctx = &session->encr_ctx; + struct icsf_multi_part_context *multi_part_ctx = NULL; + size_t block_size = 0; + int symmetric = 0; + struct icsf_object_mapping *mapping = NULL; + + /* Check session */ + if (!get_session_state(tokdata, session->handle)) { + rc = CKR_SESSION_HANDLE_INVALID; + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + goto done; + } + + /* Get algorithm type */ + if ((rc = get_crypt_type(mech, &symmetric))) + goto done; + + /* Check if key exists */ + if (!(mapping = bt_get_node_value(&icsf_data->objects, key))) { + rc = CKR_KEY_HANDLE_INVALID; + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + goto done; + } + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + + /** validate the mechanism parameter length here */ + if ((rc = validate_mech_parameters(mech))) + goto done; + + /* Initialize encryption context */ + free_encr_ctx(encr_ctx); + encr_ctx->key = key; + encr_ctx->active = TRUE; + encr_ctx->multi = FALSE; + + /* Copy mechanism */ + if (mech->pParameter == NULL || mech->ulParameterLen == 0) { + encr_ctx->mech.ulParameterLen = 0; + encr_ctx->mech.pParameter = NULL; + } else { + encr_ctx->mech.pParameter = malloc(mech->ulParameterLen); + if (!encr_ctx->mech.pParameter) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + encr_ctx->mech.ulParameterLen = mech->ulParameterLen; + memcpy(encr_ctx->mech.pParameter, mech->pParameter, + mech->ulParameterLen); + } + encr_ctx->mech.mechanism = mech->mechanism; + + /* + * Asymmetric algorithms don't support multi-part and then there's no + * need to allocate context. + */ + if (!symmetric) + goto done; + + /* Allocate context for multi-part operations */ + if (!(multi_part_ctx = malloc(sizeof(*multi_part_ctx)))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + encr_ctx->context = (void *) multi_part_ctx; + + /* Chained data has always a fixed length */ + memset(multi_part_ctx, 0, sizeof(*multi_part_ctx)); + + /* Check mechanism and get block size */ + rc = icsf_block_size(mech->mechanism, &block_size); + if (rc != CKR_OK) + goto done; + + /* + * data is used to retain data until at least the block size is reached. + */ + multi_part_ctx->data_len = block_size; + multi_part_ctx->data = malloc(multi_part_ctx->data_len); + if (!multi_part_ctx->data) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + +done: + if (rc != CKR_OK) + free_encr_ctx(encr_ctx); + + return rc; +} + +/* + * Encrypt data and finalize an encryption operation. + */ +CK_RV icsftok_encrypt(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE_PTR input_data, + CK_ULONG input_data_len, CK_BYTE_PTR output_data, + CK_ULONG_PTR p_output_data_len) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + CK_RV rc = CKR_OK; + CK_BBOOL is_length_only = (output_data == NULL); + ENCR_DECR_CONTEXT *encr_ctx = &session->encr_ctx; + struct session_state *session_state; + struct icsf_object_mapping *mapping = NULL; + char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, }; + size_t chain_data_len = sizeof(chain_data); + int reason = 0; + int symmetric = 0; + + /* Get algorithm type */ + if ((rc = get_crypt_type(&encr_ctx->mech, &symmetric))) + goto done; + + /* Check if there's a multi-part encryption in progress */ + if (encr_ctx->multi) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + /* Check session */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Check if key exists */ + if (!(mapping = bt_get_node_value(&icsf_data->objects, encr_ctx->key))) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + rc = CKR_KEY_HANDLE_INVALID; + goto done; + } + + /* Encrypt data using remote token. */ + if (symmetric) { + rc = icsf_secret_key_encrypt(session_state->ld, &reason, + &mapping->icsf_object, + &encr_ctx->mech, + ICSF_CHAINING_ONLY, (char *)input_data, + input_data_len, (char *)output_data, + p_output_data_len, chain_data, + &chain_data_len); + } else { + rc = icsf_public_key_verify(session_state->ld, &reason, TRUE, + &mapping->icsf_object, + &encr_ctx->mech, (char *)input_data, + input_data_len, (char *)output_data, + p_output_data_len); + } + if (rc) { + if (reason == ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT) { + if (is_length_only) { + /* + * Parameter too short is not a problem when + * querying the expect output size. + */ + rc = CKR_OK; + } else { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + } + } else { + TRACE_ERROR("Failed to encrypt data. reason = %d\n", reason); + rc = icsf_to_ock_err(rc, reason); + } + goto done; + } + +done: + if (mapping) { + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + } + + if (rc != CKR_BUFFER_TOO_SMALL && !(rc == CKR_OK && is_length_only)) + free_encr_ctx(encr_ctx); + + return rc; +} + +/* + * Multi-part encryption. + */ +CK_RV icsftok_encrypt_update(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE_PTR input_part, + CK_ULONG input_part_len, CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + CK_RV rc = CKR_OK; + CK_BBOOL is_length_only = (output_part == NULL); + ENCR_DECR_CONTEXT *encr_ctx = &session->encr_ctx; + struct icsf_multi_part_context *multi_part_ctx; + struct session_state *session_state; + struct icsf_object_mapping *mapping = NULL; + char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, }; + size_t chain_data_len = sizeof(chain_data); + CK_ULONG total, remaining; + char *buffer = NULL; + int chaining; + int reason = 0; + int symmetric = 0; + + /* Multi-part is not supported for asymmetric algorithms. */ + if ((rc = get_crypt_type(&encr_ctx->mech, &symmetric))) + goto done; + if (!symmetric) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + /* Check session */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Check if key exists */ + if (!(mapping = bt_get_node_value(&icsf_data->objects, encr_ctx->key))) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + rc = CKR_KEY_HANDLE_INVALID; + goto done; + } + + multi_part_ctx = (struct icsf_multi_part_context *) encr_ctx->context; + + /* Define the type of the call */ + switch (encr_ctx->mech.mechanism) { + case CKM_DES_ECB: + case CKM_DES3_ECB: + case CKM_AES_ECB: + /* ICSF just support the chaining mode ONLY for ECB. */ + chaining = ICSF_CHAINING_ONLY; + break; + default: + if (multi_part_ctx->initiated) { + chaining = ICSF_CHAINING_CONTINUE; + memcpy(chain_data, multi_part_ctx->chain_data, chain_data_len); + } else { + chaining = ICSF_CHAINING_INITIAL; + } + } + + /* + * Data needs to be sent to ICSF in chucks with size that is multiple of + * block size. Any remaining data is kept in the multi-part context and + * can be sent in a further call of the update function or when the + * finalize function is called. + */ + total = multi_part_ctx->used_data_len + input_part_len; + remaining = total % multi_part_ctx->data_len; + + /* + * If there's no enough data to make a call, skip it. + */ + if (total < multi_part_ctx->data_len) { + *p_output_part_len = 0; + goto keep_remaining_data; + } + + /* + * The data to be encrypted should have length that is multiple of the + * block size. It is composed by data kept in the multi-part context + * concatenated with part of the data given. + */ + if (!(buffer = malloc(total - remaining))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memcpy(buffer, multi_part_ctx->data, multi_part_ctx->used_data_len); + memcpy(buffer + multi_part_ctx->used_data_len, input_part, + input_part_len - remaining); + + /* Encrypt data using remote token. */ + rc = icsf_secret_key_encrypt(session_state->ld, &reason, + &mapping->icsf_object, + &encr_ctx->mech, chaining, + buffer, total - remaining, + (char *)output_part, p_output_part_len, + chain_data, &chain_data_len); + if (rc) { + if (reason == ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT) { + if (is_length_only) { + /* + * Parameter too short is not a problem when + * querying the expect output size. + */ + rc = CKR_OK; + } else { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + } + } else { + TRACE_DEVEL("Failed to encrypt data. reason = %d\n", reason); + rc = icsf_to_ock_err(rc, reason); + } + goto done; + } + + /** If this is the first block for multi-part operation, also set + * the encr_ctx->context_len here. This is needed for + * C_GetOperationState to work correctly */ + if (!multi_part_ctx->initiated) + encr_ctx->context_len = sizeof(*multi_part_ctx); + + /* + * When blocks are sent it's necessary to keep the chain data returned + * to be used in a subsequent call. + */ + if (!is_length_only) { + /* Copy chain data into context */ + memcpy(multi_part_ctx->chain_data, chain_data, chain_data_len); + + /* Mark multi-part operation as initiated */ + multi_part_ctx->initiated = TRUE; + + /* Mark the multi-part operation in encr_ctx */ + encr_ctx->multi = TRUE; + + /* Data stored in cache was used */ + multi_part_ctx->used_data_len = 0; + } + +keep_remaining_data: + /* Keep the remaining data to a next call */ + if (!is_length_only) { + /* Copy remaining part of input_part into context */ + if (total < multi_part_ctx->data_len) { + memcpy(multi_part_ctx->data + + multi_part_ctx->used_data_len, input_part, input_part_len); + } else { + memcpy(multi_part_ctx->data, + input_part + input_part_len - remaining, remaining); + } + multi_part_ctx->used_data_len = remaining; + } + +done: + if (mapping) { + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + } + + /* Free resources */ + if (buffer) + free(buffer); + + if (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL) + free_encr_ctx(encr_ctx); + + return rc; +} + +/* + * Finalize a multi-part encryption. + */ +CK_RV icsftok_encrypt_final(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + CK_RV rc = CKR_OK; + CK_BBOOL is_length_only = (output_part == NULL); + ENCR_DECR_CONTEXT *encr_ctx = &session->encr_ctx; + struct icsf_multi_part_context *multi_part_ctx; + struct session_state *session_state; + struct icsf_object_mapping *mapping = NULL; + char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, }; + size_t chain_data_len = sizeof(chain_data); + int chaining; + int reason = 0; + int symmetric = 0; + + /* Multi-part is not supported for asymmetric algorithms. */ + if ((rc = get_crypt_type(&encr_ctx->mech, &symmetric))) + goto done; + if (!symmetric) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + /* Check session */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Check if key exists */ + if (!(mapping = bt_get_node_value(&icsf_data->objects, encr_ctx->key))) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + rc = CKR_KEY_HANDLE_INVALID; + goto done; + } + + /* Define the type of the call */ + multi_part_ctx = (struct icsf_multi_part_context *) encr_ctx->context; + switch (encr_ctx->mech.mechanism) { + case CKM_DES_ECB: + case CKM_DES3_ECB: + case CKM_AES_ECB: + /* + * When not using a chained algorithm and there's no remaining + * data, don't call ICSF. + */ + *p_output_part_len = 0; + if (!multi_part_ctx->used_data_len) + goto done; + + /* ICSF just support the chaining mode ONLY for ECB. */ + chaining = ICSF_CHAINING_ONLY; + break; + default: + if (multi_part_ctx->initiated) { + chaining = ICSF_CHAINING_FINAL; + memcpy(chain_data, multi_part_ctx->chain_data, chain_data_len); + } else { + chaining = ICSF_CHAINING_ONLY; + } + } + + /* + * Encrypt data using remote token. + * + * All the data in multi-part context should be sent. + */ + rc = icsf_secret_key_encrypt(session_state->ld, &reason, + &mapping->icsf_object, + &encr_ctx->mech, chaining, + multi_part_ctx->data, + multi_part_ctx->used_data_len, + (char *)output_part, p_output_part_len, + chain_data, &chain_data_len); + if (rc) { + if (reason == ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT) { + if (is_length_only) { + /* + * Parameter too short is not a problem when + * querying the expect output size. + */ + rc = CKR_OK; + } else { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + } + } else { + TRACE_DEVEL("Failed to encrypt data. reason = %d\n", reason); + rc = icsf_to_ock_err(rc, reason); + } + goto done; + } + +done: + if (mapping) { + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + } + + if ((is_length_only && rc != CKR_OK) || + (!is_length_only && rc != CKR_BUFFER_TOO_SMALL)) + free_encr_ctx(encr_ctx); + + return rc; +} + +/* + * Initialize a decryption operation. + */ +CK_RV icsftok_decrypt_init(STDLL_TokData_t * tokdata, + SESSION * session, CK_MECHANISM_PTR mech, + CK_OBJECT_HANDLE key) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + CK_RV rc = CKR_OK; + ENCR_DECR_CONTEXT *decr_ctx = &session->decr_ctx; + struct icsf_multi_part_context *multi_part_ctx = NULL; + size_t block_size = 0; + int symmetric = 0; + struct icsf_object_mapping *mapping = NULL; + + /* Check session */ + if (!get_session_state(tokdata, session->handle)) { + rc = CKR_SESSION_HANDLE_INVALID; + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + goto done; + } + + /* Get algorithm type */ + if ((rc = get_crypt_type(mech, &symmetric))) + goto done; + + /* Check if key exists */ + if (!(mapping = bt_get_node_value(&icsf_data->objects, key))) { + rc = CKR_KEY_HANDLE_INVALID; + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + goto done; + } + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + + /** validate the mechanism parameter length here */ + if ((rc = validate_mech_parameters(mech))) + goto done; + + /* Initialize decryption context */ + free_encr_ctx(decr_ctx); + decr_ctx->key = key; + decr_ctx->active = TRUE; + decr_ctx->multi = FALSE; + + /* Copy mechanism */ + if (mech->pParameter == NULL || mech->ulParameterLen == 0) { + decr_ctx->mech.ulParameterLen = 0; + decr_ctx->mech.pParameter = NULL; + } else { + decr_ctx->mech.pParameter = malloc(mech->ulParameterLen); + if (!decr_ctx->mech.pParameter) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + decr_ctx->mech.ulParameterLen = mech->ulParameterLen; + memcpy(decr_ctx->mech.pParameter, mech->pParameter, + mech->ulParameterLen); + } + decr_ctx->mech.mechanism = mech->mechanism; + + /* + * Asymmetric algorithms don't support multi-part and then there's no + * need to allocate context. + */ + if (!symmetric) + goto done; + + /* Allocate context for multi-part operations */ + if (!(multi_part_ctx = malloc(sizeof(*multi_part_ctx)))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + decr_ctx->context = (void *) multi_part_ctx; + + /* Chained data has always a fixed length */ + memset(multi_part_ctx, 0, sizeof(*multi_part_ctx)); + + /* Check mechanism and get block size */ + rc = icsf_block_size(mech->mechanism, &block_size); + if (rc != CKR_OK) + goto done; + + /* + * data is used to retain data until at least the block size is reached. + */ + multi_part_ctx->data_len = block_size; + multi_part_ctx->data = malloc(multi_part_ctx->data_len); + if (!multi_part_ctx->data) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + +done: + if (rc != CKR_OK) + free_encr_ctx(decr_ctx); + + return rc; +} + +/* + * Decrypt data and finalize a decryption operation. + */ +CK_RV icsftok_decrypt(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE_PTR input_data, + CK_ULONG input_data_len, CK_BYTE_PTR output_data, + CK_ULONG_PTR p_output_data_len) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + CK_RV rc = CKR_OK; + CK_BBOOL is_length_only = (output_data == NULL); + ENCR_DECR_CONTEXT *decr_ctx = &session->decr_ctx; + struct session_state *session_state; + struct icsf_object_mapping *mapping = NULL; + char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, }; + size_t chain_data_len = sizeof(chain_data); + int reason = 0; + int symmetric = 0; + + /* Get algorithm type */ + if ((rc = get_crypt_type(&decr_ctx->mech, &symmetric))) + goto done; + + /* Check if there's a multi-part decryption in progress */ + if (decr_ctx->multi) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + /* Check session */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Check if key exists */ + if (!(mapping = bt_get_node_value(&icsf_data->objects, decr_ctx->key))) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + rc = CKR_KEY_HANDLE_INVALID; + goto done; + } + + /* Decrypt data using remote token. */ + if (symmetric) { + rc = icsf_secret_key_decrypt(session_state->ld, &reason, + &mapping->icsf_object, + &decr_ctx->mech, + ICSF_CHAINING_ONLY, (char *)input_data, + input_data_len, (char *)output_data, + p_output_data_len, chain_data, + &chain_data_len); + } else { + rc = icsf_private_key_sign(session_state->ld, &reason, TRUE, + &mapping->icsf_object, + &decr_ctx->mech, (char *)input_data, + input_data_len, (char *)output_data, + p_output_data_len); + } + if (rc) { + if (reason == ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT) { + if (is_length_only) { + /* + * Parameter too short is not a problem when + * querying the expect output size. + */ + rc = CKR_OK; + } else { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + } + } else { + TRACE_DEVEL("Failed to decrypt data. reason = %d\n", reason); + rc = icsf_to_ock_err(rc, reason); + } + goto done; + } + +done: + if (mapping) { + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + } + + if (rc != CKR_BUFFER_TOO_SMALL && !(rc == CKR_OK && is_length_only)) + free_encr_ctx(decr_ctx); + + return rc; +} + +/* + * Multi-part decryption. + */ +CK_RV icsftok_decrypt_update(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE_PTR input_part, + CK_ULONG input_part_len, CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + CK_RV rc = CKR_OK; + CK_BBOOL is_length_only = (output_part == NULL); + ENCR_DECR_CONTEXT *decr_ctx = &session->decr_ctx; + struct icsf_multi_part_context *multi_part_ctx; + struct session_state *session_state; + struct icsf_object_mapping *mapping = NULL; + char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, }; + size_t chain_data_len = sizeof(chain_data); + CK_ULONG total, remaining; + char *buffer = NULL; + int chaining; + int reason = 0; + int padding = 0; + int symmetric = 0; + + /* Multi-part is not supported for asymmetric algorithms. */ + if ((rc = get_crypt_type(&decr_ctx->mech, &symmetric))) + goto done; + if (!symmetric) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + /* Check session */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Check if key exists */ + if (!(mapping = bt_get_node_value(&icsf_data->objects, decr_ctx->key))) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + rc = CKR_KEY_HANDLE_INVALID; + goto done; + } + + multi_part_ctx = (struct icsf_multi_part_context *) decr_ctx->context; + + /* Define the type of the call */ + switch (decr_ctx->mech.mechanism) { + case CKM_AES_ECB: + case CKM_DES_ECB: + case CKM_DES3_ECB: + /* ICSF just support the chaining mode ONLY for ECB. */ + chaining = ICSF_CHAINING_ONLY; + break; + case CKM_AES_CBC_PAD: + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC_PAD: + padding = 1; + /* fallthrough */ + default: + if (multi_part_ctx->initiated) { + chaining = ICSF_CHAINING_CONTINUE; + memcpy(chain_data, multi_part_ctx->chain_data, chain_data_len); + } else { + chaining = ICSF_CHAINING_INITIAL; + } + } + + /* + * Data needs to be sent to ICSF in chucks with size that is multiple of + * block size. Any remaining data is kept in the multi-part context and + * can be sent in a further call of the update function or when the + * finalize function is called. + * + * When padding is used, there's no way to know if the current block of + * data is the one that contains the padding, So a block is kept in + * multi-part context when the data available is exactly multiple of the + * block size. + */ + total = multi_part_ctx->used_data_len + input_part_len; + if (!padding) { + remaining = total % multi_part_ctx->data_len; + } else { + remaining = MIN(((total - 1) % multi_part_ctx->data_len) + 1, total); + } + + /* + * If there's no enough data to make a call, skip it. + */ + if (total < multi_part_ctx->data_len || + (padding && total == multi_part_ctx->data_len)) { + *p_output_part_len = 0; + goto keep_remaining_data; + } + + + /* + * The data to be decrypted should have length that is multiple of the + * block size. It is composed by data kept in the multi-part context + * concatenated with part of the data given. + */ + if (!(buffer = malloc(total - remaining))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memcpy(buffer, multi_part_ctx->data, multi_part_ctx->used_data_len); + memcpy(buffer + multi_part_ctx->used_data_len, input_part, + input_part_len - remaining); + + /* Decrypt data using remote token. */ + rc = icsf_secret_key_decrypt(session_state->ld, &reason, + &mapping->icsf_object, + &decr_ctx->mech, chaining, + buffer, total - remaining, + (char *)output_part, p_output_part_len, + chain_data, &chain_data_len); + if (rc) { + if (reason == ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT) { + if (is_length_only) { + /* + * Parameter too short is not a problem when + * querying the expect output size. + */ + rc = CKR_OK; + } else { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + } + } else { + TRACE_DEVEL("Failed to decrypt data. reason = %d\n", reason); + rc = icsf_to_ock_err(rc, reason); + } + goto done; + } + + /* If this is the first block sent for multi-part set the context_len */ + if (!multi_part_ctx->initiated) + decr_ctx->context_len = sizeof(*multi_part_ctx); + + /* + * When blocks are sent it's necessary to keep the chain data returned + * to be used in a subsequent call. + */ + if (!is_length_only) { + /* Copy chain data into context */ + memcpy(multi_part_ctx->chain_data, chain_data, chain_data_len); + + /* Mark multi-part operation as initiated */ + multi_part_ctx->initiated = TRUE; + + /* Mark multi-part operation in decr_ctx in session */ + decr_ctx->multi = TRUE; + + /* Data stored in cache was used */ + multi_part_ctx->used_data_len = 0; + } + +keep_remaining_data: + /* Keep the remaining data to a next call */ + if (!is_length_only) { + /* Copy remaining part of input_part into context */ + if (total < multi_part_ctx->data_len || + (padding && total == multi_part_ctx->data_len)) { + memcpy(multi_part_ctx->data + + multi_part_ctx->used_data_len, input_part, input_part_len); + } else { + memcpy(multi_part_ctx->data, + input_part + input_part_len - remaining, remaining); + } + multi_part_ctx->used_data_len = remaining; + } + +done: + if (mapping) { + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + } + + /* Free resources */ + if (buffer) + free(buffer); + + if (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL) + free_encr_ctx(decr_ctx); + + return rc; +} + +/* + * Finalize a multi-part decryption. + */ +CK_RV icsftok_decrypt_final(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + CK_RV rc = CKR_OK; + CK_BBOOL is_length_only = (output_part == NULL); + ENCR_DECR_CONTEXT *decr_ctx = &session->decr_ctx; + struct icsf_multi_part_context *multi_part_ctx; + struct session_state *session_state; + struct icsf_object_mapping *mapping = NULL; + char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, }; + size_t chain_data_len = sizeof(chain_data); + int chaining; + int reason = 0; + int symmetric = 0; + + /* Multi-part is not supported for asymmetric algorithms. */ + if ((rc = get_crypt_type(&decr_ctx->mech, &symmetric))) + goto done; + if (!symmetric) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + /* Check session */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Check if key exists */ + if (!(mapping = bt_get_node_value(&icsf_data->objects, decr_ctx->key))) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + rc = CKR_KEY_HANDLE_INVALID; + goto done; + } + + /* Define the type of the call */ + multi_part_ctx = (struct icsf_multi_part_context *) decr_ctx->context; + switch (decr_ctx->mech.mechanism) { + case CKM_AES_ECB: + case CKM_DES_ECB: + case CKM_DES3_ECB: + /* + * When not using a chained algorithm and there's no remaining + * data, don't call ICSF. + */ + *p_output_part_len = 0; + if (!multi_part_ctx->used_data_len) + goto done; + + /* ICSF just support the chaining mode ONLY for ECB. */ + chaining = ICSF_CHAINING_ONLY; + break; + default: + if (multi_part_ctx->initiated) { + chaining = ICSF_CHAINING_FINAL; + memcpy(chain_data, multi_part_ctx->chain_data, chain_data_len); + } else { + chaining = ICSF_CHAINING_ONLY; + } + } + + /* + * Decrypt data using remote token. + * + * All the data in multi-part context should be sent. + */ + rc = icsf_secret_key_decrypt(session_state->ld, &reason, + &mapping->icsf_object, + &decr_ctx->mech, chaining, + multi_part_ctx->data, + multi_part_ctx->used_data_len, + (char *)output_part, p_output_part_len, + chain_data, &chain_data_len); + if (rc) { + if (reason == ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT) { + if (is_length_only) { + /* + * Parameter too short is not a problem when + * querying the expect output size. + */ + rc = CKR_OK; + } else { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + rc = CKR_BUFFER_TOO_SMALL; + } + } else { + TRACE_DEVEL("Failed to decrypt data. reason = %d\n", reason); + rc = icsf_to_ock_err(rc, reason); + } + goto done; + } + +done: + if (mapping) { + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + } + + if ((is_length_only && rc != CKR_OK) || + (!is_length_only && rc != CKR_BUFFER_TOO_SMALL)) + free_encr_ctx(decr_ctx); + + return rc; +} + +/* + * Get the attribute values for a list of attributes. + */ +CK_RV icsftok_get_attribute_value(STDLL_TokData_t * tokdata, + SESSION * sess, CK_OBJECT_HANDLE handle, + CK_ATTRIBUTE * pTemplate, CK_ULONG ulCount, + CK_ULONG * obj_size) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + CK_RV rc = CKR_OK; + CK_BBOOL priv_obj; + struct session_state *session_state; + struct icsf_object_mapping *mapping = NULL; + int reason = 0; + + CK_ATTRIBUTE priv_attr[] = { + {CKA_PRIVATE, &priv_obj, sizeof(priv_obj)} + , + }; + + /* Get session state */ + if (!(session_state = get_session_state(tokdata, sess->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + return CKR_SESSION_HANDLE_INVALID; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + return CKR_FUNCTION_FAILED; + } + + /* get the object handle */ + mapping = bt_get_node_value(&icsf_data->objects, handle); + + if (!mapping) { + TRACE_ERROR("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); + rc = CKR_OBJECT_HANDLE_INVALID; + goto done; + } + + /* get the private attribute so we can check the permissions */ + rc = icsf_get_attribute(session_state->ld, &reason, + &mapping->icsf_object, priv_attr, 1); + if (rc != CKR_OK) { + TRACE_DEVEL("icsf_get_attribute failed\n"); + rc = icsf_to_ock_err(rc, reason); + goto done; + } + + if (priv_obj == TRUE) { + if (sess->session_info.state == CKS_RO_PUBLIC_SESSION || + sess->session_info.state == CKS_RW_PUBLIC_SESSION) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + } + // get requested attributes and values if the obj_size ptr is not set + if (!obj_size) { + /* Now call icsf to get the attribute values */ + rc = icsf_get_attribute(session_state->ld, &reason, + &mapping->icsf_object, pTemplate, ulCount); + + if (rc != CKR_OK) { + TRACE_DEVEL("icsf_get_attribute failed\n"); + rc = icsf_to_ock_err(rc, reason); + } + } else { + /* if size is specified get the object size from remote end */ + rc = icsf_get_object_size(session_state->ld, &reason, + &mapping->icsf_object, ulCount, obj_size); + + if (rc != CKR_OK) { + TRACE_DEVEL("icsf_get_object_size failed\n"); + rc = icsf_to_ock_err(rc, reason); + } + } + +done: + if (mapping) { + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + } + + return rc; +} + +/* + * Set attribute values for a list of attributes. + */ +CK_RV icsftok_set_attribute_value(STDLL_TokData_t * tokdata, + SESSION * sess, CK_OBJECT_HANDLE handle, + CK_ATTRIBUTE * pTemplate, CK_ULONG ulCount) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + struct session_state *session_state; + struct icsf_object_mapping *mapping = NULL; + CK_BBOOL is_priv; + CK_BBOOL is_token; + CK_RV rc = CKR_OK; + int reason = 0; + + CK_ATTRIBUTE priv_attrs[] = { + {CKA_PRIVATE, &is_priv, sizeof(is_priv)} + , + {CKA_TOKEN, &is_token, sizeof(is_token)} + , + }; + + /* Get session state */ + if (!(session_state = get_session_state(tokdata, sess->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + return CKR_SESSION_HANDLE_INVALID; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + return CKR_FUNCTION_FAILED; + } + + /* get the object handle */ + mapping = bt_get_node_value(&icsf_data->objects, handle); + + if (!mapping) { + TRACE_ERROR("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); + rc = CKR_OBJECT_HANDLE_INVALID; + goto done; + } + + /* check permissions : + * first get CKA_PRIVATE since we need to check againse session + * icsf will check if the attributes are modifiable + */ + rc = icsf_get_attribute(session_state->ld, &reason, + &mapping->icsf_object, priv_attrs, 2); + if (rc != CKR_OK) { + TRACE_DEVEL("icsf_get_attribute failed\n"); + rc = icsf_to_ock_err(rc, reason); + goto done; + } + + /* Check permissions based on attributes and session */ + rc = check_session_permissions(sess, priv_attrs, 2); + if (rc != CKR_OK) { + TRACE_DEVEL("check_session_permissions failed\n"); + goto done; + } + + /* Now call into icsf to set the attribute values */ + rc = icsf_set_attribute(session_state->ld, &reason, + &mapping->icsf_object, pTemplate, ulCount); + if (rc != CKR_OK) { + TRACE_ERROR("icsf_set_attribute failed\n"); + rc = icsf_to_ock_err(rc, reason); + goto done; + } + +done: + if (mapping) { + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + } + + return rc; +} + +/* + * Initialize a search for token and session objects that match a template. + */ +CK_RV icsftok_find_objects_init(STDLL_TokData_t * tokdata, SESSION * sess, + CK_ATTRIBUTE * pTemplate, CK_ULONG ulCount) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + char token_name[sizeof(tokdata->nv_token_data->token_info.label) + 1]; + struct session_state *session_state; + struct icsf_object_record records[MAX_RECORDS]; + struct icsf_object_record *previous = NULL; + size_t records_len; + unsigned int i, j; + int node_number, rc; + int reason = 0; + CK_RV rv = CKR_OK; + + /* Whether we retrieve public or private objects is determined by + * the caller's SAF authority on the token, something ock doesn't + * control. + * Since an app MUST have authenticated to ICSF token to use it, + * we can always assume it is an authenticated session and anything else + * is an error. + */ + if (sess->session_info.state == CKS_RO_PUBLIC_SESSION || + sess->session_info.state == CKS_RW_PUBLIC_SESSION || + sess->session_info.state == CKS_RW_SO_FUNCTIONS) { + TRACE_ERROR("You must authenticate to access ICSF token.\n"); + return CKR_FUNCTION_FAILED; + } + + /* Initialize the found object list. In keeping with other tokens, + * if the list does not exist, allocate list big enough for MAX_RECORD + * handles. reallocate later if more needed. + */ + if (sess->find_list == NULL) { + sess->find_list = + (CK_OBJECT_HANDLE *) malloc(10 * sizeof(CK_OBJECT_HANDLE)); + if (!sess->find_list) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + sess->find_len = 10; + } + memset(sess->find_list, 0x0, sess->find_len * sizeof(CK_OBJECT_HANDLE)); + sess->find_count = 0; + sess->find_idx = 0; + + /* Prepare to query ICSF for list objects + * Copy token name from shared memory + */ + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get process lock.\n"); + return rc; + } + + strunpad(token_name, (const char *)tokdata->nv_token_data->token_info.label, + sizeof(tokdata->nv_token_data->token_info.label), ' '); + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release process lock.\n"); + return rc; + } + + /* Get session state */ + if (!(session_state = get_session_state(tokdata, sess->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + return CKR_SESSION_HANDLE_INVALID; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + return CKR_FUNCTION_FAILED; + } + + /* clear out records */ + memset(records, 0, MAX_RECORDS * (sizeof(struct icsf_object_record))); + + do { + records_len = sizeof(records) / sizeof(struct icsf_object_record); + rc = icsf_list_objects(session_state->ld, &reason, token_name, + ulCount, pTemplate, previous, records, + &records_len, 0); + if (ICSF_RC_IS_ERROR(rc)) { + TRACE_DEVEL("Failed to list objects.\n"); + rv = icsf_to_ock_err(rc, reason); + goto done; + } + + /* Now step thru the object btree so we can find the node + * value for any matching objects we retrieved from ICSF. + * If we cannot find a matching object in the btree, + * then add it so we can get a node value. + * And also because ICSF object database is authoritative. + */ + + for (i = 0; i < records_len; i++) { + + /* mark not found */ + node_number = 0; + + for (j = 1; j <= icsf_data->objects.size; j++) { + struct icsf_object_mapping *mapping = NULL; + + /* skip missing ids */ + mapping = bt_get_node_value(&icsf_data->objects, j); + if (mapping) { + if (memcmp(&records[i], + &mapping->icsf_object, + sizeof(struct icsf_object_record)) == 0) { + node_number = j; + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + break; + } + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + } else { + continue; + } + } + /* if could not find in our object tree, then add it + * since ICSF object database is authoritative. + */ + if (!node_number) { + struct icsf_object_mapping *new_mapping; + + if (!(new_mapping = malloc(sizeof(*new_mapping)))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rv = CKR_HOST_MEMORY; + goto done; + } + new_mapping->session_id = sess->handle; + new_mapping->icsf_object = records[i]; + + if (!(node_number = bt_node_add(&icsf_data->objects, + new_mapping))) { + TRACE_ERROR("Failed to add object to " "binary tree.\n"); + rv = CKR_FUNCTION_FAILED; + goto done; + } + } + + /* Add to our findobject list */ + if (node_number) { + sess->find_list[sess->find_count] = node_number; + sess->find_count++; + + if (sess->find_count >= sess->find_len) { + void *find_list; + size_t find_len = sess->find_len + MAX_RECORDS; + find_list = realloc(sess->find_list, + find_len * sizeof(CK_OBJECT_HANDLE)); + if (!find_list) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rv = CKR_HOST_MEMORY; + goto done; + } + sess->find_list = find_list; + sess->find_len = find_len; + } + } + } + + if (records_len) + previous = &records[records_len - 1]; + } while (records_len); + + sess->find_active = TRUE; + +done: + return rv; +} + +/* + * Destroy an object. + */ +CK_RV icsftok_destroy_object(STDLL_TokData_t * tokdata, SESSION * sess, + CK_OBJECT_HANDLE handle) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + struct session_state *session_state; + struct icsf_object_mapping *mapping = NULL; + int reason; + CK_RV rc = CKR_OK; + + + /* Get session state */ + if (!(session_state = get_session_state(tokdata, sess->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + return CKR_SESSION_HANDLE_INVALID;; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + return CKR_FUNCTION_FAILED; + } + + /* get the object handle */ + mapping = bt_get_node_value(&icsf_data->objects, handle); + + if (!mapping) { + TRACE_ERROR("%s\n", ock_err(ERR_OBJECT_HANDLE_INVALID)); + rc = CKR_OBJECT_HANDLE_INVALID; + goto done; + } + + /* Now remove the object from ICSF */ + rc = icsf_destroy_object(session_state->ld, &reason, &mapping->icsf_object); + if (rc != 0) { + TRACE_DEVEL("icsf_destroy_object failed\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + + /* Now remove the object from the object btree */ + bt_node_free(&icsf_data->objects, handle, TRUE); + +done: + if (mapping) { + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + } + return rc; +} + +/* + * Free all data pointed by SIGN_VERIFY_CONTEXT and set everything to zero. + */ +static void free_sv_ctx(SIGN_VERIFY_CONTEXT * ctx) +{ + struct icsf_multi_part_context *multi_part_ctx; + + if (!ctx) + return; + + /* Initialize encryption context */ + multi_part_ctx = (struct icsf_multi_part_context *) ctx->context; + if (multi_part_ctx) { + if (multi_part_ctx->data) + free(multi_part_ctx->data); + free(multi_part_ctx); + } + if (ctx->mech.pParameter) + free(ctx->mech.pParameter); + + memset(ctx, 0, sizeof(*ctx)); +} + +/* + * get the hash size for hmacs. + */ +int get_signverify_len(CK_MECHANISM mech) +{ + switch (mech.mechanism) { + case CKM_MD5_HMAC: + case CKM_SSL3_MD5_MAC: + return MD5_HASH_SIZE; + case CKM_SHA_1_HMAC: + case CKM_SSL3_SHA1_MAC: + return SHA1_HASH_SIZE; + case CKM_SHA256_HMAC: + return SHA256_HASH_SIZE; + case CKM_SHA384_HMAC: + return SHA384_HASH_SIZE; + case CKM_SHA512_HMAC: + return SHA512_HASH_SIZE; + } + + return -1; +} + +CK_RV icsftok_sign_init(STDLL_TokData_t * tokdata, + SESSION * session, CK_MECHANISM * mech, + CK_OBJECT_HANDLE key) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + struct session_state *session_state; + SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx; + struct icsf_multi_part_context *multi_part_ctx = NULL; + struct icsf_object_mapping *mapping = NULL; + CK_RV rc = CKR_OK; + CK_BBOOL multi = FALSE; + CK_BBOOL datacaching = FALSE; + CK_MAC_GENERAL_PARAMS *param; + + /* Check session */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + return CKR_SESSION_HANDLE_INVALID; + } + + /* Check if key exists */ + if (!(mapping = bt_get_node_value(&icsf_data->objects, key))) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + rc = CKR_KEY_HANDLE_INVALID; + return rc; + } + + /* Check the mechanism info */ + switch (mech->mechanism) { + case CKM_RSA_X_509: + case CKM_RSA_PKCS: + case CKM_DSA: + case CKM_ECDSA: + /* these do not do multipart and do not require + * a mechanism parameter. + */ + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + multi = FALSE; + break; + case CKM_MD5_HMAC: + case CKM_SHA_1_HMAC: + case CKM_SHA256_HMAC: + case CKM_SHA384_HMAC: + case CKM_SHA512_HMAC: + /* hmacs can do mulitpart and do not require a + * mechanism parameter. + */ + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + multi = TRUE; + break; + case CKM_SSL3_MD5_MAC: + case CKM_SSL3_SHA1_MAC: + /* can do mulitpart and take a mech parameter */ + + param = (CK_MAC_GENERAL_PARAMS *) mech->pParameter; + + if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + if (((mech->mechanism == CKM_SSL3_MD5_MAC) && (*param != 16)) || + ((mech->mechanism == CKM_SSL3_SHA1_MAC) && (*param != 20))) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + + multi = TRUE; + break; + case CKM_MD5_RSA_PKCS: + case CKM_SHA1_RSA_PKCS: + case CKM_SHA256_RSA_PKCS: + case CKM_SHA384_RSA_PKCS: + case CKM_SHA512_RSA_PKCS: + case CKM_DSA_SHA1: + case CKM_ECDSA_SHA1: + /* these can do mulitpart and require data caching + * and do not require a mechanism parameter. + */ + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + return CKR_MECHANISM_PARAM_INVALID; + } + multi = TRUE; + datacaching = TRUE; + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + /* Initialize sign context */ + free_sv_ctx(ctx); + + /* Copy mechanism */ + if (mech->pParameter == NULL || mech->ulParameterLen == 0) { + ctx->mech.ulParameterLen = 0; + ctx->mech.pParameter = NULL; + } else { + ctx->mech.pParameter = malloc(mech->ulParameterLen); + if (!ctx->mech.pParameter) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + ctx->mech.ulParameterLen = mech->ulParameterLen; + memcpy(ctx->mech.pParameter, mech->pParameter, mech->ulParameterLen); + } + ctx->mech.mechanism = mech->mechanism; + + /* If the mechanism supports multipart, prepare ctx */ + if (multi) { + /* Allocate context for multi-part operations */ + if (!(multi_part_ctx = malloc(sizeof(*multi_part_ctx)))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + ctx->context_len = sizeof(*multi_part_ctx); + ctx->context = (void *) multi_part_ctx; + memset(multi_part_ctx, 0, sizeof(*multi_part_ctx)); + + /* keep a cache to ensure multiple of blocksize + * is sent to ICSF. + */ + + if (datacaching) { + size_t blocksize; + + rc = icsf_block_size(mech->mechanism, &blocksize); + if (rc != CKR_OK) + goto done; + multi_part_ctx->data_len = blocksize; + multi_part_ctx->data = malloc(multi_part_ctx->data_len); + if (!multi_part_ctx->data) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(multi_part_ctx->data, 0, blocksize); + } + } else { + ctx->context_len = 0; + ctx->context = NULL; + } + + ctx->key = key; + ctx->multi = FALSE; + ctx->active = TRUE; + +done: + if (mapping) { + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + } + if (rc != CKR_OK) + free_sv_ctx(ctx); + + return rc; +} + +CK_RV icsftok_sign(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE * in_data, CK_ULONG in_data_len, + CK_BYTE * signature, CK_ULONG * sig_len) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + struct session_state *session_state; + SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx; + struct icsf_object_mapping *mapping = NULL; + char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, }; + size_t chain_data_len = sizeof(chain_data); + CK_RV rc = CKR_OK; + int hlen, reason; + CK_BBOOL length_only = (signature == NULL); + + if (ctx->multi == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + /* Check session */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Check if key exists */ + if (!(mapping = bt_get_node_value(&icsf_data->objects, ctx->key))) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + rc = CKR_KEY_HANDLE_INVALID; + goto done; + } + + switch (ctx->mech.mechanism) { + case CKM_MD5_HMAC: + case CKM_SHA_1_HMAC: + case CKM_SHA256_HMAC: + case CKM_SHA384_HMAC: + case CKM_SHA512_HMAC: + case CKM_SSL3_MD5_MAC: + case CKM_SSL3_SHA1_MAC: + if (length_only) { + hlen = get_signverify_len(ctx->mech); + if (hlen < 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + *sig_len = hlen; + rc = CKR_OK; + goto done; + } + + rc = icsf_hmac_sign(session_state->ld, &reason, + &mapping->icsf_object, &ctx->mech, "ONLY", + (char *)in_data, in_data_len, + (char *)signature, sig_len, + chain_data, &chain_data_len); + if (rc != 0) + rc = icsf_to_ock_err(rc, reason); + break; + case CKM_RSA_X_509: + case CKM_RSA_PKCS: + case CKM_DSA: + case CKM_ECDSA: + rc = icsf_private_key_sign(session_state->ld, &reason, FALSE, + &mapping->icsf_object, &ctx->mech, + (char *)in_data, in_data_len, + (char *)signature, sig_len); + if (rc != 0) { + if (reason == ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT && + length_only) { + rc = CKR_OK; + } else { + TRACE_DEVEL("icsf_private_key_sign failed\n"); + rc = icsf_to_ock_err(rc, reason); + } + } + break; + case CKM_MD5_RSA_PKCS: + case CKM_SHA1_RSA_PKCS: + case CKM_SHA256_RSA_PKCS: + case CKM_SHA384_RSA_PKCS: + case CKM_SHA512_RSA_PKCS: + case CKM_DSA_SHA1: + case CKM_ECDSA_SHA1: + if (length_only) { + rc = CKR_OK; + goto done; + } + + rc = icsf_hash_signverify(session_state->ld, &reason, + &mapping->icsf_object, &ctx->mech, + "ONLY", (char *)in_data, in_data_len, + (char *)signature, sig_len, + chain_data, &chain_data_len, 0); + if (rc != 0) { + if (reason == ICSF_REASON_OUTPUT_PARAMETER_TOO_SHORT && + length_only) { + rc = CKR_OK; + } else { + TRACE_DEVEL("icsf_hash_signverify failed\n"); + rc = icsf_to_ock_err(rc, reason); + } + } + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + } + +done: + if (mapping) { + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + } + if (rc != CKR_BUFFER_TOO_SMALL && !(rc == CKR_OK && length_only)) + free_sv_ctx(ctx); + + return rc; +} + +CK_RV icsftok_sign_update(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE * in_data, + CK_ULONG in_data_len) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + struct session_state *session_state; + SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx; + struct icsf_object_mapping *mapping = NULL; + struct icsf_multi_part_context *multi_part_ctx = NULL; + char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, }; + size_t chain_data_len = sizeof(chain_data); + CK_RV rc = CKR_OK; + int reason; + size_t siglen = 0; + CK_ULONG total, remain, out_len = 0; + char *buffer = NULL; + + /* Check session */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Check if key exists */ + if (!(mapping = bt_get_node_value(&icsf_data->objects, ctx->key))) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + rc = CKR_KEY_HANDLE_INVALID; + goto done; + } + + /* indicate this is multipart operation and get chain info from ctx. + * if any mechanisms that cannot do multipart sign come here, they + * will not have had ctx->context allocated and will + * get an error in switch below. + */ + ctx->multi = TRUE; + if (ctx->context) { + multi_part_ctx = (struct icsf_multi_part_context *) ctx->context; + if (multi_part_ctx->initiated) + memcpy(chain_data, multi_part_ctx->chain_data, chain_data_len); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = ERR_ARGUMENTS_BAD; + goto done; + } + + switch (ctx->mech.mechanism) { + case CKM_MD5_HMAC: + case CKM_SHA_1_HMAC: + case CKM_SHA256_HMAC: + case CKM_SHA384_HMAC: + case CKM_SHA512_HMAC: + case CKM_SSL3_MD5_MAC: + case CKM_SSL3_SHA1_MAC: + rc = icsf_hmac_sign(session_state->ld, &reason, + &mapping->icsf_object, &ctx->mech, + (multi_part_ctx->initiated) ? "MIDDLE" : "FIRST", + (char *)in_data, in_data_len, NULL, &siglen, + chain_data, &chain_data_len); + + if (rc != 0) { + TRACE_DEVEL("icsf_hmac_sign failed\n"); + rc = icsf_to_ock_err(rc, reason); + } else { + multi_part_ctx->initiated = TRUE; + memcpy(multi_part_ctx->chain_data, chain_data, chain_data_len); + } + break; + case CKM_MD5_RSA_PKCS: + case CKM_SHA1_RSA_PKCS: + case CKM_SHA256_RSA_PKCS: + case CKM_SHA384_RSA_PKCS: + case CKM_SHA512_RSA_PKCS: + case CKM_DSA_SHA1: + case CKM_ECDSA_SHA1: + /* caching data since ICSF wants in multiple of blocksize */ + if (multi_part_ctx && multi_part_ctx->data) { + + total = multi_part_ctx->used_data_len + in_data_len; + remain = total % multi_part_ctx->data_len;; + + /* if not enough to meet blocksize, cache and exit. */ + if (total < multi_part_ctx->data_len) { + memcpy(multi_part_ctx->data + multi_part_ctx->used_data_len, + (char *)in_data, in_data_len); + multi_part_ctx->used_data_len += in_data_len; + + rc = CKR_OK; + goto done; + } else { + /* there is at least 1 block */ + + out_len = total - remain; + + /* prepare a buffer to send data in */ + if (!(buffer = malloc(out_len))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memcpy(buffer, multi_part_ctx->data, + multi_part_ctx->used_data_len); + memcpy(buffer + multi_part_ctx->used_data_len, + (char *)in_data, + out_len - multi_part_ctx->used_data_len); + + /* copy remainder of data to ctx + * for next time. caching. + */ + if (remain != 0) + memcpy(multi_part_ctx->data, + in_data + (in_data_len - remain), remain); + + multi_part_ctx->used_data_len = remain; + } + } + + rc = icsf_hash_signverify(session_state->ld, &reason, + &mapping->icsf_object, &ctx->mech, + (multi_part_ctx-> + initiated) ? "MIDDLE" : "FIRST", buffer, + out_len, NULL, NULL, chain_data, + &chain_data_len, 0); + + if (rc != 0) { + TRACE_DEVEL("icsf_hash_signverify failed\n"); + rc = icsf_to_ock_err(rc, reason); + } else { + multi_part_ctx->initiated = TRUE; + memcpy(multi_part_ctx->chain_data, chain_data, chain_data_len); + } + + if (buffer) + free(buffer); + + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + } + +done: + if (mapping) { + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + } + if (rc != CKR_OK) + free_sv_ctx(ctx); + + return rc; +} + +CK_RV icsftok_sign_final(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE * signature, + CK_ULONG * sig_len) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + struct session_state *session_state; + SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx; + struct icsf_object_mapping *mapping = NULL; + struct icsf_multi_part_context *multi_part_ctx = NULL; + char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, }; + size_t chain_data_len = sizeof(chain_data); + char *buffer = NULL; + CK_RV rc = CKR_OK; + int hlen, reason; + CK_BBOOL length_only = (signature == NULL); + + /* Check session */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Check if key exists */ + if (!(mapping = bt_get_node_value(&icsf_data->objects, ctx->key))) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + rc = CKR_KEY_HANDLE_INVALID; + goto done; + } + + /* get the chain data from ctx */ + if (ctx->context) { + multi_part_ctx = (struct icsf_multi_part_context *) ctx->context; + memcpy(chain_data, multi_part_ctx->chain_data, chain_data_len); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = ERR_ARGUMENTS_BAD; + goto done; + } + + switch (ctx->mech.mechanism) { + case CKM_MD5_HMAC: + case CKM_SHA_1_HMAC: + case CKM_SHA256_HMAC: + case CKM_SHA384_HMAC: + case CKM_SHA512_HMAC: + case CKM_SSL3_MD5_MAC: + case CKM_SSL3_SHA1_MAC: + if (length_only) { + hlen = get_signverify_len(ctx->mech); + if (hlen < 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + *sig_len = hlen; + return CKR_OK; + } + + rc = icsf_hmac_sign(session_state->ld, &reason, + &mapping->icsf_object, &ctx->mech, + multi_part_ctx->initiated ? "LAST" : "ONLY", "", + 0, (char *)signature, sig_len, + chain_data, &chain_data_len); + if (rc != 0) + rc = icsf_to_ock_err(rc, reason); + break; + case CKM_MD5_RSA_PKCS: + case CKM_SHA1_RSA_PKCS: + case CKM_SHA256_RSA_PKCS: + case CKM_SHA384_RSA_PKCS: + case CKM_SHA512_RSA_PKCS: + case CKM_DSA_SHA1: + case CKM_ECDSA_SHA1: + if (length_only) { + rc = CKR_OK; + goto done; + } + + /* see if any data left in the cache */ + if (multi_part_ctx && multi_part_ctx->used_data_len) { + if (!(buffer = malloc(multi_part_ctx->used_data_len))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memcpy(buffer, multi_part_ctx->data, multi_part_ctx->used_data_len); + } + + rc = icsf_hash_signverify(session_state->ld, &reason, + &mapping->icsf_object, &ctx->mech, + multi_part_ctx->initiated ? "LAST" : "ONLY", + (buffer) ? buffer : NULL, + multi_part_ctx->used_data_len, + (char *)signature, sig_len, + chain_data, &chain_data_len, 0); + + if (rc != 0) { + if (length_only && reason == 3003) { + rc = CKR_OK; + } else { + TRACE_DEVEL("icsf_hash_signverify failed\n"); + rc = icsf_to_ock_err(rc, reason); + } + } + + if (buffer) + free(buffer); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + } + +done: + if (mapping) { + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + } + if (rc != CKR_BUFFER_TOO_SMALL && !(rc == CKR_OK && length_only)) + free_sv_ctx(ctx); + + return rc; +} + +CK_RV icsftok_verify_init(STDLL_TokData_t * tokdata, + SESSION * session, CK_MECHANISM * mech, + CK_OBJECT_HANDLE key) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + struct session_state *session_state; + SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx; + struct icsf_multi_part_context *multi_part_ctx = NULL; + struct icsf_object_mapping *mapping = NULL; + CK_RV rc = CKR_OK; + CK_BBOOL multi = FALSE; + CK_BBOOL datacaching = FALSE; + CK_MAC_GENERAL_PARAMS *param; + + /* Check session */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + return CKR_SESSION_HANDLE_INVALID; + } + + /* Check if key exists */ + if (!(mapping = bt_get_node_value(&icsf_data->objects, key))) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + rc = CKR_KEY_HANDLE_INVALID; + return rc; + } + + /* Check the mechanism info */ + switch (mech->mechanism) { + case CKM_RSA_X_509: + case CKM_RSA_PKCS: + case CKM_DSA: + case CKM_ECDSA: + /* these do not do multipart and do not require + * a mechanism parameter. + */ + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + multi = FALSE; + break; + case CKM_MD5_HMAC: + case CKM_SHA_1_HMAC: + case CKM_SHA256_HMAC: + case CKM_SHA384_HMAC: + case CKM_SHA512_HMAC: + /* hmacs can do mulitpart and do not require a + * mechanism parameter. + */ + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + multi = TRUE; + break; + case CKM_SSL3_MD5_MAC: + case CKM_SSL3_SHA1_MAC: + /* can do mulitpart and take a mech parameter */ + param = (CK_MAC_GENERAL_PARAMS *) mech->pParameter; + + if (mech->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + if (((mech->mechanism == CKM_SSL3_MD5_MAC) && (*param != 16)) || + ((mech->mechanism == CKM_SSL3_SHA1_MAC) && (*param != 20))) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + + multi = TRUE; + break; + case CKM_MD5_RSA_PKCS: + case CKM_SHA1_RSA_PKCS: + case CKM_SHA256_RSA_PKCS: + case CKM_SHA384_RSA_PKCS: + case CKM_SHA512_RSA_PKCS: + case CKM_DSA_SHA1: + case CKM_ECDSA_SHA1: + /* these can do mulitpart and require data caching + * but do not require a mechanism parameter + */ + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + multi = TRUE; + datacaching = TRUE; + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + /* Initialize ctx */ + free_sv_ctx(ctx); + + /* Copy mechanism */ + if (mech->pParameter == NULL || mech->ulParameterLen == 0) { + ctx->mech.ulParameterLen = 0; + ctx->mech.pParameter = NULL; + } else { + ctx->mech.pParameter = malloc(mech->ulParameterLen); + if (!ctx->mech.pParameter) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + ctx->mech.ulParameterLen = mech->ulParameterLen; + memcpy(ctx->mech.pParameter, mech->pParameter, mech->ulParameterLen); + } + ctx->mech.mechanism = mech->mechanism; + + /* If the mechanism supports multipart, prepare ctx */ + if (multi) { + /* Allocate context for multi-part operations */ + if (!(multi_part_ctx = malloc(sizeof(*multi_part_ctx)))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + ctx->context_len = sizeof(*multi_part_ctx); + ctx->context = (void *) multi_part_ctx; + memset(multi_part_ctx, 0, sizeof(*multi_part_ctx)); + + /* keep a cache to ensure multiple of blocksize + * is sent to ICSF. + */ + + if (datacaching) { + size_t blocksize; + + rc = icsf_block_size(mech->mechanism, &blocksize); + if (rc != CKR_OK) + goto done; + multi_part_ctx->data_len = blocksize; + multi_part_ctx->data = malloc(multi_part_ctx->data_len); + if (!multi_part_ctx->data) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(multi_part_ctx->data, 0, blocksize); + } + } else { + ctx->context_len = 0; + ctx->context = NULL; + } + + ctx->key = key; + ctx->multi = FALSE; + ctx->active = TRUE; + +done: + if (mapping) { + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + } + + if (rc != CKR_OK) + free_sv_ctx(ctx); + + return rc; +} + +CK_RV icsftok_verify(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE * in_data, CK_ULONG in_data_len, + CK_BYTE * signature, CK_ULONG sig_len) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + struct session_state *session_state; + SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx; + struct icsf_object_mapping *mapping = NULL; + char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, }; + size_t chain_data_len = sizeof(chain_data); + CK_RV rc = CKR_OK; + int reason; + + if (ctx->multi == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + /* Check session */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Check if key exists */ + if (!(mapping = bt_get_node_value(&icsf_data->objects, ctx->key))) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + rc = CKR_KEY_HANDLE_INVALID; + goto done; + } + + switch (ctx->mech.mechanism) { + case CKM_MD5_HMAC: + case CKM_SHA_1_HMAC: + case CKM_SHA256_HMAC: + case CKM_SHA384_HMAC: + case CKM_SHA512_HMAC: + case CKM_SSL3_MD5_MAC: + case CKM_SSL3_SHA1_MAC: + rc = icsf_hmac_verify(session_state->ld, &reason, + &mapping->icsf_object, &ctx->mech, "ONLY", + (char *)in_data, in_data_len, + (char *)signature, sig_len, + chain_data, &chain_data_len); + if (rc != 0) + rc = icsf_to_ock_err(rc, reason); + + break; + case CKM_RSA_X_509: + case CKM_RSA_PKCS: + case CKM_DSA: + case CKM_ECDSA: + rc = icsf_public_key_verify(session_state->ld, &reason, FALSE, + &mapping->icsf_object, &ctx->mech, + (char *)in_data, in_data_len, + (char *)signature, &sig_len); + if (rc != 0) + rc = icsf_to_ock_err(rc, reason); + break; + case CKM_MD5_RSA_PKCS: + case CKM_SHA1_RSA_PKCS: + case CKM_SHA256_RSA_PKCS: + case CKM_SHA384_RSA_PKCS: + case CKM_SHA512_RSA_PKCS: + case CKM_DSA_SHA1: + case CKM_ECDSA_SHA1: + rc = icsf_hash_signverify(session_state->ld, &reason, + &mapping->icsf_object, &ctx->mech, + "ONLY", (char *)in_data, in_data_len, + (char *)signature, &sig_len, + chain_data, &chain_data_len, 1); + if (rc != 0) + rc = icsf_to_ock_err(rc, reason); + + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + } + +done: + if (mapping) { + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + } + + free_sv_ctx(ctx); + return rc; +} + +CK_RV icsftok_verify_update(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE * in_data, + CK_ULONG in_data_len) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + struct session_state *session_state; + SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx; + struct icsf_object_mapping *mapping = NULL; + struct icsf_multi_part_context *multi_part_ctx = NULL; + char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, }; + size_t chain_data_len = sizeof(chain_data); + CK_RV rc = CKR_OK; + int reason; + CK_ULONG total, remain, out_len = 0; + char *buffer = NULL; + + /* Check session */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Check if key exists */ + if (!(mapping = bt_get_node_value(&icsf_data->objects, ctx->key))) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + rc = CKR_KEY_HANDLE_INVALID; + goto done; + } + + /* indicate this is multipart operation and get chain info from ctx. + * if any mechanisms that cannot do multipart verify come here, they + * will get an error in switch below. + */ + ctx->multi = TRUE; + if (ctx->context) { + multi_part_ctx = (struct icsf_multi_part_context *) ctx->context; + if (multi_part_ctx->initiated) + memcpy(chain_data, multi_part_ctx->chain_data, chain_data_len); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = ERR_ARGUMENTS_BAD; + goto done; + } + + switch (ctx->mech.mechanism) { + case CKM_MD5_HMAC: + case CKM_SHA_1_HMAC: + case CKM_SHA256_HMAC: + case CKM_SHA384_HMAC: + case CKM_SHA512_HMAC: + case CKM_SSL3_MD5_MAC: + case CKM_SSL3_SHA1_MAC: + rc = icsf_hmac_verify(session_state->ld, &reason, + &mapping->icsf_object, &ctx->mech, + (multi_part_ctx->initiated) ? "MIDDLE" : "FIRST", + (char *)in_data, in_data_len, "", 0, + chain_data, &chain_data_len); + + if (rc != 0) { + TRACE_DEVEL("icsf_hmac_verify failed\n"); + rc = icsf_to_ock_err(rc, reason); + } else { + multi_part_ctx->initiated = TRUE; + memcpy(multi_part_ctx->chain_data, chain_data, chain_data_len); + } + break; + case CKM_MD5_RSA_PKCS: + case CKM_SHA1_RSA_PKCS: + case CKM_SHA256_RSA_PKCS: + case CKM_SHA384_RSA_PKCS: + case CKM_SHA512_RSA_PKCS: + case CKM_DSA_SHA1: + case CKM_ECDSA_SHA1: + /* caching data since ICSF wants in multiple of blocksize */ + if (multi_part_ctx && multi_part_ctx->data) { + + total = multi_part_ctx->used_data_len + in_data_len; + remain = total % multi_part_ctx->data_len;; + + /* if not enough to meet blocksize, cache and exit. */ + if (total < multi_part_ctx->data_len) { + memcpy(multi_part_ctx->data + multi_part_ctx->used_data_len, + (char *)in_data, in_data_len); + multi_part_ctx->used_data_len += in_data_len; + + rc = CKR_OK; + goto done; + } else { + /* there is at least 1 block */ + + out_len = total - remain; + + /* prepare a buffer to send data in */ + if (!(buffer = malloc(out_len))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memcpy(buffer, multi_part_ctx->data, + multi_part_ctx->used_data_len); + memcpy(buffer + multi_part_ctx->used_data_len, + (char *)in_data, + out_len - multi_part_ctx->used_data_len); + + /* copy remainder of data to ctx + * for next time. caching. + */ + if (remain != 0) + memcpy(multi_part_ctx->data, + (char *)in_data + (in_data_len - remain), remain); + + multi_part_ctx->used_data_len = remain; + } + } + + rc = icsf_hash_signverify(session_state->ld, &reason, + &mapping->icsf_object, &ctx->mech, + (multi_part_ctx-> + initiated) ? "MIDDLE" : "FIRST", buffer, + out_len, NULL, NULL, chain_data, + &chain_data_len, 1); + + if (rc != 0) { + TRACE_DEVEL("icsf_hash_signverify failed\n"); + rc = icsf_to_ock_err(rc, reason); + } else { + multi_part_ctx->initiated = TRUE; + memcpy(multi_part_ctx->chain_data, chain_data, chain_data_len); + } + + if (buffer) + free(buffer); + + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + } + +done: + if (mapping) { + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + } + + if (rc != CKR_OK) + free_sv_ctx(ctx); + + return rc; +} + +CK_RV icsftok_verify_final(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE * signature, + CK_ULONG sig_len) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + struct session_state *session_state; + SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx; + struct icsf_object_mapping *mapping = NULL; + struct icsf_multi_part_context *multi_part_ctx = NULL; + char chain_data[ICSF_CHAINING_DATA_LEN] = { 0, }; + size_t chain_data_len = sizeof(chain_data); + CK_RV rc = CKR_OK; + int reason; + char *buffer = NULL; + + if (!sig_len) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + /* Check session */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Check if key exists */ + if (!(mapping = bt_get_node_value(&icsf_data->objects, ctx->key))) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + rc = CKR_KEY_HANDLE_INVALID; + goto done; + } + + /* get the chain data from ctx */ + if (ctx->context) { + multi_part_ctx = (struct icsf_multi_part_context *) ctx->context; + memcpy(chain_data, multi_part_ctx->chain_data, chain_data_len); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = ERR_ARGUMENTS_BAD; + goto done; + } + + switch (ctx->mech.mechanism) { + case CKM_MD5_HMAC: + case CKM_SHA_1_HMAC: + case CKM_SHA256_HMAC: + case CKM_SHA384_HMAC: + case CKM_SHA512_HMAC: + case CKM_SSL3_MD5_MAC: + case CKM_SSL3_SHA1_MAC: + /* get the chain data */ + rc = icsf_hmac_verify(session_state->ld, &reason, + &mapping->icsf_object, &ctx->mech, + multi_part_ctx->initiated ? "LAST" : "ONLY", "", + 0, (char *)signature, sig_len, + chain_data, &chain_data_len); + if (rc != 0) + rc = icsf_to_ock_err(rc, reason); + + break; + case CKM_MD5_RSA_PKCS: + case CKM_SHA1_RSA_PKCS: + case CKM_SHA256_RSA_PKCS: + case CKM_SHA384_RSA_PKCS: + case CKM_SHA512_RSA_PKCS: + case CKM_DSA_SHA1: + case CKM_ECDSA_SHA1: + /* see if any data left in the cache */ + if (multi_part_ctx && multi_part_ctx->used_data_len) { + if (!(buffer = malloc(multi_part_ctx->used_data_len))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memcpy(buffer, multi_part_ctx->data, multi_part_ctx->used_data_len); + } + + rc = icsf_hash_signverify(session_state->ld, &reason, + &mapping->icsf_object, &ctx->mech, + multi_part_ctx->initiated ? "LAST" : "ONLY", + (buffer) ? buffer : NULL, + multi_part_ctx->used_data_len, + (char *)signature, &sig_len, + chain_data, &chain_data_len, 1); + + if (rc != 0) + rc = icsf_to_ock_err(rc, reason); + + if (buffer) + free(buffer); + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + } + +done: + if (mapping) { + bt_put_node_value(&icsf_data->objects, mapping); + mapping = NULL; + } + + free_sv_ctx(ctx); + + return rc; +} + +/* + * Wrap a key and return it as binary data. + */ +CK_RV icsftok_wrap_key(STDLL_TokData_t * tokdata, + SESSION * session, CK_MECHANISM_PTR mech, + CK_OBJECT_HANDLE wrapping_key, CK_OBJECT_HANDLE key, + CK_BYTE_PTR wrapped_key, CK_ULONG_PTR p_wrapped_key_len) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + int rc = CKR_OK; + int reason = 0; + struct session_state *session_state; + struct icsf_object_mapping *wrapping_key_mapping = NULL; + struct icsf_object_mapping *key_mapping = NULL; + size_t expected_block_size = 0; + + /* Check session */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + return CKR_SESSION_HANDLE_INVALID; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + return CKR_FUNCTION_FAILED; + } + + /* Check if keys exist */ + wrapping_key_mapping = bt_get_node_value(&icsf_data->objects, wrapping_key); + key_mapping = bt_get_node_value(&icsf_data->objects, key); + if (!wrapping_key_mapping || !key_mapping) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + rc = CKR_KEY_HANDLE_INVALID; + goto done; + } + + /* validate mechanism parameters. Only 4 mechanisms support + * key wrapping in icsf token */ + switch (mech->mechanism) { + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC_PAD: + case CKM_AES_CBC_PAD: + if ((rc = icsf_block_size(mech->mechanism, &expected_block_size))) + goto done; + + if (mech->ulParameterLen != expected_block_size) { + TRACE_ERROR("Invalid mechanism parameter length: %lu " + "(expected %lu)\n", + (unsigned long) mech->ulParameterLen, + (unsigned long) expected_block_size); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + break; + case CKM_RSA_PKCS: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + break; + default: + TRACE_ERROR("icsf invalid %lu mechanism for key wrapping\n", + mech->mechanism); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + /* Call ICSF service */ + rc = icsf_wrap_key(session_state->ld, &reason, mech, + &wrapping_key_mapping->icsf_object, + &key_mapping->icsf_object, wrapped_key, + p_wrapped_key_len); + if (rc) { + TRACE_DEVEL("icsf_wrap_key failed\n"); + rc = icsf_to_ock_err(rc, reason); + goto done; + } + +done: + if (wrapping_key_mapping) { + bt_put_node_value(&icsf_data->objects, wrapping_key_mapping); + wrapping_key_mapping = NULL; + } + if (key_mapping) { + bt_put_node_value(&icsf_data->objects, key_mapping); + key_mapping = NULL; + } + + return rc; +} + +/* + * Unwrap a key from binary data and create a new key object. + */ +CK_RV icsftok_unwrap_key(STDLL_TokData_t * tokdata, + SESSION * session, CK_MECHANISM_PTR mech, + CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, + CK_BYTE_PTR wrapped_key, CK_ULONG wrapped_key_len, + CK_OBJECT_HANDLE wrapping_key, + CK_OBJECT_HANDLE_PTR p_key) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + int rc; + int reason = 0; + struct session_state *session_state; + struct icsf_object_mapping *wrapping_key_mapping = NULL; + struct icsf_object_mapping *key_mapping = NULL; + CK_ULONG node_number; + size_t expected_block_size = 0; + + /* Check session */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + return CKR_SESSION_HANDLE_INVALID; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + return CKR_FUNCTION_FAILED; + } + + /* Check if key exists */ + wrapping_key_mapping = bt_get_node_value(&icsf_data->objects, wrapping_key); + if (!wrapping_key_mapping) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + return CKR_KEY_HANDLE_INVALID; + } + + /* Allocate structure to keep ICSF object information */ + if (!(key_mapping = malloc(sizeof(*key_mapping)))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(key_mapping, 0, sizeof(*key_mapping)); + key_mapping->session_id = session->handle; + + /* validate mechanism parameters. Only 4 mechanisms support + * key wrapping in icsf token */ + switch (mech->mechanism) { + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC_PAD: + case CKM_AES_CBC_PAD: + if ((rc = icsf_block_size(mech->mechanism, &expected_block_size))) + goto done; + + if (mech->ulParameterLen != expected_block_size) { + TRACE_ERROR("Invalid mechanism parameter length: %lu " + "(expected %lu)\n", + (unsigned long) mech->ulParameterLen, + (unsigned long) expected_block_size); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + break; + case CKM_RSA_PKCS: + if (mech->ulParameterLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); + rc = CKR_MECHANISM_PARAM_INVALID; + goto done; + } + break; + default: + TRACE_ERROR("icsf invalid %lu mechanism for key wrapping\n", + mech->mechanism); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + /* Call ICSF service */ + rc = icsf_unwrap_key(session_state->ld, &reason, mech, + &wrapping_key_mapping->icsf_object, + wrapped_key, wrapped_key_len, + attrs, attrs_len, &key_mapping->icsf_object); + if (rc) { + TRACE_DEVEL("icsf_unwrap_key failed\n"); + rc = icsf_to_ock_err(rc, reason); + goto done; + } + + /* Add info about object into session */ + if (!(node_number = bt_node_add(&icsf_data->objects, key_mapping))) { + TRACE_ERROR("Failed to add object to binary tree.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Use node number as handle */ + *p_key = node_number; + +done: + if (wrapping_key_mapping) { + bt_put_node_value(&icsf_data->objects, wrapping_key_mapping); + wrapping_key_mapping = NULL; + } + + /* If allocated, object must be freed in case of failure */ + if (rc && key_mapping) + free(key_mapping); + + return rc; +} + +/* + * Derive a key from a base key, creating a new key object. + */ +CK_RV icsftok_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) +{ + icsf_private_data_t *icsf_data = tokdata->private_data; + CK_RV rc = CKR_OK; + struct session_state *session_state; + struct icsf_object_mapping *base_key_mapping = NULL; + CK_ULONG node_number; + char token_name[sizeof(tokdata->nv_token_data->token_info.label) + 1]; + CK_SSL3_KEY_MAT_PARAMS *params = { 0 }; + unsigned int i; + int reason = 0; + + /* Variable for multiple keys derivation */ + int multiple = 0; + struct icsf_object_mapping *mappings[4] = { NULL, }; + CK_OBJECT_HANDLE *keys[4] = { NULL, }; + + /* Check type of derivation */ + if (mech->mechanism == CKM_SSL3_KEY_AND_MAC_DERIVE || + mech->mechanism == CKM_TLS_KEY_AND_MAC_DERIVE) { + multiple = 1; + params = (CK_SSL3_KEY_MAT_PARAMS *) mech->pParameter; + keys[0] = ¶ms->pReturnedKeyMaterial->hClientMacSecret; + keys[1] = ¶ms->pReturnedKeyMaterial->hServerMacSecret; + keys[2] = ¶ms->pReturnedKeyMaterial->hClientKey; + keys[3] = ¶ms->pReturnedKeyMaterial->hServerKey; + } else { + keys[0] = handle; + } + + /* Check permissions based on attributes and session */ + rc = check_session_permissions(session, attrs, attrs_len); + if (rc != CKR_OK) + return rc; + + /* Copy token name from shared memory */ + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get process lock.\n"); + return rc; + } + + strunpad(token_name, (const char *)tokdata->nv_token_data->token_info.label, + sizeof(tokdata->nv_token_data->token_info.label), ' '); + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release process lock.\n"); + return rc; + } + + /* Allocate structure to keep ICSF object information */ + for (i = 0; i < sizeof(mappings) / sizeof(*mappings); i++) { + if (!(mappings[i] = malloc(sizeof(*mappings[i])))) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + memset(mappings[i], 0, sizeof(*mappings[i])); + mappings[i]->session_id = session->handle; + + /* If not deriving multiple keys, just one key is needed */ + if (!multiple) + break; + } + + /* Get session state */ + if (!(session_state = get_session_state(tokdata, session->handle))) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + /* check ldap handle */ + if (session_state->ld == NULL) { + TRACE_ERROR("No LDAP handle.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Convert the OCK_CK_OBJECT_HANDLE_PTR to ICSF */ + base_key_mapping = bt_get_node_value(&icsf_data->objects, hBaseKey); + if (!base_key_mapping) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID)); + rc = CKR_KEY_HANDLE_INVALID; + goto done; + } + + /* Call ICSF service */ + if (!multiple) + rc = icsf_derive_key(session_state->ld, &reason, mech, + &base_key_mapping->icsf_object, + &mappings[0]->icsf_object, attrs, attrs_len); + else + rc = icsf_derive_multiple_keys(session_state->ld, &reason, + mech, &base_key_mapping->icsf_object, + attrs, attrs_len, + &mappings[0]->icsf_object, + &mappings[1]->icsf_object, + &mappings[2]->icsf_object, + &mappings[3]->icsf_object, + params->pReturnedKeyMaterial->pIVClient, + params->pReturnedKeyMaterial->pIVServer); + if (rc) { + rc = icsf_to_ock_err(rc, reason); + goto done; + } + + for (i = 0; i < sizeof(mappings) / sizeof(*mappings); i++) { + /* Add info about object into session */ + if (!(node_number = bt_node_add(&icsf_data->objects, mappings[i]))) { + TRACE_ERROR("Failed to add object to binary tree.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Use node number as handle */ + *keys[i] = node_number; + + /* If not deriving multiple keys, just one key is returned */ + if (!multiple) + break; + } + +done: + if (base_key_mapping) { + bt_put_node_value(&icsf_data->objects, base_key_mapping); + base_key_mapping = NULL; + } + + /* If allocated, object must be freed in case of failure */ + if (rc) { + for (i = 0; i < sizeof(mappings) / sizeof(*mappings); i++) + if (mappings[i]) + free(mappings[i]); + } + + return rc; +} diff --git a/usr/lib/icsf_stdll/icsf_specific.h b/usr/lib/icsf_stdll/icsf_specific.h new file mode 100644 index 0000000..afc5d23 --- /dev/null +++ b/usr/lib/icsf_stdll/icsf_specific.h @@ -0,0 +1,193 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2015-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 + */ + +/* + * OpenCryptoki ICSF token - ICSF token functions + * + */ + +#ifndef ICSF_SPECIFIC_H +#define ICSF_SPECIFIC_H + +#include "pkcs11types.h" +#include "list.h" + +typedef struct { + /* + * This list contains one element to each session and it's used to keep + * session specific data. Any insertion or deletion in this list should + * be protected by sess_list_mutex. + * + * This lock is intended to protect the linked list, not the content of each + * element. Since PKCS#11 applications should not use the same session for + * different threads, the only concurrency that we have to deal is when adding + * or removing a session to or from the list. + */ + list_t sessions; + pthread_mutex_t sess_list_mutex; + + /* + * This binary tree keeps the mapping between ICSF object handles and PKCS#11 + * object handles. The tree index is used as the PKCS#11 handle. + */ + struct btree objects; +} icsf_private_data_t; + +CK_RV icsftok_init(STDLL_TokData_t * tokdata, CK_SLOT_ID slot_id, + char *conf_name); + +CK_RV icsftok_final(STDLL_TokData_t * tokdata, CK_BBOOL finalize, + CK_BBOOL in_fork_initializer); + +CK_RV icsftok_init_token(STDLL_TokData_t * tokdata, CK_SLOT_ID slot_id, + CK_CHAR_PTR pin, CK_ULONG pin_len, CK_CHAR_PTR label); + +CK_RV icsftok_init_pin(STDLL_TokData_t * tokdata, SESSION * sess, + CK_CHAR_PTR pPin, CK_ULONG ulPinLen); + +CK_RV icsftok_set_pin(STDLL_TokData_t * tokdata, SESSION * sess, + CK_CHAR_PTR pOldPin, CK_ULONG ulOldLen, + CK_CHAR_PTR pNewPin, CK_ULONG ulNewLen); + +CK_RV icsftok_open_session(STDLL_TokData_t * tokdata, SESSION * sess); + +CK_RV icsftok_close_session(STDLL_TokData_t * tokdata, SESSION * session, + CK_BBOOL in_fork_initializer); + +CK_RV icsftok_login(STDLL_TokData_t * tokdata, SESSION * sess, + CK_USER_TYPE userType, CK_CHAR_PTR pPin, CK_ULONG ulPinLen); + +CK_RV icsftok_create_object(STDLL_TokData_t * tokdata, SESSION * session, + CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, + CK_OBJECT_HANDLE_PTR handle); + +CK_RV icsftok_copy_object(STDLL_TokData_t * tokdata, + SESSION * session, CK_ATTRIBUTE_PTR attrs, + CK_ULONG attrs_len, CK_OBJECT_HANDLE src, + CK_OBJECT_HANDLE_PTR dst); + +CK_RV icsftok_destroy_object(STDLL_TokData_t * tokdata, SESSION * sess, + CK_OBJECT_HANDLE handle); + +CK_RV icsftok_get_attribute_value(STDLL_TokData_t * tokdata, + SESSION * sess, CK_OBJECT_HANDLE handle, + CK_ATTRIBUTE * pTemplate, + CK_ULONG ulCount, CK_ULONG * obj_size); + +CK_RV icsftok_set_attribute_value(STDLL_TokData_t * tokdata, + SESSION * sess, CK_OBJECT_HANDLE handle, + CK_ATTRIBUTE * pTemplate, CK_ULONG ulCount); + + +CK_RV icsftok_find_objects_init(STDLL_TokData_t * tokdata, SESSION * sess, + CK_ATTRIBUTE * pTemplate, CK_ULONG ulCount); + +CK_RV icsftok_encrypt_init(STDLL_TokData_t * tokdata, + SESSION * session, CK_MECHANISM_PTR mech, + CK_OBJECT_HANDLE key); + +CK_RV icsftok_encrypt(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE_PTR input_data, + CK_ULONG input_data_len, CK_BYTE_PTR output_data, + CK_ULONG_PTR p_output_data_len); + +CK_RV icsftok_encrypt_update(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE_PTR input_part, + CK_ULONG input_part_len, CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len); + +CK_RV icsftok_encrypt_final(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len); + +CK_RV icsftok_decrypt_init(STDLL_TokData_t * tokdata, + SESSION * session, CK_MECHANISM_PTR mech, + CK_OBJECT_HANDLE key); + +CK_RV icsftok_decrypt(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE_PTR input_data, + CK_ULONG input_data_len, CK_BYTE_PTR output_data, + CK_ULONG_PTR p_output_data_len); + +CK_RV icsftok_decrypt_update(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE_PTR input_part, + CK_ULONG input_part_len, CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len); + +CK_RV icsftok_decrypt_final(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len); + +CK_RV icsftok_sign_init(STDLL_TokData_t * tokdata, + SESSION * session, CK_MECHANISM * mech, + CK_OBJECT_HANDLE key); + +CK_RV icsftok_sign(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE * in_data, CK_ULONG in_data_len, + CK_BYTE * signature, CK_ULONG * sig_len); + +CK_RV icsftok_sign_update(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE * in_data, + CK_ULONG in_data_len); + +CK_RV icsftok_sign_final(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE * signature, + CK_ULONG * sig_len); + +CK_RV icsftok_verify_init(STDLL_TokData_t * tokdata, + SESSION * session, CK_MECHANISM * mech, + CK_OBJECT_HANDLE key); + +CK_RV icsftok_verify(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE * in_data, CK_ULONG in_data_len, + CK_BYTE * signature, CK_ULONG sig_len); + +CK_RV icsftok_verify_update(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE * in_data, + CK_ULONG in_data_len); + +CK_RV icsftok_verify_final(STDLL_TokData_t * tokdata, + SESSION * session, CK_BYTE * signature, + CK_ULONG sig_len); + +CK_RV icsftok_wrap_key(STDLL_TokData_t * tokdata, + SESSION * session, CK_MECHANISM_PTR mech, + CK_OBJECT_HANDLE wrapping_key, CK_OBJECT_HANDLE key, + CK_BYTE_PTR wrapped_key, CK_ULONG_PTR p_wrapped_key_len); + +CK_RV icsftok_unwrap_key(STDLL_TokData_t * tokdata, + SESSION * session, CK_MECHANISM_PTR mech, + CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, + CK_BYTE_PTR wrapped_key, CK_ULONG wrapped_key_len, + CK_OBJECT_HANDLE wrapping_key, + CK_OBJECT_HANDLE_PTR p_key); + +CK_RV icsftok_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); + +CK_RV icsftok_generate_key_pair(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM_PTR mech, + CK_ATTRIBUTE_PTR pub_attrs, + CK_ULONG pub_attrs_len, + CK_ATTRIBUTE_PTR priv_attrs, + CK_ULONG priv_attrs_len, + CK_OBJECT_HANDLE_PTR p_pub_key, + CK_OBJECT_HANDLE_PTR p_priv_key); + +CK_RV icsftok_generate_key(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM_PTR mech, + CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len, + CK_OBJECT_HANDLE_PTR handle); + +CK_RV icsf_get_handles(STDLL_TokData_t * tokdata, CK_SLOT_ID slot_id); + +#endif diff --git a/usr/lib/icsf_stdll/icsf_stdll.mk b/usr/lib/icsf_stdll/icsf_stdll.mk new file mode 100644 index 0000000..44a7ab1 --- /dev/null +++ b/usr/lib/icsf_stdll/icsf_stdll.mk @@ -0,0 +1,57 @@ +nobase_lib_LTLIBRARIES += opencryptoki/stdll/libpkcs11_icsf.la + +noinst_HEADERS += \ + usr/lib/icsf_stdll/icsf.h usr/lib/icsf_stdll/pbkdf.h \ + usr/lib/icsf_stdll/icsf_config.h \ + usr/lib/icsf_stdll/icsf_specific.h \ + usr/lib/icsf_stdll/tok_struct.h + +BUILT_SOURCES += usr/lib/icsf_stdll/icsf_config_parse.h +CLEANFILES += \ + usr/lib/icsf_stdll/icsf_config_lexer.c \ + usr/lib/icsf_stdll/icsf_config_parse.c \ + usr/lib/icsf_stdll/icsf_config_parse.h \ + usr/lib/icsf_stdll/icsf_config_parse.output + +opencryptoki_stdll_libpkcs11_icsf_la_CFLAGS = \ + -DNOCDMF -DNODSA -DNODH -DMMAP -I${srcdir}/usr/lib/icsf_stdll \ + -I${srcdir}/usr/lib/common -I${srcdir}/usr/include \ + -DSTDLL_NAME=\"icsftok\" \ + -DTOK_NEW_DATA_STORE=0xffffffff + +opencryptoki_stdll_libpkcs11_icsf_la_LDFLAGS = \ + -shared -Wl,-z,defs,-Bsymbolic -lcrypto -lldap -lpthread \ + -lrt -llber \ + -Wl,--version-script=${srcdir}/opencryptoki_tok.map + +opencryptoki_stdll_libpkcs11_icsf_la_SOURCES = \ + usr/lib/common/asn1.c usr/lib/common/dig_mgr.c \ + usr/lib/common/hwf_obj.c usr/lib/common/trace.c \ + usr/lib/common/key.c usr/lib/common/mech_dh.c \ + usr/lib/common/mech_rng.c usr/lib/common/sign_mgr.c \ + usr/lib/common/cert.c usr/lib/common/dp_obj.c \ + usr/lib/common/mech_aes.c usr/lib/common/mech_rsa.c \ + usr/lib/common/mech_ec.c usr/lib/common/obj_mgr.c \ + usr/lib/common/template.c usr/lib/common/p11util.c \ + usr/lib/common/data_obj.c usr/lib/common/encr_mgr.c \ + usr/lib/common/key_mgr.c usr/lib/common/mech_md2.c \ + usr/lib/common/mech_sha.c usr/lib/common/object.c \ + usr/lib/common/decr_mgr.c usr/lib/common/globals.c \ + usr/lib/common/sw_crypt.c usr/lib/common/loadsave.c \ + usr/lib/common/utility.c usr/lib/common/mech_des.c \ + usr/lib/common/mech_des3.c usr/lib/common/mech_md5.c \ + usr/lib/common/mech_ssl3.c usr/lib/common/verify_mgr.c \ + usr/lib/common/mech_list.c usr/lib/common/shared_memory.c \ + usr/lib/common/attributes.c usr/lib/icsf_stdll/new_host.c \ + usr/lib/icsf_stdll/pbkdf.c usr/lib/icsf_stdll/icsf_specific.c \ + usr/lib/icsf_stdll/icsf_config_parse.y \ + usr/lib/icsf_stdll/icsf_config_lexer.l \ + usr/lib/icsf_stdll/icsf.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/btree.c usr/lib/common/sess_mgr.c +endif diff --git a/usr/lib/icsf_stdll/new_host.c b/usr/lib/icsf_stdll/new_host.c new file mode 100644 index 0000000..f8e518f --- /dev/null +++ b/usr/lib/icsf_stdll/new_host.c @@ -0,0 +1,3311 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2015-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 + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "stdll.h" + +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_spec_struct.h" +#include "pkcs32.h" +#include "trace.h" +#include "slotmgr.h" +#include "icsf_specific.h" +#include "../api/apiproto.h" + +void SC_SetFunctionList(void); +CK_RV SC_Finalize(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, SLOT_INFO *sinfp, + struct trace_handle_t *t, CK_BBOOL in_fork_initializer); + +/* verify that the mech specified is in the + * mech list for this token... + */ +CK_RV valid_mech(STDLL_TokData_t *tokdata, CK_MECHANISM_PTR m, CK_FLAGS f) +{ + CK_RV rc; + CK_MECHANISM_INFO info; + + UNUSED(tokdata); + + if (m) { + memset(&info, 0, sizeof(info)); + rc = ock_generic_get_mechanism_info(tokdata, m->mechanism, &info); + if (rc != CKR_OK || !(info.flags & (f))) + return CKR_MECHANISM_INVALID; + } + + return CKR_OK; +} + + +/* In an STDLL this is called once for each card in the system + * therefore the initialized only flags certain one time things. + */ +CK_RV ST_Initialize(API_Slot_t *sltp, CK_SLOT_ID SlotNumber, + SLOT_INFO *sinfp, struct trace_handle_t t) +{ + CK_RV rc = CKR_OK; + char abs_tokdir_name[PATH_MAX]; + + if ((rc = check_user_and_group()) != CKR_OK) + return rc; + + /* set trace info */ + set_trace(t); + + if (sltp->TokData != NULL) { + TRACE_ERROR("Already initialized.\n"); + return CKR_CRYPTOKI_ALREADY_INITIALIZED; + } + + /* + * Create separate memory area for each token specific data + */ + sltp->TokData = (STDLL_TokData_t *) calloc(1, sizeof(STDLL_TokData_t)); + if (!sltp->TokData) { + TRACE_ERROR("Allocating host memory failed.\n"); + return CKR_HOST_MEMORY; + } + + 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); + + 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); + + if (strlen(sinfp->tokname)) { + sprintf(abs_tokdir_name, "%s/%s", CONFIG_PATH, sinfp->tokname); + TRACE_DEVEL("Token directory: %s\n", abs_tokdir_name); + init_data_store(sltp->TokData, (char *) abs_tokdir_name, + sltp->TokData->data_store); + } else { + init_data_store(sltp->TokData, (char *) PK_DIR, + sltp->TokData->data_store); + } + + sltp->TokData->version = sinfp->version; + TRACE_DEVEL("Token version: %u.%u\n", + (unsigned int)(sinfp->version >> 16), + (unsigned int)(sinfp->version & 0xffff)); + + /* Initialize Lock */ + if (XProcLock_Init(sltp->TokData) != CKR_OK) { + TRACE_ERROR("Thread lock failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Create lockfile */ + if (CreateXProcLock(sinfp->tokname, sltp->TokData) != CKR_OK) { + TRACE_ERROR("Process lock failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* Handle global initialization issues first if we have not + * been initialized. + */ + if (sltp->TokData->initialized == FALSE) { + rc = attach_shm(sltp->TokData, SlotNumber); + if (rc != CKR_OK) { + TRACE_ERROR("Could not attach to shared memory.\n"); + goto done; + } + + sltp->TokData->nv_token_data = + &(sltp->TokData->global_shm->nv_token_data); + SC_SetFunctionList(); + + rc = icsftok_init(sltp->TokData, SlotNumber, sinfp->confname); + if (rc != 0) { + sltp->FcnList = NULL; + detach_shm(sltp->TokData, 0); + if (sltp->TokData) + free(sltp->TokData); + sltp->TokData = NULL; + TRACE_DEVEL("Token Specific Init failed.\n"); + goto done; + } + sltp->TokData->initialized = TRUE; + } + + rc = load_token_data(sltp->TokData, SlotNumber); + if (rc != CKR_OK) { + sltp->FcnList = NULL; + if (sltp->TokData) + free(sltp->TokData); + sltp->TokData = NULL; + TRACE_DEVEL("Failed to load token data. (rc=0x%02lx)\n", rc); + goto done; + } + + rc = XProcLock(sltp->TokData); + if (rc != CKR_OK) + goto done; + + /* no need to return error here, we load the token data we can + * and syslog the rest + */ + load_public_token_objects(sltp->TokData); + + sltp->TokData->global_shm->publ_loaded = TRUE; + + rc = XProcUnLock(sltp->TokData); + if (rc != CKR_OK) + goto done; + + init_slotInfo(&(sltp->TokData->slot_info)); + + (sltp->FcnList) = &function_list; + +done: + if (rc != CKR_OK && sltp->TokData != NULL) { + if (sltp->TokData->initialized) { + SC_Finalize(sltp->TokData, SlotNumber, sinfp, NULL, 0); + } else { + CloseXProcLock(sltp->TokData); + free(sltp->TokData); + sltp->TokData = NULL; + } + } + + return rc; +} + +/* What does this really have to do in this new token... probably + * need to close the adapters that are opened, and clear the other + * stuff + */ +CK_RV SC_Finalize(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, SLOT_INFO *sinfp, + struct trace_handle_t *t, CK_BBOOL in_fork_initializer) +{ + CK_RV rc = CKR_OK; + + UNUSED(sid); + UNUSED(sinfp); + + if (t != NULL) + set_trace(*t); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + tokdata->initialized = FALSE; + + session_mgr_close_all_sessions(tokdata); + object_mgr_purge_token_objects(tokdata); + + /* Finally free the nodes on free list. */ + bt_destroy(&tokdata->sess_btree); + bt_destroy(&tokdata->object_map_btree); + bt_destroy(&tokdata->sess_obj_btree); + bt_destroy(&tokdata->priv_token_obj_btree); + bt_destroy(&tokdata->publ_token_obj_btree); + +#ifdef ENABLE_LOCKS + pthread_rwlock_destroy(&tokdata->sess_list_rwlock); +#endif + pthread_mutex_destroy(&tokdata->login_mutex); + + detach_shm(tokdata, in_fork_initializer); + /* close spin lock file */ + CloseXProcLock(tokdata); + + rc = icsftok_final(tokdata, TRUE, in_fork_initializer); + if (rc != CKR_OK) { + TRACE_ERROR("Token specific final call failed.\n"); + return rc; + } + + final_data_store(tokdata); + + if (tokdata) + free(tokdata); + + return rc; +} + +CK_RV SC_GetTokenInfo(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, + CK_TOKEN_INFO_PTR pInfo) +{ + CK_RV rc = CKR_OK; + time_t now; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + if (!pInfo) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + if (sid >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + rc = CKR_SLOT_ID_INVALID; + goto done; + } + copy_token_contents_sensibly(pInfo, tokdata->nv_token_data); + + /* Set the time */ + now = time((time_t *) NULL); + strftime((char *) pInfo->utcTime, 16, "%Y%m%d%H%M%S", localtime(&now)); + pInfo->utcTime[14] = '0'; + pInfo->utcTime[15] = '0'; + +done: + TRACE_INFO("C_GetTokenInfo: rc = 0x%08lx\n", rc); + + return rc; +} + +CK_RV SC_WaitForSlotEvent(STDLL_TokData_t *tokdata, CK_FLAGS flags, + CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved) +{ + UNUSED(flags); + UNUSED(pSlot); + UNUSED(pReserved); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + +/* + * Get the mechanism type list for the current token. + */ +CK_RV SC_GetMechanismList(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, + CK_MECHANISM_TYPE_PTR pMechList, CK_ULONG_PTR count) +{ + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto out; + } + if (count == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto out; + } + if (sid >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + rc = CKR_SLOT_ID_INVALID; + goto out; + } + rc = ock_generic_get_mechanism_list(tokdata, pMechList, count); + if (rc == CKR_OK) { + /* To accomodate certain special cases, we may need to + * make adjustments to the token's mechanism list. + */ + mechanism_list_transformations(pMechList, count); + } + +out: + TRACE_INFO("C_GetMechanismList: rc = 0x%08lx, # mechanisms: %lu\n", + rc, (count ? *count : 0)); + + return rc; +} + +/* + * Get the mechanism info for the current type and token. + */ +CK_RV SC_GetMechanismInfo(STDLL_TokData_t * tokdata, CK_SLOT_ID sid, + CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo) +{ + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto out; + } + if (pInfo == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto out; + } + if (sid >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + rc = CKR_SLOT_ID_INVALID; + goto out; + } + rc = ock_generic_get_mechanism_info(tokdata, type, pInfo); +out: + TRACE_INFO("C_GetMechanismInfo: rc = 0x%08lx, mech type = 0x%08lx\n", + rc, type); + + return rc; +} + +/* + * This routine should only be called if no other processes are + * attached to the token. we need to somehow check that this is the + * only process Meta API should prevent this since it knows session + * states in the shared memory. +*/ +CK_RV SC_InitToken(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, CK_CHAR_PTR pPin, + CK_ULONG ulPinLen, CK_CHAR_PTR pLabel) +{ + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + if (!pPin || !pLabel) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + if (pthread_mutex_lock(&tokdata->login_mutex)) { + TRACE_ERROR("Failed to get mutex lock.\n"); + return CKR_FUNCTION_FAILED; + } + + if (tokdata->nv_token_data->token_info.flags & CKF_SO_PIN_LOCKED) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LOCKED)); + rc = CKR_PIN_LOCKED; + goto done; + } + + rc = icsftok_init_token(tokdata, sid, pPin, ulPinLen, pLabel); + if (rc != CKR_OK) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + } +done: + TRACE_INFO("C_InitToken: rc = 0x%08lx\n", rc); + + pthread_mutex_unlock(&tokdata->login_mutex); + + return rc; +} + + +CK_RV SC_InitPIN(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_CHAR_PTR pPin, CK_ULONG ulPinLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + CK_FLAGS_32 *flags = NULL; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + if (!pPin) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + if (pthread_mutex_lock(&tokdata->login_mutex)) { + TRACE_ERROR("Failed to get mutex lock.\n"); + return CKR_FUNCTION_FAILED; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle here as handle is never set into session during creation + sess->handle = sSession->sessionh; + + if (pin_locked(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LOCKED)); + rc = CKR_PIN_LOCKED; + goto done; + } + if (sess->session_info.state != CKS_RW_SO_FUNCTIONS) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + + rc = icsftok_init_pin(tokdata, sess, pPin, ulPinLen); + if (rc == CKR_OK) { + flags = &tokdata->nv_token_data->token_info.flags; + *flags &= ~(CKF_USER_PIN_LOCKED | CKF_USER_PIN_FINAL_TRY | + CKF_USER_PIN_COUNT_LOW); + rc = save_token_data(tokdata, sess->session_info.slotID); + if (rc != CKR_OK) + TRACE_DEVEL("Failed to save token data.\n"); + } +done: + TRACE_INFO("C_InitPin: rc = 0x%08lx, session = %lu\n", + rc, sSession->sessionh); + + pthread_mutex_unlock(&tokdata->login_mutex); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + +CK_RV SC_SetPIN(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_CHAR_PTR pOldPin, CK_ULONG ulOldLen, CK_CHAR_PTR pNewPin, + CK_ULONG ulNewLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (pthread_mutex_lock(&tokdata->login_mutex)) { + TRACE_ERROR("Failed to get mutex lock.\n"); + return CKR_FUNCTION_FAILED; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle here as handle is never set into session during creation + sess->handle = sSession->sessionh; + + if (pin_locked(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LOCKED)); + rc = CKR_PIN_LOCKED; + goto done; + } + + rc = icsftok_set_pin(tokdata, sess, pOldPin, ulOldLen, pNewPin, ulNewLen); + +done: + TRACE_INFO("C_SetPin: rc = 0x%08lx, session = %lu\n", + rc, sSession->sessionh); + + pthread_mutex_unlock(&tokdata->login_mutex); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + +CK_RV SC_OpenSession(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, CK_FLAGS flags, + CK_SESSION_HANDLE_PTR phSession) +{ + CK_RV rc = CKR_OK; + SESSION *sess; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + if (phSession == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + if (sid >= NUMBER_SLOTS_MANAGED) { + TRACE_ERROR("%s\n", ock_err(ERR_SLOT_ID_INVALID)); + return CKR_SLOT_ID_INVALID; + } + flags |= CKF_SERIAL_SESSION; + if ((flags & CKF_RW_SESSION) == 0) { + if (session_mgr_so_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_WRITE_SO_EXISTS)); + return CKR_SESSION_READ_WRITE_SO_EXISTS; + } + } + + rc = session_mgr_new(tokdata, flags, sid, phSession); + if (rc != CKR_OK) { + TRACE_DEVEL("session_mgr_new() failed\n"); + return rc; + } + + sess = session_mgr_find(tokdata, *phSession); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + return CKR_SESSION_HANDLE_INVALID; + } + + sess->handle = *phSession; + rc = icsftok_open_session(tokdata, sess); + + TRACE_INFO("C_OpenSession: rc = 0x%08lx sess = %lu\n", rc, sess->handle); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + +CK_RV SC_CloseSession(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BBOOL in_fork_initializer) +{ + CK_RV rc = CKR_OK; + SESSION *sess = NULL; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle here as handle is never set into session during creation + sess->handle = sSession->sessionh; + rc = icsftok_close_session(tokdata, sess, in_fork_initializer); + if (rc) + goto done; + session_mgr_put(tokdata, sess); + sess = NULL; + + rc = session_mgr_close_session(tokdata, sSession->sessionh); + +done: + if (sess != NULL) + session_mgr_put(tokdata, sess); + + TRACE_INFO("C_CloseSession: rc = 0x%08lx, sess = %lu\n", + rc, sSession->sessionh); + + return rc; +} + +CK_RV SC_CloseAllSessions(STDLL_TokData_t *tokdata, CK_SLOT_ID sid) +{ + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + rc = session_mgr_close_all_sessions(tokdata); + if (rc != CKR_OK) { + TRACE_DEVEL("session_mgr_close_all_sessions() failed.\n"); + goto done; + } + + rc = icsftok_final(tokdata, FALSE, FALSE); + if (rc != CKR_OK) + TRACE_DEVEL("Failed to remove icsf specific session_states.\n"); + +done: + TRACE_INFO("C_CloseAllSessions: rc = 0x%08lx, slot = %lu\n", rc, sid); + + return rc; +} + +CK_RV SC_GetSessionInfo(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_SESSION_INFO_PTR pInfo) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pInfo) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + + memcpy(pInfo, &sess->session_info, sizeof(CK_SESSION_INFO)); + +done: + TRACE_INFO("C_GetSessionInfo: sess = %lu\n", sSession->sessionh); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + +CK_RV SC_GetOperationState(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pOperationState, + CK_ULONG_PTR pulOperationStateLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pulOperationStateLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (!pOperationState) + length_only = TRUE; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + rc = session_mgr_get_op_state(sess, length_only, pOperationState, + pulOperationStateLen); + if (rc != CKR_OK) + TRACE_DEVEL("session_mgr_get_op_state() failed.\n"); + +done: + TRACE_INFO("C_GetOperationState: rc = 0x%08lx, sess = %lu\n", + rc, sSession->sessionh); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_SetOperationState(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pOperationState, + CK_ULONG ulOperationStateLen, + CK_OBJECT_HANDLE hEncryptionKey, + CK_OBJECT_HANDLE hAuthenticationKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pOperationState || (ulOperationStateLen == 0)) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + rc = session_mgr_set_op_state(sess, hEncryptionKey, hAuthenticationKey, + pOperationState, ulOperationStateLen); + + if (rc != CKR_OK) + TRACE_DEVEL("session_mgr_set_op_state() failed.\n"); + +done: + TRACE_INFO("C_SetOperationState: rc = 0x%08lx, sess = %lu\n", + rc, sSession->sessionh); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Login(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_USER_TYPE userType, CK_CHAR_PTR pPin, CK_ULONG ulPinLen) +{ + SESSION *sess = NULL; + CK_FLAGS_32 *flags = NULL; + CK_RV rc = CKR_OK; + + if (pthread_mutex_lock(&tokdata->login_mutex)) { + TRACE_ERROR("Failed to get mutex lock.\n"); + return CKR_FUNCTION_FAILED; + } + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + flags = &tokdata->nv_token_data->token_info.flags; + + if (!pPin || ulPinLen > MAX_PIN_LEN) { + set_login_flags(userType, flags); + TRACE_ERROR("%s\n", ock_err(ERR_PIN_INCORRECT)); + rc = CKR_PIN_INCORRECT; + goto done; + } + + /* PKCS #11 v2.01 requires that all sessions have the same login status: + * --> all sessions are public, all are SO or all are USER + */ + if (userType == CKU_USER) { + if (session_mgr_so_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_ANOTHER_ALREADY_LOGGED_IN)); + rc = CKR_USER_ANOTHER_ALREADY_LOGGED_IN; + } + if (session_mgr_user_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_ALREADY_LOGGED_IN)); + rc = CKR_USER_ALREADY_LOGGED_IN; + } + } else if (userType == CKU_SO) { + if (session_mgr_user_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_ANOTHER_ALREADY_LOGGED_IN)); + rc = CKR_USER_ANOTHER_ALREADY_LOGGED_IN; + } + if (session_mgr_so_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_ALREADY_LOGGED_IN)); + rc = CKR_USER_ALREADY_LOGGED_IN; + } + if (session_mgr_readonly_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY_EXISTS)); + rc = CKR_SESSION_READ_ONLY_EXISTS; + } + } else { + rc = CKR_USER_TYPE_INVALID; + TRACE_ERROR("%s\n", ock_err(ERR_USER_TYPE_INVALID)); + } + if (rc != CKR_OK) + goto done; + + + if (userType == CKU_USER) { + if (*flags & CKF_USER_PIN_LOCKED) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LOCKED)); + rc = CKR_PIN_LOCKED; + goto done; + } + + rc = icsftok_login(tokdata, sess, userType, pPin, ulPinLen); + if (rc == CKR_OK) { + *flags &= ~(CKF_USER_PIN_LOCKED | + CKF_USER_PIN_FINAL_TRY | CKF_USER_PIN_COUNT_LOW); + } else if (rc == CKR_PIN_INCORRECT) { + set_login_flags(userType, flags); + } + } else { + if (*flags & CKF_SO_PIN_LOCKED) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_LOCKED)); + rc = CKR_PIN_LOCKED; + goto done; + } + + rc = icsftok_login(tokdata, sess, userType, pPin, ulPinLen); + if (rc == CKR_OK) { + *flags &= ~(CKF_SO_PIN_LOCKED | + CKF_SO_PIN_FINAL_TRY | CKF_SO_PIN_COUNT_LOW); + } else if (rc == CKR_PIN_INCORRECT) { + set_login_flags(userType, flags); + } + } +done: + if (rc == CKR_OK) { + rc = session_mgr_login_all(tokdata, userType); + if (rc != CKR_OK) { + TRACE_DEVEL("session_mgr_login_all failed.\n"); + } else { + if (sess) + rc = icsf_get_handles(tokdata, sess->session_info.slotID); + } + } + + TRACE_INFO("C_Login: rc = 0x%08lx\n", rc); + if (sess) + save_token_data(tokdata, sess->session_info.slotID); + pthread_mutex_unlock(&tokdata->login_mutex); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Logout(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + if (pthread_mutex_lock(&tokdata->login_mutex)) { + TRACE_ERROR("Failed to get mutex lock.\n"); + return CKR_FUNCTION_FAILED; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + /* all sessions have the same state so we just have to check one */ + if (session_mgr_public_session_exists(tokdata)) { + TRACE_ERROR("%s\n", ock_err(ERR_USER_NOT_LOGGED_IN)); + rc = CKR_USER_NOT_LOGGED_IN; + goto done; + } + + rc = session_mgr_logout_all(tokdata); + if (rc != CKR_OK) + TRACE_DEVEL("session_mgr_logout_all failed.\n"); + + + memset(tokdata->user_pin_md5, 0x0, MD5_HASH_SIZE); + memset(tokdata->so_pin_md5, 0x0, MD5_HASH_SIZE); + + object_mgr_purge_private_token_objects(tokdata); + +done: + TRACE_INFO("C_Logout: rc = 0x%08lx\n", rc); + + pthread_mutex_unlock(&tokdata->login_mutex); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_CreateObject(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phObject) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags)) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = icsftok_create_object(tokdata, sess, pTemplate, ulCount, phObject); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_create_object() failed.\n"); +done: + if (sess != NULL) + session_mgr_put(tokdata, sess); + + TRACE_INFO("C_CreateObject: rc = 0x%08lx\n", rc); + +#ifdef DEBUG + CK_ULONG i; + + for (i = 0; i < ulCount; i++) { + if (pTemplate[i].type == CKA_CLASS) { + TRACE_DEBUG("Object Type: 0x%02lx\n", + *((CK_ULONG *) pTemplate[i].pValue)); + } + } + if (rc == CKR_OK) + TRACE_DEBUG("Handle: %lu\n", *phObject); +#endif + + return rc; +} + + +CK_RV SC_CopyObject(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = icsftok_copy_object(tokdata, sess, pTemplate, ulCount, hObject, + phNewObject); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_copy_object() failed\n"); + +done: + if (sess != NULL) + session_mgr_put(tokdata, sess); + + TRACE_INFO("C_CopyObject:rc = 0x%08lx,old handle = %lu, " + "new handle = %lu\n", rc, hObject, *phNewObject); + + return rc; +} + + +CK_RV SC_DestroyObject(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE hObject) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = icsftok_destroy_object(tokdata, sess, hObject); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_destroy_object() failed\n"); +done: + if (sess != NULL) + session_mgr_put(tokdata, sess); + + TRACE_INFO("C_DestroyObject: rc = 0x%08lx, handle = %lu\n", rc, hObject); + + return rc; +} + + +CK_RV SC_GetObjectSize(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + /** + * ock does not do object management for icsf token. To get the + * object size call CSFPGAV and extract the attr_length returned. + * icsf_get_attribute does not pass the user provided template + * attributes to remote icsf, instead gets all the attributes from + * remote icsf and returns only the user requested attributes. + * icsf_get_object_size tries to do the same and extracts only the + * attribute_list_length from the result. Setting attribute list to + * NULL here and providing a dummy count value. + **/ + CK_ATTRIBUTE_PTR pTemplate = NULL; + CK_ULONG ulCount = 1; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + rc = icsftok_get_attribute_value(tokdata, sess, hObject, pTemplate, + ulCount, pulSize); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_get_attribute_value() failed.\n"); + + +done: + TRACE_INFO("C_GetObjectSize: rc = 0x%08lx, handle = %lu\n", rc, hObject); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_GetAttributeValue(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + rc = icsftok_get_attribute_value(tokdata, sess, hObject, pTemplate, ulCount, + NULL); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_get_attribute_value() failed.\n"); + +done: + TRACE_INFO("C_GetAttributeValue: rc = 0x%08lx, handle = %lu\n", + rc, hObject); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *ptr = NULL; + CK_ULONG i; + + attr = pTemplate; + for (i = 0; i < ulCount; i++, attr++) { + ptr = (CK_BYTE *) attr->pValue; + + TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + + if (attr->ulValueLen != (CK_ULONG) (-1) && (ptr != NULL)) + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } +#endif + + return rc; +} + + +CK_RV SC_SetAttributeValue(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + rc = icsftok_set_attribute_value(tokdata, sess, hObject, pTemplate, ulCount); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_set_attribute_values() failed.\n"); + +done: + TRACE_INFO("C_SetAttributeValue: rc = 0x%08lx, handle = %lu\n", + rc, hObject); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_ULONG i; + + attr = pTemplate; + for (i = 0; i < ulCount; i++, attr++) { + CK_BYTE *ptr = (CK_BYTE *) attr->pValue; + + TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + + if (attr->ulValueLen != (CK_ULONG) (-1) && (ptr != NULL)) + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } +#endif + + return rc; +} + + +CK_RV SC_FindObjectsInit(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->find_active == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + rc = icsftok_find_objects_init(tokdata, sess, pTemplate, ulCount); + +done: + TRACE_INFO("C_FindObjectsInit: rc = 0x%08lx\n", rc); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_ULONG i; + + attr = pTemplate; + for (i = 0; i < ulCount; i++, attr++) { + CK_BYTE *ptr = (CK_BYTE *) attr->pValue; + + TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + + if (attr->ulValueLen != (CK_ULONG) (-1) && (ptr != NULL)) + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } +#endif + + return rc; +} + + +CK_RV SC_FindObjects(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, + CK_ULONG_PTR pulObjectCount) +{ + SESSION *sess = NULL; + CK_ULONG count = 0; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!phObject || !pulObjectCount) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (sess->find_active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!sess->find_list) { + TRACE_DEVEL("sess->find_list is NULL.\n"); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + count = MIN(ulMaxObjectCount, (sess->find_count - sess->find_idx)); + + memcpy(phObject, sess->find_list + sess->find_idx, + count * sizeof(CK_OBJECT_HANDLE)); + *pulObjectCount = count; + + sess->find_idx += count; + rc = CKR_OK; + +done: + TRACE_INFO("C_FindObjects: rc = 0x%08lx, returned %lu objects\n", + rc, count); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_FindObjectsFinal(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (sess->find_active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (sess->find_list) + free(sess->find_list); + + sess->find_list = NULL; + sess->find_len = 0; + sess->find_idx = 0; + sess->find_active = FALSE; + + rc = CKR_OK; + +done: + TRACE_INFO("C_FindObjectsFinal: rc = 0x%08lx\n", rc); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_EncryptInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_ENCRYPT); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->encr_ctx.active == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + rc = icsftok_encrypt_init(tokdata, sess, pMechanism, hKey); + +done: + TRACE_INFO("C_EncryptInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)(-1))); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Encrypt(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pData, CK_ULONG ulDataLen, + CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (!pData || !pulEncryptedDataLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (sess->encr_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pEncryptedData) + length_only = TRUE; + + rc = icsftok_encrypt(tokdata, sess, pData, ulDataLen, pEncryptedData, + pulEncryptedDataLen); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_encrypt() failed.\n"); + +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { + if (sess) + encr_mgr_cleanup(&sess->encr_ctx); + } + + TRACE_INFO("C_Encrypt: rc = 0x%08lx, sess = %ld, amount = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulDataLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_EncryptUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if ((!pPart && ulPartLen != 0) || !pulEncryptedPartLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (sess->encr_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + rc = icsftok_encrypt_update(tokdata, sess, pPart, ulPartLen, pEncryptedPart, + pulEncryptedPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_encrypt_update() failed.\n"); + +done: + if (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL) { + if (sess) + encr_mgr_cleanup(&sess->encr_ctx); + } + + TRACE_INFO("C_EncryptUpdate: rc = 0x%08lx, sess = %ld, amount = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_EncryptFinal(STDLL_TokData_t * tokdata, ST_SESSION_HANDLE * sSession, + CK_BYTE_PTR pLastEncryptedPart, + CK_ULONG_PTR pulLastEncryptedPartLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (!pulLastEncryptedPartLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (sess->encr_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pLastEncryptedPart) + length_only = TRUE; + + rc = icsftok_encrypt_final(tokdata, sess, pLastEncryptedPart, + pulLastEncryptedPartLen); + if (rc != CKR_OK) + TRACE_ERROR("icsftok_encrypt_final() failed.\n"); + +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { + if (sess) + encr_mgr_cleanup(&sess->encr_ctx); + } + + TRACE_INFO("C_EncryptFinal: rc = 0x%08lx, sess = %ld\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DecryptInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_DECRYPT); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->decr_ctx.active == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + rc = icsftok_decrypt_init(tokdata, sess, pMechanism, hKey); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_decrypt_init() failed.\n"); + +done: + TRACE_INFO("C_DecryptInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)-1)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Decrypt(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, + CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (!pEncryptedData || !pulDataLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (sess->decr_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pData) + length_only = TRUE; + + rc = icsftok_decrypt(tokdata, sess, pEncryptedData, ulEncryptedDataLen, + pData, pulDataLen); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_decrypt() failed.\n"); + +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { + if (sess) + decr_mgr_cleanup(&sess->decr_ctx); + } + + TRACE_INFO("C_Decrypt: rc = 0x%08lx, sess = %ld, amount = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + ulEncryptedDataLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DecryptUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, + CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if ((!pEncryptedPart && ulEncryptedPartLen != 0) || !pulPartLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (sess->decr_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + rc = icsftok_decrypt_update(tokdata, sess, pEncryptedPart, + ulEncryptedPartLen, pPart, pulPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_decrypt_update() failed.\n"); + +done: + if (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL && sess != NULL) { + if (sess) + decr_mgr_cleanup(&sess->decr_ctx); + } + + TRACE_INFO("C_DecryptUpdate: rc = 0x%08lx, sess = %ld, amount = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + ulEncryptedPartLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DecryptFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (!pulLastPartLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + if (sess->decr_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pLastPart) + length_only = TRUE; + + rc = icsftok_decrypt_final(tokdata, sess, pLastPart, pulLastPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_decrypt_final() failed.\n"); +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { + if (sess) + decr_mgr_cleanup(&sess->decr_ctx); + } + + TRACE_INFO("C_DecryptFinal: rc = 0x%08lx, sess = %ld, amount = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pulLastPartLen ? *pulLastPartLen : 0)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DigestInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_DIGEST); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->digest_ctx.active == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + rc = CKR_OPERATION_ACTIVE; + goto done; + } + + rc = digest_mgr_init(tokdata, sess, &sess->digest_ctx, pMechanism); + if (rc != CKR_OK) + TRACE_DEVEL("digest_mgr_init() failed.\n"); + +done: + TRACE_INFO("C_DigestInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)-1)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Digest(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, + CK_ULONG_PTR pulDigestLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (sess->digest_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pDigest) + length_only = TRUE; + + rc = digest_mgr_digest(tokdata, sess, length_only, &sess->digest_ctx, + pData, ulDataLen, pDigest, pulDigestLen); + if (rc != CKR_OK) + TRACE_DEVEL("digest_mgr_digest() failed.\n"); + +done: + TRACE_INFO("C_Digest: rc = 0x%08lx, sess = %ld, datalen = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulDataLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DigestUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (sess->digest_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + /* If there is data to hash, do so. */ + if (ulPartLen) { + rc = digest_mgr_digest_update(tokdata, sess, &sess->digest_ctx, + pPart, ulPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("digest_mgr_digest_update() failed.\n"); + } + +done: + TRACE_INFO("C_DigestUpdate: rc = 0x%08lx, sess = %ld, datalen = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DigestKey(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_OBJECT_HANDLE hKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (sess->digest_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + rc = digest_mgr_digest_key(tokdata, sess, &sess->digest_ctx, hKey); + if (rc != CKR_OK) + TRACE_DEVEL("digest_mgr_digest_key() failed.\n"); + +done: + TRACE_INFO("C_DigestKey: rc = 0x%08lx, sess = %ld, key = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, hKey); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_DigestFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) +{ + SESSION *sess = NULL; + CK_BBOOL length_only = FALSE; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (sess->digest_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + if (!pDigest) + length_only = TRUE; + + rc = digest_mgr_digest_final(tokdata, sess, length_only, + &sess->digest_ctx, pDigest, pulDigestLen); + if (rc != CKR_OK) + TRACE_ERROR("digest_mgr_digest_final() failed.\n"); + +done: + TRACE_INFO("C_DigestFinal: rc = 0x%08lx, sess = %ld\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_SignInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + rc = valid_mech(tokdata, pMechanism, CKF_SIGN); + if (rc != CKR_OK) + goto done; + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->sign_ctx.active == TRUE) { + rc = CKR_OPERATION_ACTIVE; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + goto done; + } + + rc = icsftok_sign_init(tokdata, sess, pMechanism, hKey); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_sign_init() failed.\n"); + +done: + TRACE_INFO("C_SignInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)-1)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Sign(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG_PTR pulSignatureLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pData || !pulSignatureLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (sess->sign_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + rc = icsftok_sign(tokdata, sess, pData, ulDataLen, pSignature, + pulSignatureLen); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_sign() failed.\n"); + +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || pSignature)) + sign_mgr_cleanup(&sess->sign_ctx); + + TRACE_INFO("C_Sign: rc = 0x%08lx, sess = %ld, datalen = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulDataLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_SignUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pPart && ulPartLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (sess->sign_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + rc = icsftok_sign_update(tokdata, sess, pPart, ulPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_sign_update() failed.\n"); +done: + if (rc != CKR_OK) + sign_mgr_cleanup(&sess->sign_ctx); + + TRACE_INFO("C_SignUpdate: rc = 0x%08lx, sess = %ld, datalen = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_SignFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pulSignatureLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (sess->sign_ctx.active == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + rc = CKR_OPERATION_NOT_INITIALIZED; + goto done; + } + + rc = icsftok_sign_final(tokdata, sess, pSignature, pulSignatureLen); + if (rc != CKR_OK) + TRACE_ERROR("icsftok_sign_final() failed.\n"); + +done: + if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || pSignature)) + sign_mgr_cleanup(&sess->sign_ctx); + + TRACE_INFO("C_SignFinal: rc = 0x%08lx, sess = %ld\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_SignRecoverInit(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + UNUSED(sSession); + UNUSED(pMechanism); + UNUSED(hKey); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV SC_SignRecover(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pData, CK_ULONG ulDataLen, + CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) +{ + UNUSED(sSession); + UNUSED(pData); + UNUSED(ulDataLen); + UNUSED(pSignature); + UNUSED(pulSignatureLen); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV SC_VerifyInit(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + if (!pMechanism) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_VERIFY); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + if (sess->verify_ctx.active == TRUE) { + rc = CKR_OPERATION_ACTIVE; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE)); + goto done; + } + + rc = icsftok_verify_init(tokdata, sess, pMechanism, hKey); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_verify_init() failed.\n"); + +done: + TRACE_INFO("C_VerifyInit: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)-1)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_Verify(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, + CK_ULONG ulSignatureLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pData || !pSignature) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (sess->verify_ctx.active == FALSE) { + rc = CKR_OPERATION_NOT_INITIALIZED; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + goto done; + } + + rc = icsftok_verify(tokdata, sess, pData, ulDataLen, pSignature, + ulSignatureLen); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_verify() failed.\n"); + +done: + verify_mgr_cleanup(&sess->verify_ctx); + + TRACE_INFO("C_Verify: rc = 0x%08lx, sess = %ld, datalen = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulDataLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_VerifyUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pPart, CK_ULONG ulPartLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pPart && ulPartLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (sess->verify_ctx.active == FALSE) { + rc = CKR_OPERATION_NOT_INITIALIZED; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + goto done; + } + + rc = icsftok_verify_update(tokdata, sess, pPart, ulPartLen); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_verify_update() failed.\n"); + +done: + if (rc != CKR_OK) + verify_mgr_cleanup(&sess->verify_ctx); + + TRACE_INFO("C_VerifyUpdate: rc = 0x%08lx, sess = %ld, datalen = %lu\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_VerifyFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pSignature) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (sess->verify_ctx.active == FALSE) { + rc = CKR_OPERATION_NOT_INITIALIZED; + TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); + goto done; + } + + rc = icsftok_verify_final(tokdata, sess, pSignature, ulSignatureLen); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_verify_final() failed.\n"); + +done: + verify_mgr_cleanup(&sess->verify_ctx); + + TRACE_INFO("C_VerifyFinal: rc = 0x%08lx, sess = %ld\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_VerifyRecoverInit(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + UNUSED(sSession); + UNUSED(pMechanism); + UNUSED(hKey); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV SC_VerifyRecover(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen, + CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) +{ + UNUSED(sSession); + UNUSED(pSignature); + UNUSED(ulSignatureLen); + UNUSED(pData); + UNUSED(pulDataLen); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV SC_DigestEncryptUpdate(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, CK_BYTE_PTR pPart, + CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen) +{ + UNUSED(sSession); + UNUSED(pPart); + UNUSED(ulPartLen); + UNUSED(pEncryptedPart); + UNUSED(pulEncryptedPartLen); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV SC_DecryptDigestUpdate(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, + CK_ULONG_PTR pulPartLen) +{ + UNUSED(sSession); + UNUSED(pEncryptedPart); + UNUSED(ulEncryptedPartLen); + UNUSED(pPart); + UNUSED(pulPartLen); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV SC_SignEncryptUpdate(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, CK_BYTE_PTR pPart, + CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, + CK_ULONG_PTR pulEncryptedPartLen) +{ + UNUSED(sSession); + UNUSED(pPart); + UNUSED(ulPartLen); + UNUSED(pEncryptedPart); + UNUSED(pulEncryptedPartLen); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV SC_DecryptVerifyUpdate(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pEncryptedPart, + CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, + CK_ULONG_PTR pulPartLen) +{ + UNUSED(sSession); + UNUSED(pEncryptedPart); + UNUSED(ulEncryptedPartLen); + UNUSED(pPart); + UNUSED(pulPartLen); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_SUPPORTED)); + + return CKR_FUNCTION_NOT_SUPPORTED; +} + + +CK_RV SC_GenerateKey(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism || !phKey || (pTemplate == NULL && ulCount != 0)) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_GENERATE); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = icsftok_generate_key(tokdata, sess, pMechanism, pTemplate, + ulCount, phKey); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_generate_key() failed.\n"); + +done: + TRACE_INFO("C_GenerateKey: rc = %08lx, sess = %ld, mech = %lu\n", rc, + (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)(-1))); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_ULONG i; + + attr = pTemplate; + if (attr != NULL) { + for (i = 0; i < ulCount; i++, attr++) { + CK_BYTE *ptr = (CK_BYTE *) attr->pValue; + TRACE_DEBUG("%lu: Attribute type: 0x%08lx,Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + if (attr->ulValueLen != ((CK_ULONG) - 1) && (ptr != NULL)) { + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } + } + } else { + TRACE_DEBUG("No attributes\n"); + } +#endif + + return rc; +} + + +CK_RV SC_GenerateKeyPair(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, + CK_ATTRIBUTE_PTR pPublicKeyTemplate, + CK_ULONG ulPublicKeyAttributeCount, + CK_ATTRIBUTE_PTR pPrivateKeyTemplate, + CK_ULONG ulPrivateKeyAttributeCount, + CK_OBJECT_HANDLE_PTR phPublicKey, + CK_OBJECT_HANDLE_PTR phPrivateKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism || !phPublicKey || !phPrivateKey || + (!pPublicKeyTemplate && (ulPublicKeyAttributeCount != 0)) || + (!pPrivateKeyTemplate && (ulPrivateKeyAttributeCount != 0))) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_GENERATE_KEY_PAIR); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = icsftok_generate_key_pair(tokdata, sess, pMechanism, + pPublicKeyTemplate, + ulPublicKeyAttributeCount, + pPrivateKeyTemplate, + ulPrivateKeyAttributeCount, + phPublicKey, phPrivateKey); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_generate_key_pair() failed.\n"); +done: + TRACE_INFO("C_GenerateKeyPair: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : ((CK_LONG) sess->handle), + (pMechanism ? pMechanism->mechanism : (CK_ULONG)-1)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_ULONG i; + + if (rc == CKR_OK) { + TRACE_DEBUG("Public handle: %lu, Private handle: %lu\n", + *phPublicKey, *phPrivateKey); + } + + TRACE_DEBUG("Public Template:\n"); + attr = pPublicKeyTemplate; + if (attr != NULL) { + for (i = 0; i < ulPublicKeyAttributeCount; i++, attr++) { + CK_BYTE *ptr = (CK_BYTE *) attr->pValue; + TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + if (attr->ulValueLen != ((CK_ULONG) - 1) && (ptr != NULL)) + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } + } else { + TRACE_DEBUG("No Attributes\n"); + } + + TRACE_DEBUG("Private Template:\n"); + attr = pPublicKeyTemplate; + if (attr != NULL) { + for (i = 0; i < ulPublicKeyAttributeCount; i++, attr++) { + CK_BYTE *ptr = (CK_BYTE *) attr->pValue; + TRACE_DEBUG("%lu: Attribute type: 0x%08lx, Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + if (attr->ulValueLen != (CK_ULONG) (-1) && (ptr != NULL)) + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } + } else { + TRACE_DEBUG("No Attributes\n"); + } +#endif + + return rc; +} + + +CK_RV SC_WrapKey(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey, + CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey, + CK_ULONG_PTR pulWrappedKeyLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism || !pulWrappedKeyLen) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_WRAP); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = icsftok_wrap_key(tokdata, sess, pMechanism, hWrappingKey, hKey, + pWrappedKey, pulWrappedKeyLen); + if (rc != CKR_OK) + TRACE_DEVEL("*_wrap_key() failed.\n"); + +done: + TRACE_INFO("C_WrapKey: rc = 0x%08lx, sess = %ld, encrypting key = %lu, " + "wrapped key = %lu\n", rc, + (sess == NULL) ? -1 : (CK_LONG) sess->handle, + hWrappingKey, hKey); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_UnwrapKey(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey, + CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism || !pWrappedKey || (!pTemplate && ulCount != 0) || !phKey) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_UNWRAP); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = icsftok_unwrap_key(tokdata, sess, pMechanism, pTemplate, ulCount, + pWrappedKey, ulWrappedKeyLen, hUnwrappingKey, + phKey); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_unwrap_key() failed.\n"); + +done: + TRACE_INFO("C_UnwrapKey: rc = 0x%08lx, sess = %ld, decrypting key = %lu," + "unwrapped key = %lu\n", rc, + (sess == NULL) ? -1 : (CK_LONG) sess->handle, + hUnwrappingKey, (phKey ? *phKey : 0)); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *ptr = NULL; + CK_ULONG i; + + attr = pTemplate; + if (attr != NULL) { + for (i = 0; i < ulCount; i++, attr++) { + ptr = (CK_BYTE *) attr->pValue; + TRACE_DEBUG("%lu: Attribute type: 0x%08lx,Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + if (attr->ulValueLen != ((CK_ULONG) - 1) && (ptr != NULL)) { + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } + } + } else { + TRACE_DEBUG("No attributes\n"); + } +#endif + + return rc; +} + + +CK_RV SC_DeriveKey(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phKey) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pMechanism || (!pTemplate && ulCount != 0)) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + if (pMechanism->mechanism != CKM_SSL3_KEY_AND_MAC_DERIVE && !phKey) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = valid_mech(tokdata, pMechanism, CKF_DERIVE); + if (rc != CKR_OK) + goto done; + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + if (pin_expired(&sess->session_info, + tokdata->nv_token_data->token_info.flags) == TRUE) { + TRACE_ERROR("%s\n", ock_err(ERR_PIN_EXPIRED)); + rc = CKR_PIN_EXPIRED; + goto done; + } + + rc = icsftok_derive_key(tokdata, sess, pMechanism, hBaseKey, phKey, + pTemplate, ulCount); + if (rc != CKR_OK) + TRACE_DEVEL("icsftok_derive_key() failed.\n"); + +done: + TRACE_INFO("C_DeriveKey: rc = 0x%08lx, sess = %ld, mech = 0x%lx\n", + rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, + (pMechanism ? pMechanism->mechanism : (CK_ULONG)(-1))); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + +#ifdef DEBUG + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *ptr = NULL; + CK_ULONG i; + + if (rc == CKR_OK) { + switch (pMechanism->mechanism) { + case CKM_SSL3_KEY_AND_MAC_DERIVE: + { + CK_SSL3_KEY_MAT_PARAMS *pReq; + CK_SSL3_KEY_MAT_OUT *pPtr; + pReq = (CK_SSL3_KEY_MAT_PARAMS *) pMechanism->pParameter; + pPtr = pReq->pReturnedKeyMaterial; + + TRACE_DEBUG("Client MAC key: %lu, Server MAC key: %lu, " + "Client Key: %lu, Server Key: %lu\n", + pPtr->hClientMacSecret, + pPtr->hServerMacSecret, pPtr->hClientKey, + pPtr->hServerKey); + } + break; + case CKM_DH_PKCS_DERIVE: + TRACE_DEBUG("DH Shared Secret:\n"); + break; + default: + TRACE_DEBUG("Derived key: %lu\n", *phKey); + } + } + + attr = pTemplate; + if (attr != NULL) { + for (i = 0; i < ulCount; i++, attr++) { + ptr = (CK_BYTE *) attr->pValue; + TRACE_DEBUG("%lu: Attribute type: 0x%08lx,Value Length: %lu\n", + i, attr->type, attr->ulValueLen); + if (attr->ulValueLen != ((CK_ULONG) - 1) && (ptr != NULL)) { + TRACE_DEBUG("First 4 bytes: %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + } + } + } else { + TRACE_DEBUG("No attributes\n"); + } +#endif /* DEBUG */ + return rc; +} + + +CK_RV SC_SeedRandom(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen) +{ + UNUSED(sSession); + UNUSED(pSeed); + UNUSED(ulSeedLen); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_RANDOM_SEED_NOT_SUPPORTED)); + + return CKR_RANDOM_SEED_NOT_SUPPORTED; +} + + +CK_RV SC_GenerateRandom(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, + CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen) +{ + SESSION *sess = NULL; + CK_RV rc = CKR_OK; + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + rc = CKR_CRYPTOKI_NOT_INITIALIZED; + goto done; + } + + if (!pRandomData && ulRandomLen != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + sess = session_mgr_find(tokdata, sSession->sessionh); + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + rc = CKR_SESSION_HANDLE_INVALID; + goto done; + } + //set the handle into the session. + sess->handle = sSession->sessionh; + + rc = rng_generate(tokdata, pRandomData, ulRandomLen); + if (rc != CKR_OK) + TRACE_DEVEL("rng_generate() failed.\n"); + +done: + TRACE_INFO("C_GenerateRandom: rc = 0x%08lx, %lu bytes\n", rc, ulRandomLen); + + if (sess != NULL) + session_mgr_put(tokdata, sess); + + return rc; +} + + +CK_RV SC_GetFunctionStatus(STDLL_TokData_t *tokdata, + ST_SESSION_HANDLE *sSession) +{ + UNUSED(sSession); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_PARALLEL)); + + return CKR_FUNCTION_NOT_PARALLEL; +} + + +CK_RV SC_CancelFunction(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession) +{ + UNUSED(sSession); + + if (tokdata->initialized == FALSE) { + TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); + return CKR_CRYPTOKI_NOT_INITIALIZED; + } + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_NOT_PARALLEL)); + + return CKR_FUNCTION_NOT_PARALLEL; +} + + +void SC_SetFunctionList(void) +{ + function_list.ST_Initialize = ST_Initialize; + function_list.ST_GetTokenInfo = SC_GetTokenInfo; + function_list.ST_GetMechanismList = SC_GetMechanismList; + function_list.ST_GetMechanismInfo = SC_GetMechanismInfo; + function_list.ST_InitToken = SC_InitToken; + function_list.ST_InitPIN = SC_InitPIN; + function_list.ST_SetPIN = SC_SetPIN; + function_list.ST_OpenSession = SC_OpenSession; + function_list.ST_CloseSession = SC_CloseSession; + function_list.ST_GetSessionInfo = SC_GetSessionInfo; + function_list.ST_GetOperationState = SC_GetOperationState; + function_list.ST_SetOperationState = SC_SetOperationState; + function_list.ST_Login = SC_Login; + function_list.ST_Logout = SC_Logout; + function_list.ST_CreateObject = SC_CreateObject; + function_list.ST_CopyObject = SC_CopyObject; + function_list.ST_DestroyObject = SC_DestroyObject; + function_list.ST_GetObjectSize = SC_GetObjectSize; + function_list.ST_GetAttributeValue = SC_GetAttributeValue; + function_list.ST_SetAttributeValue = SC_SetAttributeValue; + function_list.ST_FindObjectsInit = SC_FindObjectsInit; + function_list.ST_FindObjects = SC_FindObjects; + function_list.ST_FindObjectsFinal = SC_FindObjectsFinal; + function_list.ST_EncryptInit = SC_EncryptInit; + function_list.ST_Encrypt = SC_Encrypt; + function_list.ST_EncryptUpdate = SC_EncryptUpdate; + function_list.ST_EncryptFinal = SC_EncryptFinal; + function_list.ST_DecryptInit = SC_DecryptInit; + function_list.ST_Decrypt = SC_Decrypt; + function_list.ST_DecryptUpdate = SC_DecryptUpdate; + function_list.ST_DecryptFinal = SC_DecryptFinal; + function_list.ST_DigestInit = SC_DigestInit; + function_list.ST_Digest = SC_Digest; + function_list.ST_DigestUpdate = SC_DigestUpdate; + function_list.ST_DigestKey = SC_DigestKey; + function_list.ST_DigestFinal = SC_DigestFinal; + function_list.ST_SignInit = SC_SignInit; + function_list.ST_Sign = SC_Sign; + function_list.ST_SignUpdate = SC_SignUpdate; + function_list.ST_SignFinal = SC_SignFinal; + function_list.ST_SignRecoverInit = SC_SignRecoverInit; + function_list.ST_SignRecover = SC_SignRecover; + function_list.ST_VerifyInit = SC_VerifyInit; + function_list.ST_Verify = SC_Verify; + function_list.ST_VerifyUpdate = SC_VerifyUpdate; + function_list.ST_VerifyFinal = SC_VerifyFinal; + function_list.ST_VerifyRecoverInit = SC_VerifyRecoverInit; + function_list.ST_VerifyRecover = SC_VerifyRecover; + function_list.ST_DigestEncryptUpdate = NULL; // SC_DigestEncryptUpdate; + function_list.ST_DecryptDigestUpdate = NULL; // SC_DecryptDigestUpdate; + function_list.ST_SignEncryptUpdate = NULL; //SC_SignEncryptUpdate; + function_list.ST_DecryptVerifyUpdate = NULL; // SC_DecryptVerifyUpdate; + function_list.ST_GenerateKey = SC_GenerateKey; + function_list.ST_GenerateKeyPair = SC_GenerateKeyPair; + function_list.ST_WrapKey = SC_WrapKey; + function_list.ST_UnwrapKey = SC_UnwrapKey; + function_list.ST_DeriveKey = SC_DeriveKey; + function_list.ST_SeedRandom = SC_SeedRandom; + function_list.ST_GenerateRandom = SC_GenerateRandom; + function_list.ST_GetFunctionStatus = NULL; // SC_GetFunctionStatus; + function_list.ST_CancelFunction = NULL; // SC_CancelFunction; +} diff --git a/usr/lib/icsf_stdll/pbkdf.c b/usr/lib/icsf_stdll/pbkdf.c new file mode 100644 index 0000000..4ddd0fd --- /dev/null +++ b/usr/lib/icsf_stdll/pbkdf.c @@ -0,0 +1,541 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2013-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 + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "pbkdf.h" +#include "trace.h" + + +CK_RV get_randombytes(unsigned char *output, int bytes) +{ + int ranfd; + int rlen; + int totallen = 0; + + ranfd = open("/dev/urandom", O_RDONLY); + if (ranfd >= 0) { + do { + rlen = read(ranfd, output + totallen, bytes - totallen); + if (rlen == -1) { + close(ranfd); + TRACE_ERROR("read failed: %s\n", strerror(errno)); + return CKR_FUNCTION_FAILED; + } + totallen += rlen; + } while (totallen < bytes); + close(ranfd); + return CKR_OK; + } + + return CKR_FUNCTION_FAILED; +} + +CK_RV set_perms(int file) +{ + struct group *grp; + + if (fchmod(file, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) != 0) { + TRACE_ERROR("fchmod failed: %s\n", strerror(errno)); + return CKR_FUNCTION_FAILED; + } + + grp = getgrnam("pkcs11"); + if (grp) { + if (fchown(file, -1, grp->gr_gid) != 0) { + TRACE_ERROR("fchown failed: %s\n", strerror(errno)); + return CKR_FUNCTION_FAILED; + } + } else { + TRACE_ERROR("getgrnam failed:%s\n", strerror(errno)); + return CKR_FUNCTION_FAILED; + } + + return CKR_OK; +} + +CK_RV encrypt_aes(CK_BYTE * inbuf, int inbuflen, CK_BYTE * dkey, + CK_BYTE * iv, CK_BYTE * outbuf, int *outbuflen) +{ + const EVP_CIPHER *cipher = EVP_aes_256_cbc(); + int tmplen; + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + + EVP_EncryptInit_ex(ctx, cipher, NULL, dkey, iv); + if (!EVP_EncryptUpdate(ctx, outbuf, outbuflen, inbuf, inbuflen)) { + TRACE_ERROR("EVP_EncryptUpdate failed.\n"); + return CKR_FUNCTION_FAILED; + } + if (!EVP_EncryptFinal_ex(ctx, outbuf + (*outbuflen), &tmplen)) { + TRACE_ERROR("EVP_EncryptFinal failed.\n"); + return CKR_FUNCTION_FAILED; + } + + *outbuflen = (*outbuflen) + tmplen; + EVP_CIPHER_CTX_free(ctx); + +#else + EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX_init(&ctx); + + EVP_EncryptInit_ex(&ctx, cipher, NULL, dkey, iv); + if (!EVP_EncryptUpdate(&ctx, outbuf, outbuflen, inbuf, inbuflen)) { + TRACE_ERROR("EVP_EncryptUpdate failed.\n"); + return CKR_FUNCTION_FAILED; + } + if (!EVP_EncryptFinal_ex(&ctx, outbuf + (*outbuflen), &tmplen)) { + TRACE_ERROR("EVP_EncryptFinal failed.\n"); + return CKR_FUNCTION_FAILED; + } + + *outbuflen = (*outbuflen) + tmplen; + EVP_CIPHER_CTX_cleanup(&ctx); +#endif + + return CKR_OK; +} + +CK_RV decrypt_aes(CK_BYTE * inbuf, int inbuflen, CK_BYTE * dkey, + CK_BYTE * iv, CK_BYTE * outbuf, int *outbuflen) +{ + int size; + const EVP_CIPHER *cipher = EVP_aes_256_cbc(); + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + + EVP_DecryptInit_ex(ctx, cipher, NULL, dkey, iv); + if (!EVP_DecryptUpdate(ctx, outbuf, outbuflen, inbuf, inbuflen)) { + TRACE_ERROR("EVP_DecryptUpdate failed.\n"); + return CKR_FUNCTION_FAILED; + } + if (!EVP_DecryptFinal_ex(ctx, outbuf + (*outbuflen), &size)) { + TRACE_ERROR("EVP_DecryptFinal failed.\n"); + return CKR_FUNCTION_FAILED; + } + + /* total length of the decrypted data */ + *outbuflen = (*outbuflen) + size; + + /* EVP_DecryptFinal removes any padding. The final length + * is the length of the decrypted data without padding. + */ + + EVP_CIPHER_CTX_free(ctx); + +#else + EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX_init(&ctx); + + EVP_DecryptInit_ex(&ctx, cipher, NULL, dkey, iv); + if (!EVP_DecryptUpdate(&ctx, outbuf, outbuflen, inbuf, inbuflen)) { + TRACE_ERROR("EVP_DecryptUpdate failed.\n"); + return CKR_FUNCTION_FAILED; + } + if (!EVP_DecryptFinal_ex(&ctx, outbuf + (*outbuflen), &size)) { + TRACE_ERROR("EVP_DecryptFinal failed.\n"); + return CKR_FUNCTION_FAILED; + } + + /* total length of the decrypted data */ + *outbuflen = (*outbuflen) + size; + + /* EVP_DecryptFinal removes any padding. The final length + * is the length of the decrypted data without padding. + */ + + EVP_CIPHER_CTX_cleanup(&ctx); +#endif + + return CKR_OK; +} + +CK_RV get_masterkey(CK_BYTE *pin, CK_ULONG pinlen, const char *fname, + CK_BYTE *masterkey, int *len) +{ + struct stat statbuf; + FILE *fp; + CK_ULONG_32 totallen, datasize, readsize; + int dkeysize; + CK_BYTE salt[SALTSIZE]; + CK_BYTE dkey[AES_KEY_SIZE_256]; + CK_BYTE outbuf[ENCRYPT_SIZE]; + CK_RV rc = CKR_OK; + size_t ret; + + /* see if the file exists */ + if ((stat(fname, &statbuf) < 0) && (errno == ENOENT)) { + TRACE_ERROR("stat() failed: File does not exist.\n"); + return CKR_FUNCTION_FAILED; + } + + /* open the file */ + fp = fopen(fname, "r"); + if (fp == NULL) { + TRACE_ERROR("fopen failed\n"); + return CKR_FUNCTION_FAILED; + } + + ret = fread(&totallen, sizeof(CK_ULONG_32), 1, fp); + if (ret != 1) { + fclose(fp); + TRACE_ERROR("fread failed.\n"); + return CKR_FUNCTION_FAILED; + } + + ret = fread(salt, SALTSIZE, 1, fp); + if (ret != 1) { + fclose(fp); + TRACE_ERROR("fread failed.\n"); + return CKR_FUNCTION_FAILED; + } + + /* get length of encryted data */ + datasize = totallen - SALTSIZE; + readsize = fread(outbuf, datasize, 1, fp); + if (readsize != 1) { + TRACE_ERROR("Could not get encrypted data in %s.\n", fname); + fclose(fp); + return CKR_FUNCTION_FAILED; + } + + fclose(fp); + + /* now derive the key using the salt and PIN */ + dkeysize = AES_KEY_SIZE_256; + rc = pbkdf(pin, pinlen, salt, dkey, dkeysize); + if (rc != CKR_OK) { + TRACE_DEBUG("pbkdf(): Failed to derive a key.\n"); + return CKR_FUNCTION_FAILED; + } + + /* decrypt the masterkey */ + /* re-use salt for iv */ + rc = decrypt_aes(outbuf, datasize, dkey, salt, masterkey, len); + if (rc != CKR_OK) { + TRACE_DEBUG("Failed to decrypt the racf pwd.\n"); + return CKR_FUNCTION_FAILED; + } + + /* make sure len is equal to our masterkey size. */ + if (*len != AES_KEY_SIZE_256) { + TRACE_ERROR("Decrypted key is invalid.\n"); + return CKR_FUNCTION_FAILED; + } + + return rc; +} + +CK_RV get_racf(CK_BYTE * masterkey, CK_ULONG mklen, CK_BYTE * racfpwd, + int *racflen) +{ + struct stat statbuf; + CK_BYTE outbuf[ENCRYPT_SIZE]; + CK_BYTE iv[AES_INIT_VECTOR_SIZE]; + int len, datasize, readsize; + FILE *fp; + CK_RV rc; + + UNUSED(mklen); + + /* see if the file exists ... */ + if ((stat(RACFFILE, &statbuf) < 0) && (errno == ENOENT)) { + TRACE_ERROR("File does not exist.\n"); + return CKR_FUNCTION_FAILED; + } + + /* if file exists, open it */ + fp = fopen(RACFFILE, "r"); + if (fp == NULL) { + TRACE_ERROR("fopen failed\n"); + return CKR_FUNCTION_FAILED; + } + + readsize = fread(&len, sizeof(CK_ULONG_32), 1, fp); + if (readsize != 1) { + TRACE_ERROR("fread failed\n"); + fclose(fp); + return CKR_FUNCTION_FAILED; + } + + readsize = fread(iv, AES_INIT_VECTOR_SIZE, 1, fp); + if (readsize != 1) { + TRACE_ERROR("fread failed\n"); + fclose(fp); + return CKR_FUNCTION_FAILED; + } + + /* get length of encryted data */ + datasize = len - AES_INIT_VECTOR_SIZE; + readsize = fread(outbuf, datasize, 1, fp); + if (readsize != 1) { + TRACE_ERROR("Could not get encrypted data in %s.\n", RACFFILE); + fclose(fp); + return CKR_FUNCTION_FAILED; + } + fclose(fp); + + /* decrypt the data using the masterkey */ + rc = decrypt_aes(outbuf, datasize, masterkey, iv, racfpwd, racflen); + + /* terminate the decrypted string. */ + memset(racfpwd + (*racflen), 0, 1); + + if (rc != CKR_OK) { + TRACE_DEBUG("Failed to decrypt the racf pwd.\n"); + return CKR_FUNCTION_FAILED; + } + + return CKR_OK; +} + +CK_RV pbkdf(CK_BYTE * password, CK_ULONG len, CK_BYTE * salt, CK_BYTE * dkey, + CK_ULONG klen) +{ + + unsigned char hash[SHA256_HASH_SIZE]; + unsigned char hash_block[SHA256_HASH_SIZE]; + unsigned char *result; + unsigned int r, num_of_blocks; + unsigned int count, hashlen; + CK_ULONG rc = CKR_OK; + unsigned int i, j; + int k; + + /* check inputs */ + if (!password || !salt) { + TRACE_ERROR("Invalid function argument(s).\n"); + return CKR_FUNCTION_FAILED; + } + + /* check length of key.. for now only 32 byte keys */ + if (klen != DKEYLEN) { + TRACE_ERROR("Only support 32 byte keys.\n"); + return CKR_FUNCTION_FAILED; + } + + /* SP 800-132 recommends a minimum iteration count of 1000. + * so lets try that for now... + */ + count = 1000; + + hashlen = SHA256_HASH_SIZE; + + /* Calculate amount of blocks in klen. + * SP 800-132: len = [kLen / hLen] (rounded up). + * r = kLen - (len - 1) * hLen; + */ + if (klen < SHA256_HASH_SIZE) { + num_of_blocks = 1; + r = klen; + } else { + num_of_blocks = klen / SHA256_HASH_SIZE; + /* round up by adding another block if there is a modulus */ + if ((klen % SHA256_HASH_SIZE) != 0) + num_of_blocks++; + r = klen - (num_of_blocks - 1) * SHA256_HASH_SIZE; + } + + /* SP 800-132: For i = 1 to len */ + for (i = 1; i <= num_of_blocks; i++) { + + /* SP 800-132: Ti = 0; */ + memset(hash_block, 0, SHA256_HASH_SIZE); + + /* SP 800-132: U0 = S || Int(i); */ + memset(hash, 0, SHA256_HASH_SIZE); + memcpy(hash, salt, SALTSIZE); + hash[SALTSIZE] = i; + hashlen = SALTSIZE + 1; + + /* SP 800-132: For j = 1 to C */ + for (j = 1; j <= count; j++) { + /* SP 800-132: Uj = HMAC(P, U(j-1)); */ + result = + HMAC(EVP_sha256(), password, len, hash, hashlen, NULL, NULL); + if (result == NULL) { + TRACE_ERROR("Failed to compute the hmac.\n"); + rc = CKR_FUNCTION_FAILED; + goto out; + } + + /* SP 800-132: Ti = Ti Exclusive_OR Uj; */ + for (k = 0; k < SHA256_HASH_SIZE; k++) + hash_block[k] ^= hash[k]; + + /* prep U(j-1) for next iteration */ + memcpy(hash, result, SHA256_HASH_SIZE); + hashlen = SHA256_HASH_SIZE; + } + + /* SP 800-132: derived_key = + * hash_block(1)||hash_block(2)||hash_block(num_of_blocks)<0...r-1> + * This means num_of_blocks are needed to concatencate + * together to make the derived key. + * However, if the derived key length is not a multiple of the + * HASH_SIZE, then we only need some of the data in the last hash_block. + * So, if there is an r, then only copy r bytes from last hash_block + * to the derived_key. + */ + if ((i == num_of_blocks) && (r != 0)) + memcpy(dkey, hash_block, r); + else + memcpy(dkey, hash_block, SHA256_HASH_SIZE); + + } + +out: + return rc; +} + +CK_RV secure_racf(CK_BYTE * racf, CK_ULONG racflen, CK_BYTE * key, + CK_ULONG keylen) +{ + CK_RV rc = CKR_OK; + CK_BYTE iv[AES_INIT_VECTOR_SIZE]; + FILE *fp; + CK_BYTE output[ENCRYPT_SIZE]; + CK_ULONG_32 totallen; + int outputlen; + + UNUSED(keylen); + + /* generate an iv... */ + if ((get_randombytes(iv, AES_INIT_VECTOR_SIZE)) != CKR_OK) { + TRACE_DEBUG("Could not generate an iv.\n"); + return CKR_FUNCTION_FAILED; + } + + /* encrypt the racf passwd using the masterkey */ + rc = encrypt_aes(racf, racflen, key, iv, output, &outputlen); + if (rc != 0) { + TRACE_DEBUG("Failed to encrypt racf pwd.\n"); + return CKR_FUNCTION_FAILED; + } + + /* store the following in the RACF file: + * 1. total length = v + encrypted data + * 2. iv + * 3. encrypted data + */ + + /* get the total length */ + totallen = outputlen + AES_INIT_VECTOR_SIZE; + + fp = fopen(RACFFILE, "w"); + if (!fp) { + TRACE_ERROR("fopen failed: %s\n", strerror(errno)); + return CKR_FUNCTION_FAILED; + } + + /* set permisions on the file */ + rc = set_perms(fileno(fp)); + if (rc != 0) { + TRACE_ERROR("Failed to set permissions on RACF file.\n"); + fclose(fp); + return CKR_FUNCTION_FAILED; + } + + /* write the info to the file */ + (void) fwrite(&totallen, sizeof(CK_ULONG_32), 1, fp); + (void) fwrite(iv, AES_INIT_VECTOR_SIZE, 1, fp); + (void) fwrite(output, outputlen, 1, fp); + + fclose(fp); + + return rc; +} + +CK_RV secure_masterkey(CK_BYTE * masterkey, CK_ULONG len, CK_BYTE * pin, + CK_ULONG pinlen, const char *fname) +{ + CK_RV rc = CKR_OK; + CK_BYTE salt[SALTSIZE]; + CK_BYTE dkey[AES_KEY_SIZE_256]; + CK_ULONG_32 totallen, dkey_size; + int outputlen; + CK_BYTE output[ENCRYPT_SIZE]; + FILE *fp; + + memset(salt, 0, SALTSIZE); + memset(dkey, 0, AES_KEY_SIZE_256); + dkey_size = AES_KEY_SIZE_256; + + /* get a salt for the password based key derivation function. */ + if ((get_randombytes(salt, SALTSIZE)) != CKR_OK) { + TRACE_DEBUG("Could not get a salt for pbkdf.\n"); + return CKR_FUNCTION_FAILED; + } + + /* get a 32 byte key */ + rc = pbkdf(pin, pinlen, salt, dkey, dkey_size); + if (rc != 0) { + TRACE_DEBUG("Failed to derive a key for encryption.\n"); + return CKR_FUNCTION_FAILED; + } + + /* encrypt the masterkey using the derived key */ + /* re-use the salt for the iv... */ + rc = encrypt_aes(masterkey, len, dkey, salt, output, &outputlen); + if (rc != 0) { + TRACE_DEBUG("Failed to encrypt masterkey.\n"); + return CKR_FUNCTION_FAILED; + } + + /* write the encrypted masterkey to named file */ + /* store the following: + * 1. total length = salt + encrypted data + * 2. salt (always SALTSIZE) + * 3. encrypted data + */ + + /* get the total length */ + totallen = outputlen + SALTSIZE; + + fp = fopen(fname, "w"); + if (!fp) { + TRACE_ERROR("fopen failed: %s\n", strerror(errno)); + return CKR_FUNCTION_FAILED; + } + + /* set permisions on the file */ + rc = set_perms(fileno(fp)); + if (rc != 0) { + TRACE_ERROR("Failed to set permissions on encrypted file.\n"); + fclose(fp); + return CKR_FUNCTION_FAILED; + } + + /* write the info to the file */ + (void) fwrite(&totallen, sizeof(CK_ULONG_32), 1, fp); + (void) fwrite(salt, SALTSIZE, 1, fp); + (void) fwrite(output, outputlen, 1, fp); + + fclose(fp); + + return rc; +} diff --git a/usr/lib/icsf_stdll/pbkdf.h b/usr/lib/icsf_stdll/pbkdf.h new file mode 100644 index 0000000..f910882 --- /dev/null +++ b/usr/lib/icsf_stdll/pbkdf.h @@ -0,0 +1,51 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2012-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 + */ + +/* + * OpenCryptoki ICSF token - LDAP functions + * + * Author: Joy Latten (jmlatten@linux.vnet.ibm.com) + * + */ + +#ifndef PBKDF_H +#define PBKDF_H + +#define SALTSIZE 16 // salt is 16 bytes +#define DKEYLEN 32 // 256 bytes is max key size to be derived +#define PIN_SIZE 80 // samedefine in pkcsconf +#define ENCRYPT_SIZE 96 // PIN_SIZE + AES_BLOCK_SIZE (for padding) + +#define ICSF_CONFIG_PATH CONFIG_PATH "/icsf" +#define RACFFILE ICSF_CONFIG_PATH "/RACF" + +CK_RV get_randombytes(unsigned char *output, int bytes); + +CK_RV encrypt_aes(CK_BYTE * racfpwd, int racflen, CK_BYTE * dkey, + CK_BYTE * iv, CK_BYTE * outbuf, int *outbuflen); + +CK_RV decrypt_aes(CK_BYTE * edata, int edatalen, CK_BYTE * dkey, + CK_BYTE * iv, CK_BYTE * ddata, int *ddatalen); + +CK_RV get_racf(CK_BYTE * mk, CK_ULONG mklen, CK_BYTE * racfpwd, int *racflen); + +CK_RV get_masterkey(CK_BYTE *pin, CK_ULONG pinlen, const char *fname, + CK_BYTE *masterkey, int *len); + +CK_RV pbkdf(CK_BYTE * passwd, CK_ULONG passwdlen, CK_BYTE * salt, + CK_BYTE * dkey, CK_ULONG klen); + +CK_RV secure_racf(CK_BYTE * racfpwd, CK_ULONG racflen, CK_BYTE * mk, + CK_ULONG mklen); + +CK_RV secure_masterkey(CK_BYTE * masterkey, CK_ULONG len, CK_BYTE * pin, + CK_ULONG pinlen, const char *fname); + +#endif diff --git a/usr/lib/icsf_stdll/tok_struct.h b/usr/lib/icsf_stdll/tok_struct.h new file mode 100644 index 0000000..af76845 --- /dev/null +++ b/usr/lib/icsf_stdll/tok_struct.h @@ -0,0 +1,130 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2013-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 + */ + +/* + * openCryptoki ICSF token + * + */ + +#ifndef __TOK_STRUCT_H +#define __TOK_STRUCT_H + +#include +#include "tok_spec_struct.h" + +#ifndef ICSF_CONFIG_PATH + +#ifndef CONFIG_PATH +#warning CONFIG_PATH not set, using default (/usr/local/var/lib/opencryptoki) +#define CONFIG_PATH "/usr/local/var/lib/opencryptoki" +#endif // #ifndef CONFIG_PATH + +#define ICSF_CONFIG_PATH CONFIG_PATH "/icsf" +#endif // #ifndef ICSF_CONFIG_PATH + +token_spec_t token_specific = { + ICSF_CONFIG_PATH, + "icsf", + // Key token size (0 is default) + 0, + // Token data info: + { + FALSE, // Don't use per guest data store + FALSE, // Don't use master key. Remaining fields are ignored + 0, // Data store encryption + NULL, // Default initialization vector for pins + NULL, // Default initialization vector for objects + }, + NULL, // creatlock + &token_specific_attach_shm, + NULL, + &token_specific_init_token_data, + &token_specific_load_token_data, + &token_specific_save_token_data, + NULL, // rng + NULL, // final + NULL, // init token + NULL, // login + NULL, // logout + NULL, // initpin + NULL, // setpin + // DES + NULL, // des_key_gen + NULL, // des_ecb + NULL, // des_cb + // Triple DES + NULL, // tdes_ecb + NULL, // tdes_cbc + NULL, // tdes_ofb + NULL, // tdes_cfb + NULL, // tdes_mac + NULL, // tdes_cmac + // RSA + NULL, // rsa_decrypt + NULL, // rsa_encrypt + NULL, // rsa_sign + NULL, // rsa_verify + NULL, // rsa_verify_recover + NULL, // rsa_x509_decrypt + NULL, // rsa_x509_encrypt + NULL, // rsa_x509_sign + NULL, // rsa_x509_verify + NULL, // rsa_x509_verify_recover + NULL, // rsa_oaep_decrypt + NULL, // rsa_oaep_encrypt + NULL, // rsa_pss_sign + NULL, // rsa_pss_verify + NULL, // rsa_generate_keypair + // Elliptic Curve + NULL, // ec_sign + NULL, // ec_verify + NULL, // ec_generate_keypair + NULL, // ecdh_derive + // DH + NULL, // dh_pkcs_derive + NULL, // dh_pkcs_key_pair_gen + // SHA + NULL, // sha_init + NULL, // sha + NULL, // sha_update + NULL, // sha_final + //HMAC + NULL, // hmac_sign_init + NULL, // hmac_sign + NULL, // hmac_sign_update + NULL, // hmac_sign_final + NULL, // hmac_verify_init + NULL, // hmac_verify + NULL, // hmac_verify_update + NULL, // hmac_verify_final + NULL, // generic_secret_key_gen + // AES + NULL, // aes_key_gen + NULL, // aes_ecb + NULL, // aes_cbc + NULL, // aes_ctr + NULL, // aes_gcm_init + NULL, // aes_gcm + NULL, // aes_gcm_update + NULL, // aes_gcm_final + NULL, // aes_ofb + NULL, // aes_cfb + NULL, // aes_mac + NULL, // aes_cmac + // DSA + NULL, // dsa_generate_keypair + NULL, // dsa_sign + NULL, // dsa_verify + NULL, // get_mechanism_list + NULL, // get_mechanism_info + NULL // object_add +}; + +#endif diff --git a/usr/lib/lib.mk b/usr/lib/lib.mk new file mode 100644 index 0000000..7bbf11b --- /dev/null +++ b/usr/lib/lib.mk @@ -0,0 +1,23 @@ +if ENABLE_LIBRARY +include usr/lib/api/api.mk +endif +if ENABLE_CCATOK +include usr/lib/cca_stdll/cca_stdll.mk +endif +if ENABLE_EP11TOK +include usr/lib/ep11_stdll/ep11_stdll.mk +endif +if ENABLE_ICATOK +include usr/lib/ica_s390_stdll/ica_s390_stdll.mk +endif +if ENABLE_SWTOK +include usr/lib/soft_stdll/soft_stdll.mk +endif +if ENABLE_TPMTOK +include usr/lib/tpm_stdll/tpm_stdll.mk +endif +if ENABLE_ICSFTOK +include usr/lib/icsf_stdll/icsf_stdll.mk +endif + +include usr/lib/common/common.mk diff --git a/usr/lib/soft_stdll/soft_specific.c b/usr/lib/soft_stdll/soft_specific.c new file mode 100644 index 0000000..f7cafab --- /dev/null +++ b/usr/lib/soft_stdll/soft_specific.c @@ -0,0 +1,3053 @@ +/* + * 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 + */ + +/*************************************************************************** + Change Log + ========== + 4/25/03 Kapil Sood (kapil@corrent.com) + Added DH key pair generation and DH shared key derivation + functions. + + + +****************************************************************************/ + +#include +#include // for memcmp() et al +#include +#include + +#include "pkcs11types.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "errno.h" +#include "tok_specific.h" +#include "tok_struct.h" +#include "trace.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * In order to make opencryptoki compatible with + * OpenSSL 1.1 API Changes and backward compatible + * we need to check for its version + */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#define OLDER_OPENSSL +#endif + +#define MAX_GENERIC_KEY_SIZE 256 + +const char manuf[] = "IBM"; +const char model[] = "Soft"; +const char descr[] = "IBM Soft token"; +const char label[] = "softtok"; + +static const MECH_LIST_ELEMENT soft_mech_list[] = { + {CKM_RSA_PKCS_KEY_PAIR_GEN, {512, 4096, CKF_GENERATE_KEY_PAIR}}, +#if !(NODSA) + {CKM_DSA_KEY_PAIR_GEN, {512, 1024, CKF_GENERATE_KEY_PAIR}}, +#endif + {CKM_DES_KEY_GEN, {8, 8, CKF_GENERATE}}, + {CKM_DES3_KEY_GEN, {24, 24, CKF_GENERATE}}, +#if !(NOCDMF) + {CKM_CDMF_KEY_GEN, {0, 0, CKF_GENERATE}}, +#endif + {CKM_RSA_PKCS, + {512, 4096, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP | CKF_SIGN | + CKF_VERIFY | CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER}}, + {CKM_RSA_PKCS_PSS, {1024, 4096, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA1_RSA_PKCS_PSS, {1024, 4096, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA224_RSA_PKCS_PSS, {1024, 4096, CKF_SIGN|CKF_VERIFY}}, + {CKM_SHA256_RSA_PKCS_PSS, {1024, 4096, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA384_RSA_PKCS_PSS, {1024, 4096, CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA512_RSA_PKCS_PSS, {1024, 4096, CKF_SIGN | CKF_VERIFY}}, +#if !(NOX509) + {CKM_RSA_X_509, + {512, 4096, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP | CKF_SIGN | + CKF_VERIFY | CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER}}, +#endif + {CKM_RSA_PKCS_OAEP, + {1024, 4096, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, +#if !(NOMD2) + {CKM_MD2_RSA_PKCS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, +#endif +#if !(NOMD5) + {CKM_MD5_RSA_PKCS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, +#endif +#if !(NOSHA1) + {CKM_SHA1_RSA_PKCS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, +#endif +#if !(NODSA) + {CKM_DSA, {512, 1024, CKF_SIGN | CKF_VERIFY}}, +#endif +/* Begin code contributed by Corrent corp. */ +#if !(NODH) + {CKM_DH_PKCS_DERIVE, {512, 2048, CKF_DERIVE}}, + {CKM_DH_PKCS_KEY_PAIR_GEN, {512, 2048, CKF_GENERATE_KEY_PAIR}}, +#endif +/* End code contributed by Corrent corp. */ + {CKM_DES_ECB, {8, 8, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {CKM_DES_CBC, {8, 8, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {CKM_DES_CBC_PAD, + {8, 8, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, +#if !(NOCDMF) + {CKM_CDMF_ECB, {0, 0, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {CKM_CDMF_CBC, {0, 0, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, +#endif + {CKM_DES3_ECB, {24, 24, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {CKM_DES3_CBC, {24, 24, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {CKM_DES3_CBC_PAD, + {24, 24, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {CKM_DES3_CMAC, {16, 24, CKF_SIGN | CKF_VERIFY}}, + {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}}, +#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_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_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_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_224, {0, 0, CKF_DIGEST}}, + {CKM_SHA512_256, {0, 0, CKF_DIGEST}}, +#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}}, +#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}}, +#endif + {CKM_SSL3_PRE_MASTER_KEY_GEN, {48, 48, CKF_GENERATE}}, + {CKM_SSL3_MASTER_KEY_DERIVE, {48, 48, CKF_DERIVE}}, + {CKM_SSL3_KEY_AND_MAC_DERIVE, {48, 48, CKF_DERIVE}}, + {CKM_SSL3_MD5_MAC, {384, 384, CKF_SIGN | CKF_VERIFY}}, + {CKM_SSL3_SHA1_MAC, {384, 384, CKF_SIGN | CKF_VERIFY}}, +#if !(NOAES) + {CKM_AES_KEY_GEN, {16, 32, CKF_GENERATE}}, + {CKM_AES_ECB, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {CKM_AES_CBC, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {CKM_AES_CBC_PAD, + {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {CKM_AES_CMAC, {16, 32, CKF_SIGN | CKF_VERIFY}}, + {CKM_AES_CMAC_GENERAL, {16, 32, CKF_SIGN | CKF_VERIFY}}, +#endif + {CKM_GENERIC_SECRET_KEY_GEN, {80, 2048, CKF_GENERATE}} +}; + +static const CK_ULONG soft_mech_list_len = + (sizeof(soft_mech_list) / sizeof(MECH_LIST_ELEMENT)); + +CK_RV token_specific_init(STDLL_TokData_t *tokdata, CK_SLOT_ID SlotNumber, + char *conf_name) +{ + UNUSED(conf_name); + + tokdata->mech_list = (MECH_LIST_ELEMENT *)soft_mech_list; + tokdata->mech_list_len = soft_mech_list_len; + + TRACE_INFO("soft %s slot=%lu running\n", __func__, SlotNumber); + + return CKR_OK; +} + +CK_RV token_specific_final(STDLL_TokData_t *tokdata, + CK_BBOOL token_specific_final) +{ + UNUSED(tokdata); + UNUSED(token_specific_final); + + TRACE_INFO("soft %s running\n", __func__); + + return CKR_OK; +} + +CK_RV token_specific_des_key_gen(STDLL_TokData_t *tokdata, CK_BYTE *des_key, + CK_ULONG len, CK_ULONG keysize) +{ + UNUSED(keysize); + + // Nothing different to do for DES or TDES here as this is just + // random data... Validation handles the rest + // Only check for weak keys when single DES. + if (len == (3 * DES_KEY_SIZE)) { + rng_generate(tokdata, des_key, len); + } else { + do { + rng_generate(tokdata, des_key, len); + } while (des_check_weak_key(des_key) == TRUE); + } + + // we really need to validate the key for parity etc... + // we should do that here... The caller validates the single des keys + // against the known and suspected poor keys.. + return CKR_OK; +} + +CK_RV token_specific_des_ecb(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, + OBJECT *key, CK_BYTE encrypt) +{ + CK_ULONG rc; + DES_key_schedule des_key2; + const_DES_cblock key_val_SSL, in_key_data; + DES_cblock out_key_data; + unsigned int i, j; + CK_ATTRIBUTE *attr = NULL; + + UNUSED(tokdata); + + // get the key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key\n"); + return CKR_FUNCTION_FAILED; + } + // Create the key schedule + memcpy(&key_val_SSL, attr->pValue, 8); + DES_set_key_unchecked(&key_val_SSL, &des_key2); + + // the des decrypt will only fail if the data length is not evenly divisible + // by 8 + if (in_data_len % 8) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + // Both the encrypt and the decrypt are done 8 bytes at a time + if (encrypt) { + for (i = 0; i < in_data_len; i = i + 8) { + memcpy(in_key_data, in_data + i, 8); + DES_ecb_encrypt(&in_key_data, &out_key_data, &des_key2, + DES_ENCRYPT); + memcpy(out_data + i, out_key_data, 8); + } + + *out_data_len = in_data_len; + rc = CKR_OK; + } else { + + for (j = 0; j < in_data_len; j = j + 8) { + memcpy(in_key_data, in_data + j, 8); + DES_ecb_encrypt(&in_key_data, &out_key_data, &des_key2, + DES_DECRYPT); + memcpy(out_data + j, out_key_data, 8); + } + + *out_data_len = in_data_len; + rc = CKR_OK; + } + + return rc; +} + +CK_RV token_specific_des_cbc(STDLL_TokData_t *tokdata, + 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) +{ + CK_ULONG rc; + CK_ATTRIBUTE *attr = NULL; + DES_cblock ivec; + DES_key_schedule des_key2; + const_DES_cblock key_val_SSL; + + UNUSED(tokdata); + + // get the key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key\n"); + return CKR_FUNCTION_FAILED; + } + // Create the key schedule + memcpy(&key_val_SSL, attr->pValue, 8); + DES_set_key_unchecked(&key_val_SSL, &des_key2); + + memcpy(&ivec, init_v, 8); + // the des decrypt will only fail if the data length is not evenly divisible + // by 8 + if (in_data_len % 8) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + + if (encrypt) { + DES_ncbc_encrypt(in_data, out_data, in_data_len, &des_key2, &ivec, + DES_ENCRYPT); + *out_data_len = in_data_len; + rc = CKR_OK; + } else { + DES_ncbc_encrypt(in_data, out_data, in_data_len, &des_key2, &ivec, + DES_DECRYPT); + *out_data_len = in_data_len; + rc = CKR_OK; + } + + return rc; +} + +CK_RV token_specific_tdes_ecb(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, + OBJECT *key, CK_BYTE encrypt) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE key_value[3 * DES_KEY_SIZE]; + CK_KEY_TYPE keytype; + unsigned int k, j; + DES_key_schedule des_key1; + DES_key_schedule des_key2; + DES_key_schedule des_key3; + const_DES_cblock key_SSL1, key_SSL2, key_SSL3, in_key_data; + DES_cblock out_key_data; + + UNUSED(tokdata); + + // get the key type + rc = template_attribute_find(key->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key\n"); + return CKR_FUNCTION_FAILED; + } + keytype = *(CK_KEY_TYPE *) attr->pValue; + + // get the key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key\n"); + return CKR_FUNCTION_FAILED; + } + if (keytype == CKK_DES2) { + memcpy(key_value, attr->pValue, 2 * DES_KEY_SIZE); + memcpy(key_value + (2 * DES_KEY_SIZE), attr->pValue, DES_KEY_SIZE); + } else { + memcpy(key_value, attr->pValue, 3 * DES_KEY_SIZE); + } + + // The key as passed is a 24 byte long string containing three des keys + // pick them apart and create the 3 corresponding key schedules + memcpy(&key_SSL1, key_value, 8); + memcpy(&key_SSL2, key_value + 8, 8); + memcpy(&key_SSL3, key_value + 16, 8); + DES_set_key_unchecked(&key_SSL1, &des_key1); + DES_set_key_unchecked(&key_SSL2, &des_key2); + DES_set_key_unchecked(&key_SSL3, &des_key3); + + // the des decrypt will only fail if the data length is not evenly divisible + // by 8 + if (in_data_len % 8) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + // the encrypt and decrypt are done 8 bytes at a time + if (encrypt) { + for (k = 0; k < in_data_len; k = k + 8) { + memcpy(in_key_data, in_data + k, 8); + DES_ecb3_encrypt((const_DES_cblock *) & in_key_data, + (DES_cblock *) & out_key_data, + &des_key1, &des_key2, &des_key3, DES_ENCRYPT); + memcpy(out_data + k, out_key_data, 8); + } + *out_data_len = in_data_len; + rc = CKR_OK; + } else { + for (j = 0; j < in_data_len; j = j + 8) { + memcpy(in_key_data, in_data + j, 8); + DES_ecb3_encrypt((const_DES_cblock *) & in_key_data, + (DES_cblock *) & out_key_data, + &des_key1, &des_key2, &des_key3, DES_DECRYPT); + memcpy(out_data + j, out_key_data, 8); + } + *out_data_len = in_data_len; + rc = CKR_OK; + } + + return rc; +} + +CK_RV token_specific_tdes_cbc(STDLL_TokData_t *tokdata, + 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) +{ + CK_ATTRIBUTE *attr = NULL; + CK_RV rc = CKR_OK; + CK_BYTE key_value[3 * DES_KEY_SIZE]; + CK_KEY_TYPE keytype; + DES_key_schedule des_key1; + DES_key_schedule des_key2; + DES_key_schedule des_key3; + const_DES_cblock key_SSL1, key_SSL2, key_SSL3; + DES_cblock ivec; + + UNUSED(tokdata); + + // get the key type + rc = template_attribute_find(key->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key\n"); + return CKR_FUNCTION_FAILED; + } + keytype = *(CK_KEY_TYPE *) attr->pValue; + + // get the key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key\n"); + return CKR_FUNCTION_FAILED; + } + if (keytype == CKK_DES2) { + memcpy(key_value, attr->pValue, 2 * DES_KEY_SIZE); + memcpy(key_value + (2 * DES_KEY_SIZE), attr->pValue, DES_KEY_SIZE); + } else { + memcpy(key_value, attr->pValue, 3 * DES_KEY_SIZE); + } + + // The key as passed in is a 24 byte string containing 3 keys + // pick it apart and create the key schedules + memcpy(&key_SSL1, key_value, 8); + memcpy(&key_SSL2, key_value + 8, 8); + memcpy(&key_SSL3, key_value + 16, 8); + DES_set_key_unchecked(&key_SSL1, &des_key1); + DES_set_key_unchecked(&key_SSL2, &des_key2); + DES_set_key_unchecked(&key_SSL3, &des_key3); + + memcpy(ivec, init_v, sizeof(ivec)); + + // the des decrypt will only fail if the data length is not evenly divisible + // by 8 + if (in_data_len % 8) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + // Encrypt or decrypt the data + if (encrypt) { + DES_ede3_cbc_encrypt(in_data, + out_data, + in_data_len, + &des_key1, + &des_key2, &des_key3, &ivec, DES_ENCRYPT); + *out_data_len = in_data_len; + rc = CKR_OK; + } else { + DES_ede3_cbc_encrypt(in_data, + out_data, + in_data_len, + &des_key1, + &des_key2, &des_key3, &ivec, DES_DECRYPT); + + *out_data_len = in_data_len; + rc = CKR_OK; + } + + return rc; +} + +// convert from the local PKCS11 template representation to +// the underlying requirement +// returns the pointer to the local key representation +static void *rsa_convert_public_key(OBJECT *key_obj) +{ + CK_BBOOL rc; + CK_ATTRIBUTE *modulus = NULL; + CK_ATTRIBUTE *pub_exp = NULL; + + RSA *rsa; + BIGNUM *bn_mod, *bn_exp; + + rc = template_attribute_find(key_obj->template, CKA_MODULUS, &modulus); + rc &= + template_attribute_find(key_obj->template, CKA_PUBLIC_EXPONENT, + &pub_exp); + + if (rc == FALSE) { + return NULL; + } + // Create an RSA key struct to return + rsa = RSA_new(); + if (rsa == NULL) + return NULL; + + // Create and init BIGNUM structs to stick in the RSA struct + bn_mod = BN_new(); + bn_exp = BN_new(); + + if (bn_exp == NULL || bn_mod == NULL) { + if (bn_mod) + free(bn_mod); + if (bn_exp) + free(bn_exp); + RSA_free(rsa); + return NULL; + } + // Convert from strings to BIGNUMs and stick them in the RSA struct + BN_bin2bn((unsigned char *) modulus->pValue, modulus->ulValueLen, bn_mod); + BN_bin2bn((unsigned char *) pub_exp->pValue, pub_exp->ulValueLen, bn_exp); + +#ifdef OLDER_OPENSSL + rsa->n = bn_mod; + rsa->e = bn_exp; +#else + RSA_set0_key(rsa, bn_mod, bn_exp, NULL); +#endif + + return (void *) rsa; +} + +static void *rsa_convert_private_key(OBJECT *key_obj) +{ + CK_ATTRIBUTE *modulus = NULL; + CK_ATTRIBUTE *pub_exp = NULL; + CK_ATTRIBUTE *priv_exp = NULL; + CK_ATTRIBUTE *prime1 = NULL; + CK_ATTRIBUTE *prime2 = NULL; + CK_ATTRIBUTE *exp1 = NULL; + CK_ATTRIBUTE *exp2 = NULL; + CK_ATTRIBUTE *coeff = NULL; + CK_BBOOL rc; + + RSA *rsa; + RSA_METHOD *meth; + BIGNUM *bn_mod, *bn_pub_exp, *bn_priv_exp, *bn_p1, *bn_p2, *bn_e1, *bn_e2, + *bn_cf; + + + rc = template_attribute_find(key_obj->template, CKA_MODULUS, &modulus); + rc &= + template_attribute_find(key_obj->template, CKA_PUBLIC_EXPONENT, + &pub_exp); + rc &= + template_attribute_find(key_obj->template, CKA_PRIVATE_EXPONENT, + &priv_exp); + rc &= template_attribute_find(key_obj->template, CKA_PRIME_1, &prime1); + rc &= template_attribute_find(key_obj->template, CKA_PRIME_2, &prime2); + rc &= template_attribute_find(key_obj->template, CKA_EXPONENT_1, &exp1); + rc &= template_attribute_find(key_obj->template, CKA_EXPONENT_2, &exp2); + rc &= template_attribute_find(key_obj->template, CKA_COEFFICIENT, &coeff); + + if (!prime2 && !modulus) { + return NULL; + } + // Create and init all the RSA and BIGNUM structs we need. + rsa = RSA_new(); + if (rsa == NULL) + return NULL; + + /* + * Depending if an engine is loaded on OpenSSL and define its own + * RSA_METHOD, we can end up having an infinite loop as the SOFT + * Token doesn't implement RSA and, instead, calls OpenSSL for it. + * So to avoid it we set RSA methods to the default rsa methods. + */ +#ifdef OLDER_OPENSSL + if (rsa->engine) { + meth = (RSA_METHOD *) rsa->meth; + const RSA_METHOD *meth2 = RSA_PKCS1_SSLeay(); + meth->rsa_pub_enc = meth2->rsa_pub_enc; + meth->rsa_pub_dec = meth2->rsa_pub_dec; + meth->rsa_priv_enc = meth2->rsa_priv_enc; + meth->rsa_priv_dec = meth2->rsa_priv_dec; + meth->rsa_mod_exp = meth2->rsa_mod_exp; + meth->bn_mod_exp = meth2->bn_mod_exp; +#else + ENGINE *e = RSA_get0_engine(rsa); + if (e) { + meth = (RSA_METHOD *) RSA_get_method(rsa); + const RSA_METHOD *meth2 = RSA_PKCS1_OpenSSL(); + RSA_meth_set_pub_enc(meth, RSA_meth_get_pub_enc(meth2)); + RSA_meth_set_pub_dec(meth, RSA_meth_get_pub_dec(meth2)); + RSA_meth_set_priv_enc(meth, RSA_meth_get_priv_enc(meth2)); + RSA_meth_set_priv_dec(meth, RSA_meth_get_priv_dec(meth2)); + RSA_meth_set_mod_exp(meth, RSA_meth_get_mod_exp(meth2)); + RSA_meth_set_bn_mod_exp(meth, RSA_meth_get_bn_mod_exp(meth2)); +#endif + } + + bn_mod = BN_new(); + bn_pub_exp = BN_new(); + bn_priv_exp = BN_new(); + bn_p1 = BN_new(); + bn_p2 = BN_new(); + bn_e1 = BN_new(); + bn_e2 = BN_new(); + bn_cf = BN_new(); + + if ((bn_cf == NULL) || (bn_e2 == NULL) || (bn_e1 == NULL) || + (bn_p2 == NULL) || (bn_p1 == NULL) || (bn_priv_exp == NULL) || + (bn_pub_exp == NULL) || (bn_mod == NULL)) { + if (rsa) + RSA_free(rsa); + if (bn_mod) + BN_free(bn_mod); + if (bn_pub_exp) + BN_free(bn_pub_exp); + if (bn_priv_exp) + BN_free(bn_priv_exp); + if (bn_p1) + BN_free(bn_p1); + if (bn_p2) + BN_free(bn_p2); + if (bn_e1) + BN_free(bn_e1); + if (bn_e2) + BN_free(bn_e2); + if (bn_cf) + BN_free(bn_cf); + return NULL; + } + + // CRT key? + if (prime1) { + if (!prime2 || !exp1 || !exp2 || !coeff) { + return NULL; + } + // Even though this is CRT key, OpenSSL requires the + // modulus and exponents filled in or encrypt and decrypt will + // not work + BN_bin2bn((unsigned char *) modulus->pValue, modulus->ulValueLen, + bn_mod); + BN_bin2bn((unsigned char *) pub_exp->pValue, pub_exp->ulValueLen, + bn_pub_exp); + BN_bin2bn((unsigned char *) priv_exp->pValue, priv_exp->ulValueLen, + bn_priv_exp); + + BN_bin2bn((unsigned char *) prime1->pValue, prime1->ulValueLen, bn_p1); + BN_bin2bn((unsigned char *) prime2->pValue, prime2->ulValueLen, bn_p2); + + BN_bin2bn((unsigned char *) exp1->pValue, exp1->ulValueLen, bn_e1); + BN_bin2bn((unsigned char *) exp2->pValue, exp2->ulValueLen, bn_e2); + BN_bin2bn((unsigned char *) coeff->pValue, coeff->ulValueLen, bn_cf); +#ifdef OLDER_OPENSSL + rsa->n = bn_mod; + rsa->d = bn_priv_exp; + rsa->p = bn_p1; + rsa->q = bn_p2; + rsa->dmp1 = bn_e1; + rsa->dmq1 = bn_e2; + rsa->iqmp = bn_cf; +#else + RSA_set0_key(rsa, bn_mod, bn_pub_exp, bn_priv_exp); + RSA_set0_factors(rsa, bn_p1, bn_p2); + RSA_set0_crt_params(rsa, bn_e1, bn_e2, bn_cf); +#endif + return rsa; + } else { // must be a non-CRT key + if (!priv_exp) { + return NULL; + } + BN_bin2bn((unsigned char *) modulus->pValue, modulus->ulValueLen, + bn_mod); + BN_bin2bn((unsigned char *) pub_exp->pValue, pub_exp->ulValueLen, + bn_pub_exp); + BN_bin2bn((unsigned char *) priv_exp->pValue, priv_exp->ulValueLen, + bn_priv_exp); +#ifdef OLDER_OPENSSL + rsa->n = bn_mod; + rsa->d = bn_priv_exp; +#else + RSA_set0_key(rsa, bn_mod, bn_pub_exp, bn_priv_exp); +#endif + } + + return (void *) rsa; +} + +static CK_RV os_specific_rsa_keygen(TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) +{ + CK_ATTRIBUTE *publ_exp = NULL; + CK_ATTRIBUTE *attr = NULL; + CK_ULONG mod_bits; + CK_BBOOL flag; + CK_RV rc; + CK_ULONG BNLength; + RSA *rsa = NULL; + const BIGNUM *bignum; + CK_BYTE *ssl_ptr = NULL; + BIGNUM *e = NULL; + + flag = template_attribute_find(publ_tmpl, CKA_MODULUS_BITS, &attr); + if (!flag) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; // should never happen + } + mod_bits = *(CK_ULONG *) attr->pValue; + + // we don't support less than 1024 bit keys in the sw + if (mod_bits < 512 || mod_bits > 4096) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_SIZE_RANGE)); + return CKR_KEY_SIZE_RANGE; + } + + flag = template_attribute_find(publ_tmpl, CKA_PUBLIC_EXPONENT, &publ_exp); + if (!flag) { + TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); + return CKR_TEMPLATE_INCOMPLETE; + } + + if (publ_exp->ulValueLen > sizeof(CK_ULONG)) { + TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID)); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + e = BN_new(); + rsa = RSA_new(); + + if (e == NULL || rsa == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + BN_bin2bn(publ_exp->pValue, publ_exp->ulValueLen, e); + + if (!RSA_generate_key_ex(rsa, mod_bits, e, NULL)) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + // Now fill in the objects.. + // + // modulus: n + // +#ifdef OLDER_OPENSSL + bignum = rsa->n; +#else + RSA_get0_key(rsa, &bignum, NULL, NULL); +#endif + BNLength = BN_num_bytes(bignum); + ssl_ptr = malloc(BNLength); + if (ssl_ptr == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + BNLength = BN_bn2bin(bignum, ssl_ptr); + rc = build_attribute(CKA_MODULUS, ssl_ptr, BNLength, &attr); // in bytes + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto done; + } + template_update_attribute(publ_tmpl, attr); + free(ssl_ptr); + ssl_ptr = NULL; + + // Public Exponent +#ifdef OLDER_OPENSSL + bignum = rsa->e; +#else + RSA_get0_key(rsa, NULL, &bignum, NULL); +#endif + BNLength = BN_num_bytes(bignum); + ssl_ptr = malloc(BNLength); + if (ssl_ptr == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + BNLength = BN_bn2bin(bignum, ssl_ptr); + // in bytes + rc = build_attribute(CKA_PUBLIC_EXPONENT, ssl_ptr, BNLength, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto done; + } + template_update_attribute(publ_tmpl, attr); + + /* add public exponent to the private template. Its already an attribute in + * the private template at this point, we're just making its value correct + */ + rc = build_attribute(CKA_PUBLIC_EXPONENT, ssl_ptr, BNLength, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto done; + } + template_update_attribute(priv_tmpl, attr); + free(ssl_ptr); + ssl_ptr = NULL; + + // local = TRUE + // + flag = TRUE; + rc = build_attribute(CKA_LOCAL, &flag, sizeof(CK_BBOOL), &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto done; + } + template_update_attribute(publ_tmpl, attr); + + // + // now, do the private key + // + // Cheat here and put the whole original key into the CKA_VALUE... remember + // to force the system to not return this for RSA keys.. + + // Add the modulus to the private key information +#ifdef OLDER_OPENSSL + bignum = rsa->n; +#else + RSA_get0_key(rsa, &bignum, NULL, NULL); +#endif + BNLength = BN_num_bytes(bignum); + ssl_ptr = malloc(BNLength); + if (ssl_ptr == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + BNLength = BN_bn2bin(bignum, ssl_ptr); + rc = build_attribute(CKA_MODULUS, ssl_ptr, BNLength, &attr); // in bytes + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto done; + } + template_update_attribute(priv_tmpl, attr); + free(ssl_ptr); + ssl_ptr = NULL; + + // Private Exponent +#ifdef OLDER_OPENSSL + bignum = rsa->d; +#else + RSA_get0_key(rsa, NULL, NULL, &bignum); +#endif + BNLength = BN_num_bytes(bignum); + ssl_ptr = malloc(BNLength); + if (ssl_ptr == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + BNLength = BN_bn2bin(bignum, ssl_ptr); + rc = build_attribute(CKA_PRIVATE_EXPONENT, ssl_ptr, BNLength, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto done; + } + template_update_attribute(priv_tmpl, attr); + OPENSSL_cleanse(ssl_ptr, BNLength); + free(ssl_ptr); + ssl_ptr = NULL; + + // prime #1: p + // +#ifdef OLDER_OPENSSL + bignum = rsa->p; +#else + RSA_get0_factors(rsa, &bignum, NULL); +#endif + BNLength = BN_num_bytes(bignum); + ssl_ptr = malloc(BNLength); + if (ssl_ptr == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + BNLength = BN_bn2bin(bignum, ssl_ptr); + rc = build_attribute(CKA_PRIME_1, ssl_ptr, BNLength, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto done; + } + template_update_attribute(priv_tmpl, attr); + OPENSSL_cleanse(ssl_ptr, BNLength); + free(ssl_ptr); + ssl_ptr = NULL; + + // prime #2: q + // +#ifdef OLDER_OPENSSL + bignum = rsa->q; +#else + RSA_get0_factors(rsa, NULL, &bignum); +#endif + BNLength = BN_num_bytes(bignum); + ssl_ptr = malloc(BNLength); + if (ssl_ptr == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + BNLength = BN_bn2bin(bignum, ssl_ptr); + rc = build_attribute(CKA_PRIME_2, ssl_ptr, BNLength, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto done; + } + template_update_attribute(priv_tmpl, attr); + OPENSSL_cleanse(ssl_ptr, BNLength); + free(ssl_ptr); + ssl_ptr = NULL; + + // exponent 1: d mod(p-1) + // +#ifdef OLDER_OPENSSL + bignum = rsa->dmp1; +#else + RSA_get0_crt_params(rsa, &bignum, NULL, NULL); +#endif + BNLength = BN_num_bytes(bignum); + ssl_ptr = malloc(BNLength); + if (ssl_ptr == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + BNLength = BN_bn2bin(bignum, ssl_ptr); + rc = build_attribute(CKA_EXPONENT_1, ssl_ptr, BNLength, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto done; + } + template_update_attribute(priv_tmpl, attr); + OPENSSL_cleanse(ssl_ptr, BNLength); + free(ssl_ptr); + ssl_ptr = NULL; + + // exponent 2: d mod(q-1) + // +#ifdef OLDER_OPENSSL + bignum = rsa->dmq1; +#else + RSA_get0_crt_params(rsa, NULL, &bignum, NULL); +#endif + BNLength = BN_num_bytes(bignum); + ssl_ptr = malloc(BNLength); + if (ssl_ptr == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + BNLength = BN_bn2bin(bignum, ssl_ptr); + rc = build_attribute(CKA_EXPONENT_2, ssl_ptr, BNLength, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto done; + } + template_update_attribute(priv_tmpl, attr); + OPENSSL_cleanse(ssl_ptr, BNLength); + free(ssl_ptr); + ssl_ptr = NULL; + + // CRT coefficient: q_inverse mod(p) + // +#ifdef OLDER_OPENSSL + bignum = rsa->iqmp; +#else + RSA_get0_crt_params(rsa, NULL, NULL, &bignum); +#endif + BNLength = BN_num_bytes(bignum); + ssl_ptr = malloc(BNLength); + if (ssl_ptr == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + BNLength = BN_bn2bin(bignum, ssl_ptr); + rc = build_attribute(CKA_COEFFICIENT, ssl_ptr, BNLength, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto done; + } + template_update_attribute(priv_tmpl, attr); + OPENSSL_cleanse(ssl_ptr, BNLength); + free(ssl_ptr); + ssl_ptr = NULL; + + flag = TRUE; + rc = build_attribute(CKA_LOCAL, &flag, sizeof(CK_BBOOL), &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + goto done; + } + template_update_attribute(priv_tmpl, attr); + +done: + if (e != NULL) + BN_free(e); + if (rsa != NULL) + RSA_free(rsa); + if (ssl_ptr != NULL) + free(ssl_ptr); + + return rc; +} + +CK_RV token_specific_rsa_generate_keypair(STDLL_TokData_t *tokdata, + TEMPLATE *publ_tmpl, + TEMPLATE *priv_tmpl) +{ + CK_RV rc; + + UNUSED(tokdata); + + rc = os_specific_rsa_keygen(publ_tmpl, priv_tmpl); + if (rc != CKR_OK) + TRACE_DEVEL("os_specific_rsa_keygen failed\n"); + + return rc; +} + + +static CK_RV os_specific_rsa_encrypt(CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, OBJECT *key_obj) +{ + CK_RV rc; + RSA *rsa; + int size; + + // Convert the local representation to an RSA representation + rsa = (RSA *) rsa_convert_public_key(key_obj); + if (rsa == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + return rc; + } + // Do an RSA public encryption + size = + RSA_public_encrypt(in_data_len, in_data, out_data, rsa, RSA_NO_PADDING); + if (size == -1) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_ARGUMENTS_BAD; + goto done; + } + + rc = CKR_OK; + +done: + RSA_free(rsa); + + return rc; +} + +static CK_RV os_specific_rsa_decrypt(CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, OBJECT *key_obj) +{ + CK_RV rc; + RSA *rsa; + int size; + + // Convert the local key representation to an RSA key representaion + rsa = (RSA *) rsa_convert_private_key(key_obj); + if (rsa == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + return rc; + } + // Do the private decryption + size = + RSA_private_decrypt(in_data_len, in_data, out_data, rsa, + RSA_NO_PADDING); + + if (size == -1) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + rc = CKR_OK; + +done: + RSA_free(rsa); + + return rc; +} + +CK_RV token_specific_rsa_encrypt(STDLL_TokData_t *tokdata, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len, OBJECT *key_obj) +{ + CK_RV rc; + CK_ULONG modulus_bytes; + CK_BYTE clear[MAX_RSA_KEYLEN], cipher[MAX_RSA_KEYLEN]; + CK_ATTRIBUTE *attr = NULL; + + /* format the data */ + if (!template_attribute_find(key_obj->template, CKA_MODULUS, &attr)) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + return CKR_FUNCTION_FAILED; + } + modulus_bytes = attr->ulValueLen; + + rc = rsa_format_block(tokdata, in_data, in_data_len, clear, + modulus_bytes, PKCS_BT_2); + if (rc != CKR_OK) { + TRACE_DEVEL("rsa_format_block failed\n"); + goto done; + } + // Do an RSA public encryption + rc = os_specific_rsa_encrypt(clear, modulus_bytes, cipher, key_obj); + + if (rc == CKR_OK) { + memcpy(out_data, cipher, modulus_bytes); + *out_data_len = modulus_bytes; + } else { + TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); + } + +done: + OPENSSL_cleanse(clear, sizeof(clear)); + return rc; +} + +CK_RV token_specific_rsa_decrypt(STDLL_TokData_t *tokdata, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len, OBJECT *key_obj) +{ + CK_RV rc; + CK_BYTE out[MAX_RSA_KEYLEN]; + CK_ULONG modulus_bytes; + + UNUSED(tokdata); + + modulus_bytes = in_data_len; + + rc = os_specific_rsa_decrypt(in_data, modulus_bytes, out, key_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("os_specific_rsa_decrypt failed\n"); + goto done; + } + + 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)); + return rc; +} + + +CK_RV token_specific_rsa_sign(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 data[MAX_RSA_KEYLEN], sig[MAX_RSA_KEYLEN]; + CK_ULONG modulus_bytes; + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + + UNUSED(tokdata); + UNUSED(sess); + + /* format the data */ + if (!template_attribute_find(key_obj->template, CKA_MODULUS, &attr)) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + return CKR_FUNCTION_FAILED; + } + modulus_bytes = attr->ulValueLen; + rc = rsa_format_block(tokdata, in_data, in_data_len, data, + modulus_bytes, PKCS_BT_1); + if (rc != CKR_OK) { + TRACE_DEVEL("rsa_format_block failed\n"); + return rc; + } + + /* signing is a private key operation --> decrypt */ + rc = os_specific_rsa_decrypt(data, modulus_bytes, sig, key_obj); + if (rc == CKR_OK) { + memcpy(out_data, sig, modulus_bytes); + *out_data_len = modulus_bytes; + } else { + TRACE_DEVEL("os_specific_rsa_decrypt failed\n"); + } + + return rc; +} + +CK_RV token_specific_rsa_verify(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len, + OBJECT *key_obj) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BYTE out[MAX_RSA_KEYLEN], out_data[MAX_RSA_KEYLEN]; + CK_ULONG modulus_bytes, out_data_len; + CK_BBOOL flag; + CK_RV rc; + + UNUSED(tokdata); + UNUSED(sess); + UNUSED(sig_len); + + out_data_len = MAX_RSA_KEYLEN; + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + return CKR_FUNCTION_FAILED; + } else { + modulus_bytes = attr->ulValueLen; + } + + // verifying is a public key operation --> encrypt + // + rc = os_specific_rsa_encrypt(signature, modulus_bytes, out, key_obj); + if (rc != CKR_OK) { + /* + * Return CKR_SIGNATURE_INVALID in case of CKR_ARGUMENTS_BAD + * because we dont know why the RSA op failed and it may have + * failed due to a tampered signature being greater or equal + * to the modulus. + */ + if (rc == CKR_ARGUMENTS_BAD) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + rc = CKR_SIGNATURE_INVALID; + } else { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + } + return rc; + } + + rc = rsa_parse_block(out, modulus_bytes, out_data, &out_data_len, + PKCS_BT_1); + if (rc == CKR_ENCRYPTED_DATA_INVALID) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + return CKR_SIGNATURE_INVALID; + } else if (rc != CKR_OK) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + if (in_data_len != out_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + return CKR_SIGNATURE_INVALID; + } + + if (CRYPTO_memcmp(in_data, out_data, out_data_len) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + return CKR_SIGNATURE_INVALID; + } + + return rc; +} + +CK_RV token_specific_rsa_verify_recover(STDLL_TokData_t *tokdata, + CK_BYTE *signature, CK_ULONG sig_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, + OBJECT *key_obj) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BYTE out[MAX_RSA_KEYLEN]; + CK_ULONG modulus_bytes; + CK_BBOOL flag; + CK_RV rc; + + UNUSED(tokdata); + UNUSED(sig_len); + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + return CKR_FUNCTION_FAILED; + } else { + modulus_bytes = attr->ulValueLen; + } + + // verifying is a public key operation --> encrypt + // + rc = os_specific_rsa_encrypt(signature, modulus_bytes, out, key_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); + return rc; + } + + rc = rsa_parse_block(out, modulus_bytes, out_data, out_data_len, PKCS_BT_1); + if (rc == CKR_ENCRYPTED_DATA_INVALID) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + return CKR_SIGNATURE_INVALID; + } else if (rc != CKR_OK) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + } + + return rc; +} + +CK_RV token_specific_rsa_pss_sign(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *sig, CK_ULONG *sig_len) +{ + CK_RV rc; + CK_ULONG modbytes; + CK_BBOOL flag; + CK_ATTRIBUTE *attr = NULL; + OBJECT *key_obj = NULL; + CK_BYTE *emdata = NULL; + CK_RSA_PKCS_PSS_PARAMS *pssParms = NULL; + + UNUSED(sess); + + /* check the arguments */ + if (!in_data || !sig) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + if (!ctx) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + pssParms = (CK_RSA_PKCS_PSS_PARAMS *) ctx->mech.pParameter; + + /* get the key */ + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_find_in_map1 failed\n"); + return rc; + } + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + modbytes = attr->ulValueLen; + } + + emdata = (CK_BYTE *) malloc(modbytes); + if (emdata == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + + rc = emsa_pss_encode(tokdata, pssParms, in_data, in_data_len, emdata, + &modbytes); + if (rc != CKR_OK) + goto done; + + /* signing is a private key operation --> decrypt */ + rc = os_specific_rsa_decrypt(emdata, modbytes, sig, key_obj); + if (rc == CKR_OK) + *sig_len = modbytes; + else + TRACE_DEVEL("os_specific_rsa_decrypt failed\n"); + +done: + if (emdata) + free(emdata); + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +CK_RV token_specific_rsa_pss_verify(STDLL_TokData_t *tokdata, SESSION *sess, + SIGN_VERIFY_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) +{ + CK_RV rc; + CK_ULONG modbytes; + OBJECT *key_obj = NULL; + CK_BBOOL flag; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE out[MAX_RSA_KEYLEN]; + CK_RSA_PKCS_PSS_PARAMS *pssParms = NULL; + + UNUSED(sess); + + /* check the arguments */ + if (!in_data || !signature) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + if (!ctx) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + pssParms = (CK_RSA_PKCS_PSS_PARAMS *) ctx->mech.pParameter; + + /* get the key */ + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_find_in_map1 failed\n"); + return rc; + } + + /* verify is a public key operation ... encrypt */ + rc = os_specific_rsa_encrypt(signature, sig_len, out, key_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); + goto done; + } + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + modbytes = attr->ulValueLen; + } + + /* call the pss verify scheme */ + rc = emsa_pss_verify(tokdata, pssParms, in_data, in_data_len, out, + modbytes); + +done: + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + + +CK_RV token_specific_rsa_x509_encrypt(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, OBJECT *key_obj) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BYTE clear[MAX_RSA_KEYLEN], cipher[MAX_RSA_KEYLEN]; + CK_ULONG modulus_bytes; + CK_BBOOL flag; + CK_RV rc; + + UNUSED(tokdata); + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + modulus_bytes = attr->ulValueLen; + + // prepad with zeros + // + memset(clear, 0x0, modulus_bytes - in_data_len); + memcpy(&clear[modulus_bytes - in_data_len], in_data, in_data_len); + + rc = os_specific_rsa_encrypt(clear, modulus_bytes, cipher, key_obj); + if (rc == CKR_OK) { + memcpy(out_data, cipher, modulus_bytes); + *out_data_len = modulus_bytes; + } else { + TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); + } + +done: + OPENSSL_cleanse(clear, sizeof(clear)); + return rc; +} + +CK_RV token_specific_rsa_x509_decrypt(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, OBJECT *key_obj) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BYTE out[MAX_RSA_KEYLEN]; + CK_ULONG modulus_bytes; + CK_BBOOL flag; + CK_RV rc; + + UNUSED(tokdata); + UNUSED(in_data_len); + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + modulus_bytes = attr->ulValueLen; + + rc = os_specific_rsa_decrypt(in_data, modulus_bytes, out, key_obj); + if (rc == CKR_OK) { + memcpy(out_data, out, modulus_bytes); + *out_data_len = modulus_bytes; + } else { + TRACE_DEVEL("os_specific_rsa_decrypt failed\n"); + } + +done: + OPENSSL_cleanse(out, sizeof(out)); + return rc; +} + + +CK_RV token_specific_rsa_x509_sign(STDLL_TokData_t *tokdata, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *out_data, + CK_ULONG *out_data_len, OBJECT *key_obj) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BYTE data[MAX_RSA_KEYLEN], sig[MAX_RSA_KEYLEN]; + CK_ULONG modulus_bytes; + CK_BBOOL flag; + CK_RV rc; + + UNUSED(tokdata); + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + return CKR_FUNCTION_FAILED; + } else { + modulus_bytes = attr->ulValueLen; + } + + // prepad with zeros + // + + memset(data, 0x0, modulus_bytes - in_data_len); + memcpy(&data[modulus_bytes - in_data_len], in_data, in_data_len); + + rc = os_specific_rsa_decrypt(data, modulus_bytes, sig, key_obj); + if (rc == CKR_OK) { + memcpy(out_data, sig, modulus_bytes); + *out_data_len = modulus_bytes; + } else { + TRACE_DEVEL("os_specific_rsa_decrypt failed\n"); + } + + return rc; +} + +CK_RV token_specific_rsa_x509_verify(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len, + OBJECT *key_obj) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BYTE out[MAX_RSA_KEYLEN]; + CK_ULONG modulus_bytes; + CK_BBOOL flag; + CK_RV rc; + + UNUSED(tokdata); + UNUSED(sig_len); + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + return CKR_FUNCTION_FAILED; + } else { + modulus_bytes = attr->ulValueLen; + } + + rc = os_specific_rsa_encrypt(signature, modulus_bytes, out, key_obj); + if (rc == CKR_OK) { + CK_ULONG pos1, pos2, len; + // it should be noted that in_data_len is not necessarily + // the same as the modulus length + // + for (pos1 = 0; pos1 < in_data_len; pos1++) + if (in_data[pos1] != 0) + break; + + for (pos2 = 0; pos2 < modulus_bytes; pos2++) + if (out[pos2] != 0) + break; + + // at this point, pos1 and pos2 point to the first non-zero + // bytes in the input data and the decrypted signature + // (the recovered data), respectively. + if ((in_data_len - pos1) != (modulus_bytes - pos2)) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + return CKR_SIGNATURE_INVALID; + } + len = in_data_len - pos1; + + if (CRYPTO_memcmp(&in_data[pos1], &out[pos2], len) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + return CKR_SIGNATURE_INVALID; + } + return CKR_OK; + } else { + TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); + } + + return rc; +} + +CK_RV token_specific_rsa_x509_verify_recover(STDLL_TokData_t *tokdata, + CK_BYTE *signature, + CK_ULONG sig_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, + OBJECT *key_obj) +{ + CK_ATTRIBUTE *attr = NULL; + CK_BYTE out[MAX_RSA_KEYLEN]; + CK_ULONG modulus_bytes; + CK_BBOOL flag; + CK_RV rc; + + UNUSED(tokdata); + UNUSED(sig_len); + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + return CKR_FUNCTION_FAILED; + } else { + modulus_bytes = attr->ulValueLen; + } + + rc = os_specific_rsa_encrypt(signature, modulus_bytes, out, key_obj); + if (rc == CKR_OK) { + memcpy(out_data, out, modulus_bytes); + *out_data_len = modulus_bytes; + } else { + TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); + } + + return rc; +} + +CK_RV token_specific_rsa_oaep_encrypt(STDLL_TokData_t *tokdata, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_BYTE *hash, + CK_ULONG hlen) +{ + CK_RV rc; + CK_BYTE cipher[MAX_RSA_KEYLEN]; + CK_ULONG modulus_bytes; + CK_BBOOL flag; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE *em_data = NULL; + OBJECT *key_obj = NULL; + CK_RSA_PKCS_OAEP_PARAMS_PTR oaepParms = NULL; + + if (!in_data || !out_data || !hash) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + oaepParms = (CK_RSA_PKCS_OAEP_PARAMS_PTR) ctx->mech.pParameter; + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_find_in_map1 failed\n"); + return rc; + } + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + modulus_bytes = attr->ulValueLen; + + /* pkcs1v2.2, section 7.1.1 Step 2: + * EME-OAEP encoding. + */ + em_data = (CK_BYTE *) malloc(modulus_bytes * sizeof(CK_BYTE)); + if (em_data == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + + rc = encode_eme_oaep(tokdata, in_data, in_data_len, em_data, + modulus_bytes, oaepParms->mgf, hash, hlen); + if (rc != CKR_OK) + goto done; + + rc = os_specific_rsa_encrypt(em_data, modulus_bytes, cipher, key_obj); + if (rc == CKR_OK) { + memcpy(out_data, cipher, modulus_bytes); + *out_data_len = modulus_bytes; + } else { + TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); + } + +done: + if (em_data) { + OPENSSL_cleanse(em_data, modulus_bytes * sizeof(CK_BYTE)); + free(em_data); + } + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +CK_RV token_specific_rsa_oaep_decrypt(STDLL_TokData_t *tokdata, + ENCR_DECR_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, CK_BYTE *hash, + CK_ULONG hlen) +{ + CK_RV rc; + CK_BYTE *decr_data = NULL; + OBJECT *key_obj = NULL; + CK_BBOOL flag; + CK_ATTRIBUTE *attr = NULL; + CK_RSA_PKCS_OAEP_PARAMS_PTR oaepParms = NULL; + + if (!in_data || !out_data || !hash) { + TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); + return CKR_ARGUMENTS_BAD; + } + + oaepParms = (CK_RSA_PKCS_OAEP_PARAMS_PTR) ctx->mech.pParameter; + + rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_find_in_map1 failed\n"); + return rc; + } + + flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); + if (flag == FALSE) { + TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto error; + } + + *out_data_len = attr->ulValueLen; + + decr_data = (CK_BYTE *) malloc(in_data_len); + if (decr_data == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto error; + } + + rc = os_specific_rsa_decrypt(in_data, in_data_len, decr_data, key_obj); + if (rc != CKR_OK) + goto error; + + /* pkcs1v2.2, section 7.1.2 Step 2: + * EME-OAEP decoding. + */ + rc = decode_eme_oaep(tokdata, decr_data, in_data_len, out_data, + out_data_len, oaepParms->mgf, hash, hlen); + +error: + if (decr_data) { + OPENSSL_cleanse(decr_data, in_data_len); + free(decr_data); + } + + object_put(tokdata, key_obj, TRUE); + key_obj = NULL; + + return rc; +} + +#ifndef NOAES + +CK_RV token_specific_aes_key_gen(STDLL_TokData_t *tokdata, CK_BYTE *key, + CK_ULONG len, CK_ULONG keysize) +{ + UNUSED(keysize); + + return rng_generate(tokdata, key, len); +} + +CK_RV token_specific_aes_ecb(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, + CK_ULONG *out_data_len, + OBJECT *key, CK_BYTE encrypt) +{ + AES_KEY ssl_aes_key; + unsigned int i; + CK_ATTRIBUTE *attr = NULL; + /* There's a previous check that in_data_len % AES_BLOCK_SIZE == 0, + * so this is fine */ + CK_ULONG loops = (CK_ULONG) (in_data_len / AES_BLOCK_SIZE); + + UNUSED(tokdata); + + memset(&ssl_aes_key, 0, sizeof(AES_KEY)); + + // get key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key\n"); + return CKR_FUNCTION_FAILED; + } + // AES_ecb_encrypt encrypts only a single block, so we have to break up the + // input data here + if (encrypt) { + AES_set_encrypt_key((unsigned char *) attr->pValue, + (attr->ulValueLen * 8), &ssl_aes_key); + for (i = 0; i < loops; i++) { + AES_ecb_encrypt((unsigned char *) in_data + (i * AES_BLOCK_SIZE), + (unsigned char *) out_data + (i * AES_BLOCK_SIZE), + &ssl_aes_key, AES_ENCRYPT); + } + } else { + AES_set_decrypt_key((unsigned char *) attr->pValue, + (attr->ulValueLen * 8), &ssl_aes_key); + for (i = 0; i < loops; i++) { + AES_ecb_encrypt((unsigned char *) in_data + (i * AES_BLOCK_SIZE), + (unsigned char *) out_data + (i * AES_BLOCK_SIZE), + &ssl_aes_key, AES_DECRYPT); + } + } + *out_data_len = in_data_len; + + return CKR_OK; +} + +CK_RV token_specific_aes_cbc(STDLL_TokData_t *tokdata, + 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) +{ + AES_KEY ssl_aes_key; + CK_ATTRIBUTE *attr = NULL; + + UNUSED(tokdata); + + memset(&ssl_aes_key, 0, sizeof(AES_KEY)); + + // get key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key\n"); + return CKR_FUNCTION_FAILED; + } + // AES_cbc_encrypt chunks the data into AES_BLOCK_SIZE blocks, unlike + // AES_ecb_encrypt, so no looping required. + if (encrypt) { + AES_set_encrypt_key((unsigned char *) attr->pValue, + (attr->ulValueLen * 8), &ssl_aes_key); + AES_cbc_encrypt((unsigned char *) in_data, (unsigned char *) out_data, + in_data_len, &ssl_aes_key, init_v, AES_ENCRYPT); + } else { + AES_set_decrypt_key((unsigned char *) attr->pValue, + (attr->ulValueLen * 8), &ssl_aes_key); + AES_cbc_encrypt((unsigned char *) in_data, (unsigned char *) out_data, + in_data_len, &ssl_aes_key, init_v, AES_DECRYPT); + } + *out_data_len = in_data_len; + + return CKR_OK; +} +#endif + +/* Begin code contributed by Corrent corp. */ +#ifndef NODH +// This computes DH shared secret, where: +// Output: z is computed shared secret +// Input: y is other party's public key +// x is private key +// p is prime +// All length's are in number of bytes. All data comes in as Big Endian. +CK_RV token_specific_dh_pkcs_derive(STDLL_TokData_t *tokdata, + CK_BYTE *z, + CK_ULONG *z_len, + CK_BYTE *y, + CK_ULONG y_len, + CK_BYTE *x, + CK_ULONG x_len, CK_BYTE *p, CK_ULONG p_len) +{ + CK_RV rc; + BIGNUM *bn_z, *bn_y, *bn_x, *bn_p; + BN_CTX *ctx; + + UNUSED(tokdata); + + // Create and Init the BIGNUM structures. + bn_y = BN_new(); + bn_x = BN_new(); + bn_p = BN_new(); + bn_z = BN_new(); + + if (bn_z == NULL || bn_p == NULL || bn_x == NULL || bn_y == NULL) { + if (bn_y) + BN_free(bn_y); + if (bn_x) + BN_free(bn_x); + if (bn_p) + BN_free(bn_p); + if (bn_z) + BN_free(bn_z); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + // Initialize context + ctx = BN_CTX_new(); + if (ctx == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + // Add data into these new BN structures + + BN_bin2bn((unsigned char *) y, y_len, bn_y); + BN_bin2bn((unsigned char *) x, x_len, bn_x); + BN_bin2bn((unsigned char *) p, p_len, bn_p); + + rc = BN_mod_exp(bn_z, bn_y, bn_x, bn_p, ctx); + if (rc == 0) { + BN_free(bn_z); + BN_free(bn_y); + BN_free(bn_x); + BN_free(bn_p); + BN_CTX_free(ctx); + + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + + *z_len = BN_num_bytes(bn_z); + BN_bn2bin(bn_z, z); + + BN_free(bn_z); + BN_free(bn_y); + BN_free(bn_x); + BN_free(bn_p); + BN_CTX_free(ctx); + + return CKR_OK; +} /* end token_specific_dh_pkcs_derive() */ + +// This computes DH key pair, where: +// Output: priv_tmpl is generated private key +// pub_tmpl is computed public key +// Input: pub_tmpl is public key (prime and generator) +// All length's are in number of bytes. All data comes in as Big Endian. +CK_RV token_specific_dh_pkcs_key_pair_gen(STDLL_TokData_t *tokdata, + TEMPLATE *publ_tmpl, + TEMPLATE *priv_tmpl) +{ + CK_BBOOL rc; + CK_ATTRIBUTE *prime_attr = NULL; + CK_ATTRIBUTE *base_attr = NULL; + CK_ATTRIBUTE *temp_attr = NULL; + CK_ATTRIBUTE *value_bits_attr = NULL; + CK_BYTE *temp_byte; + CK_ULONG temp_bn_len; + DH *dh; + BIGNUM *bn_p; + BIGNUM *bn_g; + const BIGNUM *temp_bn; + + UNUSED(tokdata); + + rc = template_attribute_find(publ_tmpl, CKA_PRIME, &prime_attr); + rc &= template_attribute_find(publ_tmpl, CKA_BASE, &base_attr); + + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_PRIME or CKA_BASE for the key\n"); + return CKR_FUNCTION_FAILED; + } + + if ((prime_attr->ulValueLen > 256) || (prime_attr->ulValueLen < 64)) { + TRACE_ERROR("CKA_PRIME attribute value is invalid.\n"); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + dh = DH_new(); + if (dh == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + // Create and init BIGNUM structs to stick in the DH struct + bn_p = BN_new(); + bn_g = BN_new(); + if (bn_g == NULL || bn_p == NULL) { + if (bn_g) + BN_free(bn_g); + if (bn_p) + BN_free(bn_p); + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + // Convert from strings to BIGNUMs and stick them in the DH struct + BN_bin2bn((unsigned char *) prime_attr->pValue, prime_attr->ulValueLen, + bn_p); + BN_bin2bn((unsigned char *) base_attr->pValue, base_attr->ulValueLen, bn_g); +#ifdef OLDER_OPENSSL + dh->p = bn_p; + dh->g = bn_g; +#else + DH_set0_pqg(dh, bn_p, NULL, bn_g); +#endif + + // Generate the DH Key + if (!DH_generate_key(dh)) { + TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + // Extract the public and private key components from the DH struct, + // and insert them in the publ_tmpl and priv_tmpl + + // + // pub_key + // + //temp_bn = BN_new(); +#ifdef OLDER_OPENSSL + temp_bn = dh->pub_key; +#else + DH_get0_key(dh, &temp_bn, NULL); +#endif + temp_bn_len = BN_num_bytes(temp_bn); + temp_byte = malloc(temp_bn_len); + temp_bn_len = BN_bn2bin(temp_bn, temp_byte); + // in bytes + rc = build_attribute(CKA_VALUE, temp_byte, temp_bn_len, &temp_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + return CKR_FUNCTION_FAILED; + } + template_update_attribute(publ_tmpl, temp_attr); + free(temp_byte); + + // + // priv_key + // + //temp_bn = BN_new(); +#ifdef OLDER_OPENSSL + temp_bn = dh->priv_key; +#else + DH_get0_key(dh, NULL, &temp_bn); +#endif + temp_bn_len = BN_num_bytes(temp_bn); + temp_byte = malloc(temp_bn_len); + temp_bn_len = BN_bn2bin(temp_bn, temp_byte); + // in bytes + rc = build_attribute(CKA_VALUE, temp_byte, temp_bn_len, &temp_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + return CKR_FUNCTION_FAILED; + } + template_update_attribute(priv_tmpl, temp_attr); + free(temp_byte); + + // Update CKA_VALUE_BITS attribute in the private key + value_bits_attr = + (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG)); + value_bits_attr->type = CKA_VALUE_BITS; + value_bits_attr->ulValueLen = sizeof(CK_ULONG); + value_bits_attr->pValue = + (CK_BYTE *) value_bits_attr + sizeof(CK_ATTRIBUTE); + *(CK_ULONG *) value_bits_attr->pValue = 8 * temp_bn_len; + template_update_attribute(priv_tmpl, value_bits_attr); + + // Add prime and base to the private key template + rc = build_attribute(CKA_PRIME, + (unsigned char *) prime_attr->pValue, + prime_attr->ulValueLen, &temp_attr); // in bytes + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + return CKR_FUNCTION_FAILED; + } + template_update_attribute(priv_tmpl, temp_attr); + + rc = build_attribute(CKA_BASE, + (unsigned char *) base_attr->pValue, + base_attr->ulValueLen, &temp_attr); // in bytes + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + return CKR_FUNCTION_FAILED; + } + template_update_attribute(priv_tmpl, temp_attr); + + // Cleanup DH key + DH_free(dh); + + return CKR_OK; +} /* end token_specific_dh_key_pair_gen() */ +#endif +/* End code contributed by Corrent corp. */ + +CK_RV token_specific_get_mechanism_list(STDLL_TokData_t *tokdata, + CK_MECHANISM_TYPE_PTR pMechanismList, + CK_ULONG_PTR pulCount) +{ + return ock_generic_get_mechanism_list(tokdata, pMechanismList, pulCount); +} + +CK_RV token_specific_get_mechanism_info(STDLL_TokData_t *tokdata, + CK_MECHANISM_TYPE type, + CK_MECHANISM_INFO_PTR pInfo) +{ + return ock_generic_get_mechanism_info(tokdata, type, pInfo); +} + +CK_RV token_specific_sha_init(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, + CK_MECHANISM *mech) +{ + int rc; + CK_ULONG len; + + UNUSED(tokdata); + + switch (mech->mechanism) { + case CKM_SHA_1: + len = sizeof(SHA_CTX); + break; + case CKM_SHA224: + len = sizeof(SHA256_CTX); + break; + case CKM_SHA256: + len = sizeof(SHA256_CTX); + break; + case CKM_SHA384: + len = sizeof(SHA512_CTX); + break; + case CKM_SHA512: + case CKM_SHA512_224: + case CKM_SHA512_256: + len = sizeof(SHA512_CTX); + break; + default: + return CKR_MECHANISM_INVALID; + } + + ctx->context_len = len; + ctx->context = (CK_BYTE *) malloc(len); + if (ctx->context == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return CKR_HOST_MEMORY; + } + + switch (mech->mechanism) { + case CKM_SHA_1: + rc = SHA1_Init((SHA_CTX *)ctx->context); + break; + case CKM_SHA224: + rc = SHA224_Init((SHA256_CTX *)ctx->context); + break; + case CKM_SHA256: + rc = SHA256_Init((SHA256_CTX *)ctx->context); + break; + case CKM_SHA384: + rc = SHA384_Init((SHA512_CTX *)ctx->context); + break; + case CKM_SHA512: + case CKM_SHA512_224: + case CKM_SHA512_256: + rc = SHA512_Init((SHA512_CTX *)ctx->context); + break; + default: /* cannot happen */ + rc = CKR_MECHANISM_INVALID; + } + + if (!rc) { + free(ctx->context); + ctx->context = NULL; + ctx->context_len = 0; + return CKR_FUNCTION_FAILED; + } + + switch (mech->mechanism) { + case CKM_SHA512_224: + { + SHA512_CTX *c = (SHA512_CTX *)ctx->context; + + /* SHA-512/224 uses a distinct initial hash value */ + c->h[0] = 0x8c3d37c819544da2ULL; + c->h[1] = 0x73e1996689dcd4d6ULL; + c->h[2] = 0x1dfab7ae32ff9c82ULL; + c->h[3] = 0x679dd514582f9fcfULL; + c->h[4] = 0x0f6d2b697bd44da8ULL; + c->h[5] = 0x77e36f7304c48942ULL; + c->h[6] = 0x3f9d85a86a1d36c8ULL; + c->h[7] = 0x1112e6ad91d692a1ULL; + break; + } + case CKM_SHA512_256: + { + SHA512_CTX *c = (SHA512_CTX *)ctx->context; + + /* SHA-512/256 uses a distinct initial hash value */ + c->h[0] = 0x22312194fc2bf72cULL; + c->h[1] = 0x9f555fa3c84c64c2ULL; + c->h[2] = 0x2393b86b6f53b151ULL; + c->h[3] = 0x963877195940eabdULL; + c->h[4] = 0x96283ee2a88effe3ULL; + c->h[5] = 0xbe5e1e2553863992ULL; + c->h[6] = 0x2b0199fc2c85b8aaULL; + c->h[7] = 0x0eb72ddc81c52ca2ULL; + break; + } + } + + return CKR_OK; +} + +CK_RV token_specific_sha(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + unsigned int hlen; + CK_BYTE temp_out_data[MAX_SHA_HASH_SIZE]; + CK_BYTE *orig_out_data = out_data; + + UNUSED(tokdata); + + if (!ctx || !ctx->context) + return CKR_OPERATION_NOT_INITIALIZED; + + if (!in_data || !out_data) + return CKR_ARGUMENTS_BAD; + + switch (ctx->mech.mechanism) { + case CKM_SHA_1: + hlen = SHA1_HASH_SIZE; + break; + case CKM_SHA224: + hlen = SHA224_HASH_SIZE; + break; + case CKM_SHA256: + hlen = SHA256_HASH_SIZE; + break; + case CKM_SHA384: + hlen = SHA384_HASH_SIZE; + break; + case CKM_SHA512: + hlen = SHA512_HASH_SIZE; + break; + case CKM_SHA512_224: + hlen = SHA224_HASH_SIZE; + break; + case CKM_SHA512_256: + hlen = SHA256_HASH_SIZE; + break; + default: + return CKR_MECHANISM_INVALID; + } + + if (*out_data_len < hlen) + return CKR_BUFFER_TOO_SMALL; + + switch (ctx->mech.mechanism) { + case CKM_SHA_1: + if (!SHA1_Update((SHA_CTX *)ctx->context, in_data, in_data_len) + || !SHA1_Final(out_data, (SHA_CTX *)ctx->context)) + goto error; + break; + case CKM_SHA224: + if (!SHA224_Update((SHA256_CTX *)ctx->context, in_data, in_data_len) + || !SHA224_Final(out_data, (SHA256_CTX *)ctx->context)) + goto error; + break; + case CKM_SHA256: + if (!SHA256_Update((SHA256_CTX *)ctx->context, in_data, in_data_len) + || !SHA256_Final(out_data, (SHA256_CTX *)ctx->context)) + goto error; + break; + case CKM_SHA384: + if (!SHA384_Update((SHA512_CTX *)ctx->context, in_data, in_data_len) + || !SHA384_Final(out_data, (SHA512_CTX *)ctx->context)) + goto error; + break; + case CKM_SHA512: + if (!SHA512_Update((SHA512_CTX *)ctx->context, in_data, in_data_len) + || !SHA512_Final(out_data, (SHA512_CTX *)ctx->context)) + goto error; + break; + case CKM_SHA512_224: + case CKM_SHA512_256: + out_data = temp_out_data; + + if (!SHA512_Update((SHA512_CTX *)ctx->context, in_data, in_data_len) + || !SHA512_Final(out_data, (SHA512_CTX *)ctx->context)) + goto error; + + memcpy(orig_out_data, temp_out_data, hlen); + OPENSSL_cleanse(temp_out_data, sizeof(temp_out_data)); + break; + } + + *out_data_len = hlen; + return CKR_OK; + +error: + free(ctx->context); + ctx->context = NULL; + ctx->context_len = 0; + + return CKR_FUNCTION_FAILED; +} + +CK_RV token_specific_sha_update(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + int rc; + + UNUSED(tokdata); + + if (!ctx || !ctx->context) + return CKR_OPERATION_NOT_INITIALIZED; + + if (!in_data) + return CKR_ARGUMENTS_BAD; + + switch (ctx->mech.mechanism) { + case CKM_SHA_1: + rc = SHA1_Update((SHA_CTX *) ctx->context, in_data, in_data_len); + break; + case CKM_SHA224: + rc = SHA224_Update((SHA256_CTX*) ctx->context, in_data, in_data_len); + break; + case CKM_SHA256: + rc = SHA256_Update((SHA256_CTX *) ctx->context, in_data, in_data_len); + break; + case CKM_SHA384: + rc = SHA384_Update((SHA512_CTX *) ctx->context, in_data, in_data_len); + break; + case CKM_SHA512: + case CKM_SHA512_224: + case CKM_SHA512_256: + rc = SHA512_Update((SHA512_CTX *) ctx->context, in_data, in_data_len); + break; + default: + return CKR_MECHANISM_INVALID; + } + + if (!rc) { + free(ctx->context); + ctx->context = NULL; + ctx->context_len = 0; + return CKR_FUNCTION_FAILED; + } + + return CKR_OK; +} + +CK_RV token_specific_sha_final(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, + CK_BYTE *out_data, CK_ULONG *out_data_len) +{ + unsigned int hlen; + CK_BYTE temp_out_data[MAX_SHA_HASH_SIZE]; + CK_BYTE *orig_out_data = out_data; + + UNUSED(tokdata); + + if (!ctx || !ctx->context) + return CKR_OPERATION_NOT_INITIALIZED; + + if (!out_data) + return CKR_ARGUMENTS_BAD; + + switch (ctx->mech.mechanism) { + case CKM_SHA_1: + hlen = SHA1_HASH_SIZE; + break; + case CKM_SHA224: + hlen = SHA224_HASH_SIZE; + break; + case CKM_SHA256: + hlen = SHA256_HASH_SIZE; + break; + case CKM_SHA384: + hlen = SHA384_HASH_SIZE; + break; + case CKM_SHA512: + hlen = SHA512_HASH_SIZE; + break; + case CKM_SHA512_224: + hlen = SHA224_HASH_SIZE; + break; + case CKM_SHA512_256: + hlen = SHA256_HASH_SIZE; + break; + default: + return CKR_MECHANISM_INVALID; + } + + if (*out_data_len < hlen) + return CKR_BUFFER_TOO_SMALL; + + switch (ctx->mech.mechanism) { + case CKM_SHA_1: + if (!SHA1_Final(out_data, (SHA_CTX *)ctx->context)) + goto error; + break; + case CKM_SHA224: + if (!SHA224_Final(out_data, (SHA256_CTX *)ctx->context)) + goto error; + break; + case CKM_SHA256: + if (!SHA256_Final(out_data, (SHA256_CTX *)ctx->context)) + goto error; + break; + case CKM_SHA384: + if (!SHA384_Final(out_data, (SHA512_CTX *)ctx->context)) + goto error; + break; + case CKM_SHA512: + if (!SHA512_Final(out_data, (SHA512_CTX *)ctx->context)) + goto error; + break; + case CKM_SHA512_224: + case CKM_SHA512_256: + out_data = temp_out_data; + + if (!SHA512_Final(out_data, (SHA512_CTX *)ctx->context)) + goto error; + + memcpy(orig_out_data, temp_out_data, hlen); + OPENSSL_cleanse(temp_out_data, sizeof(temp_out_data)); + break; + } + + *out_data_len = hlen; + return CKR_OK; + +error: + free(ctx->context); + ctx->context = NULL; + ctx->context_len = 0; + return CKR_FUNCTION_FAILED; +} + +static CK_RV softtok_hmac_init(STDLL_TokData_t *tokdata, + SIGN_VERIFY_CONTEXT *ctx, CK_MECHANISM_PTR mech, + CK_OBJECT_HANDLE Hkey) +{ + int rc; + OBJECT *key = NULL; + CK_ATTRIBUTE *attr = NULL; + EVP_MD_CTX *mdctx = NULL; + EVP_PKEY *pkey = NULL; + + rc = object_mgr_find_in_map1(tokdata, Hkey, &key, READ_LOCK); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to find specified object.\n"); + return rc; + } + + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, attr->pValue, + attr->ulValueLen); + if (pkey == NULL) { + TRACE_ERROR("EVP_PKEY_new_mac_key() failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + mdctx = EVP_MD_CTX_create(); + if (mdctx == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + rc = CKR_HOST_MEMORY; + goto done; + } + + switch (mech->mechanism) { + case CKM_SHA_1_HMAC_GENERAL: + case CKM_SHA_1_HMAC: + rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha1(), NULL, pkey); + break; + case CKM_SHA224_HMAC_GENERAL: + case CKM_SHA224_HMAC: + rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha224(), NULL, pkey); + break; + case CKM_SHA256_HMAC_GENERAL: + case CKM_SHA256_HMAC: + rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha256(), NULL, pkey); + break; + case CKM_SHA384_HMAC_GENERAL: + case CKM_SHA384_HMAC: + rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha384(), NULL, pkey); + break; + case CKM_SHA512_HMAC_GENERAL: + case CKM_SHA512_HMAC: + rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha512(), NULL, pkey); + break; + default: + EVP_MD_CTX_destroy(mdctx); + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + rc = CKR_MECHANISM_INVALID; + goto done; + } + + if (rc != 1) { + EVP_MD_CTX_destroy(mdctx); + ctx->context = NULL; + TRACE_ERROR("EVP_DigestSignInit failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } else { + ctx->context = (CK_BYTE *) mdctx; + } + + rc = CKR_OK; +done: +if (pkey != NULL) + EVP_PKEY_free(pkey); + + object_put(tokdata, key, TRUE); + key = NULL; + return rc; +} + +CK_RV token_specific_hmac_sign_init(STDLL_TokData_t *tokdata, SESSION *sess, + CK_MECHANISM *mech, CK_OBJECT_HANDLE Hkey) +{ + return softtok_hmac_init(tokdata, &sess->sign_ctx, mech, Hkey); +} + +CK_RV token_specific_hmac_verify_init(STDLL_TokData_t *tokdata, SESSION *sess, + CK_MECHANISM *mech, + CK_OBJECT_HANDLE Hkey) +{ + return softtok_hmac_init(tokdata, &sess->verify_ctx, mech, Hkey); +} + +static CK_RV softtok_hmac(SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BYTE *signature, + CK_ULONG *sig_len, CK_BBOOL sign) +{ + int rc; + size_t mac_len, len; + unsigned char mac[MAX_SHA_HASH_SIZE]; + EVP_MD_CTX *mdctx = NULL; + CK_RV rv = CKR_OK; + CK_BBOOL general = FALSE; + + if (!ctx || !ctx->context) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + if (sign && !sig_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + switch (ctx->mech.mechanism) { + case CKM_SHA_1_HMAC_GENERAL: + general = TRUE; + /* fallthrough */ + case CKM_SHA_1_HMAC: + mac_len = SHA1_HASH_SIZE; + break; + case CKM_SHA224_HMAC_GENERAL: + general = TRUE; + /* fallthrough */ + case CKM_SHA224_HMAC: + mac_len = SHA224_HASH_SIZE; + break; + case CKM_SHA256_HMAC_GENERAL: + general = TRUE; + /* fallthrough */ + case CKM_SHA256_HMAC: + mac_len = SHA256_HASH_SIZE; + break; + case CKM_SHA384_HMAC_GENERAL: + general = TRUE; + /* fallthrough */ + case CKM_SHA384_HMAC: + mac_len = SHA384_HASH_SIZE; + break; + case CKM_SHA512_HMAC_GENERAL: + general = TRUE; + /* fallthrough */ + case CKM_SHA512_HMAC: + mac_len = SHA512_HASH_SIZE; + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + mdctx = (EVP_MD_CTX *) ctx->context; + + rc = EVP_DigestSignUpdate(mdctx, in_data, in_data_len); + if (rc != 1) { + TRACE_ERROR("EVP_DigestSignUpdate failed.\n"); + rv = CKR_FUNCTION_FAILED; + goto done; + } + + rc = EVP_DigestSignFinal(mdctx, mac, &mac_len); + if (rc != 1) { + TRACE_ERROR("EVP_DigestSignFinal failed.\n"); + rv = CKR_FUNCTION_FAILED; + goto done; + } + + if (sign) { + if (general) + *sig_len = *(CK_ULONG *) ctx->mech.pParameter; + else + *sig_len = mac_len; + + memcpy(signature, mac, *sig_len); + + } else { + if (general) + len = *(CK_ULONG *) ctx->mech.pParameter; + else + len = mac_len; + + if (CRYPTO_memcmp(signature, mac, len) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + rv = CKR_SIGNATURE_INVALID; + } + } +done: + EVP_MD_CTX_destroy(mdctx); + ctx->context = NULL; + + return rv; +} + +CK_RV token_specific_hmac_sign(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG *sig_len) +{ + UNUSED(tokdata); + + return softtok_hmac(&sess->sign_ctx, in_data, in_data_len, signature, + sig_len, TRUE); +} + +CK_RV token_specific_hmac_verify(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) +{ + UNUSED(tokdata); + + return softtok_hmac(&sess->verify_ctx, in_data, in_data_len, signature, + &sig_len, FALSE); +} + +static CK_RV softtok_hmac_update(SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, + CK_ULONG in_data_len, CK_BBOOL sign) +{ + int rc; + EVP_MD_CTX *mdctx = NULL; + CK_RV rv = CKR_OK; + + UNUSED(sign); + + if (!ctx || !ctx->context) + return CKR_OPERATION_NOT_INITIALIZED; + + mdctx = (EVP_MD_CTX *) ctx->context; + + rc = EVP_DigestSignUpdate(mdctx, in_data, in_data_len); + if (rc != 1) { + TRACE_ERROR("EVP_DigestSignUpdate failed.\n"); + rv = CKR_FUNCTION_FAILED; + } else { + ctx->context = (CK_BYTE *) mdctx; + return CKR_OK; + } + + EVP_MD_CTX_destroy(mdctx); + ctx->context = NULL; + return rv; +} + +CK_RV token_specific_hmac_sign_update(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BYTE *in_data, CK_ULONG in_data_len) +{ + UNUSED(tokdata); + + return softtok_hmac_update(&sess->sign_ctx, in_data, in_data_len, TRUE); +} + +CK_RV token_specific_hmac_verify_update(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BYTE *in_data, + CK_ULONG in_data_len) +{ + UNUSED(tokdata); + + return softtok_hmac_update(&sess->verify_ctx, in_data, in_data_len, FALSE); +} + +static CK_RV softtok_hmac_final(SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *signature, + CK_ULONG *sig_len, CK_BBOOL sign) +{ + int rc; + size_t mac_len, len; + unsigned char mac[MAX_SHA_HASH_SIZE]; + EVP_MD_CTX *mdctx = NULL; + CK_RV rv = CKR_OK; + CK_BBOOL general = FALSE; + + if (!ctx || !ctx->context) + return CKR_OPERATION_NOT_INITIALIZED; + + if (sign && !sig_len) { + TRACE_ERROR("%s received bad argument(s)\n", __func__); + return CKR_FUNCTION_FAILED; + } + + switch (ctx->mech.mechanism) { + case CKM_SHA_1_HMAC_GENERAL: + general = TRUE; + /* fallthrough */ + case CKM_SHA_1_HMAC: + mac_len = SHA1_HASH_SIZE; + break; + case CKM_SHA224_HMAC_GENERAL: + general = TRUE; + /* fallthrough */ + case CKM_SHA224_HMAC: + mac_len = SHA224_HASH_SIZE; + break; + case CKM_SHA256_HMAC_GENERAL: + general = TRUE; + /* fallthrough */ + case CKM_SHA256_HMAC: + mac_len = SHA256_HASH_SIZE; + break; + case CKM_SHA384_HMAC_GENERAL: + general = TRUE; + /* fallthrough */ + case CKM_SHA384_HMAC: + mac_len = SHA384_HASH_SIZE; + break; + case CKM_SHA512_HMAC_GENERAL: + general = TRUE; + /* fallthrough */ + case CKM_SHA512_HMAC: + mac_len = SHA512_HASH_SIZE; + break; + default: + TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); + return CKR_MECHANISM_INVALID; + } + + if (signature == NULL) { + if (sign) { + if (general) + *sig_len = *(CK_ULONG *) ctx->mech.pParameter; + else + *sig_len = (CK_ULONG) mac_len; + } + return CKR_OK; + } + + mdctx = (EVP_MD_CTX *) ctx->context; + + rc = EVP_DigestSignFinal(mdctx, mac, &mac_len); + if (rc != 1) { + TRACE_ERROR("EVP_DigestSignFinal failed.\n"); + rv = CKR_FUNCTION_FAILED; + goto done; + } + + if (sign) { + if (general) + *sig_len = *(CK_ULONG *) ctx->mech.pParameter; + else + *sig_len = mac_len; + + memcpy(signature, mac, *sig_len); + + } else { + if (general) + len = *(CK_ULONG *) ctx->mech.pParameter; + else + len = mac_len; + + if (CRYPTO_memcmp(signature, mac, len) != 0) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + rv = CKR_SIGNATURE_INVALID; + } + } +done: + EVP_MD_CTX_destroy(mdctx); + ctx->context = NULL; + return rv; +} + +CK_RV token_specific_hmac_sign_final(STDLL_TokData_t *tokdata, SESSION *sess, + CK_BYTE *signature, CK_ULONG *sig_len) +{ + UNUSED(tokdata); + + return softtok_hmac_final(&sess->sign_ctx, signature, sig_len, TRUE); +} + +CK_RV token_specific_hmac_verify_final(STDLL_TokData_t *tokdata, + SESSION *sess, CK_BYTE *signature, + CK_ULONG sig_len) +{ + UNUSED(tokdata); + + return softtok_hmac_final(&sess->verify_ctx, signature, &sig_len, FALSE); +} + +CK_RV token_specific_generic_secret_key_gen(STDLL_TokData_t *tokdata, + TEMPLATE *tmpl) +{ + CK_ATTRIBUTE *attr = NULL; + CK_ATTRIBUTE *gkey = NULL; + CK_RV rc = CKR_OK; + CK_BYTE secret_key[MAX_GENERIC_KEY_SIZE]; + CK_ULONG key_length = 0; + CK_ULONG key_length_in_bits = 0; + + rc = template_attribute_find(tmpl, CKA_VALUE_LEN, &attr); + if (rc == FALSE) { + TRACE_ERROR("CKA_VALUE_LEN missing in (HMAC) key template\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + + //app specified key length in bytes + key_length = *(CK_ULONG *) attr->pValue; + key_length_in_bits = key_length * 8; + + /* After looking at fips cavs test vectors for HMAC ops, + * it was decided that the key length should fall between + * 80 and 2048 bits inclusive. openssl does not explicitly + * specify limits to key sizes for secret keys + */ + if ((key_length_in_bits < 80) || (key_length_in_bits > 2048)) { + TRACE_ERROR("Generic secret key size of %lu bits not within" + " required range of 80-2048 bits\n", key_length_in_bits); + return CKR_KEY_SIZE_RANGE; + } + + rc = rng_generate(tokdata, secret_key, key_length); + if (rc != CKR_OK) { + TRACE_DEVEL("Generic secret key generation failed.\n"); + return rc; + } + + rc = build_attribute(CKA_VALUE, secret_key, key_length, &gkey); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute(CKA_VALUE) failed\n"); + return rc; + } + + rc = template_update_attribute(tmpl, gkey); + if (rc != CKR_OK) + TRACE_DEVEL("template_update_attribute(CKA_VALUE) failed.\n"); + + return rc; +} + +CK_RV token_specific_tdes_cmac(STDLL_TokData_t *tokdata, CK_BYTE *message, + CK_ULONG message_len, OBJECT *key, CK_BYTE *mac, + CK_BBOOL first, CK_BBOOL last, CK_VOID_PTR *ctx) +{ + int rc; + CK_RV rv = CKR_OK; + CK_ATTRIBUTE *attr = NULL; + CK_KEY_TYPE keytype; + CMAC_CTX *cmac_ctx; + const EVP_CIPHER *cipher; + size_t maclen; + + UNUSED(tokdata); + + if (first) { + // get the key type + rc = template_attribute_find(key->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + keytype = *(CK_KEY_TYPE *) attr->pValue; + + // get the key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + switch (keytype) { + case CKK_DES2: + cipher = EVP_des_ede_cbc(); + break; + case CKK_DES3: + cipher = EVP_des_ede3_cbc(); + break; + default: + TRACE_ERROR("Invalid key type: %lu\n", keytype); + return CKR_KEY_TYPE_INCONSISTENT; + } + if (cipher == NULL) { + TRACE_ERROR("Failed to allocate cipher\n"); + return CKR_HOST_MEMORY; + } + + cmac_ctx = CMAC_CTX_new(); + if (cmac_ctx == NULL) { + TRACE_ERROR("Failed to allocate CMAC context\n"); + return CKR_HOST_MEMORY; + } + + rc = CMAC_Init(cmac_ctx, attr->pValue, attr->ulValueLen, cipher, NULL); + if (rc != 1) { + TRACE_ERROR("CMAC_Init failed\n"); + CMAC_CTX_free(cmac_ctx); + return CKR_FUNCTION_FAILED; + } + + *ctx = cmac_ctx; + } + + cmac_ctx = (CMAC_CTX *)*ctx; + + rc = CMAC_Update(cmac_ctx, message, message_len); + if (rc != 1) { + TRACE_ERROR("CMAC_Update failed\n"); + rv = CKR_FUNCTION_FAILED; + } + + if (last) { + maclen = AES_BLOCK_SIZE; + rc = CMAC_Final(cmac_ctx, mac, &maclen); + if (rc != 1) { + TRACE_ERROR("CMAC_Final failed\n"); + rv = CKR_FUNCTION_FAILED; + } + } + + if (last || (first && rv != CKR_OK)) { + CMAC_CTX_free(cmac_ctx); + *ctx = NULL; + } + + return rv; +} + + +CK_RV token_specific_aes_cmac(STDLL_TokData_t *tokdata, CK_BYTE *message, + CK_ULONG message_len, OBJECT *key, CK_BYTE *mac, + CK_BBOOL first, CK_BBOOL last, CK_VOID_PTR *ctx) +{ + int rc; + CK_RV rv = CKR_OK; + CK_ATTRIBUTE *attr = NULL; + CMAC_CTX *cmac_ctx; + const EVP_CIPHER *cipher; + size_t maclen; + + UNUSED(tokdata); + + if (first) { + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); + return CKR_FUNCTION_FAILED; + } + + switch (attr->ulValueLen * 8) { + case 128: + cipher = EVP_aes_128_cbc(); + break; + case 192: + cipher = EVP_aes_192_cbc(); + break; + case 256: + cipher = EVP_aes_256_cbc(); + break; + default: + TRACE_ERROR("Invalid key size: %lu\n", attr->ulValueLen); + return CKR_KEY_TYPE_INCONSISTENT; + } + if (cipher == NULL) { + TRACE_ERROR("Failed to allocate cipher\n"); + return CKR_HOST_MEMORY; + } + + cmac_ctx = CMAC_CTX_new(); + if (cmac_ctx == NULL) { + TRACE_ERROR("Failed to allocate CMAC context\n"); + return CKR_HOST_MEMORY; + } + + rc = CMAC_Init(cmac_ctx, attr->pValue, attr->ulValueLen, cipher, NULL); + if (rc != 1) { + TRACE_ERROR("CMAC_Init failed\n"); + CMAC_CTX_free(cmac_ctx); + return CKR_FUNCTION_FAILED; + } + + *ctx = cmac_ctx; + } + + cmac_ctx = (CMAC_CTX *)*ctx; + + rc = CMAC_Update(cmac_ctx, message, message_len); + if (rc != 1) { + TRACE_ERROR("CMAC_Update failed\n"); + rv = CKR_FUNCTION_FAILED; + } + + if (last) { + maclen = AES_BLOCK_SIZE; + rc = CMAC_Final(cmac_ctx, mac, &maclen); + if (rc != 1) { + TRACE_ERROR("CMAC_Final failed\n"); + rv = CKR_FUNCTION_FAILED; + } + } + + if (last || (first && rv != CKR_OK)) { + CMAC_CTX_free(cmac_ctx); + *ctx = NULL; + } + + return rv; +} diff --git a/usr/lib/soft_stdll/soft_stdll.mk b/usr/lib/soft_stdll/soft_stdll.mk new file mode 100644 index 0000000..cecb16a --- /dev/null +++ b/usr/lib/soft_stdll/soft_stdll.mk @@ -0,0 +1,42 @@ +nobase_lib_LTLIBRARIES += opencryptoki/stdll/libpkcs11_sw.la + +noinst_HEADERS += usr/lib/soft_stdll/tok_struct.h + +opencryptoki_stdll_libpkcs11_sw_la_CFLAGS = \ + -DDEV -D_THREAD_SAFE -DSHALLOW=0 -DSWTOK=1 -DLITE=0 -DNOCDMF \ + -DNOMD2 -DNODSA -DNORIPE -fPIC -I${srcdir}/usr/lib/soft_stdll \ + -DTOK_NEW_DATA_STORE=0x0003000c \ + -I${srcdir}/usr/lib/common -I${srcdir}/usr/include \ + -DSTDLL_NAME=\"swtok\" + +opencryptoki_stdll_libpkcs11_sw_la_LDFLAGS = \ + -shared -Wl,-z,defs,-Bsymbolic -lc -lpthread -lcrypto -lrt \ + -Wl,--version-script=${srcdir}/opencryptoki_tok.map + +opencryptoki_stdll_libpkcs11_sw_la_SOURCES = \ + usr/lib/common/asn1.c usr/lib/common/cert.c \ + usr/lib/common/hwf_obj.c usr/lib/common/dp_obj.c \ + usr/lib/common/data_obj.c usr/lib/common/decr_mgr.c \ + usr/lib/common/dig_mgr.c usr/lib/common/encr_mgr.c \ + usr/lib/common/globals.c usr/lib/common/sw_crypt.c \ + usr/lib/common/loadsave.c usr/lib/common/key.c \ + usr/lib/common/key_mgr.c usr/lib/common/mech_aes.c \ + usr/lib/common/mech_des.c usr/lib/common/mech_des3.c \ + usr/lib/common/mech_dh.c usr/lib/common/mech_md5.c \ + usr/lib/common/mech_md2.c usr/lib/common/mech_rng.c \ + usr/lib/common/mech_rsa.c usr/lib/common/mech_sha.c \ + usr/lib/common/mech_ssl3.c usr/lib/common/mech_ec.c \ + usr/lib/common/new_host.c usr/lib/common/obj_mgr.c \ + usr/lib/common/object.c usr/lib/common/sign_mgr.c \ + usr/lib/common/template.c usr/lib/common/p11util.c \ + usr/lib/common/utility.c usr/lib/common/verify_mgr.c \ + usr/lib/common/trace.c usr/lib/common/mech_list.c \ + usr/lib/common/shared_memory.c usr/lib/soft_stdll/soft_specific.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/common/btree.c usr/lib/common/sess_mgr.c +endif diff --git a/usr/lib/soft_stdll/tok_struct.h b/usr/lib/soft_stdll/tok_struct.h new file mode 100644 index 0000000..1ee86fc --- /dev/null +++ b/usr/lib/soft_stdll/tok_struct.h @@ -0,0 +1,164 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2002-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 + */ + +/*************************************************************************** + Change Log + ========== + 4/25/03 Kapil Sood (kapil@corrent.com) + Added DH key pair generation and DH shared key derivation + functions. + + + +****************************************************************************/ + +// SAB FIXME need to figure out a better way... +// // to get the variant dependency out +#ifndef __TOK_STRUCT_H +#define __TOK_STRUCT_H +#include + +#include "tok_spec_struct.h" + +// #define PK_LITE_DIR "/etc/pkcs11/lite" +// +// #define PK_DIR PK_LITE_DIR +// #define SUB_DIR "lite" +// +// +// #define DBGTAG "ICA_STDLL_Debug" +// +// +// + +#ifndef SW_CONFIG_PATH + +#ifndef CONFIG_PATH +#warning CONFIG_PATH not set, using default (/usr/local/var/lib/opencryptoki) +#define CONFIG_PATH "/usr/local/var/lib/opencryptoki" +#endif // #ifndef CONFIG_PATH + +#define SW_CONFIG_PATH CONFIG_PATH "/swtok" +#endif // #ifndef SW_CONFIG_PATH + +token_spec_t token_specific = { + SW_CONFIG_PATH, + "swtok", + 0, // keysize + // Token data info: + { + FALSE, // Don't use per guest data store + TRUE, // Use master key + CKM_DES3_CBC, // Data store encryption + (CK_BYTE *)"12345678", // Default initialization vector for pins + (CK_BYTE *)"10293847", // Default initialization vector for objects + }, + NULL, // t_creatlock + NULL, // t_attach_shm + &token_specific_init, + NULL, // init_token_data + NULL, // load_token_data + NULL, // save_token_data + NULL, // random number generator + &token_specific_final, + NULL, // init_token + NULL, // login + NULL, // logout + NULL, // init_pin + NULL, // set_pin + // DES + &token_specific_des_key_gen, + &token_specific_des_ecb, + &token_specific_des_cbc, + // Triple DES + &token_specific_tdes_ecb, + &token_specific_tdes_cbc, + NULL, // des3_ofb + NULL, // des3_cfb + NULL, // des3_mac + &token_specific_tdes_cmac, + // RSA + &token_specific_rsa_decrypt, + &token_specific_rsa_encrypt, + &token_specific_rsa_sign, + &token_specific_rsa_verify, + &token_specific_rsa_verify_recover, + &token_specific_rsa_x509_decrypt, + &token_specific_rsa_x509_encrypt, + &token_specific_rsa_x509_sign, + &token_specific_rsa_x509_verify, + &token_specific_rsa_x509_verify_recover, + &token_specific_rsa_oaep_decrypt, + &token_specific_rsa_oaep_encrypt, + &token_specific_rsa_pss_sign, + &token_specific_rsa_pss_verify, + &token_specific_rsa_generate_keypair, + // Elliptic Curve + NULL, // ec_sign + NULL, // ec_verify + NULL, // ec_generate_keypair + NULL, // ecdh_derive +/* Begin code contributed by Corrent corp. */ + // DH +#ifndef NODH + &token_specific_dh_pkcs_derive, + &token_specific_dh_pkcs_key_pair_gen, +#else + NULL, // dh_pkcs_derive + NULL, // dh_pkcs_key_pair_gen +#endif +/* End code contributed by Corrent corp. */ + &token_specific_sha_init, + &token_specific_sha, + &token_specific_sha_update, + &token_specific_sha_final, + // HMAC + &token_specific_hmac_sign_init, + &token_specific_hmac_sign, + &token_specific_hmac_sign_update, + &token_specific_hmac_sign_final, + &token_specific_hmac_verify_init, + &token_specific_hmac_verify, + &token_specific_hmac_verify_update, + &token_specific_hmac_verify_final, + &token_specific_generic_secret_key_gen, + // AES +#ifndef NOAES + &token_specific_aes_key_gen, + &token_specific_aes_ecb, + &token_specific_aes_cbc, +#else + NULL, // aes_key_gen + NULL, // aes_ecb + NULL, // aes_cbc +#endif + NULL, // aes_ctr + NULL, // aes_gcm_init + NULL, // aes_gcm + NULL, // aes_gcm_update + NULL, // aes_gcm_final + NULL, // aes_ofb + NULL, // aes_cfb + NULL, // aes_mac +#ifndef NOAES + &token_specific_aes_cmac, +#else + NULL, // aes_cmac +#endif + // DSA + NULL, // dsa_generate_keypair + NULL, // dsa_sign + NULL, // dsa_verify + &token_specific_get_mechanism_list, + &token_specific_get_mechanism_info, + NULL // object_add +}; + +#endif diff --git a/usr/lib/tpm_stdll/defs.h b/usr/lib/tpm_stdll/defs.h new file mode 100644 index 0000000..aed29e8 --- /dev/null +++ b/usr/lib/tpm_stdll/defs.h @@ -0,0 +1,27 @@ +/* + * 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: defs.h + * + * Contains various definitions needed by both the host-side + * and coprocessor-side code. + */ + +#ifndef _TPM_DEFS_H +#define _TPM_DEFS_H + +#include "../common/defs.h" + +#undef MAX_PIN_LEN +#undef MIN_PIN_LEN +#define MAX_PIN_LEN 127 +#define MIN_PIN_LEN 6 + +#endif diff --git a/usr/lib/tpm_stdll/tok_struct.h b/usr/lib/tpm_stdll/tok_struct.h new file mode 100644 index 0000000..74dd361 --- /dev/null +++ b/usr/lib/tpm_stdll/tok_struct.h @@ -0,0 +1,118 @@ +/* + * 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 + */ + +#include "tpm_specific.h" + +#ifndef TPM_CONFIG_PATH + +#ifndef CONFIG_PATH +#warning CONFIG_PATH not set, using default (/usr/local/var/lib/opencryptoki) +#define CONFIG_PATH "/usr/local/var/lib/opencryptoki" +#endif // #ifndef CONFIG_PATH + +#define TPM_CONFIG_PATH CONFIG_PATH "/tpm" +#endif // #ifndef TPM_CONFIG_PATH + +struct token_specific_struct token_specific = { + TPM_CONFIG_PATH, + "tpm", + 0, + // Token data info: + { + TRUE, // Use per guest data store + TRUE, // Use master key + CKM_AES_CBC, // Data store encryption + NULL, // Default initialization vector for pins + (CK_BYTE *)")#%&!*)^!()$&!&N",// Default initialization vector + // for objects + }, + token_specific_creatlock, + NULL, // attach_shm + &token_specific_init, + &token_specific_init_token_data, + NULL, // load_token_data + NULL, // save_token_data + &token_specific_rng, + &token_specific_final, + &token_specific_init_token, + &token_specific_login, + &token_specific_logout, + &token_specific_init_pin, + &token_specific_set_pin, + // DES + &token_specific_des_key_gen, + &token_specific_des_ecb, + &token_specific_des_cbc, + // Triple DES + &token_specific_tdes_ecb, + &token_specific_tdes_cbc, + NULL, // tdes_ofb + NULL, // tdes_cfb + NULL, // tdes_mac + NULL, // tdes_cmac + // RSA + &token_specific_rsa_decrypt, + &token_specific_rsa_encrypt, + &token_specific_rsa_sign, + &token_specific_rsa_verify, + &token_specific_rsa_verify_recover, + NULL, // rsa_x509_decrypt + NULL, // rsa_x509_encrypt + NULL, // rsa_x509_sign + NULL, // rsa_x509_verify + NULL, // rsa_x509_verify_recover + NULL, // rsa_oaep_decrypt + NULL, // rsa_oaep_encrypt + NULL, // rsa_pss_sign + NULL, // rsa_pss_verify + &token_specific_rsa_generate_keypair, + // Elliptic Curve + NULL, // ec_sign + NULL, // ec_verify + NULL, // ec_generate_keypair + NULL, // ecdh_derive + NULL, // dh_pkcs_derive + NULL, // dh_pkcs_key_pair_gen + // SHA + NULL, // sha_init + NULL, // sha + NULL, // sha_update + NULL, // sha_final + // HMAC + NULL, // hmac_sign_init + NULL, // hmac_sign + NULL, // hmac_sign_update + NULL, // hmac_sign_final + NULL, // hmac_verify_init + NULL, // hmac_verify + NULL, // hmac_verify_update + NULL, // hmac_verify_final + NULL, // generic_secret_key_gen + // AES + &token_specific_aes_key_gen, + &token_specific_aes_ecb, + &token_specific_aes_cbc, + NULL, // aes_ctr + NULL, // aes_gcm_init + NULL, // aes_gcm + NULL, // aes_gcm_update + NULL, // aes_gcm_final + NULL, // aes_ofb + NULL, // aes_cfb + NULL, // aes_mac + NULL, // aes_cmac + // DSA + NULL, // dsa_generate_keypair + NULL, // dsa_sign + NULL, // dsa_verify + &token_specific_get_mechanism_list, + &token_specific_get_mechanism_info, + NULL // object_add +}; diff --git a/usr/lib/tpm_stdll/tpm_openssl.c b/usr/lib/tpm_stdll/tpm_openssl.c new file mode 100644 index 0000000..e1fc080 --- /dev/null +++ b/usr/lib/tpm_stdll/tpm_openssl.c @@ -0,0 +1,235 @@ +/* + * 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 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "stdll.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_specific.h" +#include "tok_spec_struct.h" +#include "trace.h" + +#include "tpm_specific.h" + +/* + * In order to make opencryptoki compatible with + * OpenSSL 1.1 API Changes and backward compatible + * we need to check for its version + */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#define OLDER_OPENSSL +#endif + +#ifdef DEBUG +void openssl_print_errors() +{ + ERR_load_ERR_strings(); + ERR_load_crypto_strings(); + ERR_print_errors_fp(stderr); +} +#endif + +RSA *openssl_gen_key() +{ + RSA *rsa; + int rc, counter = 0; + char buf[32]; +#ifndef OLDER_OPENSSL + BIGNUM *bne; +#endif + + token_specific_rng(NULL, (CK_BYTE *) buf, 32); + RAND_seed(buf, 32); + +regen_rsa_key: +#ifdef OLDER_OPENSSL + rsa = RSA_generate_key(2048, 65537, NULL, NULL); + if (rsa == NULL) { +#else + bne = BN_new(); + rc = BN_set_word(bne, 65537); + if (!rc) { + fprintf(stderr, "Error generating bne\n"); + ERR_load_crypto_strings(); + ERR_print_errors_fp(stderr); + return NULL; + } + + rsa = RSA_new(); + rc = RSA_generate_key_ex(rsa, 2048, bne, NULL); + if (!rc) { +#endif + fprintf(stderr, "Error generating user's RSA key\n"); + ERR_load_crypto_strings(); + ERR_print_errors_fp(stderr); + return NULL; + } + + rc = RSA_check_key(rsa); + switch (rc) { + case 0: + /* rsa is not a valid RSA key */ + RSA_free(rsa); + counter++; + if (counter == KEYGEN_RETRY) { + TRACE_DEVEL("Tried %d times to generate a " + "valid RSA key, failed.\n", KEYGEN_RETRY); + return NULL; + } + goto regen_rsa_key; + break; + case 1: + /* success case, rsa is a valid key */ + break; + case -1: + /* fall through */ + default: + DEBUG_openssl_print_errors(); + break; + } + + return rsa; +} + +int openssl_write_key(STDLL_TokData_t * tokdata, RSA * rsa, char *filename, + CK_BYTE * pPin) +{ + BIO *b = NULL; + char loc[PATH_MAX]; + struct passwd *pw = NULL; + + errno = 0; + if ((pw = getpwuid(getuid())) == NULL) { + TRACE_ERROR("Error getting username: %s\n", strerror(errno)); + return -1; + } + + sprintf(loc, "%s/%s/%s", tokdata->pk_dir, pw->pw_name, filename); + + b = BIO_new_file(loc, "w"); + if (!b) { + TRACE_ERROR("Error opening file for write: %s\n", loc); + return -1; + } + + if (!PEM_write_bio_RSAPrivateKey(b, rsa, + EVP_aes_256_cbc(), NULL, 0, 0, pPin)) { + BIO_free(b); + TRACE_ERROR("Writing key %s to disk failed.\n", loc); + DEBUG_openssl_print_errors(); + return -1; + } + + BIO_free(b); + + if (util_set_file_mode(loc, (S_IRUSR | S_IWUSR))) { + TRACE_ERROR("Setting file mode of %s failed\n", loc); + } + + return 0; +} + +CK_RV openssl_read_key(STDLL_TokData_t * tokdata, char *filename, + CK_BYTE * pPin, RSA ** ret) +{ + BIO *b = NULL; + RSA *rsa = NULL; + char loc[PATH_MAX]; + struct passwd *pw = NULL; + CK_RV rc = CKR_FUNCTION_FAILED; + + errno = 0; + if ((pw = getpwuid(getuid())) == NULL) { + TRACE_ERROR("Error getting username: %s\n", strerror(errno)); + return CKR_FUNCTION_FAILED; + } + + sprintf(loc, "%s/%s/%s", tokdata->pk_dir, pw->pw_name, filename); + + /* we can't allow a pin of NULL here, since openssl will try to prompt + * for a password in PEM_read_bio_RSAPrivateKey */ + if (pPin == NULL) + return CKR_PIN_INCORRECT; + + b = BIO_new_file(loc, "r+"); + if (b == NULL) { + TRACE_ERROR("Error opening file for read: %s\n", loc); + return CKR_FILE_NOT_FOUND; + } + + if ((rsa = PEM_read_bio_RSAPrivateKey(b, NULL, 0, pPin)) == NULL) { + TRACE_ERROR("Reading key %s from disk failed.\n", loc); + DEBUG_openssl_print_errors(); + if (ERR_GET_REASON(ERR_get_error()) == PEM_R_BAD_DECRYPT) { + rc = CKR_PIN_INCORRECT; + } + BIO_free(b); + return rc; + } + + BIO_free(b); + *ret = rsa; + + return CKR_OK; +} + +int openssl_get_modulus_and_prime(RSA * rsa, unsigned int *size_n, + unsigned char *n, unsigned int *size_p, + unsigned char *p) +{ +#ifndef OLDER_OPENSSL + const BIGNUM *n_tmp, *p_tmp; +#endif + + /* get the modulus from the RSA object */ +#ifdef OLDER_OPENSSL + if ((*size_n = BN_bn2bin(rsa->n, n)) <= 0) { +#else + RSA_get0_key(rsa, &n_tmp, NULL, NULL); + if ((*size_n = BN_bn2bin(n_tmp, n)) <= 0) { +#endif + DEBUG_openssl_print_errors(); + return -1; + } + + /* get one of the primes from the RSA object */ +#ifdef OLDER_OPENSSL + if ((*size_p = BN_bn2bin(rsa->p, p)) <= 0) { +#else + RSA_get0_factors(rsa, &p_tmp, NULL); + if ((*size_p = BN_bn2bin(p_tmp, p)) <= 0) { +#endif + DEBUG_openssl_print_errors(); + return -1; + } + + return 0; +} diff --git a/usr/lib/tpm_stdll/tpm_specific.c b/usr/lib/tpm_stdll/tpm_specific.c new file mode 100644 index 0000000..dc5f80f --- /dev/null +++ b/usr/lib/tpm_stdll/tpm_specific.c @@ -0,0 +1,3683 @@ +/* + * 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 + */ + +/* + * tpm_specific.c + * + * Feb 10, 2005 + * + * Author: Kent Yoder + * + * Encryption routines are based on ../soft_stdll/soft_specific.c. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "pkcs11types.h" +#include "stdll.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "tok_specific.h" +#include "tok_spec_struct.h" +#include "tok_struct.h" +#include "trace.h" +#include "ock_syslog.h" + +#include "tpm_specific.h" + +#include "../api/apiproto.h" + +typedef struct { + CK_BYTE master_key_private[MK_SIZE]; + + /* The context we'll use globally to connect to the TSP */ + TSS_HCONTEXT tspContext; + + /* TSP key handles */ + TSS_HKEY hSRK; + TSS_HKEY hPublicRootKey; + TSS_HKEY hPublicLeafKey; + TSS_HKEY hPrivateRootKey; + TSS_HKEY hPrivateLeafKey; + + /* TSP policy handles */ + TSS_HPOLICY hDefaultPolicy; + + /* PKCS#11 key handles */ + CK_OBJECT_HANDLE ckPublicRootKey; + CK_OBJECT_HANDLE ckPublicLeafKey; + CK_OBJECT_HANDLE ckPrivateRootKey; + CK_OBJECT_HANDLE ckPrivateLeafKey; + + int not_initialized; + + CK_BYTE current_user_pin_sha[SHA1_HASH_SIZE]; + CK_BYTE current_so_pin_sha[SHA1_HASH_SIZE]; +} tpm_private_data_t; + +TSS_RESULT util_set_public_modulus(TSS_HCONTEXT tspContext, TSS_HKEY, + unsigned long, unsigned char *); + +const char manuf[] = "IBM"; +const char model[] = "TPM"; +const char descr[] = "IBM TPM v1.1 token"; +const char label[] = "tpmtok"; + +static const MECH_LIST_ELEMENT tpm_mech_list[] = { + {CKM_RSA_PKCS_KEY_PAIR_GEN, {512, 2048, CKF_GENERATE_KEY_PAIR}}, + {CKM_DES_KEY_GEN, {0, 0, CKF_GENERATE}}, + {CKM_DES3_KEY_GEN, {0, 0, CKF_GENERATE}}, + {CKM_RSA_PKCS, {512, 2048, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | + CKF_UNWRAP | CKF_SIGN | CKF_VERIFY | CKF_SIGN_RECOVER | + CKF_VERIFY_RECOVER}}, + {CKM_MD5_RSA_PKCS, {512, 2048, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {CKM_SHA1_RSA_PKCS, {512, 2048, CKF_HW | CKF_SIGN | CKF_VERIFY}}, + {CKM_DES_ECB, {0, 0, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {CKM_DES_CBC, {0, 0, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {CKM_DES_CBC_PAD, + {0, 0, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {CKM_DES3_ECB, {0, 0, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {CKM_DES3_CBC, {0, 0, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {CKM_DES3_CBC_PAD, + {0, 0, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {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_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_SSL3_PRE_MASTER_KEY_GEN, {48, 48, CKF_GENERATE}}, + {CKM_SSL3_MASTER_KEY_DERIVE, {48, 48, CKF_DERIVE}}, + {CKM_SSL3_KEY_AND_MAC_DERIVE, {48, 48, CKF_DERIVE}}, + {CKM_SSL3_MD5_MAC, {384, 384, CKF_SIGN | CKF_VERIFY}}, + {CKM_SSL3_SHA1_MAC, {384, 384, CKF_SIGN | CKF_VERIFY}}, + {CKM_AES_KEY_GEN, {16, 32, CKF_GENERATE}}, + {CKM_AES_ECB, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {CKM_AES_CBC, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, + {CKM_AES_CBC_PAD, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | + CKF_UNWRAP}}, +}; + +static const CK_ULONG tpm_mech_list_len = + (sizeof(tpm_mech_list) / sizeof(MECH_LIST_ELEMENT)); + +static void clear_internal_structures(STDLL_TokData_t * tokdata) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + + tpm_data->hSRK = NULL_HKEY; + tpm_data->hPrivateLeafKey = NULL_HKEY; + tpm_data->hPublicLeafKey = NULL_HKEY; + tpm_data->hPrivateRootKey = NULL_HKEY; + tpm_data->hPublicRootKey = NULL_HKEY; + + memset(tpm_data->master_key_private, 0, MK_SIZE); + memset(tpm_data->current_so_pin_sha, 0, SHA1_HASH_SIZE); + memset(tpm_data->current_user_pin_sha, 0, SHA1_HASH_SIZE); +} + +CK_RV token_specific_rng(STDLL_TokData_t * tokdata, CK_BYTE * output, + CK_ULONG bytes) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + TSS_RESULT rc; + TSS_HTPM hTPM; + BYTE *random_bytes = NULL; + + UNUSED(tokdata); + + rc = Tspi_Context_GetTpmObject(tpm_data->tspContext, &hTPM); + if (rc) { + TRACE_ERROR("Tspi_Context_GetTpmObject: %x\n", rc); + return CKR_FUNCTION_FAILED; + } + + rc = Tspi_TPM_GetRandom(hTPM, bytes, &random_bytes); + if (rc) { + TRACE_ERROR("Tspi_TPM_GetRandom failed. rc=0x%x\n", rc); + return CKR_FUNCTION_FAILED; + } + + memcpy(output, random_bytes, bytes); + Tspi_Context_FreeMemory(tpm_data->tspContext, random_bytes); + + return CKR_OK; +} + +CK_RV token_specific_init(STDLL_TokData_t * tokdata, CK_SLOT_ID SlotNumber, + char *conf_name) +{ + tpm_private_data_t *tpm_data; + TSS_RESULT result; + char path_buf[PATH_MAX], fname[PATH_MAX]; + struct stat statbuf; + + UNUSED(conf_name); + + TRACE_INFO("tpm %s slot=%lu running\n", __func__, SlotNumber); + + tokdata->mech_list = (MECH_LIST_ELEMENT *)tpm_mech_list; + tokdata->mech_list_len = tpm_mech_list_len; + + // if the user specific directory doesn't exist, create it + sprintf(path_buf, "%s", get_pk_dir(tokdata, fname)); + if (stat(path_buf, &statbuf) < 0) { + if (mkdir(path_buf, S_IRUSR | S_IWUSR | S_IXUSR) == -1) { + TRACE_ERROR("mkdir(%s): %s\n", path_buf, strerror(errno)); + return CKR_FUNCTION_FAILED; + } + } + // now create userdir/TOK_OBJ if it doesn't exist + strncat(path_buf, "/", sizeof(path_buf) - (strlen(path_buf) + 1)); + strncat(path_buf, PK_LITE_OBJ_DIR, + sizeof(path_buf) - (strlen(PK_LITE_OBJ_DIR) + 1)); + if (stat(path_buf, &statbuf) < 0) { + if (mkdir(path_buf, S_IRUSR | S_IWUSR | S_IXUSR) == -1) { + TRACE_ERROR("mkdir(%s): %s\n", path_buf, strerror(errno)); + return CKR_FUNCTION_FAILED; + } + } + + tpm_data = (tpm_private_data_t *)calloc(1, sizeof(tpm_private_data_t)); + tokdata->private_data = tpm_data; + + tpm_data->tspContext = NULL_HCONTEXT; + clear_internal_structures(tokdata); + + result = Tspi_Context_Create(&tpm_data->tspContext); + if (result) { + TRACE_ERROR("Tspi_Context_Create failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + result = Tspi_Context_Connect(tpm_data->tspContext, NULL); + if (result) { + TRACE_ERROR("Tspi_Context_Connect failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + result = Tspi_Context_GetDefaultPolicy(tpm_data->tspContext, + &tpm_data->hDefaultPolicy); + if (result) { + TRACE_ERROR("Tspi_Context_GetDefaultPolicy failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + OpenSSL_add_all_algorithms(); + + return CKR_OK; +} + +CK_RV token_find_key(STDLL_TokData_t * tokdata, int key_type, + CK_OBJECT_CLASS class, CK_OBJECT_HANDLE * handle) +{ + CK_BYTE *key_id = util_create_id(key_type); + CK_RV rc = CKR_OK; + CK_BBOOL true = TRUE; + CK_ATTRIBUTE tmpl[] = { + {CKA_ID, key_id, strlen((char *) key_id)}, + {CKA_CLASS, &class, sizeof(class)}, + {CKA_HIDDEN, &true, sizeof(CK_BBOOL)} + }; + CK_OBJECT_HANDLE hObj; + CK_ULONG ulObjCount; + SESSION dummy_sess; + + /* init the dummy session state to something that will find any object on + * the token */ + memset(&dummy_sess, 0, sizeof(SESSION)); + dummy_sess.session_info.state = CKS_RO_USER_FUNCTIONS; + + rc = object_mgr_find_init(tokdata, &dummy_sess, tmpl, 3); + if (rc != CKR_OK) { + goto done; + } + + /* pulled from SC_FindObjects */ + ulObjCount = MIN(1, (dummy_sess.find_count - dummy_sess.find_idx)); + memcpy(&hObj, dummy_sess.find_list + dummy_sess.find_idx, + ulObjCount * sizeof(CK_OBJECT_HANDLE)); + dummy_sess.find_idx += ulObjCount; + + if (ulObjCount > 1) { + TRACE_INFO("More than one matching key found in the store!\n"); + rc = CKR_KEY_NOT_FOUND; + goto done; + } else if (ulObjCount < 1) { + TRACE_INFO("key with ID=\"%s\" not found in the store!\n", key_id); + rc = CKR_KEY_NOT_FOUND; + goto done; + } + + *handle = hObj; +done: + object_mgr_find_final(&dummy_sess); + free(key_id); + + return rc; +} + +CK_RV token_get_key_blob(STDLL_TokData_t * tokdata, CK_OBJECT_HANDLE ckKey, + CK_ULONG * blob_size, CK_BYTE ** ret_blob) +{ + CK_RV rc = CKR_OK; + CK_BYTE_PTR blob = NULL; + CK_ATTRIBUTE tmpl[] = { + {CKA_IBM_OPAQUE, NULL_PTR, 0} + }; + SESSION dummy_sess; + + /* set up dummy session */ + memset(&dummy_sess, 0, sizeof(SESSION)); + dummy_sess.session_info.state = CKS_RO_USER_FUNCTIONS; + + /* find object the first time to return the size of the buffer needed */ + rc = object_mgr_get_attribute_values(tokdata, &dummy_sess, ckKey, tmpl, 1); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_get_attribute_values failed:rc=0x%lx\n", rc); + goto done; + } + + blob = malloc(tmpl[0].ulValueLen); + if (blob == NULL) { + TRACE_ERROR("malloc %ld bytes failed.\n", tmpl[0].ulValueLen); + rc = CKR_HOST_MEMORY; + goto done; + } + + tmpl[0].pValue = blob; + /* find object the 2nd time to fill the buffer with data */ + rc = object_mgr_get_attribute_values(tokdata, &dummy_sess, ckKey, tmpl, 1); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_get_attribute_values failed:rc=0x%lx\n", rc); + goto done; + } + + *ret_blob = blob; + *blob_size = tmpl[0].ulValueLen; + +done: + return rc; +} + +CK_RV token_wrap_sw_key(STDLL_TokData_t * tokdata, + int size_n, unsigned char *n, int size_p, + unsigned char *p, TSS_HKEY hParentKey, + TSS_FLAG initFlags, TSS_HKEY * phKey) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + TSS_RESULT result; + TSS_HPOLICY hPolicy; + TSS_BOOL get_srk_pub_key = TRUE; + UINT32 key_size; + + key_size = util_get_keysize_flag(size_n * 8); + if (initFlags == 0) { + TRACE_ERROR("Invalid key size.\n"); + return CKR_FUNCTION_FAILED; + } + + /* create the TSS key object */ + result = Tspi_Context_CreateObject(tpm_data->tspContext, + TSS_OBJECT_TYPE_RSAKEY, + TSS_KEY_MIGRATABLE | initFlags | + key_size, phKey); + if (result != TSS_SUCCESS) { + TRACE_ERROR("Tspi_Context_CreateObject failed: rc=0x%x\n", result); + return result; + } + + result = util_set_public_modulus(tpm_data->tspContext, *phKey, size_n, n); + if (result != TSS_SUCCESS) { + TRACE_DEVEL("util_set_public_modulus failed:rc=0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + *phKey = NULL_HKEY; + return result; + } + + /* set the private key data in the TSS object */ + result = Tspi_SetAttribData(*phKey, TSS_TSPATTRIB_KEY_BLOB, + TSS_TSPATTRIB_KEYBLOB_PRIVATE_KEY, size_p, p); + if (result != TSS_SUCCESS) { + TRACE_ERROR("Tspi_SetAttribData failed: rc=0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + *phKey = NULL_HKEY; + return result; + } + + /* if the parent wrapping key is the SRK, we need to manually pull + * out the SRK's pub key, which is not stored in persistent storage + * for privacy reasons */ + if (hParentKey == tpm_data->hSRK && get_srk_pub_key == TRUE) { + UINT32 pubKeySize; + BYTE *pubKey; + result = Tspi_Key_GetPubKey(hParentKey, &pubKeySize, &pubKey); + if (result != TSS_SUCCESS) { + if (result == TPM_E_INVALID_KEYHANDLE) { + OCK_SYSLOG(LOG_WARNING, + "Warning: Your TPM is not configured to allow " + "reading the public SRK by anyone but the owner. " + "Use tpm_restrictsrk -a to allow reading the public " + "SRK"); + } else { + OCK_SYSLOG(LOG_ERR, "Tspi_Key_GetPubKey failed: rc=0x%x", + result); + } + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + *phKey = NULL_HKEY; + return result; + } + Tspi_Context_FreeMemory(tpm_data->tspContext, pubKey); + get_srk_pub_key = FALSE; + } + + result = Tspi_Context_CreateObject(tpm_data->tspContext, + TSS_OBJECT_TYPE_POLICY, + TSS_POLICY_MIGRATION, &hPolicy); + if (result != TSS_SUCCESS) { + TRACE_ERROR("Tspi_Context_CreateObject: 0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + *phKey = NULL_HKEY; + return result; + } + + result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_NONE, 0, NULL); + if (result != TSS_SUCCESS) { + TRACE_ERROR("Tspi_Policy_SetSecret failed. rc=0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + Tspi_Context_CloseObject(tpm_data->tspContext, hPolicy); + *phKey = NULL_HKEY; + return result; + } + + result = Tspi_Policy_AssignToObject(hPolicy, *phKey); + if (result != TSS_SUCCESS) { + TRACE_ERROR("Tspi_Policy_AssignToObject: 0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + Tspi_Context_CloseObject(tpm_data->tspContext, hPolicy); + *phKey = NULL_HKEY; + return result; + } + + if (TPMTOK_TSS_KEY_TYPE(initFlags) == TSS_KEY_TYPE_LEGACY) { + result = Tspi_SetAttribUint32(*phKey, TSS_TSPATTRIB_KEY_INFO, + TSS_TSPATTRIB_KEYINFO_ENCSCHEME, + TSS_ES_RSAESPKCSV15); + if (result) { + TRACE_ERROR("Tspi_SetAttribUint32 failed. rc=0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + Tspi_Context_CloseObject(tpm_data->tspContext, hPolicy); + return result; + } + + result = Tspi_SetAttribUint32(*phKey, TSS_TSPATTRIB_KEY_INFO, + TSS_TSPATTRIB_KEYINFO_SIGSCHEME, + TSS_SS_RSASSAPKCS1V15_DER); + if (result) { + TRACE_ERROR("Tspi_SetAttribUint32 failed. rc=0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + Tspi_Context_CloseObject(tpm_data->tspContext, hPolicy); + return result; + } + } + + result = Tspi_Key_WrapKey(*phKey, hParentKey, NULL_HPCRS); + if (result != TSS_SUCCESS) { + TRACE_ERROR("Tspi_Key_WrapKey failed: rc=0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + *phKey = NULL_HKEY; + } + + return result; +} + +/* + * Create a TPM key blob for an imported key. This function is only called when + * a key is in active use, so any failure should trickle through. + * + * Note: The passed Object ckObject must not hold a lock, this function might + * need to acquire a WRITE lock on the object! + */ +CK_RV token_wrap_key_object(STDLL_TokData_t * tokdata, + CK_OBJECT_HANDLE ckObject, TSS_HKEY hParentKey, + TSS_HKEY * phKey) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + CK_RV rc = CKR_OK; + CK_ATTRIBUTE *attr = NULL, *new_attr, *prime_attr; + CK_ULONG class, key_type; + CK_BBOOL found; + OBJECT *obj = NULL; + + TSS_RESULT result; + TSS_FLAG initFlags = 0; + BYTE *rgbBlob; + UINT32 ulBlobLen; + + rc = object_mgr_find_in_map1(tokdata, ckObject, &obj, WRITE_LOCK); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_find_in_map1 failed. rc=0x%lx\n", rc); + return rc; + } + + /* if the object isn't a key, fail */ + found = template_attribute_find(obj->template, CKA_KEY_TYPE, &attr); + if (found == FALSE) { + TRACE_ERROR("template_attribute_find(CKA_KEY_TYPE) failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + key_type = *((CK_ULONG *) attr->pValue); + + if (key_type != CKK_RSA) { + TRACE_ERROR("Bad key type!\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + found = template_attribute_find(obj->template, CKA_CLASS, &attr); + if (found == FALSE) { + TRACE_ERROR("template_attribute_find(CKA_CLASS) failed.\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + class = *((CK_ULONG *) attr->pValue); + + if (class == CKO_PRIVATE_KEY) { + /* In order to create a full TSS key blob using a PKCS#11 private key + * object, we need one of the two primes, the modulus and the private + * exponent and we need the public exponent to be correct */ + + /* check the least likely attribute to exist first, the primes */ + found = template_attribute_find(obj->template, + CKA_PRIME_1, &prime_attr); + if (found == FALSE) { + found = template_attribute_find(obj->template, + CKA_PRIME_2, &prime_attr); + if (found == FALSE) { + TRACE_ERROR("Couldn't find prime1 or prime2 of" + " key object to wrap\n"); + rc = CKR_TEMPLATE_INCONSISTENT; + goto done; + } + } + + /* Make sure the public exponent is usable */ + if ((util_check_public_exponent(obj->template))) { + TRACE_ERROR("Invalid public exponent\n"); + rc = CKR_TEMPLATE_INCONSISTENT; + goto done; + } + + /* get the modulus */ + found = template_attribute_find(obj->template, CKA_MODULUS, &attr); + if (found == FALSE) { + TRACE_ERROR("Couldn't find a required attribute of " + "key object\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* make sure the key size is usable */ + initFlags = util_get_keysize_flag(attr->ulValueLen * 8); + if (initFlags == 0) { + TRACE_ERROR("Invalid key size.\n"); + rc = CKR_TEMPLATE_INCONSISTENT; + goto done; + } + + /* generate the software based key */ + rc = token_wrap_sw_key(tokdata, (int) attr->ulValueLen, attr->pValue, + (int) prime_attr->ulValueLen, + prime_attr->pValue, + hParentKey, + TSS_KEY_TYPE_LEGACY | TSS_KEY_NO_AUTHORIZATION, + phKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_wrap_sw_key failed. rc=0x%lu\n", rc); + goto done; + } + } else if (class == CKO_PUBLIC_KEY) { + /* Make sure the public exponent is usable */ + if ((util_check_public_exponent(obj->template))) { + TRACE_DEVEL("Invalid public exponent\n"); + rc = CKR_TEMPLATE_INCONSISTENT; + goto done; + } + + /* grab the modulus to put into the TSS key object */ + found = template_attribute_find(obj->template, CKA_MODULUS, &attr); + if (found == FALSE) { + TRACE_ERROR("Couldn't find a required attribute of " + "key object\n"); + rc = CKR_TEMPLATE_INCONSISTENT; + goto done; + } + + /* make sure the key size is usable */ + initFlags = util_get_keysize_flag(attr->ulValueLen * 8); + if (initFlags == 0) { + TRACE_ERROR("Invalid key size.\n"); + rc = CKR_TEMPLATE_INCONSISTENT; + goto done; + } + + initFlags |= + TSS_KEY_TYPE_LEGACY | TSS_KEY_MIGRATABLE | TSS_KEY_NO_AUTHORIZATION; + + result = Tspi_Context_CreateObject(tpm_data->tspContext, + TSS_OBJECT_TYPE_RSAKEY, + initFlags, phKey); + if (result) { + TRACE_ERROR("Tspi_Context_CreateObject failed. " "rc=0x%x\n", + result); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + result = util_set_public_modulus(tpm_data->tspContext, *phKey, + attr->ulValueLen, attr->pValue); + if (result) { + TRACE_DEVEL("util_set_public_modulus failed: 0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + *phKey = NULL_HKEY; + rc = CKR_FUNCTION_FAILED; + goto done; + } + } else { + TRACE_ERROR("Bad key class!\n"); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* grab the entire key blob to put into the PKCS#11 object */ + result = Tspi_GetAttribData(*phKey, TSS_TSPATTRIB_KEY_BLOB, + TSS_TSPATTRIB_KEYBLOB_BLOB, + &ulBlobLen, &rgbBlob); + if (result) { + TRACE_ERROR("Tspi_GetAttribData failed with rc: 0x%x\n", result); + rc = CKR_FUNCTION_FAILED; + goto done; + } + + /* insert the key blob into the object */ + rc = build_attribute(CKA_IBM_OPAQUE, rgbBlob, ulBlobLen, &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_atribute failed\n"); + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); + goto done; + } + template_update_attribute(obj->template, new_attr); + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); + + /* if this is a token object, save it with the new attribute so that we + * don't have to go down this path again */ + if (!object_is_session_object(obj)) { + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get process lock.\n"); + goto done; + } + rc = save_token_object(tokdata, obj); + if (rc != CKR_OK) { + XProcUnLock(tokdata); + } else { + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release process lock.\n"); + goto done; + } + } + } + +done: + object_put(tokdata, obj, TRUE); + obj = NULL; + + return rc; +} + +/* + * load a key in the TSS hierarchy from its CK_OBJECT_HANDLE + * + * Note: The passed Object ckKey must not hold a lock, this function might + * need to acquire a READ or WRITE lock on the object! + */ +CK_RV token_load_key(STDLL_TokData_t * tokdata, CK_OBJECT_HANDLE ckKey, + TSS_HKEY hParentKey, CK_CHAR_PTR passHash, + TSS_HKEY * phKey) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + TSS_RESULT result; + TSS_HPOLICY hPolicy; + CK_BYTE *blob = NULL; + CK_ULONG ulBlobSize = 0; + CK_RV rc; + + rc = token_get_key_blob(tokdata, ckKey, &ulBlobSize, &blob); + if (rc != CKR_OK) { + if (rc != CKR_ATTRIBUTE_TYPE_INVALID) { + TRACE_DEVEL("token_get_key_blob failed. rc=0x%lx\n", rc); + return rc; + } + /* the key blob wasn't found, so check for a modulus + * to load */ + TRACE_DEVEL("key blob not found, checking for modulus\n"); + rc = token_wrap_key_object(tokdata, ckKey, hParentKey, phKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_wrap_key_object failed. rc=0x%lx\n", rc); + return rc; + } + } + + if (blob != NULL) { + /* load the key inside the TSS */ + result = Tspi_Context_LoadKeyByBlob(tpm_data->tspContext, + hParentKey, + ulBlobSize, blob, phKey); + if (result) { + TRACE_ERROR("Tspi_Context_LoadKeyByBlob: 0x%x\n", result); + goto done; + } + } +#if 0 + if ((result = Tspi_GetPolicyObject(*phKey, TSS_POLICY_USAGE, &hPolicy))) { + TRACE_ERROR("Tspi_GetPolicyObject: 0x%x\n", result); + goto done; + } +#else + result = Tspi_Context_CreateObject(tpm_data->tspContext, + TSS_OBJECT_TYPE_POLICY, + TSS_POLICY_USAGE, &hPolicy); + if (result) { + TRACE_ERROR("Tspi_Context_CreateObject: 0x%x\n", result); + goto done; + } +#endif + + if (passHash == NULL) { + result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_NONE, 0, NULL); + } else { + result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_SHA1, + SHA1_HASH_SIZE, passHash); + } + if (result != TSS_SUCCESS) { + TRACE_ERROR("Tspi_Policy_SetSecret: 0x%x\n", result); + goto done; + } + + result = Tspi_Policy_AssignToObject(hPolicy, *phKey); + if (result) { + TRACE_ERROR("Tspi_Policy_AssignToObject: 0x%x\n", result); + goto done; + } +done: + free(blob); + + return result; +} + +TSS_RESULT token_load_srk(STDLL_TokData_t * tokdata) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + TSS_HPOLICY hPolicy; + TSS_RESULT result; + TSS_UUID SRK_UUID = TSS_UUID_SRK; + struct srk_info srk; + + if (tpm_data->hSRK != NULL_HKEY) + return TSS_SUCCESS; + + /* load the SRK */ + result = Tspi_Context_LoadKeyByUUID(tpm_data->tspContext, + TSS_PS_TYPE_SYSTEM, SRK_UUID, + &tpm_data->hSRK); + if (result) { + TRACE_ERROR("Tspi_Context_LoadKeyByUUID failed. rc=0x%x\n", result); + goto done; + } +#if 0 + if ((result = Tspi_GetPolicyObject(tpm_data->hSRK, TSS_POLICY_USAGE, + &hPolicy))) { + TRACE_ERROR("Tspi_GetPolicyObject failed. rc=0x%x\n", result); + goto done; + } +#else + result = Tspi_Context_CreateObject(tpm_data->tspContext, + TSS_OBJECT_TYPE_POLICY, + TSS_POLICY_USAGE, &hPolicy); + if (result) { + TRACE_ERROR("Tspi_Context_CreateObject failed. rc=0x%x\n", result); + goto done; + } + + result = Tspi_Policy_AssignToObject(hPolicy, tpm_data->hSRK); + if (result) { + TRACE_ERROR("Tspi_Policy_AssignToObject failed. rc=0x%x\n", result); + goto done; + } +#endif + + /* get the srk info */ + memset(&srk, 0, sizeof(srk)); + if (get_srk_info(&srk)) + return -1; + + result = Tspi_Policy_SetSecret(hPolicy, (TSS_FLAG) srk.mode, + srk.len, (BYTE *) srk.secret); + if (result) + TRACE_ERROR("Tspi_Policy_SetSecret failed. rc=0x%x\n", result); + + if (srk.secret) + free(srk.secret); + +done: + return result; +} + +TSS_RESULT token_load_public_root_key(STDLL_TokData_t * tokdata) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + TSS_RESULT result; + BYTE *blob; + CK_ULONG blob_size; + + if (tpm_data->hPublicRootKey != NULL_HKEY) + return TSS_SUCCESS; + + result = token_load_srk(tokdata); + if (result) { + TRACE_DEVEL("token_load_srk failed. rc=0x%x\n", result); + return result; + } + + result = token_find_key(tokdata, TPMTOK_PUBLIC_ROOT_KEY, + CKO_PRIVATE_KEY, &tpm_data->ckPublicRootKey); + if (result) { + TRACE_ERROR("token_find_key failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + result = token_get_key_blob(tokdata, tpm_data->ckPublicRootKey, &blob_size, + &blob); + if (result) { + TRACE_DEVEL("token_get_key_blob failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + /* load the Public Root Key */ + result = Tspi_Context_LoadKeyByBlob(tpm_data->tspContext, tpm_data->hSRK, + blob_size, blob, + &tpm_data->hPublicRootKey); + if (result) { + TRACE_ERROR("Tspi_Context_LoadKeyByBlob failed. rc=0x%x\n", result); + free(blob); + return CKR_FUNCTION_FAILED; + } + free(blob); + + return result; +} + +TSS_RESULT tss_generate_key(STDLL_TokData_t * tokdata, + TSS_FLAG initFlags, BYTE * passHash, + TSS_HKEY hParentKey, TSS_HKEY * phKey) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + TSS_RESULT result; + TSS_HPOLICY hPolicy, hMigPolicy = 0; + + result = Tspi_Context_CreateObject(tpm_data->tspContext, + TSS_OBJECT_TYPE_RSAKEY, + initFlags, phKey); + if (result) { + TRACE_ERROR("Tspi_Context_CreateObject failed. rc=0x%x\n", result); + return result; + } +#if 0 + if ((result = Tspi_GetPolicyObject(*phKey, TSS_POLICY_USAGE, &hPolicy))) { + TRACE_ERROR("Tspi_GetPolicyObject failed. rc=0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + return result; + } +#else + result = Tspi_Context_CreateObject(tpm_data->tspContext, + TSS_OBJECT_TYPE_POLICY, + TSS_POLICY_USAGE, &hPolicy); + if (result) { + TRACE_ERROR("Tspi_Context_CreateObject: 0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + return result; + } +#endif + + if (passHash == NULL) { + result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_NONE, 0, NULL); + } else { + result = + Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_SHA1, 20, passHash); + } + if (result != TSS_SUCCESS) { + TRACE_ERROR("Tspi_Policy_SetSecret failed. rc=0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + Tspi_Context_CloseObject(tpm_data->tspContext, hPolicy); + return result; + } + + result = Tspi_Policy_AssignToObject(hPolicy, *phKey); + if (result) { + TRACE_ERROR("Tspi_Policy_AssignToObject: 0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + Tspi_Context_CloseObject(tpm_data->tspContext, hPolicy); + return result; + } + + if (TPMTOK_TSS_KEY_MIG_TYPE(initFlags) == TSS_KEY_MIGRATABLE) { + result = Tspi_Context_CreateObject(tpm_data->tspContext, + TSS_OBJECT_TYPE_POLICY, + TSS_POLICY_MIGRATION, &hMigPolicy); + if (result) { + TRACE_ERROR("Tspi_Context_CreateObject: 0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + Tspi_Context_CloseObject(tpm_data->tspContext, hPolicy); + return result; + } + + if (passHash == NULL) { + result = + Tspi_Policy_SetSecret(hMigPolicy, TSS_SECRET_MODE_NONE, 0, + NULL); + } else { + result = Tspi_Policy_SetSecret(hMigPolicy, TSS_SECRET_MODE_SHA1, 20, + passHash); + } + + if (result != TSS_SUCCESS) { + TRACE_ERROR("Tspi_Policy_SetSecret failed. rc=0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + Tspi_Context_CloseObject(tpm_data->tspContext, hPolicy); + Tspi_Context_CloseObject(tpm_data->tspContext, hMigPolicy); + return result; + } + + result = Tspi_Policy_AssignToObject(hMigPolicy, *phKey); + if (result) { + TRACE_ERROR("Tspi_Policy_AssignToObject: 0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + Tspi_Context_CloseObject(tpm_data->tspContext, hPolicy); + Tspi_Context_CloseObject(tpm_data->tspContext, hMigPolicy); + return result; + } + } + + if (TPMTOK_TSS_KEY_TYPE(initFlags) == TSS_KEY_TYPE_LEGACY) { + result = Tspi_SetAttribUint32(*phKey, TSS_TSPATTRIB_KEY_INFO, + TSS_TSPATTRIB_KEYINFO_ENCSCHEME, + TSS_ES_RSAESPKCSV15); + if (result) { + TRACE_ERROR("Tspi_SetAttribUint32 failed. rc=0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + Tspi_Context_CloseObject(tpm_data->tspContext, hPolicy); + Tspi_Context_CloseObject(tpm_data->tspContext, hMigPolicy); + return result; + } + + result = Tspi_SetAttribUint32(*phKey, TSS_TSPATTRIB_KEY_INFO, + TSS_TSPATTRIB_KEYINFO_SIGSCHEME, + TSS_SS_RSASSAPKCS1V15_DER); + if (result) { + TRACE_ERROR("Tspi_SetAttribUint32 failed. rc=0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + Tspi_Context_CloseObject(tpm_data->tspContext, hPolicy); + Tspi_Context_CloseObject(tpm_data->tspContext, hMigPolicy); + return result; + } + } + + result = Tspi_Key_CreateKey(*phKey, hParentKey, 0); + if (result) { + TRACE_ERROR("Tspi_Key_CreateKey failed with rc: 0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + Tspi_Context_CloseObject(tpm_data->tspContext, hPolicy); + Tspi_Context_CloseObject(tpm_data->tspContext, hMigPolicy); + } + + return result; +} + +TSS_RESULT tss_change_auth(STDLL_TokData_t * tokdata, + TSS_HKEY hObjectToChange, TSS_HKEY hParentObject, + CK_CHAR * passHash) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + TSS_RESULT result; + TSS_HPOLICY hPolicy; + + result = Tspi_Context_CreateObject(tpm_data->tspContext, + TSS_OBJECT_TYPE_POLICY, + TSS_POLICY_USAGE, &hPolicy); + if (result) { + TRACE_ERROR("Tspi_Context_CreateObject failed: 0x%x\n", result); + return result; + } + + result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_SHA1, + SHA1_HASH_SIZE, passHash); + if (result) { + TRACE_ERROR("Tspi_Policy_SetSecret failed: 0x%x\n", result); + return result; + } + + result = Tspi_ChangeAuth(hObjectToChange, hParentObject, hPolicy); + if (result) { + TRACE_ERROR("Tspi_ChangeAuth failed: 0x%x\n", result); + } + + return result; +} + +CK_RV token_store_priv_key(STDLL_TokData_t * tokdata, TSS_HKEY hKey, + int key_type, CK_OBJECT_HANDLE * ckKey) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + CK_ATTRIBUTE *new_attr = NULL; + OBJECT *priv_key_obj = NULL; + BYTE *rgbBlob = NULL, *rgbPrivBlob = NULL; + UINT32 ulBlobLen = 0, ulPrivBlobLen = 0; + CK_BBOOL flag; + CK_BYTE *key_id = util_create_id(key_type); + CK_RV rc; + SESSION dummy_sess; + + /* set up dummy session */ + memset(&dummy_sess, 0, sizeof(SESSION)); + dummy_sess.session_info.state = CKS_RW_USER_FUNCTIONS; + + /* grab the entire key blob to put into the PKCS#11 private key object */ + rc = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB, + TSS_TSPATTRIB_KEYBLOB_BLOB, &ulBlobLen, &rgbBlob); + if (rc) { + TRACE_ERROR("Tspi_GetAttribData failed with rc: 0x%lx\n", rc); + free(key_id); + return rc; + } + + /* grab the encrypted provate key to put into the object */ + rc = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB, + TSS_TSPATTRIB_KEYBLOB_PRIVATE_KEY, + &ulPrivBlobLen, &rgbPrivBlob); + if (rc) { + TRACE_ERROR("Tspi_GetAttribData failed with rc: 0x%lx\n", rc); + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); + free(key_id); + return rc; + } + + /* create skeleton for the private key object */ + rc = object_create_skel(tokdata, NULL, 0, MODE_KEYGEN, + CKO_PRIVATE_KEY, CKK_RSA, &priv_key_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("objectr_create_skel: 0x%lx\n", rc); + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbPrivBlob); + free(key_id); + return rc; + } + + /* add the ID attribute */ + rc = build_attribute(CKA_ID, key_id, strlen((char *) key_id), &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbPrivBlob); + free(key_id); + object_free(priv_key_obj); + return rc; + } + template_update_attribute(priv_key_obj->template, new_attr); + free(key_id); + + /* add the key blob to the PKCS#11 object template */ + rc = build_attribute(CKA_IBM_OPAQUE, rgbBlob, ulBlobLen, &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbPrivBlob); + object_free(priv_key_obj); + return rc; + } + template_update_attribute(priv_key_obj->template, new_attr); + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); + + /* add the private key blob to the PKCS#11 object template */ + rc = build_attribute(CKA_MODULUS, rgbPrivBlob, ulPrivBlobLen, &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbPrivBlob); + object_free(priv_key_obj); + return rc; + } + template_update_attribute(priv_key_obj->template, new_attr); + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbPrivBlob); + + /* add the HIDDEN attribute */ + flag = TRUE; + rc = build_attribute(CKA_HIDDEN, &flag, sizeof(CK_BBOOL), &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + object_free(priv_key_obj); + return rc; + } + template_update_attribute(priv_key_obj->template, new_attr); + + /* set CKA_ALWAYS_SENSITIVE to true */ + rc = build_attribute(CKA_ALWAYS_SENSITIVE, &flag, + sizeof(CK_BBOOL), &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + object_free(priv_key_obj); + return rc; + } + template_update_attribute(priv_key_obj->template, new_attr); + + /* set CKA_NEVER_EXTRACTABLE to true */ + rc = build_attribute(CKA_NEVER_EXTRACTABLE, + &flag, sizeof(CK_BBOOL), &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + object_free(priv_key_obj); + return rc; + } + template_update_attribute(priv_key_obj->template, new_attr); + + /* make the object reside on the token, as if that were possible */ + rc = build_attribute(CKA_TOKEN, &flag, sizeof(CK_BBOOL), &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + object_free(priv_key_obj); + return rc; + } + template_update_attribute(priv_key_obj->template, new_attr); + + flag = FALSE; + rc = build_attribute(CKA_PRIVATE, &flag, sizeof(CK_BBOOL), &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed\n"); + object_free(priv_key_obj); + return rc; + } + template_update_attribute(priv_key_obj->template, new_attr); + + rc = object_mgr_create_final(tokdata, &dummy_sess, priv_key_obj, ckKey); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_create_final failed.\n"); + object_free(priv_key_obj); + priv_key_obj = NULL; + } + + return rc; +} + +CK_RV token_store_pub_key(STDLL_TokData_t * tokdata, TSS_HKEY hKey, + int key_type, CK_OBJECT_HANDLE * ckKey) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + CK_RV rc; + TSS_RESULT result; + CK_ATTRIBUTE *new_attr = NULL; + OBJECT *pub_key_obj; + CK_BBOOL flag = TRUE; + CK_OBJECT_CLASS pub_class = CKO_PUBLIC_KEY; + CK_KEY_TYPE type = CKK_RSA; + CK_BYTE *key_id = util_create_id(key_type); + CK_BYTE pub_exp[] = { 1, 0, 1 }; // 65537 + CK_ATTRIBUTE pub_tmpl[] = { + {CKA_CLASS, &pub_class, sizeof(pub_class)}, + {CKA_KEY_TYPE, &type, sizeof(type)}, + {CKA_ID, key_id, strlen((char *) key_id)}, + {CKA_PUBLIC_EXPONENT, pub_exp, sizeof(pub_exp)}, + {CKA_MODULUS, NULL_PTR, 0} + }; + BYTE *rgbPubBlob = NULL; + UINT32 ulBlobLen = 0; + SESSION dummy_sess; + + /* set up dummy session */ + memset(&dummy_sess, 0, sizeof(SESSION)); + dummy_sess.session_info.state = CKS_RW_USER_FUNCTIONS; + + /* grab the public key to put into the PKCS#11 public key object */ + result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_RSAKEY_INFO, + TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, + &ulBlobLen, &rgbPubBlob); + if (result) { + TRACE_ERROR("Tspi_GetAttribData failed with rc: 0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, hKey); + free(key_id); + return result; + } + + pub_tmpl[4].pValue = rgbPubBlob; + pub_tmpl[4].ulValueLen = ulBlobLen; + + /* create skeleton for the private key object */ + rc = object_create_skel(tokdata, pub_tmpl, 5, MODE_CREATE, + CKO_PUBLIC_KEY, CKK_RSA, &pub_key_obj); + if (rc != CKR_OK) { + TRACE_DEVEL("object_create_skel: 0x%lx\n", rc); + Tspi_Context_CloseObject(tpm_data->tspContext, hKey); + free(key_id); + return rc; + } + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbPubBlob); + + /* make the object reside on the token, as if that were possible */ + rc = build_attribute(CKA_TOKEN, &flag, sizeof(CK_BBOOL), &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build attribute failed.\n"); + object_free(pub_key_obj); + goto done; + } + template_update_attribute(pub_key_obj->template, new_attr); + + /* set the object to be hidden */ + rc = build_attribute(CKA_HIDDEN, &flag, sizeof(CK_BBOOL), &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build attribute failed.\n"); + object_free(pub_key_obj); + goto done; + } + template_update_attribute(pub_key_obj->template, new_attr); + + rc = object_mgr_create_final(tokdata, &dummy_sess, pub_key_obj, ckKey); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_create_final failed\n"); + object_free(pub_key_obj); + pub_key_obj = NULL; + goto done; + } + +done: + return rc; +} + +CK_RV token_update_private_key(STDLL_TokData_t * tokdata, TSS_HKEY hKey, + int key_type) +{ + CK_OBJECT_HANDLE ckHandle; + CK_RV rc; + SESSION dummy_sess; + + /* set up dummy session */ + memset(&dummy_sess, 0, sizeof(SESSION)); + dummy_sess.session_info.state = CKS_RW_USER_FUNCTIONS; + + /* find the private key portion of the key */ + rc = token_find_key(tokdata, key_type, CKO_PRIVATE_KEY, &ckHandle); + if (rc != CKR_OK) { + TRACE_ERROR("token_find_key failed: 0x%lx\n", rc); + return rc; + } + + /* destroy the private key and create a new one */ + rc = object_mgr_destroy_object(tokdata, &dummy_sess, ckHandle); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_destroy_object failed: 0x%lx\n", rc); + return rc; + } + + rc = token_store_priv_key(tokdata, hKey, key_type, &ckHandle); + if (rc != CKR_OK) { + TRACE_DEVEL("token_store_priv_key failed: 0x%lx\n", rc); + } + + return rc; +} + +CK_RV token_store_tss_key(STDLL_TokData_t * tokdata, TSS_HKEY hKey, + int key_type, CK_OBJECT_HANDLE * ckKey) +{ + CK_RV rc; + + /* create a PKCS#11 pub key object for the key */ + rc = token_store_pub_key(tokdata, hKey, key_type, ckKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_store_pub_key failed. rc=0x%lx\n", rc); + return rc; + } + + /* create a PKCS#11 private key object for the key */ + rc = token_store_priv_key(tokdata, hKey, key_type, ckKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_store_priv_key failed. rc=0x%lx\n", rc); + } + + return rc; +} + +CK_RV token_generate_leaf_key(STDLL_TokData_t * tokdata, int key_type, + CK_CHAR_PTR passHash, TSS_HKEY * phKey) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + CK_RV rc = CKR_FUNCTION_FAILED; + TSS_RESULT result; + TSS_HKEY hParentKey; + CK_OBJECT_HANDLE *ckKey; + TSS_FLAG initFlags = TSS_KEY_MIGRATABLE | TSS_KEY_TYPE_BIND | + TSS_KEY_SIZE_2048 | TSS_KEY_AUTHORIZATION; + + switch (key_type) { + case TPMTOK_PUBLIC_LEAF_KEY: + hParentKey = tpm_data->hPublicRootKey; + ckKey = &tpm_data->ckPublicRootKey; + break; + case TPMTOK_PRIVATE_LEAF_KEY: + hParentKey = tpm_data->hPrivateRootKey; + ckKey = &tpm_data->ckPrivateRootKey; + break; + default: + TRACE_ERROR("Unknown key type.\n"); + goto done; + break; + } + + result = tss_generate_key(tokdata, initFlags, passHash, hParentKey, phKey); + if (result) { + TRACE_ERROR("tss_generate_key returned 0x%x\n", result); + return result; + } + + rc = token_store_tss_key(tokdata, *phKey, key_type, ckKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_store_tss_key failed. rc=0x%x\n", result); + } + +done: + return rc; +} + +CK_RV token_verify_pin(STDLL_TokData_t * tokdata, TSS_HKEY hKey) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + TSS_HENCDATA hEncData; + UINT32 ulUnboundDataLen; + BYTE *rgbUnboundData; + char *rgbData = "CRAPPENFEST"; + TSS_RESULT result; + CK_RV rc = CKR_FUNCTION_FAILED; + + result = Tspi_Context_CreateObject(tpm_data->tspContext, + TSS_OBJECT_TYPE_ENCDATA, + TSS_ENCDATA_BIND, &hEncData); + if (result) { + TRACE_ERROR("Tspi_Context_CreateObject failed. rc=0x%x\n", result); + goto done; + } + + result = Tspi_Data_Bind(hEncData, hKey, strlen(rgbData), (BYTE *) rgbData); + if (result) { + TRACE_ERROR("Tspi_Data_Bind returned 0x%x\n", result); + goto done; + } + + /* unbind the junk data to test the key's auth data */ + result = + Tspi_Data_Unbind(hEncData, hKey, &ulUnboundDataLen, &rgbUnboundData); + if (result == TCPA_E_AUTHFAIL) { + rc = CKR_PIN_INCORRECT; + TRACE_ERROR("Tspi_Data_Unbind returned TCPA_AUTHFAIL\n"); + goto done; + } else if (result != TSS_SUCCESS) { + TRACE_ERROR("Tspi_Data_ Unbind returned 0x%x\n", result); + goto done; + } + + rc = memcmp(rgbUnboundData, rgbData, ulUnboundDataLen); + + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbUnboundData); +done: + Tspi_Context_CloseObject(tpm_data->tspContext, hEncData); + + return rc; +} + +CK_RV token_create_private_tree(STDLL_TokData_t * tokdata, CK_BYTE * pinHash, + CK_BYTE * pPin) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + CK_RV rc; + TSS_RESULT result; + RSA *rsa; + unsigned int size_n, size_p; + unsigned char n[256], p[256]; + + /* all sw generated keys are 2048 bits */ + if ((rsa = openssl_gen_key()) == NULL) + return CKR_HOST_MEMORY; + + if (openssl_get_modulus_and_prime(rsa, &size_n, n, &size_p, p) != 0) { + TRACE_DEVEL("openssl_get_modulus_and_prime failed\n"); + return CKR_FUNCTION_FAILED; + } + + /* generate the software based user base key */ + rc = token_wrap_sw_key(tokdata, size_n, n, size_p, p, tpm_data->hSRK, + TSS_KEY_NO_AUTHORIZATION | TSS_KEY_TYPE_STORAGE, + &tpm_data->hPrivateRootKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_wrap_sw_key failed. rc=0x%lu\n", rc); + return rc; + } + + if (openssl_write_key(tokdata, rsa, TPMTOK_PRIV_ROOT_KEY_FILE, pPin)) { + TRACE_DEVEL("openssl_write_key failed.\n"); + RSA_free(rsa); + return CKR_FUNCTION_FAILED; + } + + RSA_free(rsa); + + /* store the user base key in a PKCS#11 object internally */ + rc = token_store_tss_key(tokdata, tpm_data->hPrivateRootKey, + TPMTOK_PRIVATE_ROOT_KEY, + &tpm_data->ckPrivateRootKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_store_tss_key failed. rc=0x%lx\n", rc); + return rc; + } + + result = Tspi_Key_LoadKey(tpm_data->hPrivateRootKey, tpm_data->hSRK); + if (result) { + TRACE_ERROR("Tspi_Key_LoadKey: 0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, + tpm_data->hPrivateRootKey); + tpm_data->hPrivateRootKey = NULL_HKEY; + return CKR_FUNCTION_FAILED; + } + + /* generate the private leaf key */ + rc = token_generate_leaf_key(tokdata, TPMTOK_PRIVATE_LEAF_KEY, + pinHash, &tpm_data->hPrivateLeafKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_generate_leaf_key failed. rc=0x%lx\n", rc); + return rc; + } + + result = Tspi_Key_LoadKey(tpm_data->hPrivateLeafKey, + tpm_data->hPrivateRootKey); + if (result) { + TRACE_ERROR("Tspi_Key_LoadKey: 0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, + tpm_data->hPrivateRootKey); + tpm_data->hPrivateRootKey = NULL_HKEY; + Tspi_Context_CloseObject(tpm_data->tspContext, + tpm_data->hPrivateLeafKey); + tpm_data->hPrivateRootKey = NULL_HKEY; + return CKR_FUNCTION_FAILED; + } + + return rc; +} + +CK_RV token_create_public_tree(STDLL_TokData_t * tokdata, CK_BYTE * pinHash, + CK_BYTE * pPin) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + CK_RV rc; + TSS_RESULT result; + RSA *rsa; + unsigned int size_n, size_p; + unsigned char n[256], p[256]; + + /* all sw generated keys are 2048 bits */ + if ((rsa = openssl_gen_key()) == NULL) + return CKR_HOST_MEMORY; + + if (openssl_get_modulus_and_prime(rsa, &size_n, n, &size_p, p) != 0) { + TRACE_DEVEL("openssl_get_modulus_and_prime failed\n"); + return CKR_FUNCTION_FAILED; + } + + /* create the public root key */ + rc = token_wrap_sw_key(tokdata, size_n, n, size_p, p, tpm_data->hSRK, + TSS_KEY_NO_AUTHORIZATION | TSS_KEY_TYPE_STORAGE, + &tpm_data->hPublicRootKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_wrap_sw_key failed. rc=0x%lx\n", rc); + return rc; + } + + if (openssl_write_key(tokdata, rsa, TPMTOK_PUB_ROOT_KEY_FILE, pPin)) { + TRACE_DEVEL("openssl_write_key\n"); + RSA_free(rsa); + return CKR_FUNCTION_FAILED; + } + + RSA_free(rsa); + + result = Tspi_Key_LoadKey(tpm_data->hPublicRootKey, tpm_data->hSRK); + if (result) { + TRACE_ERROR("Tspi_Key_LoadKey: 0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, + tpm_data->hPublicRootKey); + tpm_data->hPublicRootKey = NULL_HKEY; + return CKR_FUNCTION_FAILED; + } + + rc = token_store_tss_key(tokdata, tpm_data->hPublicRootKey, + TPMTOK_PUBLIC_ROOT_KEY, &tpm_data->ckPublicRootKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_store_tss_key failed. rc=0x%lx\n", rc); + return rc; + } + + /* create the SO's leaf key */ + rc = token_generate_leaf_key(tokdata, TPMTOK_PUBLIC_LEAF_KEY, + pinHash, &tpm_data->hPublicLeafKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_generate_leaf_key failed. rc=0x%lx\n", rc); + return rc; + } + + result = Tspi_Key_LoadKey(tpm_data->hPublicLeafKey, + tpm_data->hPublicRootKey); + if (result) { + TRACE_ERROR("Tspi_Key_LoadKey: 0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, + tpm_data->hPublicRootKey); + tpm_data->hPublicRootKey = NULL_HKEY; + Tspi_Context_CloseObject(tpm_data->tspContext, + tpm_data->hPublicLeafKey); + tpm_data->hPublicLeafKey = NULL_HKEY; + return CKR_FUNCTION_FAILED; + } + + return rc; +} + +CK_RV token_migrate(STDLL_TokData_t * tokdata, int key_type, CK_BYTE * pin) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + RSA *rsa; + char *backup_loc; + unsigned int size_n, size_p; + unsigned char n[256], p[256]; + TSS_RESULT result; + TSS_HKEY *phKey; + CK_RV rc; + CK_OBJECT_HANDLE *ckHandle; + SESSION dummy_sess; + + /* set up dummy session */ + memset(&dummy_sess, 0, sizeof(SESSION)); + dummy_sess.session_info.state = CKS_RW_USER_FUNCTIONS; + + if (key_type == TPMTOK_PUBLIC_ROOT_KEY) { + backup_loc = TPMTOK_PUB_ROOT_KEY_FILE; + phKey = &tpm_data->hPublicRootKey; + ckHandle = &tpm_data->ckPublicRootKey; + } else if (key_type == TPMTOK_PRIVATE_ROOT_KEY) { + backup_loc = TPMTOK_PRIV_ROOT_KEY_FILE; + phKey = &tpm_data->hPrivateRootKey; + ckHandle = &tpm_data->ckPrivateRootKey; + } else { + TRACE_ERROR("Invalid key type.\n"); + return CKR_FUNCTION_FAILED; + } + + /* read the backup key with the old pin */ + if ((rc = openssl_read_key(tokdata, backup_loc, pin, &rsa))) { + if (rc == CKR_FILE_NOT_FOUND) + rc = CKR_FUNCTION_FAILED; + TRACE_DEVEL("openssl_read_key failed\n"); + return rc; + } + + /* So, reading the backup openssl key off disk succeeded with the SOs PIN. + * We will now try to re-wrap that key with the current SRK + */ + if (openssl_get_modulus_and_prime(rsa, &size_n, n, &size_p, p) != 0) { + TRACE_DEVEL("openssl_get_modulus_and_prime failed\n"); + return CKR_FUNCTION_FAILED; + } + + rc = token_wrap_sw_key(tokdata, size_n, n, size_p, p, tpm_data->hSRK, + TSS_KEY_TYPE_STORAGE | TSS_KEY_NO_AUTHORIZATION, + phKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_wrap_sw_key failed. rc=0x%lx\n", rc); + RSA_free(rsa); + return rc; + } + RSA_free(rsa); + + result = Tspi_Key_LoadKey(*phKey, tpm_data->hSRK); + if (result) { + TRACE_ERROR("Tspi_Key_LoadKey: 0x%x\n", result); + Tspi_Context_CloseObject(tpm_data->tspContext, *phKey); + *phKey = NULL_HKEY; + return CKR_FUNCTION_FAILED; + } + + /* Loading succeeded, so we need to get rid of the old PKCS#11 objects + * and store them anew. + */ + rc = token_find_key(tokdata, key_type, CKO_PUBLIC_KEY, ckHandle); + if (rc != CKR_OK) { + TRACE_ERROR("token_find_key failed. rc=0x%lx\n", rc); + return CKR_FUNCTION_FAILED; + } + + rc = object_mgr_destroy_object(tokdata, &dummy_sess, *ckHandle); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_destroy_object failed: 0x%lx\n", rc); + return rc; + } + + rc = token_find_key(tokdata, key_type, CKO_PRIVATE_KEY, ckHandle); + if (rc != CKR_OK) { + TRACE_ERROR("token_find_key failed. rc=0x%lx\n", rc); + return CKR_FUNCTION_FAILED; + } + + rc = object_mgr_destroy_object(tokdata, &dummy_sess, *ckHandle); + if (rc != CKR_OK) { + TRACE_DEVEL("object_mgr_destroy_object failed: 0x%lx\n", rc); + return rc; + } + + rc = token_store_tss_key(tokdata, *phKey, key_type, ckHandle); + if (rc != CKR_OK) { + TRACE_DEVEL("token_store_tss_key failed: 0x%lx\n", rc); + return rc; + } + + return CKR_OK; +} + +CK_RV save_masterkey_private(STDLL_TokData_t * tokdata) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + char fname[PATH_MAX]; + struct stat file_stat; + int err; + FILE *fp = NULL; + struct passwd *pw = NULL; + + TSS_RESULT result; + TSS_HENCDATA hEncData; + BYTE *encrypted_masterkey; + UINT32 encrypted_masterkey_size; + + pw = getpwuid(getuid()); + if (pw == NULL) { + TRACE_ERROR("getpwuid failed: %s\n", strerror(errno)); + return CKR_FUNCTION_FAILED; + } + //fp = fopen("/etc/pkcs11/tpm/MK_PRIVATE", "r"); + sprintf(fname, "%s/%s/%s", tokdata->pk_dir, pw->pw_name, + TPMTOK_MASTERKEY_PRIVATE); + + /* if file exists, assume its been written correctly before */ + err = stat(fname, &file_stat); + if (err == 0) { + return CKR_OK; + } else if (errno != ENOENT) { + /* some error other than file doesn't exist */ + return CKR_FUNCTION_FAILED; + } + + /* encrypt the private masterkey using the private leaf key */ + result = Tspi_Context_CreateObject(tpm_data->tspContext, + TSS_OBJECT_TYPE_ENCDATA, + TSS_ENCDATA_BIND, &hEncData); + if (result) { + TRACE_ERROR("Tspi_Context_CreateObject failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + result = Tspi_Data_Bind(hEncData, tpm_data->hPrivateLeafKey, + MK_SIZE, tpm_data->master_key_private); + if (result) { + TRACE_ERROR("Tspi_Data_Bind failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + result = Tspi_GetAttribData(hEncData, TSS_TSPATTRIB_ENCDATA_BLOB, + TSS_TSPATTRIB_ENCDATABLOB_BLOB, + &encrypted_masterkey_size, + &encrypted_masterkey); + if (result) { + TRACE_ERROR("Tspi_GetAttribData failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + if (encrypted_masterkey_size > 256) { + Tspi_Context_FreeMemory(tpm_data->tspContext, encrypted_masterkey); + return CKR_DATA_LEN_RANGE; + } + + /* write the encrypted key to disk */ + if ((fp = fopen(fname, "w")) == NULL) { + TRACE_ERROR("Error opening %s for write: %s\n", fname, strerror(errno)); + Tspi_Context_FreeMemory(tpm_data->tspContext, encrypted_masterkey); + return CKR_FUNCTION_FAILED; + } + + err = fwrite(encrypted_masterkey, encrypted_masterkey_size, 1, fp); + if (err == 0) { + TRACE_ERROR("Error writing %s: %s\n", fname, strerror(errno)); + Tspi_Context_FreeMemory(tpm_data->tspContext, encrypted_masterkey); + fclose(fp); + return CKR_FUNCTION_FAILED; + } + + Tspi_Context_FreeMemory(tpm_data->tspContext, encrypted_masterkey); + fclose(fp); + + return CKR_OK; +} + +CK_RV load_masterkey_private(STDLL_TokData_t * tokdata) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + FILE *fp = NULL; + int err; + struct stat file_stat; + CK_BYTE encrypted_masterkey[256]; + char fname[PATH_MAX]; + CK_RV rc; + struct passwd *pw = NULL; + + TSS_RESULT result; + TSS_HENCDATA hEncData; + BYTE *masterkey; + UINT32 masterkey_size, encrypted_masterkey_size = 256; + + pw = getpwuid(getuid()); + if (pw == NULL) { + TRACE_ERROR("getpwuid failed: %s\n", strerror(errno)); + return CKR_FUNCTION_FAILED; + } + + sprintf(fname, "%s/%s/%s", tokdata->pk_dir, pw->pw_name, + TPMTOK_MASTERKEY_PRIVATE); + + /* if file exists, check its size */ + err = stat(fname, &file_stat); + if (err == 0) { + if (file_stat.st_size != 256) { + TRACE_ERROR("Private master key has been corrupted\n"); + return CKR_FUNCTION_FAILED; + } + } else if (errno == ENOENT) { + TRACE_INFO("Private master key doesn't exist, creating it...\n"); + + /* create the private master key, then save */ + rc = token_specific_rng(tokdata, tpm_data->master_key_private, MK_SIZE); + if (rc != CKR_OK) { + TRACE_DEVEL("token_rng failed. rc=0x%lx\n", rc); + return rc; + } + + return save_masterkey_private(tokdata); + } else { + /* some error other than file doesn't exist */ + TRACE_ERROR("stat of private masterkey failed: %s\n", strerror(errno)); + return CKR_FUNCTION_FAILED; + } + + //fp = fopen("/etc/pkcs11/tpm/MK_PUBLIC", "r"); + if ((fp = fopen(fname, "r")) == NULL) { + TRACE_ERROR("Error opening %s: %s\n", fname, strerror(errno)); + return CKR_FUNCTION_FAILED; + } + + if (fread(encrypted_masterkey, encrypted_masterkey_size, 1, fp) == 0) { + TRACE_ERROR("Error reading %s: %s\n", fname, strerror(errno)); + fclose(fp); + return CKR_FUNCTION_FAILED; + } + fclose(fp); + + /* decrypt the private masterkey using the private leaf key */ + result = Tspi_Context_CreateObject(tpm_data->tspContext, + TSS_OBJECT_TYPE_ENCDATA, + TSS_ENCDATA_BIND, &hEncData); + if (result) { + TRACE_ERROR("Tspi_Context_CreateObject failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + result = Tspi_SetAttribData(hEncData, TSS_TSPATTRIB_ENCDATA_BLOB, + TSS_TSPATTRIB_ENCDATABLOB_BLOB, + encrypted_masterkey_size, + encrypted_masterkey); + if (result) { + TRACE_ERROR("Tspi_SetAttribData failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + result = Tspi_Data_Unbind(hEncData, tpm_data->hPrivateLeafKey, + &masterkey_size, &masterkey); + if (result) { + TRACE_ERROR("Tspi_Data_Unbind failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + if (masterkey_size != MK_SIZE) { + TRACE_ERROR("decrypted private master key size is %u, " + "should be %u\n", masterkey_size, MK_SIZE); + Tspi_Context_FreeMemory(tpm_data->tspContext, masterkey); + return CKR_FUNCTION_FAILED; + } + + memcpy(tpm_data->master_key_private, masterkey, MK_SIZE); + Tspi_Context_FreeMemory(tpm_data->tspContext, masterkey); + + return CKR_OK; +} + + +CK_RV token_specific_login(STDLL_TokData_t * tokdata, SESSION * sess, + CK_USER_TYPE userType, CK_CHAR_PTR pPin, + CK_ULONG ulPinLen) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + CK_RV rc; + CK_BYTE hash_sha[SHA1_HASH_SIZE]; + TSS_RESULT result; + + UNUSED(sess); + + result = token_load_srk(tokdata); + if (result) { + TRACE_DEVEL("token_load_srk failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + rc = compute_sha1(tokdata, pPin, ulPinLen, hash_sha); + if (rc != CKR_OK) { + TRACE_ERROR("compute_sha1 failed. rc=0x%lx\n", rc); + return CKR_FUNCTION_FAILED; + } + + if (userType == CKU_USER) { + /* If the public root key doesn't exist yet, the SO hasn't init'd the + * token */ + result = token_load_public_root_key(tokdata); + if (result) { + TRACE_DEVEL("token_load_public_root_key failed. " + "rc=0x%x\n", result); + return CKR_USER_PIN_NOT_INITIALIZED; + } + + /* find, load the private root key */ + rc = token_find_key(tokdata, TPMTOK_PRIVATE_ROOT_KEY, + CKO_PRIVATE_KEY, &tpm_data->ckPrivateRootKey); + if (rc != CKR_OK) { + /* user's key chain not found, this must be the initial login */ + if (memcmp(hash_sha, default_user_pin_sha, SHA1_HASH_SIZE)) { + TRACE_ERROR("token_find_key failed and PIN != default\n"); + return CKR_PIN_INCORRECT; + } + + tpm_data->not_initialized = 1; + return CKR_OK; + } + + rc = token_load_key(tokdata, tpm_data->ckPrivateRootKey, + tpm_data->hSRK, NULL, &tpm_data->hPrivateRootKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_load_key failed. rc=0x%lx\n", rc); + + /* Here, we've found the private root key, but its load failed. + * This should only happen in a migration path, where we have + * the PKCS#11 key store available, but the SRK is now + * different. So, we will try to decrypt the PEM backup file + * for the private root key using the given password. If that + * succeeds, we will assume that we're in a migration path and + * re-wrap the private root key to the new SRK. + */ + if ((token_migrate(tokdata, TPMTOK_PRIVATE_ROOT_KEY, pPin))) { + TRACE_DEVEL("token_migrate. rc=0x%lx\n", rc); + return rc; + } + + /* At this point, the public root key has been successfully read + * from backup, re-wrapped to the new SRK, loaded and the PKCS#11 + * objects have been updated. Proceed with login as normal. + */ + } + + /* find, load the user leaf key */ + rc = token_find_key(tokdata, TPMTOK_PRIVATE_LEAF_KEY, + CKO_PRIVATE_KEY, &tpm_data->ckPrivateLeafKey); + if (rc != CKR_OK) { + TRACE_ERROR("token_find_key failed. rc=0x%lx\n", rc); + return CKR_FUNCTION_FAILED; + } + + rc = token_load_key(tokdata, tpm_data->ckPrivateLeafKey, + tpm_data->hPrivateRootKey, + hash_sha, &tpm_data->hPrivateLeafKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_load_key failed. rc=0x%lx\n", rc); + return CKR_FUNCTION_FAILED; + } + + rc = token_verify_pin(tokdata, tpm_data->hPrivateLeafKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_verify_pin failed. failed. rc=0x%lx\n", rc); + return rc; + } + + memcpy(tpm_data->current_user_pin_sha, hash_sha, SHA1_HASH_SIZE); + + /* load private data encryption key here */ + rc = load_masterkey_private(tokdata); + if (rc != CKR_OK) { + TRACE_DEVEL("load_masterkey_private failed. rc=0x%lx\n", rc); + Tspi_Key_UnloadKey(tpm_data->hPrivateLeafKey); + tpm_data->hPrivateLeafKey = NULL_HKEY; + return rc; + } + + rc = XProcLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to get process lock.\n"); + return rc; + } + + rc = load_private_token_objects(tokdata); + + if (rc != CKR_OK) { + XProcUnLock(tokdata); + return rc; + } + + tokdata->global_shm->priv_loaded = TRUE; + + rc = XProcUnLock(tokdata); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to release process lock.\n"); + return rc; + } + } else { + /* SO path -- + */ + /* find, load the root key */ + rc = token_find_key(tokdata, TPMTOK_PUBLIC_ROOT_KEY, + CKO_PRIVATE_KEY, &tpm_data->ckPublicRootKey); + if (rc != CKR_OK) { + /* The SO hasn't set her PIN yet, compare the login pin with + * the hard-coded value */ + if (memcmp(default_so_pin_sha, hash_sha, SHA1_HASH_SIZE)) { + TRACE_ERROR("token_find_key failed and PIN != default\n"); + return CKR_PIN_INCORRECT; + } + + tpm_data->not_initialized = 1; + return CKR_OK; + } + + /* The SO's key hierarchy has previously been created, so load the key + * hierarchy and verify the pin using the TPM. */ + rc = token_load_key(tokdata, tpm_data->ckPublicRootKey, + tpm_data->hSRK, NULL, &tpm_data->hPublicRootKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_load_key failed. rc=0x%lx\n", rc); + + /* Here, we've found the public root key, but its load failed. + * This should only happen in a migration path, where we have + * the PKCS#11 key store available, but the SRK is now + * different. So, we will try to decrypt the PEM backup file + * for the public root key using the given password. If that + * succeeds, we will assume that we're in a migration path and + * re-wrap the public root key to the new SRK. + */ + if ((token_migrate(tokdata, TPMTOK_PUBLIC_ROOT_KEY, pPin))) { + TRACE_DEVEL("token_migrate. rc=0x%lx\n", rc); + return rc; + } + + /* At this point, the public root key has been successfully read + * from backup, re-wrapped to the new SRK, loaded and the PKCS#11 + * objects have been updated. Proceed with login as normal. + */ + } + + /* find, load the public leaf key */ + rc = token_find_key(tokdata, TPMTOK_PUBLIC_LEAF_KEY, + CKO_PRIVATE_KEY, &tpm_data->ckPublicLeafKey); + if (rc != CKR_OK) { + TRACE_ERROR("token_find_key failed. rc=0x%lx\n", rc); + return CKR_FUNCTION_FAILED; + } + + rc = token_load_key(tokdata, tpm_data->ckPublicLeafKey, + tpm_data->hPublicRootKey, hash_sha, + &tpm_data->hPublicLeafKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_load_key failed. rc=0x%lx\n", rc); + return CKR_FUNCTION_FAILED; + } + + rc = token_verify_pin(tokdata, tpm_data->hPublicLeafKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_verify_pin failed. rc=0x%lx\n", rc); + return rc; + } + + memcpy(tpm_data->current_so_pin_sha, hash_sha, SHA1_HASH_SIZE); + } + + return rc; +} + +CK_RV token_specific_logout(STDLL_TokData_t *tokdata) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + + if (tpm_data->hPrivateLeafKey != NULL_HKEY) { + Tspi_Key_UnloadKey(tpm_data->hPrivateLeafKey); + } else if (tpm_data->hPublicLeafKey != NULL_HKEY) { + Tspi_Key_UnloadKey(tpm_data->hPublicLeafKey); + } + + clear_internal_structures(tokdata); + + return CKR_OK; +} + +CK_RV token_specific_init_pin(STDLL_TokData_t * tokdata, SESSION * sess, + CK_CHAR_PTR pPin, CK_ULONG ulPinLen) +{ + UNUSED(tokdata); + UNUSED(sess); + UNUSED(pPin); + UNUSED(ulPinLen); + + /* Since the SO must log in before calling C_InitPIN, we will + * be able to return CKR_OK automatically here. + * This is because the USER key structure is created at the + * time of her first login, not at C_InitPIN time. + */ + return CKR_OK; +} + +CK_RV check_pin_properties(CK_USER_TYPE userType, CK_BYTE * pinHash, + CK_ULONG ulPinLen) +{ + /* make sure the new PIN is different */ + if (userType == CKU_USER) { + if (!memcmp(pinHash, default_user_pin_sha, SHA1_HASH_SIZE)) { + TRACE_ERROR("new PIN must not be the default\n"); + return CKR_PIN_INVALID; + } + } else { + if (!memcmp(pinHash, default_so_pin_sha, SHA1_HASH_SIZE)) { + TRACE_ERROR("new PIN must not be the default\n"); + return CKR_PIN_INVALID; + } + } + + if (ulPinLen > MAX_PIN_LEN || ulPinLen < MIN_PIN_LEN) { + TRACE_ERROR("New PIN is out of size range\n"); + return CKR_PIN_LEN_RANGE; + } + + return CKR_OK; +} + +/* use this function call from set_pin only, where a not logged in public + * session can provide the user pin which must be verified. This function + * assumes that the pin has already been set once, so there's no migration + * path option or checking of the default user pin. + */ +CK_RV verify_user_pin(STDLL_TokData_t * tokdata, CK_BYTE * hash_sha) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + CK_RV rc; + + /* find, load the private root key */ + rc = token_find_key(tokdata, TPMTOK_PRIVATE_ROOT_KEY, + CKO_PRIVATE_KEY, &tpm_data->ckPrivateRootKey); + if (rc != CKR_OK) { + TRACE_ERROR("token_find_key failed. rc=0x%lx\n", rc); + return CKR_FUNCTION_FAILED; + } + + rc = token_load_key(tokdata, tpm_data->ckPrivateRootKey, + tpm_data->hSRK, NULL, &tpm_data->hPrivateRootKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_load_key failed. rc=0x%lx\n", rc); + return CKR_FUNCTION_FAILED; + } + + /* find, load the user leaf key */ + rc = token_find_key(tokdata, TPMTOK_PRIVATE_LEAF_KEY, + CKO_PRIVATE_KEY, &tpm_data->ckPrivateLeafKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_find_key failed. rc=0x%lx\n", rc); + return CKR_FUNCTION_FAILED; + } + + rc = token_load_key(tokdata, tpm_data->ckPrivateLeafKey, + tpm_data->hPrivateRootKey, hash_sha, + &tpm_data->hPrivateLeafKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_load_key failed. rc=0x%lx\n", rc); + return CKR_FUNCTION_FAILED; + } + + rc = token_verify_pin(tokdata, tpm_data->hPrivateLeafKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_verify_pin failed. failed. rc=0x%lx\n", rc); + return rc; + } + + return CKR_OK; +} + +CK_RV token_specific_set_pin(STDLL_TokData_t * tokdata, SESSION * sess, + CK_CHAR_PTR pOldPin, CK_ULONG ulOldPinLen, + CK_CHAR_PTR pNewPin, CK_ULONG ulNewPinLen) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + CK_BYTE oldpin_hash[SHA1_HASH_SIZE], newpin_hash[SHA1_HASH_SIZE]; + CK_RV rc; + RSA *rsa_root; + TSS_RESULT result; + + if (!sess) { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_HANDLE_INVALID)); + return CKR_SESSION_HANDLE_INVALID; + } + + rc = compute_sha1(tokdata, pOldPin, ulOldPinLen, oldpin_hash); + if (rc != CKR_OK) { + TRACE_ERROR("compute_sha1 failed. rc=0x%lx\n", rc); + return CKR_FUNCTION_FAILED; + } + + rc = compute_sha1(tokdata, pNewPin, ulNewPinLen, newpin_hash); + if (rc != CKR_OK) { + TRACE_ERROR("compute_sha1 failed. rc=0x%lx\n", rc); + return CKR_FUNCTION_FAILED; + } + + result = token_load_srk(tokdata); + if (result) { + TRACE_DEVEL("token_load_srk failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + /* From the PKCS#11 2.20 spec: "C_SetPIN modifies the PIN of the user that + * is currently logged in, or the CKU_USER PIN if the session is not logged + * in." + * A non R/W session fails with CKR_SESSION_READ_ONLY. + */ + if (sess->session_info.state == CKS_RW_USER_FUNCTIONS || + sess->session_info.state == CKS_RW_PUBLIC_SESSION) { + if (tpm_data->not_initialized) { + if (memcmp(oldpin_hash, default_user_pin_sha, SHA1_HASH_SIZE)) { + TRACE_ERROR("old PIN != default for an " + "uninitialized user\n"); + return CKR_PIN_INCORRECT; + } + + rc = check_pin_properties(CKU_USER, newpin_hash, ulNewPinLen); + if (rc != CKR_OK) { + return rc; + } + + rc = token_create_private_tree(tokdata, newpin_hash, pNewPin); + if (rc != CKR_OK) { + TRACE_DEVEL("FAILED creating USER tree.\n"); + return CKR_FUNCTION_FAILED; + } + + tokdata->nv_token_data->token_info.flags &= + ~(CKF_USER_PIN_TO_BE_CHANGED); + tokdata->nv_token_data->token_info.flags |= + CKF_USER_PIN_INITIALIZED; + + return save_token_data(tokdata, sess->session_info.slotID); + } + + if (sess->session_info.state == CKS_RW_USER_FUNCTIONS) { + /* if we're already logged in, just verify the hash */ + if (memcmp(tpm_data->current_user_pin_sha, oldpin_hash, + SHA1_HASH_SIZE)) { + TRACE_ERROR("USER pin incorrect\n"); + return CKR_PIN_INCORRECT; + } + } else { + rc = verify_user_pin(tokdata, oldpin_hash); + if (rc != CKR_OK) { + return rc; + } + } + + rc = check_pin_properties(CKU_USER, newpin_hash, ulNewPinLen); + if (rc != CKR_OK) { + return rc; + } + + /* change the auth on the TSS object */ + result = tss_change_auth(tokdata, tpm_data->hPrivateLeafKey, + tpm_data->hPrivateRootKey, newpin_hash); + if (result) { + TRACE_ERROR("tss_change_auth failed\n"); + return CKR_FUNCTION_FAILED; + } + + /* destroy the old PKCS#11 priv key object and create a new one */ + rc = token_update_private_key(tokdata, tpm_data->hPrivateLeafKey, + TPMTOK_PRIVATE_LEAF_KEY); + if (rc != CKR_OK) { + TRACE_DEVEL("token_update_private_key failed.\n"); + return rc; + } + + /* read the backup key with the old pin */ + rc = openssl_read_key(tokdata, TPMTOK_PRIV_ROOT_KEY_FILE, pOldPin, + &rsa_root); + if (rc != CKR_OK) { + if (rc == CKR_FILE_NOT_FOUND) { + /* If the user has moved his backup PEM file off site, allow a + * change auth to succeed without updating it. */ + return CKR_OK; + } + + TRACE_DEVEL("openssl_read_key failed\n"); + return rc; + } + + /* write it out using the new pin */ + rc = openssl_write_key(tokdata, rsa_root, TPMTOK_PRIV_ROOT_KEY_FILE, + pNewPin); + if (rc != CKR_OK) { + RSA_free(rsa_root); + TRACE_DEVEL("openssl_write_key failed\n"); + return CKR_FUNCTION_FAILED; + } + RSA_free(rsa_root); + } else if (sess->session_info.state == CKS_RW_SO_FUNCTIONS) { + if (tpm_data->not_initialized) { + if (memcmp(default_so_pin_sha, oldpin_hash, SHA1_HASH_SIZE)) { + TRACE_ERROR("old PIN != default for an " "uninitialized SO\n"); + return CKR_PIN_INCORRECT; + } + + rc = check_pin_properties(CKU_SO, newpin_hash, ulNewPinLen); + if (rc != CKR_OK) { + return rc; + } + + rc = token_create_public_tree(tokdata, newpin_hash, pNewPin); + if (rc != CKR_OK) { + TRACE_DEVEL("FAILED creating SO tree.\n"); + return CKR_FUNCTION_FAILED; + } + + tokdata->nv_token_data->token_info.flags &= + ~(CKF_SO_PIN_TO_BE_CHANGED); + + return save_token_data(tokdata, sess->session_info.slotID); + } + + if (memcmp(tpm_data->current_so_pin_sha, oldpin_hash, SHA1_HASH_SIZE)) { + TRACE_ERROR("SO PIN incorrect\n"); + return CKR_PIN_INCORRECT; + } + + rc = check_pin_properties(CKU_SO, newpin_hash, ulNewPinLen); + if (rc != CKR_OK) { + return rc; + } + + /* change auth on the SO's leaf key */ + result = tss_change_auth(tokdata, tpm_data->hPublicLeafKey, + tpm_data->hPublicRootKey, newpin_hash); + if (result) { + TRACE_ERROR("tss_change_auth failed\n"); + return CKR_FUNCTION_FAILED; + } + + rc = token_update_private_key(tokdata, tpm_data->hPublicLeafKey, + TPMTOK_PUBLIC_LEAF_KEY); + if (rc != CKR_OK) { + TRACE_DEVEL("token_update_private_key failed.\n"); + return rc; + } + + /* change auth on the public root key's openssl backup */ + rc = openssl_read_key(tokdata, TPMTOK_PUB_ROOT_KEY_FILE, pOldPin, + &rsa_root); + if (rc != CKR_OK) { + if (rc == CKR_FILE_NOT_FOUND) { + /* If the user has moved his backup PEM file off site, allow a + * change auth to succeed without updating it. */ + return CKR_OK; + } + + TRACE_DEVEL("openssl_read_key failed\n"); + return rc; + } + + /* write it out using the new pin */ + rc = openssl_write_key(tokdata, rsa_root, TPMTOK_PUB_ROOT_KEY_FILE, + pNewPin); + if (rc != CKR_OK) { + RSA_free(rsa_root); + TRACE_DEVEL("openssl_write_key failed\n"); + return CKR_FUNCTION_FAILED; + } + RSA_free(rsa_root); + } else { + TRACE_ERROR("%s\n", ock_err(ERR_SESSION_READ_ONLY)); + rc = CKR_SESSION_READ_ONLY; + } + + return rc; +} + +static CK_RV delete_tpm_data(STDLL_TokData_t * tokdata) +{ + char *cmd = NULL; + struct passwd *pw = NULL; + + pw = getpwuid(getuid()); + if (pw == NULL) { + TRACE_ERROR("getpwuid failed: %s\n", strerror(errno)); + return CKR_FUNCTION_FAILED; + } + // delete the TOK_OBJ data files + if (asprintf(&cmd, "%s %s/%s/%s/* > /dev/null 2>&1", DEL_CMD, + tokdata->pk_dir, pw->pw_name, PK_LITE_OBJ_DIR) < 0) { + return CKR_HOST_MEMORY; + } + if (system(cmd) == -1) + TRACE_ERROR("system() failed.\n"); + + free(cmd); + + // delete the OpenSSL backup keys + if (asprintf(&cmd, "%s %s/%s/%s > /dev/null 2>&1", DEL_CMD, + tokdata->pk_dir, pw->pw_name, TPMTOK_PUB_ROOT_KEY_FILE) < 0) { + return CKR_HOST_MEMORY; + } + if (system(cmd) == -1) + TRACE_ERROR("system() failed.\n"); + + free(cmd); + + if (asprintf(&cmd, "%s %s/%s/%s > /dev/null 2>&1", DEL_CMD, + tokdata->pk_dir, pw->pw_name, TPMTOK_PRIV_ROOT_KEY_FILE) < 0) { + return CKR_HOST_MEMORY; + } + if (system(cmd) == -1) + TRACE_ERROR("system() failed.\n"); + + free(cmd); + + // delete the masterkey + if (asprintf(&cmd, "%s %s/%s/%s > /dev/null 2>&1", DEL_CMD, + tokdata->pk_dir, pw->pw_name, TPMTOK_MASTERKEY_PRIVATE) < 0) { + return CKR_HOST_MEMORY; + } + if (system(cmd) == -1) + TRACE_ERROR("system() failed.\n"); + + free(cmd); + + return CKR_OK; +} + +/* only called at token init time */ +CK_RV token_specific_init_token(STDLL_TokData_t * tokdata, CK_SLOT_ID sid, + CK_CHAR_PTR pPin, CK_ULONG ulPinLen, + CK_CHAR_PTR pLabel) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + CK_BYTE hash_sha[SHA1_HASH_SIZE]; + CK_RV rc; + + rc = compute_sha1(tokdata, pPin, ulPinLen, hash_sha); + if (rc != CKR_OK) { + TRACE_ERROR("compute_sha1 failed. rc=0x%lx\n", rc); + return CKR_FUNCTION_FAILED; + } + + /* find, load the migratable root key */ + rc = token_find_key(tokdata, TPMTOK_PUBLIC_ROOT_KEY, + CKO_PRIVATE_KEY, &tpm_data->ckPublicRootKey); + if (rc != CKR_OK) { + /* The SO hasn't set her PIN yet, compare the login pin with + * the hard-coded value */ + if (memcmp(default_so_pin_sha, hash_sha, SHA1_HASH_SIZE)) { + TRACE_ERROR("token_find_key failed and PIN != default\n"); + return CKR_PIN_INCORRECT; + } + goto done; + } + + rc = token_load_srk(tokdata); + if (rc != CKR_OK) { + TRACE_DEVEL("token_load_srk failed. rc = 0x%lx\n", rc); + return CKR_FUNCTION_FAILED; + } + + /* we found the root key, so check by loading the chain */ + rc = token_load_key(tokdata, tpm_data->ckPublicRootKey, + tpm_data->hSRK, NULL, &tpm_data->hPublicRootKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_load_key failed. rc=0x%lx\n", rc); + return CKR_FUNCTION_FAILED; + } + + /* find, load the public leaf key */ + rc = token_find_key(tokdata, TPMTOK_PUBLIC_LEAF_KEY, + CKO_PRIVATE_KEY, &tpm_data->ckPublicLeafKey); + if (rc != CKR_OK) { + TRACE_ERROR("token_find_key failed. rc=0x%lx\n", rc); + return CKR_FUNCTION_FAILED; + } + + rc = token_load_key(tokdata, tpm_data->ckPublicLeafKey, + tpm_data->hPublicRootKey, hash_sha, + &tpm_data->hPublicLeafKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_load_key(MigLeafKey) Failed.\n"); + return CKR_FUNCTION_FAILED; + } + + rc = token_verify_pin(tokdata, tpm_data->hPublicLeafKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_verify_pin failed. rc=0x%lx\n", rc); + return rc; + } + +done: + // Before we reconstruct all the data, we should delete the + // token objects from the filesystem. + object_mgr_destroy_token_objects(tokdata); + rc = delete_tpm_data(tokdata); + if (rc != CKR_OK) + return rc; + + // META This should be fine since the open session checking should occur at + // the API not the STDLL + load_token_data(tokdata, sid); + init_slotInfo(&tokdata->slot_info); + memcpy(tokdata->nv_token_data->so_pin_sha, hash_sha, SHA1_HASH_SIZE); + tokdata->nv_token_data->token_info.flags |= CKF_TOKEN_INITIALIZED; + memcpy(tokdata->nv_token_data->token_info.label, pLabel, 32); + + // New for v2.11 - KEY + tokdata->nv_token_data->token_info.flags |= CKF_TOKEN_INITIALIZED; + + rc = save_token_data(tokdata, sid); + if (rc != CKR_OK) { + TRACE_DEVEL("save_token_data failed.\n"); + return rc; + } + + return CKR_OK; +} + +CK_RV token_specific_final(STDLL_TokData_t *tokdata, + CK_BBOOL in_fork_initializer) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + TSS_RESULT result; + + TRACE_INFO("tpm %s running\n", __func__); + + /* + * Only close the context if not in in_fork_initializer. If we close the + * context in a forked child process, this also closes the parent's context. + */ + if (!in_fork_initializer) { + result = Tspi_Context_Close(tpm_data->tspContext); + if (result) { + TRACE_ERROR("Tspi_Context_Close failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + } + + clear_internal_structures(tokdata); + + free(tpm_data); + tokdata->private_data = NULL; + + return CKR_OK; +} + +CK_RV token_specific_des_key_gen(STDLL_TokData_t * tokdata, CK_BYTE * des_key, + CK_ULONG len, CK_ULONG keysize) +{ + UNUSED(keysize); + + // Nothing different to do for DES or TDES here as this is just + // random data... Validation handles the rest + // Only check for weak keys when DES. + if (len == (3 * DES_KEY_SIZE)) { + rng_generate(tokdata, des_key, len); + } else { + do { + rng_generate(tokdata, des_key, len); + } while (des_check_weak_key(des_key) == TRUE); + } + + // we really need to validate the key for parity etc... + // we should do that here... The caller validates the single des keys + // against the known and suspected poor keys.. + return CKR_OK; +} + +CK_RV token_specific_des_ecb(STDLL_TokData_t * tokdata, + CK_BYTE * in_data, + CK_ULONG in_data_len, + CK_BYTE * out_data, + CK_ULONG * out_data_len, + OBJECT * key, CK_BYTE encrypt) +{ + CK_ULONG rc; + CK_ATTRIBUTE *attr = NULL; + + DES_key_schedule des_key2; + const_DES_cblock key_val_SSL, in_key_data; + DES_cblock out_key_data; + unsigned int i, j; + + UNUSED(tokdata); + + // get the key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("template_attribute_find(CKA_VALUE) failed.\n"); + return CKR_FUNCTION_FAILED; + } + // Create the key schedule + memcpy(&key_val_SSL, attr->pValue, 8); + DES_set_key_unchecked(&key_val_SSL, &des_key2); + + // the des decrypt will only fail if the data length is not evenly divisible + // by 8 + if (in_data_len % 8) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + // Both the encrypt and the decrypt are done 8 bytes at a time + if (encrypt) { + for (i = 0; i < in_data_len; i = i + 8) { + memcpy(in_key_data, in_data + i, 8); + DES_ecb_encrypt(&in_key_data, &out_key_data, &des_key2, + DES_ENCRYPT); + memcpy(out_data + i, out_key_data, 8); + } + + *out_data_len = in_data_len; + rc = CKR_OK; + } else { + + for (j = 0; j < in_data_len; j = j + 8) { + memcpy(in_key_data, in_data + j, 8); + DES_ecb_encrypt(&in_key_data, &out_key_data, &des_key2, + DES_DECRYPT); + memcpy(out_data + j, out_key_data, 8); + } + + *out_data_len = in_data_len; + rc = CKR_OK; + } + + return rc; +} + +CK_RV token_specific_des_cbc(STDLL_TokData_t * tokdata, + 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) +{ + CK_ULONG rc; + CK_ATTRIBUTE *attr = NULL; + + DES_cblock ivec; + + DES_key_schedule des_key2; + const_DES_cblock key_val_SSL; + + UNUSED(tokdata); + + // get the key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("template_attribute_find(CKA_VALUE) failed.\n"); + return CKR_FUNCTION_FAILED; + } + // Create the key schedule + memcpy(&key_val_SSL, attr->pValue, 8); + DES_set_key_unchecked(&key_val_SSL, &des_key2); + + memcpy(&ivec, init_v, 8); + // the des decrypt will only fail if the data length is not evenly divisible + // by 8 + if (in_data_len % 8) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + + + if (encrypt) { + DES_ncbc_encrypt(in_data, out_data, in_data_len, &des_key2, &ivec, + DES_ENCRYPT); + *out_data_len = in_data_len; + rc = CKR_OK; + } else { + DES_ncbc_encrypt(in_data, out_data, in_data_len, &des_key2, &ivec, + DES_DECRYPT); + *out_data_len = in_data_len; + rc = CKR_OK; + } + return rc; +} + +CK_RV token_specific_tdes_ecb(STDLL_TokData_t * tokdata, + CK_BYTE * in_data, + CK_ULONG in_data_len, + CK_BYTE * out_data, + CK_ULONG * out_data_len, + OBJECT * key, CK_BYTE encrypt) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + CK_KEY_TYPE keytype; + CK_BYTE key_value[3 * DES_KEY_SIZE]; + + unsigned int k, j; + DES_key_schedule des_key1; + DES_key_schedule des_key2; + DES_key_schedule des_key3; + + const_DES_cblock key_SSL1, key_SSL2, key_SSL3, in_key_data; + DES_cblock out_key_data; + + UNUSED(tokdata); + + // get the key type + rc = template_attribute_find(key->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("template_attribute_find(CKA_KEY_TYPE) failed.\n"); + return CKR_FUNCTION_FAILED; + } + keytype = *(CK_KEY_TYPE *) attr->pValue; + + // get the key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("template_attribute_find(CKA_VALUE) failed.\n"); + return CKR_FUNCTION_FAILED; + } + if (keytype == CKK_DES2) { + memcpy(key_value, attr->pValue, 2 * DES_KEY_SIZE); + memcpy(key_value + (2 * DES_KEY_SIZE), attr->pValue, DES_KEY_SIZE); + } else { + memcpy(key_value, attr->pValue, 3 * DES_KEY_SIZE); + } + + // The key as passed is a 24 byte long string containing three des keys + // pick them apart and create the 3 corresponding key schedules + memcpy(&key_SSL1, key_value, 8); + memcpy(&key_SSL2, key_value + 8, 8); + memcpy(&key_SSL3, key_value + 16, 8); + DES_set_key_unchecked(&key_SSL1, &des_key1); + DES_set_key_unchecked(&key_SSL2, &des_key2); + DES_set_key_unchecked(&key_SSL3, &des_key3); + + // the des decrypt will only fail if the data length is not evenly divisible + // by 8 + if (in_data_len % 8) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + // the encrypt and decrypt are done 8 bytes at a time + if (encrypt) { + for (k = 0; k < in_data_len; k = k + 8) { + memcpy(in_key_data, in_data + k, 8); + DES_ecb3_encrypt((const_DES_cblock *) & in_key_data, + (DES_cblock *) & out_key_data, + &des_key1, &des_key2, &des_key3, DES_ENCRYPT); + memcpy(out_data + k, out_key_data, 8); + } + *out_data_len = in_data_len; + rc = CKR_OK; + } else { + for (j = 0; j < in_data_len; j = j + 8) { + memcpy(in_key_data, in_data + j, 8); + DES_ecb3_encrypt((const_DES_cblock *) & in_key_data, + (DES_cblock *) & out_key_data, + &des_key1, &des_key2, &des_key3, DES_DECRYPT); + memcpy(out_data + j, out_key_data, 8); + } + *out_data_len = in_data_len; + rc = CKR_OK; + } + + return rc; +} + +CK_RV token_specific_tdes_cbc(STDLL_TokData_t * tokdata, + 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) +{ + CK_RV rc = CKR_OK; + CK_ATTRIBUTE *attr = NULL; + CK_KEY_TYPE keytype; + CK_BYTE key_value[3 * DES_KEY_SIZE]; + + DES_key_schedule des_key1; + DES_key_schedule des_key2; + DES_key_schedule des_key3; + + const_DES_cblock key_SSL1, key_SSL2, key_SSL3; + DES_cblock ivec; + + UNUSED(tokdata); + + // get the key type + rc = template_attribute_find(key->template, CKA_KEY_TYPE, &attr); + if (rc == FALSE) { + TRACE_ERROR("template_attribute_find(CKA_KEY_TYPE) failed.\n"); + return CKR_FUNCTION_FAILED; + } + keytype = *(CK_KEY_TYPE *) attr->pValue; + + // get the key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("template_attribute_find(CKA_VALUE) failed.\n"); + return CKR_FUNCTION_FAILED; + } + if (keytype == CKK_DES2) { + memcpy(key_value, attr->pValue, 2 * DES_KEY_SIZE); + memcpy(key_value + (2 * DES_KEY_SIZE), attr->pValue, DES_KEY_SIZE); + } else { + memcpy(key_value, attr->pValue, 3 * DES_KEY_SIZE); + } + + // The key as passed in is a 24 byte string containing 3 keys + // pick it apart and create the key schedules + memcpy(&key_SSL1, key_value, 8); + memcpy(&key_SSL2, key_value + 8, 8); + memcpy(&key_SSL3, key_value + 16, 8); + DES_set_key_unchecked(&key_SSL1, &des_key1); + DES_set_key_unchecked(&key_SSL2, &des_key2); + DES_set_key_unchecked(&key_SSL3, &des_key3); + + memcpy(ivec, init_v, sizeof(ivec)); + + // the des decrypt will only fail if the data length is not evenly divisible + // by 8 + if (in_data_len % 8) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + return CKR_DATA_LEN_RANGE; + } + // Encrypt or decrypt the data + if (encrypt) { + DES_ede3_cbc_encrypt(in_data, + out_data, + in_data_len, + &des_key1, + &des_key2, &des_key3, &ivec, DES_ENCRYPT); + *out_data_len = in_data_len; + rc = CKR_OK; + } else { + DES_ede3_cbc_encrypt(in_data, + out_data, + in_data_len, + &des_key1, + &des_key2, &des_key3, &ivec, DES_DECRYPT); + + *out_data_len = in_data_len; + rc = CKR_OK; + } + + return rc; +} + +/* wrap the 20 bytes of auth data @authData and store in an attribute of the two + * keys. + */ +CK_RV token_wrap_auth_data(STDLL_TokData_t * tokdata, + CK_BYTE * authData, TEMPLATE * publ_tmpl, + TEMPLATE * priv_tmpl) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + CK_RV rc; + CK_ATTRIBUTE *new_attr; + + TSS_HKEY hParentKey; + TSS_HENCDATA hEncData; + BYTE *blob; + UINT32 blob_size; + + if ((tpm_data->hPrivateLeafKey == NULL_HKEY) && + (tpm_data->hPublicLeafKey == NULL_HKEY)) { + TRACE_ERROR("Shouldn't be wrapping auth data in a " "public path!\n"); + return CKR_FUNCTION_FAILED; + } else if (tpm_data->hPublicLeafKey != NULL_HKEY) { + hParentKey = tpm_data->hPublicLeafKey; + } else { + hParentKey = tpm_data->hPrivateLeafKey; + } + + /* create the encrypted data object */ + rc = Tspi_Context_CreateObject(tpm_data->tspContext, + TSS_OBJECT_TYPE_ENCDATA, + TSS_ENCDATA_BIND, &hEncData); + if (rc != CKR_OK) { + TRACE_ERROR("Tspi_Context_CreateObject failed. rc=0x%lx\n", rc); + return rc; + } + + rc = Tspi_Data_Bind(hEncData, hParentKey, SHA1_HASH_SIZE, authData); + if (rc != CKR_OK) { + TRACE_ERROR("Tspi_Data_Bind failed. rc=0x%lx\n", rc); + return rc; + } + + /* pull the encrypted data out of the encrypted data object */ + rc = Tspi_GetAttribData(hEncData, TSS_TSPATTRIB_ENCDATA_BLOB, + TSS_TSPATTRIB_ENCDATABLOB_BLOB, &blob_size, &blob); + if (rc != CKR_OK) { + TRACE_ERROR("Tspi_SetAttribData failed. rc=0x%lx\n", rc); + return rc; + } + + rc = build_attribute(CKA_ENC_AUTHDATA, blob, blob_size, &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed.\n"); + return rc; + } + template_update_attribute(publ_tmpl, new_attr); + + rc = build_attribute(CKA_ENC_AUTHDATA, blob, blob_size, &new_attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute failed.\n"); + return rc; + } + template_update_attribute(priv_tmpl, new_attr); + + return rc; +} + +CK_RV token_unwrap_auth_data(STDLL_TokData_t * tokdata, + CK_BYTE * encAuthData, CK_ULONG encAuthDataLen, + TSS_HKEY hKey, BYTE ** authData) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + TSS_RESULT result; + TSS_HENCDATA hEncData; + BYTE *buf; + UINT32 buf_size; + + result = Tspi_Context_CreateObject(tpm_data->tspContext, + TSS_OBJECT_TYPE_ENCDATA, + TSS_ENCDATA_BIND, &hEncData); + if (result) { + TRACE_ERROR("Tspi_Context_CreateObject failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + result = Tspi_SetAttribData(hEncData, TSS_TSPATTRIB_ENCDATA_BLOB, + TSS_TSPATTRIB_ENCDATABLOB_BLOB, + encAuthDataLen, encAuthData); + if (result) { + TRACE_ERROR("Tspi_SetAttribData failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + /* unbind the data, receiving the plaintext back */ + result = Tspi_Data_Unbind(hEncData, hKey, &buf_size, &buf); + if (result) { + TRACE_ERROR("Tspi_Data_Unbind failed: rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + if (buf_size != SHA1_HASH_SIZE) { + TRACE_ERROR("auth data decrypt error.\n"); + return CKR_FUNCTION_FAILED; + } + + *authData = buf; + + return CKR_OK; +} + +// convert from the local PKCS11 template representation to +// the underlying requirement +// returns the pointer to the local key representation +CK_BYTE *rsa_convert_public_key(OBJECT * key_obj) +{ + CK_ATTRIBUTE *modulus = NULL; + CK_BYTE *ret; + CK_RV rc; + + rc = template_attribute_find(key_obj->template, CKA_MODULUS, &modulus); + if (rc == FALSE) { + return NULL; + } + + ret = malloc(modulus->ulValueLen); + if (ret == NULL) { + TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); + return NULL; + } + + memcpy(ret, modulus->pValue, modulus->ulValueLen); + + return ret; +} + +CK_RV token_specific_rsa_generate_keypair(STDLL_TokData_t * tokdata, + TEMPLATE * publ_tmpl, + TEMPLATE * priv_tmpl) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + CK_ATTRIBUTE *attr = NULL; + CK_ULONG mod_bits = 0; + CK_BBOOL flag; + CK_RV rc; + CK_BYTE tpm_pubexp[3] = { 1, 0, 1 }; // 65537 + + TSS_FLAG initFlags = 0; + BYTE authHash[SHA1_HASH_SIZE]; + BYTE *authData = NULL; + TSS_HKEY hKey = NULL_HKEY; + TSS_HKEY hParentKey = NULL_HKEY; + TSS_RESULT result; + UINT32 ulBlobLen; + BYTE *rgbBlob; + + /* Make sure the public exponent is usable */ + if ((util_check_public_exponent(publ_tmpl))) { + TRACE_DEVEL("Invalid public exponent\n"); + return CKR_TEMPLATE_INCONSISTENT; + } + + flag = template_attribute_find(publ_tmpl, CKA_MODULUS_BITS, &attr); + if (!flag) { + TRACE_ERROR("template_attribute_find(CKA_MODULUS_BITS) failed.\n"); + return CKR_TEMPLATE_INCOMPLETE; // should never happen + } + mod_bits = *(CK_ULONG *) attr->pValue; + + if ((initFlags = util_get_keysize_flag(mod_bits)) == 0) { + TRACE_ERROR("%s\n", ock_err(ERR_KEY_SIZE_RANGE)); + return CKR_KEY_SIZE_RANGE; + } + + /* If we're not logged in, hPrivateLeafKey and hPublicLeafKey + * should be NULL */ + if ((tpm_data->hPrivateLeafKey == NULL_HKEY) && + (tpm_data->hPublicLeafKey == NULL_HKEY)) { + /* public session, wrap key with the PRK */ + initFlags |= + TSS_KEY_TYPE_LEGACY | TSS_KEY_NO_AUTHORIZATION | TSS_KEY_MIGRATABLE; + + if ((result = token_load_public_root_key(tokdata))) { + TRACE_DEVEL("token_load_public_root_key failed. " + "rc=%x\n", result); + return CKR_FUNCTION_FAILED; + } + + hParentKey = tpm_data->hPublicRootKey; + } else if (tpm_data->hPrivateLeafKey != NULL_HKEY) { + /* logged in USER session */ + initFlags |= + TSS_KEY_TYPE_LEGACY | TSS_KEY_AUTHORIZATION | TSS_KEY_MIGRATABLE; + + /* get a random SHA1 hash for the auth data */ + if ((rc = token_specific_rng(tokdata, authHash, SHA1_HASH_SIZE))) { + TRACE_DEVEL("token_rng failed. rc=%lx\n", rc); + return CKR_FUNCTION_FAILED; + } + + authData = authHash; + hParentKey = tpm_data->hPrivateRootKey; + } else { + /* logged in SO session */ + initFlags |= + TSS_KEY_TYPE_LEGACY | TSS_KEY_AUTHORIZATION | TSS_KEY_MIGRATABLE; + + /* get a random SHA1 hash for the auth data */ + rc = token_specific_rng(tokdata, authHash, SHA1_HASH_SIZE); + if (rc != CKR_OK) { + TRACE_DEVEL("token_rng failed. rc=0x%lx\n", rc); + return CKR_FUNCTION_FAILED; + } + + authData = authHash; + hParentKey = tpm_data->hPublicRootKey; + } + + result = tss_generate_key(tokdata, initFlags, authData, hParentKey, &hKey); + if (result) { + TRACE_ERROR("tss_generate_key returned 0x%x\n", result); + return result; + } + + result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB, + TSS_TSPATTRIB_KEYBLOB_BLOB, + &ulBlobLen, &rgbBlob); + if (result) { + TRACE_ERROR("Tspi_GetAttribData failed with rc: 0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + rc = build_attribute(CKA_IBM_OPAQUE, rgbBlob, ulBlobLen, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute(CKA_IBM_OPAQUE) failed.\n"); + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); + return rc; + } + template_update_attribute(priv_tmpl, attr); + + rc = build_attribute(CKA_IBM_OPAQUE, rgbBlob, ulBlobLen, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute(CKA_IBM_OPAQUE) failed.\n"); + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); + return rc; + } + template_update_attribute(publ_tmpl, attr); + + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); + + /* grab the public key to put into the public key object */ + result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_RSAKEY_INFO, + TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, + &ulBlobLen, &rgbBlob); + if (result) { + TRACE_ERROR("Tspi_GetAttribData failed with rc: 0x%x\n", result); + return result; + } + + /* add the public key blob to the object template */ + rc = build_attribute(CKA_MODULUS, rgbBlob, ulBlobLen, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute(CKA_MODULUS) failed.\n"); + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); + return rc; + } + template_update_attribute(publ_tmpl, attr); + + /* add the public key blob to the object template */ + rc = build_attribute(CKA_MODULUS, rgbBlob, ulBlobLen, &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute(CKA_MODULUS) failed.\n"); + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); + return rc; + } + template_update_attribute(priv_tmpl, attr); + Tspi_Context_FreeMemory(tpm_data->tspContext, rgbBlob); + + /* put the public exponent into the private key object */ + rc = build_attribute(CKA_PUBLIC_EXPONENT, + tpm_pubexp, sizeof(tpm_pubexp), &attr); + if (rc != CKR_OK) { + TRACE_DEVEL("build_attribute(CKA_PUBLIC_EXPONENT) failed.\n"); + return rc; + } + template_update_attribute(priv_tmpl, attr); + + /* wrap the authdata and put it into an object */ + if (authData != NULL) { + rc = token_wrap_auth_data(tokdata, authData, publ_tmpl, priv_tmpl); + if (rc != CKR_OK) { + TRACE_DEVEL("token_wrap_auth_data failed with rc: 0x%lx\n", rc); + } + } + + return rc; +} + +CK_RV token_rsa_load_key(STDLL_TokData_t * tokdata, OBJECT * key_obj, + TSS_HKEY * phKey) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + TSS_RESULT result; + TSS_HPOLICY hPolicy = NULL_HPOLICY; + TSS_HKEY hParentKey; + BYTE *authData = NULL; + CK_ATTRIBUTE *attr; + CK_RV rc; + CK_OBJECT_HANDLE handle; + + if (tpm_data->hPrivateLeafKey != NULL_HKEY) { + hParentKey = tpm_data->hPrivateRootKey; + } else { + result = token_load_public_root_key(tokdata); + if (result) { + TRACE_DEVEL("token_load_public_root_key failed. " + "rc=%x\n", result); + return CKR_FUNCTION_FAILED; + } + + hParentKey = tpm_data->hPublicRootKey; + } + + + rc = template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr); + if (rc == FALSE) { + /* if the key blob wasn't found, then try to wrap the key */ + rc = object_mgr_find_in_map2(tokdata, key_obj, &handle); + if (rc != CKR_OK) + return CKR_FUNCTION_FAILED; + + /* The Object holds the READ lock, but token_load_key might need the + * WRITE lock, so unlock the object + */ + rc = object_unlock(key_obj); + if (rc != CKR_OK) + return rc; + + rc = token_load_key(tokdata, handle, hParentKey, NULL, phKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_load_key failed. rc=0x%lx\n", rc); + object_lock(key_obj, READ_LOCK); + return rc; + } + + /* Get the READ lock again */ + rc = object_lock(key_obj, READ_LOCK); + if (rc != CKR_OK) + return rc; + + /* try again to get the CKA_IBM_OPAQUE attr */ + rc = template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr); + if (rc == FALSE) { + TRACE_ERROR("Could not find key blob\n"); + return rc; + } + } + + result = Tspi_Context_LoadKeyByBlob(tpm_data->tspContext, hParentKey, + attr->ulValueLen, attr->pValue, phKey); + if (result) { + TRACE_ERROR("Tspi_Context_LoadKeyByBlob failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + /* auth data may be required */ + if (template_attribute_find(key_obj->template, CKA_ENC_AUTHDATA, &attr) == + TRUE && attr) { + if ((tpm_data->hPrivateLeafKey == NULL_HKEY) && + (tpm_data->hPublicLeafKey == NULL_HKEY)) { + TRACE_ERROR("Shouldn't be in a public session here\n"); + return CKR_FUNCTION_FAILED; + } else if (tpm_data->hPublicLeafKey != NULL_HKEY) { + hParentKey = tpm_data->hPublicLeafKey; + } else { + hParentKey = tpm_data->hPrivateLeafKey; + } + + result = token_unwrap_auth_data(tokdata, attr->pValue, attr->ulValueLen, + hParentKey, &authData); + if (result) { + TRACE_DEVEL("token_unwrap_auth_data: 0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + result = Tspi_GetPolicyObject(*phKey, TSS_POLICY_USAGE, &hPolicy); + if (result) { + TRACE_ERROR("Tspi_GetPolicyObject: 0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + /* If the policy handle returned is the same as the context's default + * policy, then a new policy must be created and assigned to the key. + * Otherwise, just set the secret in the policy */ + if (hPolicy == tpm_data->hDefaultPolicy) { + result = Tspi_Context_CreateObject(tpm_data->tspContext, + TSS_OBJECT_TYPE_POLICY, + TSS_POLICY_USAGE, &hPolicy); + if (result) { + TRACE_ERROR("Tspi_Context_CreateObject: 0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_SHA1, + SHA1_HASH_SIZE, authData); + if (result) { + TRACE_ERROR("Tspi_Policy_SetSecret failed. " + "rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + result = Tspi_Policy_AssignToObject(hPolicy, *phKey); + if (result) { + TRACE_ERROR("Tspi_Policy_AssignToObject failed." + " rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + } else { + result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_SHA1, + SHA1_HASH_SIZE, authData); + if (result) { + TRACE_ERROR("Tspi_Policy_SetSecret failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + } + + Tspi_Context_FreeMemory(tpm_data->tspContext, authData); + } + + return CKR_OK; +} + +CK_RV token_specific_rsa_decrypt(STDLL_TokData_t * tokdata, + CK_BYTE * in_data, + CK_ULONG in_data_len, + CK_BYTE * out_data, + CK_ULONG * out_data_len, OBJECT * key_obj) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + CK_RV rc; + TSS_RESULT result; + TSS_HKEY hKey; + TSS_HENCDATA hEncData = NULL_HENCDATA; + UINT32 buf_size = 0; + BYTE *buf = NULL; + + rc = token_rsa_load_key(tokdata, key_obj, &hKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_rsa_load_key failed. rc=0x%lx\n", rc); + return rc; + } + + /* push the data into the encrypted data object */ + result = Tspi_Context_CreateObject(tpm_data->tspContext, + TSS_OBJECT_TYPE_ENCDATA, + TSS_ENCDATA_BIND, &hEncData); + if (result) { + TRACE_ERROR("Tspi_Context_CreateObject failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + result = Tspi_SetAttribData(hEncData, TSS_TSPATTRIB_ENCDATA_BLOB, + TSS_TSPATTRIB_ENCDATABLOB_BLOB, + in_data_len, in_data); + if (result) { + TRACE_ERROR("Tspi_SetAttribData failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + /* unbind the data, receiving the plaintext back */ + TRACE_DEVEL("unbinding data with size: %ld\n", in_data_len); + + result = Tspi_Data_Unbind(hEncData, hKey, &buf_size, &buf); + if (result) { + TRACE_ERROR("Tspi_Data_Unbind failed: 0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + if (*out_data_len < buf_size) { + TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); + Tspi_Context_FreeMemory(tpm_data->tspContext, buf); + return CKR_BUFFER_TOO_SMALL; + } + + memcpy(out_data, buf, buf_size); + *out_data_len = buf_size; + + Tspi_Context_FreeMemory(tpm_data->tspContext, buf); + + return CKR_OK; +} + +CK_RV token_specific_rsa_verify(STDLL_TokData_t * tokdata, + SESSION * sess, + CK_BYTE * in_data, + CK_ULONG in_data_len, + CK_BYTE * sig, + CK_ULONG sig_len, OBJECT * key_obj) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + TSS_RESULT result; + TSS_HHASH hHash; + TSS_HKEY hKey; + CK_RV rc; + + UNUSED(sess); + + rc = token_rsa_load_key(tokdata, key_obj, &hKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_rsa_load_key failed. rc=0x%lx\n", rc); + return rc; + } + + /* Create the hash object we'll use to sign */ + result = Tspi_Context_CreateObject(tpm_data->tspContext, + TSS_OBJECT_TYPE_HASH, + TSS_HASH_OTHER, &hHash); + if (result) { + TRACE_ERROR("Tspi_Context_CreateObject failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + /* Insert the data into the hash object */ + result = Tspi_Hash_SetHashValue(hHash, in_data_len, in_data); + if (result) { + TRACE_ERROR("Tspi_Hash_SetHashValue failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + /* Verify */ + result = Tspi_Hash_VerifySignature(hHash, hKey, sig_len, sig); + if (result != TSS_SUCCESS && TPMTOK_TSS_ERROR_CODE(result) != TSS_E_FAIL) { + TRACE_ERROR("Tspi_Hash_VerifySignature failed. rc=0x%x\n", result); + } + + if (TPMTOK_TSS_ERROR_CODE(result) == TSS_E_FAIL) { + rc = CKR_SIGNATURE_INVALID; + } else { + rc = CKR_OK; + } + + return rc; +} + +CK_RV token_specific_rsa_sign(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) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + TSS_RESULT result; + TSS_HHASH hHash; + BYTE *sig; + UINT32 sig_len; + TSS_HKEY hKey; + CK_RV rc; + + UNUSED(sess); + + rc = token_rsa_load_key(tokdata, key_obj, &hKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_rsa_load_key failed. rc=0x%lx\n", rc); + return rc; + } + + /* Create the hash object we'll use to sign */ + result = Tspi_Context_CreateObject(tpm_data->tspContext, + TSS_OBJECT_TYPE_HASH, + TSS_HASH_OTHER, &hHash); + if (result) { + TRACE_ERROR("Tspi_Context_CreateObject failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + /* Insert the data into the hash object */ + result = Tspi_Hash_SetHashValue(hHash, in_data_len, in_data); + if (result) { + TRACE_ERROR("Tspi_Hash_SetHashValue failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + /* Sign */ + result = Tspi_Hash_Sign(hHash, hKey, &sig_len, &sig); + if (result) { + TRACE_ERROR("Tspi_Hash_Sign failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + if (sig_len > *out_data_len) { + TRACE_ERROR("Buffer too small to hold result.\n"); + Tspi_Context_FreeMemory(tpm_data->tspContext, sig); + return CKR_BUFFER_TOO_SMALL; + } + + memcpy(out_data, sig, sig_len); + *out_data_len = sig_len; + Tspi_Context_FreeMemory(tpm_data->tspContext, sig); + + return CKR_OK; +} + + +CK_RV token_specific_rsa_encrypt(STDLL_TokData_t * tokdata, + CK_BYTE * in_data, + CK_ULONG in_data_len, + CK_BYTE * out_data, + CK_ULONG * out_data_len, OBJECT * key_obj) +{ + tpm_private_data_t *tpm_data = (tpm_private_data_t *)tokdata->private_data; + TSS_RESULT result; + TSS_HENCDATA hEncData; + BYTE *dataBlob; + UINT32 dataBlobSize; + TSS_HKEY hKey; + CK_RV rc; + + rc = token_rsa_load_key(tokdata, key_obj, &hKey); + if (rc != CKR_OK) { + TRACE_DEVEL("token_rsa_load_key failed. rc=0x%lx\n", rc); + return rc; + } + + result = Tspi_Context_CreateObject(tpm_data->tspContext, + TSS_OBJECT_TYPE_ENCDATA, + TSS_ENCDATA_BIND, &hEncData); + if (result) { + TRACE_ERROR("Tspi_Context_CreateObject failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + result = Tspi_Data_Bind(hEncData, hKey, in_data_len, in_data); + if (result) { + TRACE_ERROR("Tspi_Data_Bind failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + result = Tspi_GetAttribData(hEncData, TSS_TSPATTRIB_ENCDATA_BLOB, + TSS_TSPATTRIB_ENCDATABLOB_BLOB, + &dataBlobSize, &dataBlob); + if (result) { + TRACE_ERROR("Tspi_SetAttribData failed. rc=0x%x\n", result); + return CKR_FUNCTION_FAILED; + } + + if (dataBlobSize > *out_data_len) { + TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); + Tspi_Context_FreeMemory(tpm_data->tspContext, dataBlob); + return CKR_DATA_LEN_RANGE; + } + + memcpy(out_data, dataBlob, dataBlobSize); + *out_data_len = dataBlobSize; + Tspi_Context_FreeMemory(tpm_data->tspContext, dataBlob); + + return CKR_OK; +} + +CK_RV token_specific_rsa_verify_recover(STDLL_TokData_t * tokdata, + CK_BYTE * signature, CK_ULONG sig_len, + CK_BYTE * out_data, + CK_ULONG * out_data_len, + OBJECT * key_obj) +{ + CK_RV rc; + + rc = token_specific_rsa_encrypt(tokdata, signature, sig_len, out_data, + out_data_len, key_obj); + + if (rc != CKR_OK) + TRACE_DEVEL("token specific rsa_encrypt failed.\n"); + + return rc; +} + +CK_RV token_specific_aes_key_gen(STDLL_TokData_t * tokdata, CK_BYTE * key, + CK_ULONG len, CK_ULONG keysize) +{ + UNUSED(keysize); + + return token_specific_rng(tokdata, key, len); +} + +CK_RV token_specific_aes_ecb(STDLL_TokData_t * tokdata, + CK_BYTE * in_data, + CK_ULONG in_data_len, + CK_BYTE * out_data, + CK_ULONG * out_data_len, + OBJECT * key, CK_BYTE encrypt) +{ + CK_ATTRIBUTE *attr = NULL; + AES_KEY ssl_aes_key; + unsigned int i; + /* There's a previous check that in_data_len % AES_BLOCK_SIZE == 0, + * so this is fine */ + CK_ULONG loops = (CK_ULONG) (in_data_len / AES_BLOCK_SIZE); + + UNUSED(tokdata); + + // get the key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("template_attribute_find(CKA_VALUE) failed.\n"); + return CKR_FUNCTION_FAILED; + } + + memset(&ssl_aes_key, 0, sizeof(AES_KEY)); + + // AES_ecb_encrypt encrypts only a single block, so we have to break up the + // input data here + if (encrypt) { + AES_set_encrypt_key((unsigned char *) attr->pValue, + (attr->ulValueLen * 8), &ssl_aes_key); + for (i = 0; i < loops; i++) { + AES_ecb_encrypt((unsigned char *) in_data + (i * AES_BLOCK_SIZE), + (unsigned char *) out_data + (i * AES_BLOCK_SIZE), + &ssl_aes_key, AES_ENCRYPT); + } + } else { + AES_set_decrypt_key((unsigned char *) attr->pValue, + (attr->ulValueLen * 8), &ssl_aes_key); + for (i = 0; i < loops; i++) { + AES_ecb_encrypt((unsigned char *) in_data + (i * AES_BLOCK_SIZE), + (unsigned char *) out_data + (i * AES_BLOCK_SIZE), + &ssl_aes_key, AES_DECRYPT); + } + } + *out_data_len = in_data_len; + + return CKR_OK; +} + +CK_RV token_specific_aes_cbc(STDLL_TokData_t * tokdata, + 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) +{ + AES_KEY ssl_aes_key; + CK_ATTRIBUTE *attr = NULL; + + UNUSED(tokdata); + + // get the key value + if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { + TRACE_ERROR("template_attribute_find(CKA_VALUE) failed.\n"); + return CKR_FUNCTION_FAILED; + } + + memset(&ssl_aes_key, 0, sizeof(AES_KEY)); + + // AES_cbc_encrypt chunks the data into AES_BLOCK_SIZE blocks, unlike + // AES_ecb_encrypt, so no looping required. + if (encrypt) { + AES_set_encrypt_key((unsigned char *) attr->pValue, + (attr->ulValueLen * 8), &ssl_aes_key); + AES_cbc_encrypt((unsigned char *) in_data, (unsigned char *) out_data, + in_data_len, &ssl_aes_key, init_v, AES_ENCRYPT); + } else { + AES_set_decrypt_key((unsigned char *) attr->pValue, + (attr->ulValueLen * 8), &ssl_aes_key); + AES_cbc_encrypt((unsigned char *) in_data, (unsigned char *) out_data, + in_data_len, &ssl_aes_key, init_v, AES_DECRYPT); + } + *out_data_len = in_data_len; + + return CKR_OK; +} + +CK_RV token_specific_get_mechanism_list(STDLL_TokData_t * tokdata, + CK_MECHANISM_TYPE_PTR pMechanismList, + CK_ULONG_PTR pulCount) +{ + return ock_generic_get_mechanism_list(tokdata, pMechanismList, pulCount); +} + +CK_RV token_specific_get_mechanism_info(STDLL_TokData_t * tokdata, + CK_MECHANISM_TYPE type, + CK_MECHANISM_INFO_PTR pInfo) +{ + return ock_generic_get_mechanism_info(tokdata, type, pInfo); +} + +int token_specific_creatlock(void) +{ + char lockfile[PATH_MAX + (sizeof(LOCKDIR_PATH) - 1) + + 2 * (sizeof(SUB_DIR) - 1) + + (sizeof("///LCK..") - 1) + 1]; + char lockdir[(sizeof(LOCKDIR_PATH) - 1) + (sizeof(SUB_DIR) - 1) + + (sizeof("/") - 1) + 1]; + struct passwd *pw = NULL; + struct stat statbuf; + mode_t mode = (S_IRUSR | S_IWUSR | S_IXUSR); + int lockfd = -1;; + int ret = -1; + struct group *grp = NULL; + + /* get userid */ + pw = getpwuid(getuid()); + if (pw == NULL) { + OCK_SYSLOG(LOG_ERR, "getpwuid(): %s\n", strerror(errno)); + return -1; + } + if (strlen(pw->pw_name) > PATH_MAX) { + OCK_SYSLOG(LOG_ERR, "Username(%s) too long\n", pw->pw_name); + return -1; + } + + /** create lock subdir for each token if it doesn't exist. + * The root /var/lock/opencryptoki directory should be created in slotmgr + * daemon **/ + sprintf(lockdir, "%s/%s", LOCKDIR_PATH, SUB_DIR); + + ret = stat(lockdir, &statbuf); + if (ret != 0 && errno == ENOENT) { + /* dir does not exist, try to create it */ + ret = mkdir(lockdir, S_IRWXU | S_IRWXG); + if (ret != 0) { + OCK_SYSLOG(LOG_ERR, + "Directory(%s) missing: %s\n", lockdir, strerror(errno)); + goto err; + } + grp = getgrnam("pkcs11"); + if (grp == NULL) { + fprintf(stderr, "getgrname(pkcs11): %s", strerror(errno)); + goto err; + } + /* set ownership to euid, and pkcs11 group */ + if (chown(lockdir, geteuid(), grp->gr_gid) != 0) { + fprintf(stderr, "Failed to set owner:group \ + ownership\ + on %s directory", lockdir); + goto err; + } + /* mkdir does not set group permission right, so + ** trying explictly here again */ + if (chmod(lockdir, S_IRWXU | S_IRWXG) != 0) { + fprintf(stderr, "Failed to change \ + permissions\ + on %s directory", lockdir); + goto err; + } + } + + /* create user-specific directory */ + sprintf(lockfile, "%s/%s/%s", LOCKDIR_PATH, SUB_DIR, pw->pw_name); + + /* see if it exists, otherwise mkdir will fail */ + if (stat(lockfile, &statbuf) < 0) { + if (mkdir(lockfile, mode) == -1) { + OCK_SYSLOG(LOG_ERR, "mkdir(%s): %s\n", lockfile, strerror(errno)); + return -1; + } + + /* ensure correct perms on user dir */ + if (chmod(lockfile, mode) == -1) { + OCK_SYSLOG(LOG_ERR, "chmod(%s): %s\n", lockfile, strerror(errno)); + return -1; + } + } + + /* create user lock file */ + memset(lockfile, 0, sizeof(lockfile)); + sprintf(lockfile, "%s/%s/%s/LCK..%s", LOCKDIR_PATH, SUB_DIR, pw->pw_name, + SUB_DIR); + + lockfd = open(lockfile, O_CREAT | O_RDWR, mode); + if (lockfd == -1) { + OCK_SYSLOG(LOG_ERR, "open(%s): %s\n", lockfile, strerror(errno)); + return -1; + } else { + /* umask may prevent correct mode, so set it. */ + if (fchmod(lockfd, mode) == -1) { + OCK_SYSLOG(LOG_ERR, "fchmod(%s): %s\n", lockfile, strerror(errno)); + goto err; + } + } + + return lockfd; +err: + if (lockfd != -1) + close(lockfd); + + return -1; +} + +CK_RV token_specific_init_token_data(STDLL_TokData_t * tokdata, + CK_SLOT_ID slot_id) +{ + UNUSED(tokdata); + UNUSED(slot_id); + + /* do nothing. */ + return CKR_OK; +} diff --git a/usr/lib/tpm_stdll/tpm_specific.h b/usr/lib/tpm_stdll/tpm_specific.h new file mode 100644 index 0000000..541b679 --- /dev/null +++ b/usr/lib/tpm_stdll/tpm_specific.h @@ -0,0 +1,91 @@ +/* + * 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 + */ + +#ifndef _TPM_SPECIFIC_H_ +#define _TPM_SPECIFIC_H_ + +#include + +/* TSS key type helper */ +#define TPMTOK_TSS_KEY_TYPE_MASK 0x000000F0 +#define TPMTOK_TSS_KEY_TYPE(x) (x & TPMTOK_TSS_KEY_TYPE_MASK) +#define TPMTOK_TSS_KEY_MIG_TYPE(x) (x & TSS_KEY_MIGRATABLE) + +#define TPMTOK_TSS_MAX_ERROR 0x00000FFF +#define TPMTOK_TSS_ERROR_CODE(x) (x & TPMTOK_TSS_MAX_ERROR) + +/* key types in the TPM token */ +#define TPMTOK_PRIVATE_ROOT_KEY 1 +#define TPMTOK_PRIVATE_LEAF_KEY 2 +#define TPMTOK_PUBLIC_ROOT_KEY 3 +#define TPMTOK_PUBLIC_LEAF_KEY 4 + +/* key identifiers for the PKCS#11 objects */ +#define TPMTOK_PRIVATE_ROOT_KEY_ID "PRIVATE ROOT KEY" +#define TPMTOK_PRIVATE_LEAF_KEY_ID "PRIVATE LEAF KEY" +#define TPMTOK_PUBLIC_ROOT_KEY_ID "PUBLIC ROOT KEY" +#define TPMTOK_PUBLIC_LEAF_KEY_ID "PUBLIC LEAF KEY" + +#define TPMTOK_PRIVATE_ROOT_KEY_ID_SIZE strlen(TPMTOK_PRIVATE_ROOT_KEY_ID) +#define TPMTOK_PRIVATE_LEAF_KEY_ID_SIZE strlen(TPMTOK_PRIVATE_LEAF_KEY_ID) +#define TPMTOK_PUBLIC_ROOT_KEY_ID_SIZE strlen(TPMTOK_PUBLIC_ROOT_KEY_ID) +#define TPMTOK_PUBLIC_LEAF_KEY_ID_SIZE strlen(TPMTOK_PUBLIC_LEAF_KEY_ID) + +#define TPMTOK_PUB_ROOT_KEY_FILE "PUBLIC_ROOT_KEY.pem" +#define TPMTOK_PRIV_ROOT_KEY_FILE "PRIVATE_ROOT_KEY.pem" + +/* TPM token specific return codes */ +#define CKR_KEY_NOT_FOUND CKR_VENDOR_DEFINED + 0x0f000000 +#define CKR_FILE_NOT_FOUND CKR_VENDOR_DEFINED + 0x0f000001 + +#define TPMTOK_MASTERKEY_PRIVATE "MK_PRIVATE" + +#ifdef DEBUG +#define DEBUG_openssl_print_errors() openssl_print_errors() +#else +#define DEBUG_openssl_print_errors() +#endif + +/* retry count for generating software RSA keys */ +#define KEYGEN_RETRY 5 + +RSA *openssl_gen_key(); +int openssl_write_key(STDLL_TokData_t *, RSA *, char *, CK_BYTE *); +CK_RV openssl_read_key(STDLL_TokData_t *, char *, CK_BYTE *, RSA **); +int openssl_get_modulus_and_prime(RSA *, unsigned int *, unsigned char *, + unsigned int *, unsigned char *); +int util_set_file_mode(char *, mode_t); +CK_BYTE *util_create_id(int); +CK_RV util_set_username(char **); +unsigned int util_get_keysize_flag(CK_ULONG); +CK_ULONG util_check_public_exponent(TEMPLATE *); + +#define NULL_HKEY 0 +#define NULL_HENCDATA 0 +#define NULL_HPOLICY 0 +#define NULL_HCONTEXT 0 +#define NULL_HPCRS 0 + +/* CKA_ENC_AUTHDATA will be used to store the encrypted SHA-1 hashes of auth + * data passed in for TPM keys. The authdata will be encrypted using either the + * public leaf key or the private leaf key */ +#define CKA_ENC_AUTHDATA CKA_VENDOR_DEFINED + 0x01000001 + +#define MK_SIZE (AES_KEY_SIZE_256) + +struct srk_info { + char *secret; + int mode; + int len; +}; + +int get_srk_info(struct srk_info *srk); + +#endif diff --git a/usr/lib/tpm_stdll/tpm_stdll.mk b/usr/lib/tpm_stdll/tpm_stdll.mk new file mode 100644 index 0000000..49d7886 --- /dev/null +++ b/usr/lib/tpm_stdll/tpm_stdll.mk @@ -0,0 +1,46 @@ +nobase_lib_LTLIBRARIES += opencryptoki/stdll/libpkcs11_tpm.la + +noinst_HEADERS += \ + usr/lib/tpm_stdll/defs.h usr/lib/tpm_stdll/tpm_specific.h \ + usr/lib/tpm_stdll/tok_struct.h + +opencryptoki_stdll_libpkcs11_tpm_la_CFLAGS = \ + -DLINUX -DNOCDMF -DNODSA -DNODH -DMMAP \ + -DTOK_NEW_DATA_STORE=0xffffffff \ + -I${srcdir}/usr/lib/tpm_stdll -I${srcdir}/usr/lib/common \ + -I${srcdir}/usr/include -DSTDLL_NAME=\"tpmtok\" + +opencryptoki_stdll_libpkcs11_tpm_la_LDFLAGS = \ + -shared -Wl,-z,defs,-Bsymbolic -lcrypto -ltspi -lpthread -lrt \ + -Wl,--version-script=${srcdir}/opencryptoki_tok.map + +opencryptoki_stdll_libpkcs11_tpm_la_SOURCES = \ + usr/lib/common/asn1.c usr/lib/common/dig_mgr.c \ + usr/lib/common/hwf_obj.c usr/lib/common/trace.c \ + usr/lib/common/key.c usr/lib/common/mech_dh.c \ + usr/lib/common/mech_rng.c usr/lib/common/new_host.c \ + usr/lib/common/sign_mgr.c usr/lib/common/cert.c \ + usr/lib/common/dp_obj.c usr/lib/common/mech_aes.c \ + usr/lib/common/mech_rsa.c usr/lib/common/mech_ec.c \ + usr/lib/common/obj_mgr.c usr/lib/common/template.c \ + usr/lib/common/p11util.c usr/lib/common/data_obj.c \ + usr/lib/common/encr_mgr.c usr/lib/common/key_mgr.c \ + usr/lib/common/mech_md2.c usr/lib/common/mech_sha.c \ + usr/lib/common/object.c usr/lib/common/decr_mgr.c \ + usr/lib/common/globals.c usr/lib/common/sw_crypt.c \ + usr/lib/common/loadsave.c usr/lib/common/utility.c \ + usr/lib/common/mech_des.c usr/lib/common/mech_des3.c \ + usr/lib/common/mech_md5.c usr/lib/common/mech_ssl3.c \ + usr/lib/common/verify_mgr.c usr/lib/common/mech_list.c \ + usr/lib/common/shared_memory.c usr/lib/tpm_stdll/tpm_specific.c \ + usr/lib/tpm_stdll/tpm_openssl.c usr/lib/tpm_stdll/tpm_util.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 diff --git a/usr/lib/tpm_stdll/tpm_util.c b/usr/lib/tpm_stdll/tpm_util.c new file mode 100644 index 0000000..6d5fe33 --- /dev/null +++ b/usr/lib/tpm_stdll/tpm_util.c @@ -0,0 +1,328 @@ +/* + * 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 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "pkcs11types.h" +#include "stdll.h" +#include "defs.h" +#include "host_defs.h" +#include "h_extern.h" +#include "trace.h" + +#include "tpm_specific.h" + +static const struct { + TSS_FLAG mode; + const char *str; +} tss_modes[] = { + {TSS_SECRET_MODE_NONE, "TSS_SECRET_MODE_NONE"}, + {TSS_SECRET_MODE_SHA1, "TSS_SECRET_MODE_SHA1"}, + {TSS_SECRET_MODE_PLAIN, "TSS_SECRET_MODE_PLAIN"}, + {TSS_SECRET_MODE_POPUP, "TSS_SECRET_MODE_POPUP"}, + {TSS_SECRET_MODE_CALLBACK, "TSS_SECRET_MODE_CALLBACK"}, +}; + +UINT32 util_get_keysize_flag(CK_ULONG size) +{ + switch (size) { + case 512: + return TSS_KEY_SIZE_512; + break; + case 1024: + return TSS_KEY_SIZE_1024; + break; + case 2048: + return TSS_KEY_SIZE_2048; + break; + default: + break; + } + + return 0; +} + +CK_BYTE *util_create_id(int type) +{ + CK_BYTE *ret = NULL; + int size = 0; + + switch (type) { + case TPMTOK_PRIVATE_ROOT_KEY: + size = TPMTOK_PRIVATE_ROOT_KEY_ID_SIZE + 1; + if ((ret = malloc(size)) == NULL) { + TRACE_ERROR("malloc of %d bytes failed.", size); + break; + } + + sprintf((char *) ret, "%s", TPMTOK_PRIVATE_ROOT_KEY_ID); + break; + case TPMTOK_PUBLIC_ROOT_KEY: + size = TPMTOK_PUBLIC_ROOT_KEY_ID_SIZE + 1; + if ((ret = malloc(size)) == NULL) { + TRACE_ERROR("malloc of %d bytes failed.", size); + break; + } + + sprintf((char *) ret, "%s", TPMTOK_PUBLIC_ROOT_KEY_ID); + break; + case TPMTOK_PUBLIC_LEAF_KEY: + size = TPMTOK_PUBLIC_LEAF_KEY_ID_SIZE + 1; + if ((ret = malloc(size)) == NULL) { + TRACE_ERROR("malloc of %d bytes failed.", size); + break; + } + + sprintf((char *) ret, "%s", TPMTOK_PUBLIC_LEAF_KEY_ID); + break; + case TPMTOK_PRIVATE_LEAF_KEY: + size = TPMTOK_PRIVATE_LEAF_KEY_ID_SIZE + 1; + if ((ret = malloc(size)) == NULL) { + TRACE_ERROR("malloc of %d bytes failed.", size); + break; + } + + sprintf((char *) ret, "%s", TPMTOK_PRIVATE_LEAF_KEY_ID); + break; + default: + TRACE_ERROR("Unknown type: %d\n", type); + break; + } + + return ret; +} + +int util_set_file_mode(char *filename, mode_t mode) +{ + struct stat file_stat; + + if (stat(filename, &file_stat) == -1) { + TRACE_ERROR("stat failed: %s\n", strerror(errno)); + return -1; + } else if ((file_stat.st_mode ^ mode) != 0) { + if (chmod(filename, mode) == -1) { + TRACE_ERROR("chmod(%s) failed: %s\n", filename, strerror(errno)); + return -1; + } + } + + return 0; +} + +/* make sure the public exponent attribute is 65537 */ +CK_ULONG util_check_public_exponent(TEMPLATE * tmpl) +{ + CK_BBOOL flag; + CK_ATTRIBUTE *publ_exp_attr; + CK_BYTE pubexp_bytes[] = { 1, 0, 1 }; + CK_ULONG publ_exp, rc = 1; + + flag = template_attribute_find(tmpl, CKA_PUBLIC_EXPONENT, &publ_exp_attr); + if (!flag) { + TRACE_ERROR("Couldn't find public exponent attribute.\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + + switch (publ_exp_attr->ulValueLen) { + case 3: + rc = memcmp(pubexp_bytes, publ_exp_attr->pValue, 3); + break; + case sizeof(CK_ULONG): + publ_exp = *((CK_ULONG *) publ_exp_attr->pValue); + if (publ_exp == 65537) + rc = 0; + break; + default: + break; + } + + return rc; +} + +TSS_RESULT util_set_public_modulus(TSS_HCONTEXT tspContext, TSS_HKEY hKey, + unsigned long size_n, unsigned char *n) +{ + UINT64 offset; + UINT32 blob_size; + BYTE *blob, pub_blob[1024]; + TCPA_PUBKEY pub_key; + TSS_RESULT result; + + /* Get the TCPA_PUBKEY blob from the key object. */ + result = + Tspi_GetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB, + TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY, &blob_size, &blob); + if (result != TSS_SUCCESS) { + TRACE_ERROR("Tspi_GetAttribData failed: rc=0x%x", result); + return result; + } + + offset = 0; + result = Trspi_UnloadBlob_PUBKEY(&offset, blob, &pub_key); + if (result != TSS_SUCCESS) { + TRACE_ERROR("Tspi_GetAttribData failed: rc=0x%x", result); + return result; + } + + Tspi_Context_FreeMemory(tspContext, blob); + /* Free the first dangling reference, putting 'n' in its place */ + free(pub_key.pubKey.key); + pub_key.pubKey.keyLength = size_n; + pub_key.pubKey.key = n; + + offset = 0; + Trspi_LoadBlob_PUBKEY(&offset, pub_blob, &pub_key); + + /* Free the second dangling reference */ + free(pub_key.algorithmParms.parms); + + /* set the public key data in the TSS object */ + result = + Tspi_SetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB, + TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY, (UINT32) offset, + pub_blob); + if (result != TSS_SUCCESS) { + TRACE_ERROR("Tspi_SetAttribData failed: rc=0x%x", result); + return result; + } + + return TSS_SUCCESS; +} + +TSS_FLAG get_srk_mode(void) +{ + char *mode = NULL; + int i; + int num_modes = sizeof(tss_modes) / sizeof(tss_modes[0]); + + mode = getenv("OCK_SRK_MODE"); + if (mode == NULL) + return 0; + + /* parse */ + for (i = 0; i < num_modes; i++) { + if (strncmp(mode, tss_modes[i].str, strlen(mode)) == 0) + return tss_modes[i].mode; + } + + TRACE_ERROR("Unknown TSS mode set in OCK_SRK_MODE, %s.\n", mode); + return -1; +} + +int get_srk_info(struct srk_info *srk) +{ + char *passwd_ptr = NULL; + char *secret = NULL; + int i; + + srk->mode = get_srk_mode(); + if (srk->mode == -1) + return -1; + + srk->secret = NULL; + passwd_ptr = getenv("OCK_SRK_SECRET"); + + /* If nothing is set, then use original opencryptoki default of + * secret is NULL and TSS_SECRET_MODE_PLAIN. + */ + if (passwd_ptr == NULL) { + srk->len = 0; + if (srk->mode == 0) { + srk->mode = TSS_SECRET_MODE_PLAIN; + return 0; + } + } else { + srk->len = strlen(passwd_ptr); + } + + /* A mode required at this point... */ + if (srk->mode == 0) { + TRACE_ERROR("SRK policy's secret mode is not set.\n"); + return -1; + } + + /* + * getenv() returns a ptr to the actual string in our env, + * so be sure to make a copy to avoid problems. + */ + + if (srk->len != 0) { + if ((secret = (char *) malloc(srk->len + 1)) == NULL) { + TRACE_ERROR("malloc of %d bytes failed.\n", srk->len); + return -1; + } + memcpy(secret, passwd_ptr, srk->len); + secret[srk->len] = '\0'; + srk->secret = secret; + } + + /* Secrets that are a hash, need to be converted from a + * hex string to an array of bytes. + */ + if (srk->mode == TSS_SECRET_MODE_SHA1) { + + char *secret_h; + int h_len = TPM_SHA1_160_HASH_LEN; + + if ((secret_h = (char *) malloc(h_len)) == NULL) { + TRACE_ERROR("malloc of %d bytes failed.\n", h_len); + goto error; + } + + /* reuse passwd ptr since we dont need it anymore. */ + passwd_ptr = secret; + + /* Assume hash is read in as string of hexidecimal digits. + * 2 hex digits are required to represent a byte. + * thus we need 2 * TPM_SHA1_160_HASH_LEN to + * represent the hash. + */ + if (srk->len != (h_len * 2)) { + free(secret_h); + TRACE_DEVEL("Hashed secret is %d bytes, expected %d.\n", + srk->len, h_len * 2); + goto error; + } + + /* convert hexadecimal string into a byte array... */ + for (i = 0; i < h_len; i++) { + sscanf(passwd_ptr, "%2hhx", (unsigned char *)&secret_h[i]); + passwd_ptr += 2; + } + + srk->len = h_len; + srk->secret = secret_h; + free(secret); + } + + return 0; + +error: + if (secret) + free(secret); + + return -1; +} diff --git a/usr/sbin/p11sak/p11sak.c b/usr/sbin/p11sak/p11sak.c new file mode 100644 index 0000000..63dcae4 --- /dev/null +++ b/usr/sbin/p11sak/p11sak.c @@ -0,0 +1,2092 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2001-2020 + * + * This program is provided under the terms of the Common Public License, + * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this + * software constitutes recipient's acceptance of CPL-1.0 terms which can be + * found in the file LICENSE file or at + * https://opensource.org/licenses/cpl1.0.php + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + + +#include + +#include "p11sak.h" + +static const char *default_pkcs11lib = "libopencryptoki.so"; + +static void *pkcs11lib = NULL; +static CK_FUNCTION_LIST *funcs = NULL; + +static void unload_pkcs11lib(void) +{ + if (pkcs11lib) + dlclose(pkcs11lib); +} + +static void load_pkcs11lib(void) +{ + CK_RV rc; + CK_RV(*pfoo) (); + const char *libname; + + /* check for environment variable PKCSLIB */ + libname = getenv("PKCSLIB"); + if (libname == NULL || strlen(libname) < 1) + libname = default_pkcs11lib; + + /* try to load the pkcs11 lib */ + pkcs11lib = dlopen(libname, RTLD_NOW); + if (!pkcs11lib) { + printf("Error: failed to open pkcs11 lib '%s'\n", libname); + exit(99); + } + + /* get function list */ + *(void **)(&pfoo) = dlsym(pkcs11lib, "C_GetFunctionList"); + if (!pfoo) { + dlclose(pkcs11lib); + printf("Error: failed to resolve symbol '%s' from pkcs11 lib '%s'\n", + "C_GetFunctionList", libname); + exit(99); + } + rc = pfoo(&funcs); + if (rc != CKR_OK) { + dlclose(pkcs11lib); + printf("Error: C_GetFunctionList() on pkcs11 lib '%s' failed with rc=0x%lX)\n", + libname, rc); + exit(99); + } + + atexit(unload_pkcs11lib); +} + +static CK_RV get_pin(char **pin, size_t *pinlen) { + struct termios old, new; + int nread; + char *buff = NULL; + size_t buflen; + CK_RV rc = 0; + + /* turn echoing off */ + if (tcgetattr(fileno(stdin), &old) != 0) + return -1; + + new = old; + new.c_lflag &= ~ECHO; + if (tcsetattr(fileno(stdin), TCSAFLUSH, &new) != 0) + return -1; + + /* read the pin + * Note: getline will allocate memory for buff. free it when done. + */ + nread = getline(&buff, &buflen, stdin); + if (nread == -1) { + rc = -1; + goto done; + } + + /* Restore terminal */ + (void) tcsetattr(fileno(stdin), TCSAFLUSH, &old); + + /* start a newline */ + printf("\n"); + fflush(stdout); + + /* Allocate PIN. + * Note: nread includes carriage return. + * Replace with terminating NULL. + */ + *pin = (char*) malloc(nread); + if (*pin == NULL) { + rc = -ENOMEM; + goto done; + } + + /* strip the carriage return since not part of pin. */ + buff[nread - 1] = '\0'; + memcpy(*pin, buff, nread); + /* don't include the terminating null in the pinlen */ + *pinlen = nread - 1; + + done: if (buff) + free(buff); + + return rc; +} +/** + * Translates the given key type to its string representation. + */ +static const char* kt2str(p11sak_kt ktype) { + switch (ktype) { + case kt_DES: + return "DES"; + case kt_3DES: + return "3DES"; + case kt_AES: + return "AES"; + case kt_RSAPKCS: + return "RSA_PKCS"; + case kt_EC: + return "EC"; + case kt_GENERIC: + return "GENERIC"; + case kt_SECRET: + return "SECRET"; + case kt_PUBLIC: + return "PUBLIC"; + case kt_PRIVATE: + return "PRIVATE"; + case no_key_type: + return "NO_KEYTYPE"; + default: + return "NO_KEYTYPE"; + } +} +/** + * Translates the given key type to its CK_KEY_TYPE + */ +static CK_RV kt2CKK(p11sak_kt ktype, CK_KEY_TYPE *a_key_type) { + 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_RSAPKCS: + *a_key_type = CKK_RSA; + break; + case kt_EC: + *a_key_type = CKK_EC; + break; + case kt_GENERIC: + *a_key_type = CKK_GENERIC_SECRET; + break; + default: + 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) { + 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; + 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) { + switch (cmd) { + case no_cmd: + return "no_cmd"; + case gen_key: + return "generate-key"; + case list_key: + return "list-key"; + default: + return "unknown p11sak cmd"; + } +} +/** + * Translates the given attribute type to its long name. + */ +static const char* CKA2a(CK_ATTRIBUTE_TYPE attr_type) { + 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"; + } +} +/** + * Translates the given key type to its related char string. + */ +static const char* CKK2a(CK_KEY_TYPE t) { + switch (t) { + case CKK_DES: + return "DES"; + case CKK_DES3: + return "3DES"; + case CKK_AES: + return "AES"; + case CKK_EC: + return "EC"; + 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"; + } +} +/** + * Translates the given bool to its related char string. + */ +static const char* CK_BBOOL2a(CK_BBOOL b) { + switch (b) { + case 0: + return "CK_FALSE"; + case 1: + return "CK_TRUE"; + default: + return "unknown value"; + } +} +/** + * Translates the given ULONG value to a byte string. + */ +static CK_BYTE* CK_ULONG2bigint(CK_ULONG ul, CK_BYTE *bytes, CK_ULONG *len) { + CK_BYTE *ulp; + CK_ULONG tul = 1; + CK_BYTE *tulp; + int i, j, s; + + s = 0; + ulp = (CK_BYTE*) &ul; + tulp = (CK_BYTE*) &tul; + + 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; + } + } else { + for (i = 0; i <= (int) sizeof(CK_ULONG) - 1; i++) { + bytes[i] = ulp[i]; + if (s == 0 && bytes[i] != 0) + s = i; + } + } + *len = sizeof(CK_ULONG) - s; + + return &bytes[s]; +} +/** + * print help functions + */ +static void print_cmd_help(void) { + 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("\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(" rsa\n"); + printf(" ec\n"); + printf(" public\n"); + printf(" private\n"); + printf(" secret\n"); + printf("\n Options:\n"); + printf(" -l, --long list output with long format\n"); + printf( + " --slot SLOTID openCryptoki repository token SLOTID.\n"); + printf(" --pin PIN pkcs11 user PIN\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(" rsa [1024 | 2048 | 4096]\n"); + printf(" ec [prime256v1 | secp384r1 | secp521]\n"); + printf("\n Options:\n"); + printf( + " --slot SLOTID openCryptoki repository token SLOTID.\n"); + printf(" --pin PIN pkcs11 user PIN\n"); + printf( + " --label LABEL key label LABEL to be listed\n"); + printf( + " --exponent EXP set RSA exponent EXP\n"); + printf( + " --attr [M R L S E D G V W U A X N T] set key attributes\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( + " --label LABEL key label LABEL to be listed\n"); + printf( + " --attr [M R L S E D G V W U A X N T] 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( + " --label LABEL key label LABEL to be listed\n"); + printf( + " --attr [M R L S E D G V W U A X N T] 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( + " --label LABEL key label LABEL to be listed\n"); + printf( + " --exponent EXP set RSA exponent EXP\n"); + printf( + " --attr [M R L S E D G V W U A X N T] set key attributes\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(" secp384r1\n"); + printf(" secp521\n"); + printf("\n Options:\n"); + printf( + " --slot SLOTID openCryptoki repository token SLOTID.\n"); + printf(" --pin PIN pkcs11 user PIN\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 T] set key attributes\n"); + printf(" -h, --help Show this help\n\n"); +} +/** + * Print help for generate-key command + */ +static CK_RV print_gen_keys_help(p11sak_kt *kt) { + + 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_RSAPKCS: + print_gen_rsa_help(); + break; + case kt_EC: + print_gen_ec_help(); + break; + case no_key_type: + print_gen_help(); + break; + default: + print_gen_help(); + } + + return CKR_OK; +} +/** + * Print help for attributes + */ +static void print_gen_attr_help(void) { + printf("\n"); + printf(" Setting CK_ATTRIBUTE\n"); + printf("\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("\n"); + printf(" CKA_TOKEN and CKA_PRIVATE are 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("\n"); + + printf("\n"); +} +/** + * 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) { + CK_ULONG *mod_bits; + CK_ULONG ulpubexp; + CK_BYTE *pubexp; + CK_BYTE *spubexp; + CK_ULONG spubexplen; + + if (!(mod_bits = malloc(sizeof(CK_ULONG)))) { + printf("Error: failed to allocate memory for mod_bits.\n"); + return CKR_HOST_MEMORY; + } + *mod_bits = modulusbits; + + pubattr[*pubcount].type = CKA_MODULUS_BITS; + pubattr[*pubcount].pValue = mod_bits; + pubattr[*pubcount].ulValueLen = sizeof(CK_ULONG); + (*pubcount)++; + + if (exponent > 0) + ulpubexp = exponent; + else + ulpubexp = 65537; /* default for RSA_PKCS */ + + if (!(pubexp = malloc(sizeof(CK_ULONG)))) { + printf("Error: failed to allocate memory for public exponent.\n"); + return CKR_HOST_MEMORY; + } + + spubexp = CK_ULONG2bigint(ulpubexp, pubexp, &spubexplen); + pubattr[*pubcount].type = CKA_PUBLIC_EXPONENT; + pubattr[*pubcount].pValue = spubexp; + pubattr[*pubcount].ulValueLen = spubexplen; + (*pubcount)++; + + 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) { + pubattr[*pubcount].type = CKA_EC_PARAMS; + if (strcmp(ECcurve, "prime256v1") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) prime256v1; + pubattr[*pubcount].ulValueLen = sizeof(prime256v1); + } else if (strcmp(ECcurve, "prime192") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) prime192; + pubattr[*pubcount].ulValueLen = sizeof(prime192); + } else if (strcmp(ECcurve, "secp224") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) secp224; + pubattr[*pubcount].ulValueLen = sizeof(secp224); + } else if (strcmp(ECcurve, "secp384r1") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) secp384r1; + pubattr[*pubcount].ulValueLen = sizeof(secp384r1); + } else if (strcmp(ECcurve, "secp521r1") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) secp521r1; + pubattr[*pubcount].ulValueLen = sizeof(secp521r1); + } else if (strcmp(ECcurve, "secp265k1") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) secp256k1; + pubattr[*pubcount].ulValueLen = sizeof(secp256k1); + } else if (strcmp(ECcurve, "brainpoolP160r1") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP160r1; + pubattr[*pubcount].ulValueLen = sizeof(brainpoolP160r1); + } else if (strcmp(ECcurve, "brainpoolP160t1") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP160t1; + pubattr[*pubcount].ulValueLen = sizeof(brainpoolP160t1); + } else if (strcmp(ECcurve, "brainpoolP192r1") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP192r1; + pubattr[*pubcount].ulValueLen = sizeof(brainpoolP192r1); + } else if (strcmp(ECcurve, "brainpoolP192t1") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP192t1; + pubattr[*pubcount].ulValueLen = sizeof(brainpoolP192t1); + } else if (strcmp(ECcurve, "brainpoolP224r1") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP224r1; + pubattr[*pubcount].ulValueLen = sizeof(brainpoolP224r1); + } else if (strcmp(ECcurve, "brainpoolP224t1") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP224t1; + pubattr[*pubcount].ulValueLen = sizeof(brainpoolP224t1); + } else if (strcmp(ECcurve, "brainpoolP256r1") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP256r1; + pubattr[*pubcount].ulValueLen = sizeof(brainpoolP256r1); + } else if (strcmp(ECcurve, "brainpoolP256t1") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP256t1; + pubattr[*pubcount].ulValueLen = sizeof(brainpoolP256t1); + } else if (strcmp(ECcurve, "brainpoolP320r1") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP320r1; + pubattr[*pubcount].ulValueLen = sizeof(brainpoolP320r1); + } else if (strcmp(ECcurve, "brainpoolP320t1") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP320t1; + pubattr[*pubcount].ulValueLen = sizeof(brainpoolP320t1); + } else if (strcmp(ECcurve, "brainpoolP384r1") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP384r1; + pubattr[*pubcount].ulValueLen = sizeof(brainpoolP384r1); + } else if (strcmp(ECcurve, "brainpoolP384t1") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP384t1; + pubattr[*pubcount].ulValueLen = sizeof(brainpoolP384t1); + } else if (strcmp(ECcurve, "brainpoolP512r1") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP512r1; + pubattr[*pubcount].ulValueLen = sizeof(brainpoolP512r1); + } else if (strcmp(ECcurve, "brainpoolP512t1") == 0) { + pubattr[*pubcount].pValue = (CK_BYTE*) brainpoolP512t1; + pubattr[*pubcount].ulValueLen = sizeof(brainpoolP512t1); + } else { + printf("Unexpected case while parsing EC curves.\n"); + printf("Note: not all tokens support all curves."); + return CKR_ARGUMENTS_BAD; + } + (*pubcount)++; + + return CKR_OK; +} +/** + * Builds two CKA_LABEL attributes from given label. + */ +static CK_RV set_labelpair_attr(const char *label, CK_ATTRIBUTE *pubattr, + CK_ULONG *pubcount, CK_ATTRIBUTE *prvattr, CK_ULONG *prvcount) { + char *publabel; + char *prvlabel; + + if (!(publabel = malloc(strlen(label) + 5))) { + printf("Error allocating space for publabel\n"); + return CKR_HOST_MEMORY; + } + publabel = strcpy(publabel, label); + publabel = strcat(publabel, ":pub"); + + if (!(prvlabel = malloc(strlen(label) + 5))) { + printf("Error allocating space for prvlabel\n"); + return CKR_HOST_MEMORY; + } + prvlabel = strcpy(prvlabel, label); + prvlabel = strcat(prvlabel, ":prv"); + + pubattr[*pubcount].type = CKA_LABEL; + pubattr[*pubcount].pValue = publabel; + pubattr[*pubcount].ulValueLen = strlen(publabel) + 1; + (*pubcount)++; + + prvattr[*prvcount].type = CKA_LABEL; + prvattr[*prvcount].pValue = prvlabel; + prvattr[*prvcount].ulValueLen = strlen(prvlabel) + 1; + (*prvcount)++; + + return CKR_OK; +} +/** + * Set mechanism according to given key type. + */ +static CK_RV key_pair_gen_mech(p11sak_kt kt, CK_MECHANISM *pmech) { + 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_RSAPKCS: + pmech->mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; + break; + case kt_EC: + pmech->mechanism = CKM_EC_KEY_PAIR_GEN; + break; + default: + return CKR_MECHANISM_INVALID; + break; + } + + return CKR_OK; +} +/** + * Set default asymmetric key attributes. + */ +static CK_RV set_battr(const char *attr_string, CK_ATTRIBUTE *pubattr, + CK_ULONG *pubcount, CK_ATTRIBUTE *prvattr, CK_ULONG *prvcount) { + int i = 0; + + pubattr[*pubcount].type = CKA_TOKEN; + pubattr[*pubcount].pValue = &ckb_true; + pubattr[*pubcount].ulValueLen = sizeof(CK_BBOOL); + (*pubcount)++; + pubattr[*pubcount].type = CKA_PRIVATE; + pubattr[*pubcount].pValue = &ckb_true; + pubattr[*pubcount].ulValueLen = sizeof(CK_BBOOL); + (*pubcount)++; + + prvattr[*prvcount].type = CKA_TOKEN; + prvattr[*prvcount].pValue = &ckb_true; + prvattr[*prvcount].ulValueLen = sizeof(CK_BBOOL); + (*prvcount)++; + prvattr[*prvcount].type = CKA_PRIVATE; + prvattr[*prvcount].pValue = &ckb_true; + prvattr[*prvcount].ulValueLen = sizeof(CK_BBOOL); + (*prvcount)++; + + if (attr_string) { + for (i = 0; i < (int) strlen(attr_string); i++) { + + switch (attr_string[i]) { + case 'S': /* private sensitive */ + prvattr[*prvcount].type = CKA_SENSITIVE; + prvattr[*prvcount].pValue = &ckb_true; + prvattr[*prvcount].ulValueLen = sizeof(CK_BBOOL); + (*prvcount)++; + break; + case 'D': /* private decrypt RSA only*/ + prvattr[*prvcount].type = CKA_DECRYPT; + prvattr[*prvcount].pValue = &ckb_true; + prvattr[*prvcount].ulValueLen = sizeof(CK_BBOOL); + (*prvcount)++; + pubattr[*pubcount].type = CKA_ENCRYPT; + pubattr[*pubcount].pValue = &ckb_true; + pubattr[*pubcount].ulValueLen = sizeof(CK_BBOOL); + (*pubcount)++; + break; + case 'G': /* private sign */ + prvattr[*prvcount].type = CKA_SIGN; + prvattr[*prvcount].pValue = &ckb_true; + prvattr[*prvcount].ulValueLen = sizeof(CK_BBOOL); + (*prvcount)++; + pubattr[*pubcount].type = CKA_VERIFY; + pubattr[*pubcount].pValue = &ckb_true; + pubattr[*pubcount].ulValueLen = sizeof(CK_BBOOL); + (*pubcount)++; + break; + case 'U': /* private unwrap RSA only */ + prvattr[*prvcount].type = CKA_UNWRAP; + prvattr[*prvcount].pValue = &ckb_true; + prvattr[*prvcount].ulValueLen = sizeof(CK_BBOOL); + (*prvcount)++; + pubattr[*pubcount].type = CKA_WRAP; + pubattr[*pubcount].pValue = &ckb_true; + pubattr[*pubcount].ulValueLen = sizeof(CK_BBOOL); + (*pubcount)++; + break; + case 'X': /* private extractable */ + prvattr[*prvcount].type = CKA_EXTRACTABLE; + prvattr[*prvcount].pValue = &ckb_true; + prvattr[*prvcount].ulValueLen = sizeof(CK_BBOOL); + (*prvcount)++; + break; + default: + printf("Unknown argument '%c'\n", attr_string[i]); + } + } + } + return CKR_OK; +} + +static CK_ULONG char2attrtype(char c) { + 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; + default: + return 0; + } +} + +static void set_bool_attr_from_string(CK_ATTRIBUTE *attr, char *attr_string) { + int i; + + if (!attr_string) + return; + + for (i = 0; i < (int) strlen(attr_string); i++) { + if (char2attrtype(attr_string[i]) == attr->type) { + attr->pValue = &ckb_true; + } + } +} +/** + * Generation of the symmetric key + */ +static CK_RV tok_key_gen(CK_SESSION_HANDLE session, CK_ULONG keylength, + CK_MECHANISM *pmech, char *attr_string, CK_OBJECT_HANDLE *phkey, + char *label) { + CK_RV ret; + int i = 0; + + /* Boolean attributes (cannot be specified by user) */ + CK_BBOOL a_token = ckb_true; // always true + CK_BBOOL a_private = ckb_true; // always true + + /* Boolean attributes from user input */ + CK_BBOOL a_modifiable = ckb_false; + CK_BBOOL a_derive = ckb_false; + CK_BBOOL a_sensitive = ckb_false; + CK_BBOOL a_encrypt = ckb_false; + CK_BBOOL a_decrypt = ckb_false; + CK_BBOOL a_sign = ckb_false; + CK_BBOOL a_verify = ckb_false; + CK_BBOOL a_wrap = ckb_false; + CK_BBOOL a_unwrap = ckb_false; + CK_BBOOL a_extractable = ckb_false; + CK_ULONG bs = sizeof(CK_BBOOL); + + /* Non-boolean attributes */ + CK_ULONG a_value_len = keylength / 8; + + CK_ATTRIBUTE tmplt[] = { + // boolean attrs + { CKA_TOKEN, &a_token, bs }, { CKA_PRIVATE, &a_private, bs }, { + CKA_MODIFIABLE, &a_modifiable, bs }, { CKA_DERIVE, + &a_derive, bs }, { CKA_SENSITIVE, &a_sensitive, bs }, { + CKA_ENCRYPT, &a_encrypt, bs }, + { CKA_DECRYPT, &a_decrypt, bs }, { CKA_SIGN, &a_sign, bs }, { + CKA_VERIFY, &a_verify, bs }, { CKA_WRAP, &a_wrap, bs }, { + CKA_UNWRAP, &a_unwrap, bs }, { CKA_EXTRACTABLE, + &a_extractable, bs }, + // non-boolean attrs + { CKA_VALUE_LEN, &a_value_len, sizeof(CK_ULONG) }, { CKA_LABEL, + label, strlen(label) } }; + CK_ULONG num_attrs = sizeof(tmplt) / sizeof(CK_ATTRIBUTE); + CK_ULONG num_bools = num_attrs - 2; + + /* set boolean attributes */ + for (i = 0; i < (int) num_bools; i++) { + set_bool_attr_from_string(&tmplt[i], attr_string); + } + + /* generate key */ + ret = funcs->C_GenerateKey(session, pmech, tmplt, num_attrs, phkey); + if (ret != CKR_OK) { + printf("Key generation of key of length %ld bytes failed\n", + a_value_len); + printf("in tok_key_gen (error code 0x%lX)\n", ret); + } + return ret; +} + +/** + * Generation of the asymmetric key pair + */ +static CK_RV key_pair_gen(CK_SESSION_HANDLE session, 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_RV ret; + + printf("Generate asymmetric key: %s\n", kt2str(kt)); + + ret = funcs->C_GenerateKeyPair(session, pmech, pubattr, pubcount, prvattr, + prvcount, phpubkey, phprvkey); + if (ret != CKR_OK) { + printf("Key pair generation failed (error code 0x%lX)\n", ret); + return ret; + } + + printf("Asymmetric key pair generation successful!\n"); + + return CKR_OK; +} + +/** + * + */ +static CK_RV tok_key_list_init(CK_SESSION_HANDLE session, p11sak_kt kt, char *label) { + CK_RV rc; + CK_ULONG count; + + /* Boolean Attributes */ + CK_BBOOL a_token; + CK_BBOOL a_private; + CK_ULONG bs = sizeof(CK_BBOOL); + + /* key Type attributes */ + CK_KEY_TYPE a_key_type; + CK_OBJECT_CLASS a_cko; + + CK_ATTRIBUTE tmplt[4]; + + a_token = CK_TRUE; + tmplt[0].type = CKA_TOKEN; + tmplt[0].pValue = &a_token; + tmplt[0].ulValueLen = bs; + a_private = CK_TRUE; + tmplt[1].type = CKA_PRIVATE; + tmplt[1].pValue = &a_private; + tmplt[1].ulValueLen = bs; + + if (kt < kt_SECRET) { + rc = kt2CKK(kt, &a_key_type); + if (rc != CKR_OK) { + printf("Keytype could not be set (error code 0x%lX)\n", rc); + return rc; + } + } else { + rc = kt2CKO(kt, &a_cko); + if (rc != CKR_OK) { + printf("Keyobject could not be set (error code 0x%lX)\n", rc); + return rc; + } + } + + /* Set template */ + switch (kt) { + case kt_DES: + case kt_3DES: + case kt_AES: + case kt_GENERIC: + case kt_RSAPKCS: + case kt_EC: + tmplt[2].type = CKA_KEY_TYPE; + tmplt[2].pValue = &a_key_type; + tmplt[2].ulValueLen = sizeof(CK_KEY_TYPE); + break; + case kt_SECRET: + case kt_PUBLIC: + case kt_PRIVATE: + tmplt[2].type = CKA_CLASS; + tmplt[2].pValue = &a_cko; + tmplt[2].ulValueLen = sizeof(CK_OBJECT_CLASS); + break; + default: + printf("Unknown key type\n"); + return CKR_ARGUMENTS_BAD; + } + + if (label != NULL_PTR) { + tmplt[3].type = CKA_LABEL; + tmplt[3].pValue = label; + tmplt[3].ulValueLen = strlen(label) + 1; + count = 4; + } else + count = 3; + + rc = funcs->C_FindObjectsInit(session, tmplt, count); + if (rc != CKR_OK) { + printf("C_FindObjectInit failed\n"); + printf("in tok_key_list_init (error code 0x%lX)\n", rc); + 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_ATTRIBUTE attr, p11sak_kt ktype) { + switch (ktype) { + case kt_DES: + case kt_3DES: + case kt_AES: + case kt_SECRET: + switch (attr.type) { + case CKA_TRUSTED: + return 1; + default: + return 0; + } + 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; + } + break; + case kt_PRIVATE: + switch (attr.type) { + case CKA_ENCRYPT: + case CKA_VERIFY: + case CKA_WRAP: + return 1; + default: + return 0; + } + break; + default: + /* key type not handled here */ + return 0; + } +} + +/** + * Columns: T P M R L S E D G V W U X A N + */ +static CK_ATTRIBUTE_TYPE col2type(int col) { + 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; + } +} + +static void short_print(int col, CK_ATTRIBUTE attr[], p11sak_kt ktype) { + int j = 0; + int attr_count = 0; + + switch (ktype) { + case kt_SECRET: + attr_count = SEC_KEY_MAX_BOOL_ATTR_COUNT; + break; + case kt_PUBLIC: + attr_count = PUB_KEY_MAX_BOOL_ATTR_COUNT; + break; + case kt_PRIVATE: + attr_count = PRV_KEY_MAX_BOOL_ATTR_COUNT; + break; + default: + attr_count = PUB_KEY_MAX_BOOL_ATTR_COUNT; + } + + for (j = 0; j < attr_count; j++) { + if (attr[j].type == col2type(col) && !attr_na(attr[j], ktype)) { + printf(" %d ", *(CK_BBOOL*) attr[j].pValue); + return; + } + } + + printf(" - "); + return; +} +/** + * + */ +static CK_RV sec_key_print_attributes(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE hkey, + int long_print) { + CK_RV ret; + 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_ULONG bs = sizeof(CK_BBOOL); + + CK_ATTRIBUTE bool_tmplt[] = { { CKA_TOKEN, &a_token, bs }, { CKA_PRIVATE, + &a_private, bs }, { CKA_MODIFIABLE, &a_modifiable, bs }, { + CKA_DERIVE, &a_derive, bs }, { CKA_LOCAL, &a_local, bs }, { + CKA_SENSITIVE, &a_sensitive, bs }, { CKA_ENCRYPT, &a_encrypt, bs }, + { CKA_DECRYPT, &a_decrypt, bs }, { CKA_SIGN, &a_sign, bs }, { + CKA_VERIFY, &a_verify, bs }, { CKA_WRAP, &a_wrap, bs }, { + CKA_UNWRAP, &a_unwrap, bs }, { CKA_EXTRACTABLE, + &a_extractable, bs }, { CKA_ALWAYS_SENSITIVE, + &a_always_sensitive, bs }, { CKA_NEVER_EXTRACTABLE, + &a_never_extractable, bs }, }; + CK_ULONG count = sizeof(bool_tmplt) / sizeof(CK_ATTRIBUTE); + + ret = funcs->C_GetAttributeValue(session, hkey, bool_tmplt, count); + if (ret != CKR_OK) { + printf("Attribute retrieval failed (error code 0x%lX)\n", ret); + return ret; + } + + if (long_print) { + for (i = 0; i < (int) count; i++) { + if (bool_tmplt[i].ulValueLen != sizeof(CK_BBOOL)) { + printf(" 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)); + } + } + printf("|\n"); + } else { + printf(" |"); + for (i = 2; i < KEY_MAX_BOOL_ATTR_COUNT; i++) + short_print(i, bool_tmplt, kt_SECRET); + printf("|"); + } + + return CKR_OK; +} +/** + * + */ +static CK_RV priv_key_print_attributes(CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE hkey, int long_print) { + CK_RV ret; + 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_ULONG bs = sizeof(CK_BBOOL); + + CK_ATTRIBUTE bool_tmplt[] = { { CKA_TOKEN, &a_token, bs }, { CKA_PRIVATE, + &a_private, bs }, { CKA_MODIFIABLE, &a_modifiable, bs }, { + CKA_DERIVE, &a_derive, bs }, { CKA_LOCAL, &a_local, bs }, { + CKA_SENSITIVE, &a_sensitive, bs }, { CKA_DECRYPT, &a_decrypt, bs }, + { CKA_SIGN, &a_sign, bs }, { CKA_UNWRAP, &a_unwrap, bs }, { + CKA_EXTRACTABLE, &a_extractable, bs }, { + CKA_ALWAYS_SENSITIVE, &a_always_sensitive, bs }, { + CKA_NEVER_EXTRACTABLE, &a_never_extractable, bs } }; + CK_ULONG count = sizeof(bool_tmplt) / sizeof(CK_ATTRIBUTE); + + ret = funcs->C_GetAttributeValue(session, hkey, bool_tmplt, count); + if (ret != CKR_OK) { + printf("Attribute retrieval failed (error code 0x%lX)\n", ret); + return ret; + } + + /* Long print */ + if (long_print) { + for (i = 0; i < (int) count; i++) { + if (bool_tmplt[i].ulValueLen != sizeof(CK_BBOOL)) { + printf(" 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)); + } + } + printf("|\n"); + } else { + /* Short print */ + printf(" |"); + for (i = 2; i < KEY_MAX_BOOL_ATTR_COUNT; i++) + short_print(i, bool_tmplt, kt_PRIVATE); + printf("|"); + } + + return CKR_OK; +} + +/** + * + */ +static CK_RV pub_key_print_attributes(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE hkey, + int long_print) { + CK_RV ret; + 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_ULONG bs = sizeof(CK_BBOOL); + + CK_ATTRIBUTE bool_tmplt[] = { { CKA_TOKEN, &a_token, bs }, { CKA_PRIVATE, + &a_private, bs }, { CKA_MODIFIABLE, &a_modifiable, bs }, { + CKA_DERIVE, &a_derive, bs }, { CKA_LOCAL, &a_local, bs }, { + CKA_ENCRYPT, &a_encrypt, bs }, { CKA_VERIFY, &a_verify, bs }, { + CKA_WRAP, &a_wrap, bs } }; + CK_ULONG count = sizeof(bool_tmplt) / sizeof(CK_ATTRIBUTE); + + ret = funcs->C_GetAttributeValue(session, hkey, bool_tmplt, count); + if (ret != CKR_OK) { + printf("Attribute retrieval failed (error code 0x%lX)\n", ret); + return ret; + } + + /* Long print */ + if (long_print) { + for (i = 0; i < (int) count; i++) { + if (bool_tmplt[i].ulValueLen != sizeof(CK_BBOOL)) { + printf(" 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)); + } + } + printf("|\n"); + } else { + /* Short print */ + printf(" |"); + for (i = 2; i < KEY_MAX_BOOL_ATTR_COUNT; i++) + short_print(i, bool_tmplt, kt_PUBLIC); + printf("|"); + } + + return CKR_OK; +} + +/** + * + */ +static CK_RV tok_key_get_label_attr(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE hkey, + char **plabel) { + CK_RV ret; + char *label; + CK_ATTRIBUTE template[1] = { { CKA_LABEL, NULL_PTR, 0 } }; + + ret = funcs->C_GetAttributeValue(session, hkey, template, 1); + if (ret != CKR_OK) { + printf("Key cannot show CKA_LABEL attribute (error code 0x%lX)\n", ret); + return ret; + } + + label = malloc(template[0].ulValueLen); + if (!label) { + printf("Error: cannot malloc storage for label.\n"); + return CKR_HOST_MEMORY; + } + + template[0].pValue = label; + ret = funcs->C_GetAttributeValue(session, hkey, template, 1); + if (ret != CKR_OK) { + printf("Error retrieving CKA_LABEL attribute (error code 0x%lX)\n", + ret); + return ret; + } + + label[template[0].ulValueLen] = 0; + *plabel = label; + + return CKR_OK; +} + +/** + * + */ +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) { + CK_RV ret; + char *buffer; + CK_OBJECT_CLASS oclass; + CK_KEY_TYPE kt; + CK_ULONG vl; + + CK_ATTRIBUTE template[1] = + { { CKA_CLASS, &oclass, sizeof(CK_OBJECT_CLASS) } }; + + ret = funcs->C_GetAttributeValue(session, hkey, template, 1); + if (ret != CKR_OK) { + printf("Object does not have CKA_CLASS attribute (error code 0x%lX)\n", + ret); + return ret; + } + + buffer = malloc(16); + + if (!buffer) { + return CKR_HOST_MEMORY; + } + + switch (oclass) { + case CKO_SECRET_KEY: + buffer[0] = 0; + break; + case CKO_PUBLIC_KEY: + strcpy(buffer, "public "); + break; + case CKO_PRIVATE_KEY: + strcpy(buffer, "private "); + break; + } + + template[0].type = CKA_KEY_TYPE; + template[0].pValue = &kt; + template[0].ulValueLen = sizeof(CK_KEY_TYPE); + ret = funcs->C_GetAttributeValue(session, hkey, template, 1); + if (ret != CKR_OK) { + printf( + "Object does not have CKA_KEY_TYPE attribute (error code 0x%lX)\n", + ret); + return ret; + } + strcat(buffer, CKK2a(kt)); + + *klength = 0; + switch (kt) { + case CKK_AES: + case CKK_GENERIC_SECRET: + template[0].type = CKA_VALUE_LEN; + template[0].pValue = &vl; + template[0].ulValueLen = sizeof(CK_ULONG); + ret = funcs->C_GetAttributeValue(session, hkey, template, 1); + if (ret != CKR_OK) { + printf( + "Object does not have CKA_VALUE_LEN attribute (error code 0x%lX)\n", + ret); + return ret; + } + *klength = vl * 8; + break; + } + + *ktype = buffer; + *keyclass = oclass; + + return CKR_OK; +} + +/** + * Check args for gen_key command. + */ +static CK_RV check_args_gen_key(p11sak_kt *kt, CK_ULONG keylength, char *ECcurve) { + + switch (*kt) { + case kt_DES: + case kt_3DES: + break; + case kt_AES: + if ((keylength == 128) || (keylength == 192) || (keylength == 256)) { + break; + } else { + printf( + "Cipher key type [%d] and key bit length %ld is not supported. Try adding argument -bits <128|192|256>\n", + *kt, keylength); + return CKR_ARGUMENTS_BAD; + } + break; + case kt_RSAPKCS: + if ((keylength == 1024) || (keylength == 2048) || (keylength == 4096)) { + break; + } else { + printf( + "[%d] RSA modulus bit length %ld NOT supported. Try adding argument -bits <1024|2048|4096>\n", + *kt, keylength); + } + break; + case kt_EC: + if (ECcurve == NULL) { + printf( + "Cipher key type [%d] supported but EC curve not set in arguments. Try argument -curve \n", + *kt); + return CKR_ARGUMENTS_BAD; + } + break; + case kt_GENERIC: + case kt_SECRET: + case kt_PUBLIC: + case kt_PRIVATE: + break; + default: + printf("Cipher key type [%d] is not set or not supported\n", *kt); + print_gen_help(); + return CKR_ARGUMENTS_BAD; + } + + return CKR_OK; +} + +/** + * Check args for list_key command. + */ +static CK_RV check_args_list_key(p11sak_kt *kt) { + switch (*kt) { + case kt_AES: +// *kt = kt_AES; +// break; + case kt_RSAPKCS: +// *kt = kt_RSAPKCS; +// break; + case kt_DES: + case kt_3DES: + case kt_EC: + case kt_GENERIC: + case kt_SECRET: + case kt_PUBLIC: + case kt_PRIVATE: + break; + default: + printf("Cipher key type [%d] is not set or not supported\n", *kt); + print_listkeys_help(); + 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 { + printf("Unknown command %s\n", cmd2str(cmd)); + cmd = no_cmd; + } + return cmd; +} + +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; + } + + return 0; +} + +static CK_ULONG get_ulong_arg(int pos, char *argv[], int argc) { + if (pos < argc) + return atol(argv[pos]); + else + return 0; +} + +static char* get_string_arg(int pos, char *argv[], int argc) { + if (pos < argc) + return argv[pos]; + else + return NULL; +} + +/** + * 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, char **pin, int *long_print) { + CK_RV ret; + int i; + + if (last_parm_is_help(argv, argc)) { + print_listkeys_help(); + return CKR_ARGUMENTS_BAD; + } + + for (i = 2; i < argc; i++) { + /* Get arguments */ + if (strcmp(argv[i], "DES") == 0 || strcmp(argv[i], "des") == 0) { + *kt = kt_DES; + *keylength = 64; + } else if (strcmp(argv[i], "3DES") == 0 + || strcmp(argv[i], "3des") == 0) { + *kt = kt_3DES; + *keylength = 192; + } else if (strcmp(argv[i], "AES") == 0 || strcmp(argv[i], "aes") == 0) { + *kt = kt_AES; + } else if (strcmp(argv[i], "RSA") == 0 || strcmp(argv[i], "rsa") == 0) { + *kt = kt_RSAPKCS; + } else if (strcmp(argv[i], "EC") == 0 || strcmp(argv[i], "ec") == 0) { + *kt = kt_EC; + } else if (strcmp(argv[i], "GENERIC") == 0 + || strcmp(argv[i], "generic") == 0) { + *kt = kt_GENERIC; + } else if (strcmp(argv[i], "SECRET") == 0 + || strcmp(argv[i], "secret") == 0) { + *kt = kt_SECRET; + } else if (strcmp(argv[i], "PUBLIC") == 0 + || strcmp(argv[i], "public") == 0) { + *kt = kt_PUBLIC; + } else if (strcmp(argv[i], "PRIVATE") == 0 + || strcmp(argv[i], "private") == 0) { + *kt = kt_PRIVATE; + /* Get options */ + } else if (strcmp(argv[i], "--slot") == 0) { + *slot = (CK_ULONG) atol(argv[i + 1]); + i++; + } else if (strcmp(argv[i], "--pin") == 0) { + *pin = argv[i + 1]; + i++; + } else if ((strcmp(argv[i], "-l") == 0) + || (strcmp(argv[i], "--long") == 0)) { + *long_print = 1; + } else if ((strcmp(argv[i], "-h") == 0) + || (strcmp(argv[i], "--help") == 0)) { + print_listkeys_help(); + return CKR_ARGUMENTS_BAD; + } else { + printf("Unknown argument or option %s for command list-key\n", argv[i]); + return CKR_ARGUMENTS_BAD; + } + } + + ret = check_args_list_key(kt); + + if (*slot == 0) { + printf("Slot number must be specified.\n"); + ret = CKR_ARGUMENTS_BAD; + } + + + return ret; +} +/** + * Parse the generate-key args. + */ +static CK_RV parse_gen_key_args(char *argv[], int argc, p11sak_kt *kt, + CK_ULONG *keylength, char **ECcurve, CK_SLOT_ID *slot, + char **pin, CK_ULONG *exponent, char **label, char **attr_string) { + CK_RV ret; + int i; + + for (i = 2; i < argc; i++) { + /* Get arguments */ + if (strcmp(argv[i], "DES") == 0 || strcmp(argv[i], "des") == 0) { + *kt = kt_DES; + *keylength = 64; + } else if (strcmp(argv[i], "3DES") == 0 + || strcmp(argv[i], "3des") == 0) { + *kt = kt_3DES; + *keylength = 192; + } else if (strcmp(argv[i], "AES") == 0 || strcmp(argv[i], "aes") == 0) { + *kt = kt_AES; + *keylength = get_ulong_arg(i + 1, argv, argc); + i++; + } else if (strcmp(argv[i], "RSA") == 0 || strcmp(argv[i], "rsa") == 0) { + *kt = kt_RSAPKCS; + *keylength = get_ulong_arg(i + 1, argv, argc); + i++; + } else if (strcmp(argv[i], "EC") == 0 || strcmp(argv[i], "ec") == 0) { + *kt = kt_EC; + *ECcurve = get_string_arg(i + 1, argv, argc); + i++; + /* Get options */ + } else if (strcmp(argv[i], "--slot") == 0) { + *slot = (CK_ULONG) atol(argv[i + 1]); + i++; + } else if (strcmp(argv[i], "--pin") == 0) { + *pin = argv[i + 1]; + i++; + } else if (strcmp(argv[i], "--label") == 0) { + *label = argv[i + 1]; + i++; + } else if (strcmp(argv[i], "--exponent") == 0) { + *exponent = atol(argv[i + 1]); + i++; + } else if ((strcmp(argv[i], "--attr") == 0)) { + *attr_string = argv[i + 1]; + i++; + } else if ((strcmp(argv[i], "-h") == 0) + || (strcmp(argv[i], "--help") == 0)) { + print_gen_keys_help(kt); + return CKR_ARGUMENTS_BAD; + } else { + printf("Unknown argument or option %s for command generate-key\n", argv[i]); + return CKR_ARGUMENTS_BAD; + } + } + + if (last_parm_is_help(argv, argc)) { + print_gen_keys_help(kt); + for (i = 2; i < argc; i++) { + if ((strcmp(argv[i], "--attr") == 0)) { + print_gen_attr_help(); + } + } + return CKR_ARGUMENTS_BAD; + } + + /* Check args */ + ret = check_args_gen_key(kt, *keylength, *ECcurve); + + /* Check required options */ + if (*label == NULL) { + printf("Key label must be specified.\n"); + ret = CKR_ARGUMENTS_BAD; + } + + if (*slot == 0) { + printf("Slot number must be specified.\n"); + ret = CKR_ARGUMENTS_BAD; + } + + return ret; +} + +/** + * Parse the p11sak command args. + */ +static CK_RV parse_cmd_args(p11sak_cmd cmd, char *argv[], int argc, p11sak_kt *kt, + CK_ULONG *keylength, char **ECcurve, CK_SLOT_ID *slot, char **pin, + CK_ULONG *exponent, char **label, char **attr_string, int *long_print) { + CK_RV ret; + + switch (cmd) { + case gen_key: + ret = parse_gen_key_args(argv, argc, kt, keylength, ECcurve, + slot, pin, exponent, label, attr_string); + break; + case list_key: + ret = parse_list_key_args(argv, argc, kt, keylength, slot, pin, long_print); + break; + default: + printf("Error: unknown command %d specified.\n", cmd); + ret = CKR_ARGUMENTS_BAD; + } + + return ret; +} +/** + * Generate a symmetric key. + */ +static CK_RV generate_symmetric_key(CK_SESSION_HANDLE session, + p11sak_kt kt, CK_ULONG keylength, char *label, char *attr_string) { + CK_OBJECT_HANDLE hkey; + CK_MECHANISM mech; + CK_RV ret; + + printf("Generate symmetric key %s with keylen=%ld and label=[%s]\n", + kt2str(kt), keylength, label); + + ret = key_pair_gen_mech(kt, &mech); + if (ret != CKR_OK) { + printf("Error setting the mechanism (error code 0x%lX)\n", ret); + goto done; + } + + ret = tok_key_gen(session, keylength, &mech, attr_string, &hkey, label); + if (ret != CKR_OK) { + printf("Key generation failed (error code 0x%lX)\n", ret); + goto done; + } + + printf("Symmetric key generation successful!\n"); + + done: + + return ret; +} +/** + * Generate an asymmetric key. + */ +static CK_RV generate_asymmetric_key(CK_SESSION_HANDLE session, CK_SLOT_ID slot, + p11sak_kt kt, CK_ULONG keylength, CK_ULONG exponent, char *ECcurve, + char *label, char *attr_string) { + CK_OBJECT_HANDLE pub_keyh, prv_keyh; + CK_ATTRIBUTE pub_attr[KEY_MAX_BOOL_ATTR_COUNT + 2]; + CK_ULONG pub_acount = 0; + CK_ATTRIBUTE prv_attr[KEY_MAX_BOOL_ATTR_COUNT + 2]; + CK_ULONG prv_acount = 0; + CK_MECHANISM mech; + CK_RV ret; + + if (kt == kt_RSAPKCS) { + ret = read_rsa_args((CK_ULONG) keylength, exponent, pub_attr, + &pub_acount); + if (ret) { + printf("Error setting RSA parameters!\n"); + goto done; + } + } else if (kt == kt_EC) { + ret = read_ec_args(ECcurve, pub_attr, &pub_acount); + if (ret) { + printf("Error parsing EC parameters!\n"); + goto done; + } + } else { + printf("The key type %d is not yet supported.\n", kt); + ret = CKR_KEY_TYPE_INCONSISTENT; + goto done; + } + + ret = set_labelpair_attr(label, pub_attr, &pub_acount, prv_attr, + &prv_acount); + if (ret != CKR_OK) { + printf("Error setting the label attributes (error code 0x%lX)\n", ret); + goto done; + } + + ret = key_pair_gen_mech(kt, &mech); + if (ret != CKR_OK) { + printf("Error setting the mechanism (error code 0x%lX)\n", ret); + goto done; + } + + ret = set_battr(attr_string, pub_attr, &pub_acount, prv_attr, &prv_acount); + if (ret != CKR_OK) { + printf("Error setting binary attributes (error code 0x%lX)\n", ret); + goto done; + } + + ret = key_pair_gen(session, kt, &mech, pub_attr, pub_acount, prv_attr, + prv_acount, &pub_keyh, &prv_keyh); + if (ret != CKR_OK) { + printf( + "Generating a key pair in the token in slot %ld failed (error code 0x%lX)\n", + slot, ret); + goto done; + } + + done: + + return ret; +} +/** + * Generate a new ckey. + */ +static CK_RV generate_ckey(CK_SESSION_HANDLE session, CK_SLOT_ID slot, p11sak_kt kt, + CK_ULONG keylength, char *ECcurve, CK_ULONG exponent, char *label, + char *attr_string) { + switch (kt) { + case kt_DES: + case kt_3DES: + case kt_AES: + return generate_symmetric_key(session, kt, keylength, label, + attr_string); + case kt_RSAPKCS: + case kt_EC: + return generate_asymmetric_key(session, slot, kt, keylength, exponent, + ECcurve, label, attr_string); + default: + printf("Error: cannot create a key of type %i (%s)\n", kt, kt2str(kt)); + return CKR_ARGUMENTS_BAD; + } +} +/** + * List the given ckey. + */ +static CK_RV list_ckey(CK_SESSION_HANDLE session, p11sak_kt kt, int long_print) { + CK_ULONG keylength, count; + CK_OBJECT_CLASS keyclass; + CK_OBJECT_HANDLE hkey; + char *keytype = NULL; + char *label = NULL; + CK_RV ret; + int CELL_SIZE = 11; + + ret = tok_key_list_init(session, kt, label); + if (ret != CKR_OK) { + printf("Init token key list failed (error code 0x%lX)\n", ret); + return ret; + } + + if (long_print == 0) { + printf("\n"); + printf( + " | M R L S E D G V W U X A N | KEY TYPE | LABEL\n"); + printf( + " |---------------------------------------+-------------+-------------\n"); + } + + while (1) { + ret = funcs->C_FindObjects(session, &hkey, 1, &count); + if (ret != CKR_OK) { + printf("C_FindObjects failed (error code 0x%lX)\n", ret); + return 1; + } + if (count == 0) + break; + + ret = tok_key_get_key_type(session, hkey, &keyclass, &keytype, + &keylength); + if (ret != CKR_OK) { + printf("Invalid key type (error code 0x%lX)\n", ret); + continue; + } + + ret = tok_key_get_label_attr(session, hkey, &label); + if (ret != CKR_OK) { + printf("Retrieval of label failed (error code 0x%lX)\n", ret); + } else if (long_print) { + printf("Label: %s\t\t", label); + } + + if (long_print) { + printf("\n Key: "); + if (keylength > 0) + printf("%s %ld\t\t", keytype, keylength); + else + printf("%s\t\t", keytype); + + printf("\n Attributes:\n"); + } + + switch (keyclass) { + case CKO_SECRET_KEY: + ret = sec_key_print_attributes(session, hkey, long_print); + if (ret != CKR_OK) { + printf( + "Secret key attribute printing failed(error code 0x%lX)\n", + ret); + goto done; + } + break; + case CKO_PRIVATE_KEY: + ret = priv_key_print_attributes(session, hkey, long_print); + if (ret != CKR_OK) { + printf( + "Private key attribute printing failed (error code 0x%lX)\n", + ret); + goto done; + } + break; + case CKO_PUBLIC_KEY: + ret = pub_key_print_attributes(session, hkey, long_print); + if (ret != CKR_OK) { + printf( + "Public key attribute printing failed (error code 0x%lX)\n", + ret); + goto done; + } + break; + default: + printf("Unhandled keyclass in list_ckey! Should not occur (?)\n"); + break; + } + + if (long_print == 0) { + if (keylength > 0) { + char tmp[16]; + snprintf(tmp, sizeof(tmp), "%s %ld", keytype, keylength); + printf(" %*s | ", CELL_SIZE, tmp); + } else + printf(" %*s | ", CELL_SIZE, keytype); + printf("%s\n", label); + } + } + + ret = funcs->C_FindObjectsFinal(session); + if (ret != CKR_OK) { + printf("C_FindObjectsFinal failed (error code 0x%lX)\n", ret); + goto done; + } + + ret = CKR_OK; + + done: free(label); + free(keytype); + return ret; +} + +static CK_RV execute_cmd(CK_SESSION_HANDLE session, CK_SLOT_ID slot, p11sak_cmd cmd, + p11sak_kt kt, CK_ULONG keylength, CK_ULONG exponent, char *ECcurve, + char *label, char *attr_string, int long_print) { + CK_RV ret; + + switch (cmd) { + case gen_key: + ret = generate_ckey(session, slot, kt, keylength, ECcurve, exponent, + label, attr_string); + break; + case list_key: + ret = list_ckey(session, kt, long_print); + break; + default: + printf(" Unknown COMMAND %c\n", cmd); + print_cmd_help(); + ret = CKR_ARGUMENTS_BAD; + break; + } + + return ret; +} + +static CK_RV start_session(CK_SESSION_HANDLE *session, CK_SLOT_ID slot, + CK_CHAR_PTR pin, CK_ULONG pinlen) { + CK_SESSION_HANDLE tmp_sess; + CK_TOKEN_INFO tokeninfo; + CK_SLOT_INFO slotinfo; + CK_RV ret; + + ret = funcs->C_Initialize(NULL_PTR); + if (ret != CKR_OK) { + printf("Error in C_Initialize (error code 0x%lX)\n", ret); + goto done; + } + + ret = funcs->C_GetSlotInfo(slot, &slotinfo); + if (ret != CKR_OK) { + printf("Slot %ld not available (error code 0x%lX)\n", slot, ret); + goto done; + } + + ret = funcs->C_GetTokenInfo(slot, &tokeninfo); + if (ret != CKR_OK) { + printf("Token at slot %ld not available (error code 0x%lX)\n", slot, + ret); + goto done; + } + + ret = funcs->C_OpenSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, + NULL_PTR, &tmp_sess); + if (ret != CKR_OK) { + printf("Opening a session failed (error code 0x%lX)\n", ret); + goto done; + } + + ret = funcs->C_Login(tmp_sess, CKU_USER, pin, pinlen); + if (ret != CKR_OK) { + printf("Login failed (error code 0x%lX)\n", ret); + goto done; + } + + *session = tmp_sess; + ret = CKR_OK; + + done: + + return ret; +} + +static CK_RV close_session(CK_SESSION_HANDLE session) { + CK_RV ret; + + ret = funcs->C_Logout(session); + if (ret != CKR_OK) { + printf("Logout failed (error code 0x%lX)\n", ret); + return ret; + } + + ret = funcs->C_Finalize(NULL_PTR); + if (ret != CKR_OK) { + printf("Error in C_Finalize: (error code 0x%lX)\n", ret); + } + + return ret; +} + +int main(int argc, char *argv[]) { + int long_print = 0; + p11sak_kt kt = no_key_type; + p11sak_cmd cmd = no_cmd; + CK_ULONG exponent = 0; + CK_SLOT_ID slot = 0; + char *label = NULL; + char *ECcurve = NULL; + char *attr_string = NULL; + CK_ULONG keylength = 0; + CK_RV ret = CKR_OK; + CK_SESSION_HANDLE session; + char *pin = NULL; + size_t pinlen; + + /* Check if just help requested */ +// if (argc < 3 && last_parm_is_help(argv, argc)) { +// if (argc < 3 || last_parm_is_help(argv, argc)) { + if (argc < 3) { + print_cmd_help(); + ret = CKR_OK; + goto done; + } + + /* Parse command */ + cmd = parse_cmd(argv[1]); + if (cmd == no_cmd) { + ret = CKR_ARGUMENTS_BAD; + print_cmd_help(); + goto done; + } + + /* Parse command args */ + ret = parse_cmd_args(cmd, argv, argc, &kt, &keylength, &ECcurve, + &slot, &pin, &exponent, &label, &attr_string, &long_print); + if (ret != CKR_OK) { + goto done; + } + +// /* Parse options */ +// ret = parse_options(cmd, argv, argc, &slot, &pin, &exponent, &label, +// &attr_string, &long_print); +// if (ret != CKR_OK) { +// goto done; +// } + + /* now try to load the pkcs11 lib (will exit(99) on failure) */ + load_pkcs11lib(); + + /* Prompt for PIN if not already set via option */ + if (!pin) { + printf("Please enter user PIN:"); + ret = get_pin(&pin, &pinlen); + + if (strlen(pin) == 0) { + char *s = getenv("PKCS11_USER_PIN"); + if (s) { + strcpy((char*) pin, s); + } else { + goto done; + } + } + } + + /* Open PKCS#11 session */ + ret = start_session(&session, slot, (CK_CHAR_PTR) pin, strlen(pin)); + if (ret != CKR_OK) { + printf("Error: failed to open session (error code 0x%lX)\n", ret); + goto done; + } + + /* Execute command */ + ret = execute_cmd(session, slot, cmd, kt, keylength, exponent, ECcurve, + label, attr_string, long_print); + if (ret != CKR_OK) { + printf("Error: failed to execute p11sak command (error code 0x%lX)\n", + ret); + goto done; + } + + /* Close PKCS#11 session */ + ret = close_session(session); + if (ret != CKR_OK) { + printf("Error: failed to close session (error code 0x%lX)\n", ret); + goto done; + } + + ret = CKR_OK; + + done: + + return ret; +} diff --git a/usr/sbin/p11sak/p11sak.h b/usr/sbin/p11sak/p11sak.h new file mode 100644 index 0000000..9a2d9f1 --- /dev/null +++ b/usr/sbin/p11sak/p11sak.h @@ -0,0 +1,75 @@ +/* + * 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 + */ + +typedef enum { + no_cmd, gen_key, list_key, +} p11sak_cmd; + +/* + * The first enum items are for SYMMETRIC keys for kt <= 2. + * The last enum items are for ASYMMETRIC keys for kt >= 3 + */ +typedef enum { + kt_DES, + kt_3DES, + kt_AES, + kt_RSAPKCS, + kt_EC, + kt_GENERIC, + kt_SECRET, + kt_PUBLIC, + kt_PRIVATE, + no_key_type +} p11sak_kt; + +#define KEY_MAX_BOOL_ATTR_COUNT 15 +#define SEC_KEY_MAX_BOOL_ATTR_COUNT 15 +#define PRV_KEY_MAX_BOOL_ATTR_COUNT 12 +#define PUB_KEY_MAX_BOOL_ATTR_COUNT 8 + +const CK_BYTE brainpoolP160r1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, + 0x08, 0x01, 0x01, 0x01 }; +const CK_BYTE brainpoolP160t1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, + 0x08, 0x01, 0x01, 0x02 }; +const CK_BYTE brainpoolP192r1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, + 0x08, 0x01, 0x01, 0x03 }; +const CK_BYTE brainpoolP192t1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, + 0x08, 0x01, 0x01, 0x04 }; +const CK_BYTE brainpoolP224r1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, + 0x08, 0x01, 0x01, 0x05 }; +const CK_BYTE brainpoolP224t1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, + 0x08, 0x01, 0x01, 0x06 }; +const CK_BYTE brainpoolP256r1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, + 0x08, 0x01, 0x01, 0x07 }; +const CK_BYTE brainpoolP256t1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, + 0x08, 0x01, 0x01, 0x08 }; +const CK_BYTE brainpoolP320r1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, + 0x08, 0x01, 0x01, 0x09 }; +const CK_BYTE brainpoolP320t1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, + 0x08, 0x01, 0x01, 0x0A }; +const CK_BYTE brainpoolP384r1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, + 0x08, 0x01, 0x01, 0x0B }; +const CK_BYTE brainpoolP384t1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, + 0x08, 0x01, 0x01, 0x0C }; +const CK_BYTE brainpoolP512r1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, + 0x08, 0x01, 0x01, 0x0D }; +const CK_BYTE brainpoolP512t1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, + 0x08, 0x01, 0x01, 0x0E }; +const CK_BYTE prime192[] = { 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, + 0x01, 0x01 }; +const CK_BYTE secp224[] = { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x21 }; +const CK_BYTE prime256v1[] = { 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, + 0x01, 0x07 }; +const CK_BYTE secp384r1[] = { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22 }; +const CK_BYTE secp521r1[] = { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23 }; +const CK_BYTE secp256k1[] = { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x0A }; + +CK_BBOOL ckb_true = CK_TRUE; +CK_BBOOL ckb_false = CK_FALSE; diff --git a/usr/sbin/p11sak/p11sak.mk b/usr/sbin/p11sak/p11sak.mk new file mode 100644 index 0000000..b3eb699 --- /dev/null +++ b/usr/sbin/p11sak/p11sak.mk @@ -0,0 +1,12 @@ +sbin_PROGRAMS += usr/sbin/p11sak/p11sak +noinst_HEADERS += usr/sbin/p11sak/p11sak.h + +usr_sbin_p11sak_p11sak_LDFLAGS = -ldl + +usr_sbin_p11sak_p11sak_CFLAGS = \ + -DLINUX -DPROGRAM_NAME=\"$(@)\" \ + -I${srcdir}/usr/include \ + -I${srcdir}/usr/sbin/p11sak + +usr_sbin_p11sak_p11sak_SOURCES = \ + usr/sbin/p11sak/p11sak.c diff --git a/usr/sbin/pkcscca/pkcscca.c b/usr/sbin/pkcscca/pkcscca.c new file mode 100644 index 0000000..9c846b5 --- /dev/null +++ b/usr/sbin/pkcscca/pkcscca.c @@ -0,0 +1,2522 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2014-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 + */ + +/* + * pkcscca - A tool for PKCS#11 CCA token. + * Currently, only migrates CCA private token objects from CCA cipher + * to using a software cipher. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "sw_crypt.h" +#include "pkcscca.h" + + +int v_flag = 0; +void *p11_lib = NULL; +void (*CSNDKTC) (); +void (*CSNBKTC) (); +void (*CSNBKTC2) (); +void (*CSNBDEC) (); +void *lib_csulcca; + +static struct algo aes = {(CK_BYTE *)"RTCMK AES ", (CK_BYTE *)"AES", 2 }; +static struct algo des = {(CK_BYTE *)"RTCMK ", (CK_BYTE *)"DES", 1 }; +static struct algo hmac = {(CK_BYTE *)"RTCMK HMAC ", (CK_BYTE *)"HMAC", 2 }; +static struct algo ecc = {(CK_BYTE *)"RTCMK ECC ", (CK_BYTE *)"ECC", 2 }; +static struct algo rsa = {(CK_BYTE *)"RTCMK ", (CK_BYTE *)"RSA", 1 }; + +int compute_hash(int hash_type, int buf_size, char *buf, char *digest) +{ + EVP_MD_CTX *md_ctx = NULL; + unsigned int result_size; + int rc; + + md_ctx = EVP_MD_CTX_create(); + + switch (hash_type) { + case HASH_SHA1: + rc = EVP_DigestInit(md_ctx, EVP_sha1()); + break; + case HASH_MD5: + rc = EVP_DigestInit(md_ctx, EVP_md5()); + break; + default: + EVP_MD_CTX_destroy(md_ctx); + return -1; + break; + } + + if (rc != 1) { + fprintf(stderr, "EVP_DigestInit() failed: rc = %d\n", rc); + return -1; + } + + rc = EVP_DigestUpdate(md_ctx, buf, buf_size); + if (rc != 1) { + fprintf(stderr, "EVP_DigestUpdate() failed: rc = %d\n", rc); + return -1; + } + + result_size = EVP_MD_CTX_size(md_ctx); + rc = EVP_DigestFinal(md_ctx, (unsigned char *) digest, &result_size); + if (rc != 1) { + fprintf(stderr, "EVP_DigestFinal() failed: rc = %d\n", rc); + return -1; + } + + EVP_MD_CTX_destroy(md_ctx); + + return 0; +} + +int cca_decrypt(unsigned char *in_data, unsigned long in_data_len, + unsigned char *out_data, unsigned long *out_data_len, + unsigned char *init_v, unsigned char *key_value) +{ + long return_code, reason_code, rule_array_count, length; + unsigned char chaining_vector[18]; + unsigned char rule_array[256]; + + length = in_data_len; + rule_array_count = 1; + memcpy(rule_array, "CBC ", 8); + + CSNBDEC(&return_code, &reason_code, NULL, NULL, key_value, + &length, in_data, init_v, &rule_array_count, + rule_array, chaining_vector, out_data); + + if (return_code != 0) { + fprintf(stderr, + "CSNBDEC (DES3 DECRYPT) failed: " + "return_code=%ld reason_code=%ld\n", + return_code, reason_code); + return -1; + } + + *out_data_len = length; + + return 0; +} + +// Function: dlist_remove_node() +// +// Attempts to remove the specified node from the list. The caller is +// responsible for freeing the data associated with the node prior to +// calling this routine +// +DL_NODE *dlist_remove_node(DL_NODE *list, DL_NODE *node) +{ + DL_NODE *temp = list; + + if (!list || !node) + return NULL; + + // special case: removing head of the list + // + if (list == node) { + temp = list->next; + if (temp) + temp->prev = NULL; + + free(list); + return temp; + } + // we have no guarantee that the node is in the list + // so search through the list to find it + // + while ((temp != NULL) && (temp->next != node)) + temp = temp->next; + + if (temp != NULL) { + DL_NODE *next = node->next; + + temp->next = next; + if (next) + next->prev = temp; + + free(node); + } + + return list; +} + +// Function: dlist_add_as_first() +// +// Adds the specified node to the start of the list +// +// Returns: pointer to the start of the list +// +DL_NODE *dlist_add_as_first(DL_NODE *list, void *data) +{ + DL_NODE *node = NULL; + + if (!data) + return list; + + node = (DL_NODE *) malloc(sizeof(DL_NODE)); + if (!node) + return NULL; + + node->data = data; + node->prev = NULL; + node->next = list; + if (list) + list->prev = node; + + return node; +} + +CK_ULONG dlist_length(DL_NODE *list) +{ + DL_NODE *temp = list; + CK_ULONG len = 0; + + while (temp) { + len++; + temp = temp->next; + } + + return len; +} + +/* template_free() */ +CK_RV template_free(TEMPLATE *tmpl) +{ + if (!tmpl) + return CKR_OK; + + while (tmpl->attribute_list) { + CK_ATTRIBUTE *attr = (CK_ATTRIBUTE *) tmpl->attribute_list->data; + + if (attr) + free(attr); + + tmpl->attribute_list = dlist_remove_node(tmpl->attribute_list, + tmpl->attribute_list); + } + + free(tmpl); + + return CKR_OK; +} + +/* template_update_attribute() + * + * modifies an existing attribute or adds a new attribute to the template + * + * Returns: TRUE on success, FALSE on failure + */ +CK_RV template_update_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE *new_attr) +{ + DL_NODE *node = NULL; + CK_ATTRIBUTE *attr = NULL; + + if (!tmpl || !new_attr) { + fprintf(stderr, "Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + 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) { + free(attr); + tmpl->attribute_list = + dlist_remove_node(tmpl->attribute_list, node); + break; + } + + node = node->next; + } + + /* add the new attribute */ + tmpl->attribute_list = dlist_add_as_first(tmpl->attribute_list, new_attr); + + return CKR_OK; +} + +/* Modified version of template_unflatten that checks + * that buf isn't overread. buf_size=-1 turns off checking + * (for backwards compatability) + */ +CK_RV template_unflatten_withSize(TEMPLATE **new_tmpl, CK_BYTE *buf, + CK_ULONG count, int buf_size) +{ + TEMPLATE *tmpl = NULL; + CK_ATTRIBUTE *a2 = NULL; + CK_BYTE *ptr = NULL; + CK_ULONG i, len; + CK_RV rc; + CK_ULONG_32 long_len = sizeof(CK_ULONG); + CK_ULONG_32 attr_ulong_32; + CK_ULONG attr_ulong; + CK_ATTRIBUTE *a1_64 = NULL; + CK_ATTRIBUTE_32 *a1 = NULL; + + + if (!new_tmpl || !buf) { + fprintf(stderr, "Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + tmpl = (TEMPLATE *) malloc(sizeof(TEMPLATE)); + if (!tmpl) { + fprintf(stderr, "Failed to allocate template\n"); + return CKR_HOST_MEMORY; + } + memset(tmpl, 0x0, sizeof(TEMPLATE)); + + ptr = buf; + for (i = 0; i < count; i++) { + if (buf_size >= 0 && + ((ptr + sizeof(CK_ATTRIBUTE)) > (buf + buf_size))) { + template_free(tmpl); + return CKR_FUNCTION_FAILED; + } + + if (long_len == 4) { + a1_64 = (CK_ATTRIBUTE *) ptr; + + len = sizeof(CK_ATTRIBUTE) + a1_64->ulValueLen; + a2 = (CK_ATTRIBUTE *) malloc(len); + if (!a2) { + template_free(tmpl); + fprintf(stderr, "Failed to allocate attribute\n"); + return CKR_HOST_MEMORY; + } + + /* if a buffer size is given, make sure it + * doesn't get overrun + */ + if (buf_size >= 0 && + (((unsigned char *) a1_64 + len) + > ((unsigned char *) buf + buf_size))) { + free(a2); + template_free(tmpl); + return CKR_FUNCTION_FAILED; + } + memcpy(a2, a1_64, len); + } else { + a1 = (CK_ATTRIBUTE_32 *) ptr; + + if ((a1->type == CKA_CLASS || a1->type == CKA_KEY_TYPE + || a1->type == CKA_MODULUS_BITS + || a1->type == CKA_VALUE_BITS + || a1->type == CKA_CERTIFICATE_TYPE + || a1->type == CKA_VALUE_LEN) + && a1->ulValueLen != 0) { + len = sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG); + } else { + len = sizeof(CK_ATTRIBUTE) + a1->ulValueLen; + } + + a2 = (CK_ATTRIBUTE *) malloc(len); + if (!a2) { + template_free(tmpl); + fprintf(stderr, "Failed to allocate attribute\n"); + return CKR_HOST_MEMORY; + } + a2->type = a1->type; + + if ((a1->type == CKA_CLASS || a1->type == CKA_KEY_TYPE + || a1->type == CKA_MODULUS_BITS + || a1->type == CKA_VALUE_BITS + || a1->type == CKA_CERTIFICATE_TYPE + || a1->type == CKA_VALUE_LEN) + && a1->ulValueLen != 0) { + + a2->ulValueLen = sizeof(CK_ULONG); + + { + CK_ULONG_32 *p32; + CK_BYTE *pb2; + + pb2 = (CK_BYTE *) a1; + pb2 += sizeof(CK_ATTRIBUTE_32); + p32 = (CK_ULONG_32 *) pb2; + attr_ulong_32 = *p32; + } + + attr_ulong = attr_ulong_32; + + { + CK_BYTE *pb2; + pb2 = (CK_BYTE *) a2; + pb2 += sizeof(CK_ATTRIBUTE); + memcpy(pb2, (CK_BYTE *) & attr_ulong, sizeof(CK_ULONG)); + } + } else { + CK_BYTE *pb2, *pb; + + a2->ulValueLen = a1->ulValueLen; + pb2 = (CK_BYTE *) a2; + pb2 += sizeof(CK_ATTRIBUTE); + pb = (CK_BYTE *) a1; + pb += sizeof(CK_ATTRIBUTE_32); + /* if a buffer size is given, make sure it + * doesn't get overrun + */ + if (buf_size >= 0 && (pb + a1->ulValueLen) > (buf + buf_size)) { + free(a2); + template_free(tmpl); + return CKR_FUNCTION_FAILED; + } + memcpy(pb2, pb, a1->ulValueLen); + } + } + + if (a2->ulValueLen != 0) + a2->pValue = (CK_BYTE *) a2 + sizeof(CK_ATTRIBUTE); + else + a2->pValue = NULL; + + rc = template_update_attribute(tmpl, a2); + if (rc != CKR_OK) { + free(a2); + template_free(tmpl); + return rc; + } + if (long_len == 4) + ptr += len; + else + ptr += sizeof(CK_ATTRIBUTE_32) + a1->ulValueLen; + } + + *new_tmpl = tmpl; + + return CKR_OK; +} + +/* template_flatten() + * this still gets used when saving token objects to disk + */ +CK_RV template_flatten(TEMPLATE *tmpl, CK_BYTE *dest) +{ + DL_NODE *node = NULL; + CK_BYTE *ptr = NULL; + CK_ULONG_32 long_len; + CK_ATTRIBUTE_32 *attr_32 = NULL; + CK_ULONG Val; + CK_ULONG_32 Val_32; + CK_ULONG *pVal; + + long_len = sizeof(CK_ULONG); + + if (!tmpl || !dest) { + fprintf(stderr, "Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + ptr = dest; + node = tmpl->attribute_list; + while (node) { + CK_ATTRIBUTE *attr = (CK_ATTRIBUTE *) node->data; + + if (long_len == 4) { + memcpy(ptr, attr, sizeof(CK_ATTRIBUTE) + attr->ulValueLen); + ptr += sizeof(CK_ATTRIBUTE) + attr->ulValueLen; + } else { + attr_32 = malloc(sizeof(CK_ATTRIBUTE_32)); + if (!attr_32) { + fprintf(stderr, "Failed to allocate attribute\n"); + return CKR_HOST_MEMORY; + } + attr_32->type = attr->type; + attr_32->pValue = 0x00; + if ((attr->type == CKA_CLASS || + attr->type == CKA_KEY_TYPE || + attr->type == CKA_MODULUS_BITS || + attr->type == CKA_VALUE_BITS || + attr->type == CKA_CERTIFICATE_TYPE || + attr->type == CKA_VALUE_LEN) && attr->ulValueLen != 0) { + + attr_32->ulValueLen = sizeof(CK_ULONG_32); + + memcpy(ptr, attr_32, sizeof(CK_ATTRIBUTE_32)); + ptr += sizeof(CK_ATTRIBUTE_32); + + pVal = (CK_ULONG *) attr->pValue; + Val = *pVal; + Val_32 = (CK_ULONG_32) Val; + memcpy(ptr, &Val_32, sizeof(CK_ULONG_32)); + ptr += sizeof(CK_ULONG_32); + } else { + attr_32->ulValueLen = attr->ulValueLen; + memcpy(ptr, attr_32, sizeof(CK_ATTRIBUTE_32)); + ptr += sizeof(CK_ATTRIBUTE_32); + if (attr->ulValueLen != 0) { + memcpy(ptr, attr->pValue, attr->ulValueLen); + ptr += attr->ulValueLen; + } + } + free(attr_32); + } + + node = node->next; + } + + return CKR_OK; +} + +CK_ULONG template_get_count(TEMPLATE *tmpl) +{ + if (tmpl == NULL) + return 0; + + return dlist_length(tmpl->attribute_list); +} + +CK_ULONG template_get_compressed_size(TEMPLATE *tmpl) +{ + DL_NODE *node; + CK_ULONG size = 0; + + if (tmpl == NULL) + return 0; + node = tmpl->attribute_list; + while (node) { + CK_ATTRIBUTE *attr = (CK_ATTRIBUTE *) node->data; + + size += sizeof(CK_ATTRIBUTE_32); + if ((attr->type == CKA_CLASS || attr->type == CKA_KEY_TYPE + || attr->type == CKA_MODULUS_BITS + || attr->type == CKA_VALUE_BITS + || attr->type == CKA_CERTIFICATE_TYPE + || attr->type == CKA_VALUE_LEN) + && attr->ulValueLen != 0) { + size += sizeof(CK_ULONG_32); + } else { + size += attr->ulValueLen; + } + + node = node->next; + } + + return size; +} + +/* template_get_class */ +CK_BBOOL template_get_class(TEMPLATE *tmpl, CK_ULONG *class, + CK_ULONG *subclass) +{ + DL_NODE *node; + CK_BBOOL found = FALSE; + + if (!tmpl || !class || !subclass) + return FALSE; + + node = tmpl->attribute_list; + + /* have to iterate through all attributes. no early exits */ + while (node) { + CK_ATTRIBUTE *attr = (CK_ATTRIBUTE *) node->data; + + if (attr->type == CKA_CLASS) { + *class = *(CK_OBJECT_CLASS *) attr->pValue; + found = TRUE; + } + + /* underneath, these guys are both CK_ULONG so we + * could combine this + */ + if (attr->type == CKA_CERTIFICATE_TYPE) + *subclass = *(CK_CERTIFICATE_TYPE *) attr->pValue; + + if (attr->type == CKA_KEY_TYPE) + *subclass = *(CK_KEY_TYPE *) attr->pValue; + + node = node->next; + } + + return found; +} + +/* template_attribute_find() + * + * find the attribute in the list and return its value + */ +CK_BBOOL template_attribute_find(TEMPLATE *tmpl, CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE **attr) +{ + DL_NODE *node = NULL; + CK_ATTRIBUTE *a = NULL; + + if (!tmpl || !attr) + return FALSE; + + node = tmpl->attribute_list; + + while (node != NULL) { + a = (CK_ATTRIBUTE *) node->data; + + if (type == a->type) { + *attr = a; + return TRUE; + } + + node = node->next; + } + + *attr = NULL; + + return FALSE; +} + +CK_RV build_attribute(CK_ATTRIBUTE_TYPE type, + CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **attrib) +{ + CK_ATTRIBUTE *attr = NULL; + + attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + data_len); + if (!attr) { + fprintf(stderr, "Failed to allocate attribute\n"); + return CKR_HOST_MEMORY; + } + attr->type = type; + attr->ulValueLen = data_len; + + if (data_len > 0) { + attr->pValue = (CK_BYTE *) attr + sizeof(CK_ATTRIBUTE); + memcpy(attr->pValue, data, data_len); + } else { + attr->pValue = NULL; + } + + *attrib = attr; + + return CKR_OK; +} + +// object_free() +// +// does what it says... +// +void object_free(OBJECT * obj) +{ + /* refactorization here to do actual free - fix from coverity scan */ + if (obj) { + if (obj->template) + template_free(obj->template); + free(obj); + } +} + +//Modified object_restore to prevent buffer overflow +//If data_size=-1, won't do bounds checking +CK_RV object_restore_withSize(CK_BYTE * data, OBJECT ** new_obj, + CK_BBOOL replace, int data_size) +{ + TEMPLATE *tmpl = NULL; + OBJECT *obj = NULL; + CK_ULONG offset = 0; + CK_ULONG_32 count = 0; + CK_RV rc; + CK_OBJECT_CLASS_32 class32; + + if (!data || !new_obj) { + fprintf(stderr, "Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + obj = (OBJECT *) malloc(sizeof(OBJECT)); + if (!obj) { + fprintf(stderr, "Failed to allocate object\n"); + rc = CKR_HOST_MEMORY; + goto error; + } + + + memset(obj, 0x0, sizeof(OBJECT)); + + memcpy( &class32, data + offset, sizeof(CK_OBJECT_CLASS_32) ); + obj->class = class32; + offset += sizeof(CK_OBJECT_CLASS_32); + + memcpy(&count, data + offset, sizeof(CK_ULONG_32)); + offset += sizeof(CK_ULONG_32); + + + memcpy(&obj->name, data + offset, 8); + offset += 8; + + rc = template_unflatten_withSize(&tmpl, data + offset, count, data_size); + if (rc != CKR_OK) { + fprintf(stderr, "template_unflatten_withSize failed rc=%lx.\n", rc); + goto error; + } + obj->template = tmpl; + + if (replace == FALSE) { + *new_obj = obj; + } else { + template_free((*new_obj)->template); + memcpy(*new_obj, obj, sizeof(OBJECT)); + + free(obj); // don't want to do object_free() here! + } + + return CKR_OK; + +error: + if (obj) + object_free(obj); + if (tmpl) + template_free(tmpl); + + return rc; +} + +// object_flatten() - this is still used when saving token objects +// +CK_RV object_flatten(OBJECT * obj, CK_BYTE ** data, CK_ULONG * len) +{ + CK_BYTE *buf = NULL; + CK_ULONG tmpl_len, total_len; + CK_ULONG offset; + CK_ULONG_32 count; + CK_OBJECT_CLASS_32 class32; + long rc; + + if (!obj) { + fprintf(stderr, "Invalid function arguments.\n"); + return CKR_FUNCTION_FAILED; + } + count = template_get_count(obj->template); + tmpl_len = template_get_compressed_size(obj->template); + + total_len = tmpl_len + sizeof(CK_OBJECT_CLASS_32) + sizeof(CK_ULONG_32) + 8; + + buf = (CK_BYTE *) malloc(total_len); + if (!buf) { // SAB XXX FIXME This was DATA + fprintf(stderr, "Failed to allocate buffer\n"); + return CKR_HOST_MEMORY; + } + + memset((CK_BYTE *) buf, 0x0, total_len); + + offset = 0; + + class32 = obj->class; + memcpy( buf + offset, &class32, sizeof(CK_OBJECT_CLASS_32) ); + offset += sizeof(CK_OBJECT_CLASS_32); + + memcpy(buf + offset, &count, sizeof(CK_ULONG_32)); + offset += sizeof(CK_ULONG_32); + + memcpy(buf + offset, &obj->name, sizeof(CK_BYTE) * 8); + offset += 8; + rc = template_flatten(obj->template, buf + offset); + if (rc != CKR_OK) { + free(buf); + return rc; + } + + *data = buf; + *len = total_len; + + return CKR_OK; +} + +CK_RV add_pkcs_padding(CK_BYTE *ptr, + CK_ULONG block_size, CK_ULONG data_len, + CK_ULONG total_len) +{ + CK_ULONG i, pad_len; + CK_BYTE pad_value; + + pad_len = block_size - (data_len % block_size); + pad_value = (CK_BYTE) pad_len; + + if (data_len + pad_len > total_len) { + fprintf(stderr, "The total length is too small to add padding.\n"); + return CKR_FUNCTION_FAILED; + } + for (i = 0; i < pad_len; i++) + ptr[i] = pad_value; + + return CKR_OK; +} + +#define CKR_IBM_NOT_TOUCHED -1 + +int adjust_secret_key_attributes(OBJECT *obj, CK_ULONG key_type) +{ + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + CK_ATTRIBUTE *value_attr = NULL; + CK_ATTRIBUTE *ibm_opaque_attr = NULL; + CK_ULONG key_size; + struct secaeskeytoken *aes_token; + CK_BYTE *zero = NULL; + + if (key_type != CKK_AES) { + /* DES/3DES keys are already contained in CKA_IBM_OPAQUE */ + return CKR_IBM_NOT_TOUCHED; + } + + /* Don't touch if object already has an IBM_OPAQUE attribute */ + if (template_attribute_find(obj->template, CKA_IBM_OPAQUE, &attr)) + return CKR_IBM_NOT_TOUCHED; + + if (!template_attribute_find(obj->template, CKA_VALUE, &value_attr)) { + fprintf(stderr, "No CKA_VALUE attribute found\n"); + return CKR_TEMPLATE_INCOMPLETE; + } + + aes_token = (struct secaeskeytoken *)value_attr->pValue; + if (value_attr->ulValueLen != sizeof(struct secaeskeytoken) || + aes_token->type != 0x01 || + aes_token->version != 0x04) { + fprintf(stderr, "CKA_VALUE does not contain a CCA secure key\n"); + return CKR_IBM_NOT_TOUCHED; + } + + /* Move CKA_VALUE to CKA_IBM_OPAQUE */ + rc = build_attribute(CKA_IBM_OPAQUE, value_attr->pValue, + value_attr->ulValueLen, &ibm_opaque_attr); + if (rc != CKR_OK) + goto cleanup; + + rc = template_update_attribute(obj->template, ibm_opaque_attr); + if (rc != CKR_OK) + goto cleanup; + + /* Provide dummy CKA_VAUE attribute in (clear) key size */ + key_size = aes_token->bitsize / 8; + zero = (CK_BYTE *)calloc(key_size, 1); + if (zero == NULL) { + fprintf(stderr, "Failed to allocate zero value\n"); + rc = CKR_HOST_MEMORY; + goto cleanup; + } + + rc = build_attribute(CKA_VALUE, zero, key_size, &value_attr); + if (rc != CKR_OK) + goto cleanup; + + rc = template_update_attribute(obj->template, value_attr); + if (rc != CKR_OK) + goto cleanup; + + free(zero); + + return CKR_OK; + +cleanup: + if (ibm_opaque_attr) + free(ibm_opaque_attr); + if (zero) + free(zero); + return rc; +} + +/* + * OCK version 2.x create AES key objects with the CCA secure key stored + * in CKA_VALUE. OCK 3.x requires the secure in CKA_IBM_OPAQUE instead. + * Note: Other key types, such as DES/3DES keys as well as symmetric + * keys (RSA, EC, etc) already store the key in CKA_IBM_OPAQUE in OCK 2.x + * + * This function moves the CCA AES key from CKA_VALUE to CKA_IBM_OPAQUE + * and supplies a dummy (all zero) key in CKA_VALUE. + */ +int adjust_key_object_attributes(unsigned char *data, unsigned long data_len, + unsigned char **new_data, + unsigned long *new_data_len) +{ + int rc; + OBJECT *obj = NULL; + CK_ULONG class, subclass = 0; + + *new_data = NULL; + *new_data_len = 0; + + /* Now unflatten the OBJ */ + rc = object_restore_withSize(data, &obj, CK_FALSE, data_len); + if (rc) + goto cleanup; + + if (!template_get_class(obj->template, &class, &subclass)) { + fprintf(stderr, "No CKA_CLASS attribute found\n"); + rc = CKR_TEMPLATE_INCOMPLETE; + goto cleanup; + } + + switch(class) { + case CKO_SECRET_KEY: + rc = adjust_secret_key_attributes(obj, subclass); + if (rc == CKR_IBM_NOT_TOUCHED) { + rc = CKR_OK; + goto cleanup; + } + break; + default: + /* no need to modify the object */ + rc = CKR_OK; + goto cleanup; + } + if (rc != CKR_OK) + goto cleanup; + + /* flatten the object */ + rc = object_flatten(obj, new_data, new_data_len); + if (rc) + goto cleanup; + +cleanup: + if (obj) + object_free(obj); + + return rc; +} + +int reencrypt_private_token_object(unsigned char *data, unsigned long len, + unsigned char *new_cipher, + unsigned long *new_cipher_len, + unsigned char *masterkey) +{ + unsigned char *clear = NULL; + unsigned char des3_key[64]; + unsigned char sw_des3_key[3 * DES_KEY_SIZE]; + unsigned long clear_len; + unsigned char *new_obj_data = NULL; + unsigned long new_obj_data_len; + CK_ULONG_32 obj_data_len_32; + CK_ULONG padded_len; + CK_ULONG block_size = DES_BLOCK_SIZE; + CK_BYTE *ptr = NULL; + CK_BYTE hash_sha[SHA1_HASH_SIZE]; + CK_RV rc; + int ret; + + /* cca wants 8 extra bytes for padding purposes */ + clear_len = len + 8; + clear = (unsigned char *) malloc(clear_len); + if (!clear) { + fprintf(stderr, "malloc() failed: %s.\n", strerror(errno)); + ret = -1; + goto done; + } + + /* decrypt using cca des3 */ + memcpy(des3_key, masterkey, MASTER_KEY_SIZE); + ret = cca_decrypt(data, len, clear, &clear_len, (CK_BYTE *)"10293847", + des3_key); + if (ret) + goto done; + + /* Validate the hash */ + memcpy(&obj_data_len_32, clear, sizeof(CK_ULONG_32)); + if (obj_data_len_32 >= clear_len) { + fprintf(stderr, "Decrypted object data is inconsistent. Possibly already migrated?\n"); + ret = CKR_FUNCTION_FAILED; + goto done; + } + + ret = compute_sha1((char *)(clear + sizeof(CK_ULONG_32)), + obj_data_len_32, (char *)hash_sha); + if (ret != CKR_OK) { + goto done; + } + + if (memcmp(clear + sizeof(CK_ULONG_32) + obj_data_len_32, hash_sha, + SHA1_HASH_SIZE) != 0) { + fprintf(stderr, "Stored hash does not match restored data hash.\n"); + ret = CKR_FUNCTION_FAILED; + goto done; + } + + /* Adjust the key object attributes */ + ret = adjust_key_object_attributes(clear + sizeof(CK_ULONG_32), + obj_data_len_32, + &new_obj_data, &new_obj_data_len); + if (ret) + goto done; + + if (new_obj_data != NULL) { + free(clear); + + /* build data to be encrypted */ + clear_len = sizeof(CK_ULONG_32) + new_obj_data_len + SHA1_HASH_SIZE; + padded_len = block_size * (clear_len / block_size + 1); + + clear = malloc(padded_len); + if (!clear) { + fprintf(stderr, "Failed to allocate buffer\n"); + goto done; + } + + ptr = clear; + obj_data_len_32 = new_obj_data_len; + memcpy(ptr, &obj_data_len_32, sizeof(CK_ULONG_32)); + ptr += sizeof(CK_ULONG_32); + memcpy(ptr, new_obj_data, obj_data_len_32); + ptr += obj_data_len_32; + compute_sha1((char *)new_obj_data, new_obj_data_len, (char *)hash_sha); + memcpy(ptr, hash_sha, SHA1_HASH_SIZE); + + add_pkcs_padding(clear + clear_len, block_size, clear_len, + padded_len); + + clear_len = padded_len; + } + /* now encrypt using software des3 */ + memcpy(sw_des3_key, masterkey, 3 * DES_KEY_SIZE); + rc = sw_des3_cbc_encrypt(clear, clear_len, new_cipher, new_cipher_len, + (CK_BYTE *)"10293847", sw_des3_key); + if (rc != CKR_OK) + ret = -1; + +done: + if (clear) + free(clear); + if (new_obj_data) + free(new_obj_data); + + return ret; +} + +int load_token_objects(unsigned char *data_store, + unsigned char *masterkey) +{ + FILE *fp1 = NULL, *fp2 = NULL; + unsigned char *buf = NULL; + char tmp[PATH_MAX], fname[PATH_MAX], iname[PATH_MAX]; + CK_BBOOL priv; + unsigned int size; + int rc = 0, scount = 0, fcount = 0; + size_t read_size; + unsigned char *new_cipher = NULL; + unsigned long new_cipher_len; + + snprintf(iname, sizeof(iname), "%s/TOK_OBJ/OBJ.IDX", data_store); + + fp1 = fopen((char *) iname, "r"); + if (!fp1) + return -1; // no token objects + + while (fgets((char *) tmp, 50, fp1)) { + tmp[strlen((char *) tmp) - 1] = 0; + + snprintf((char *) fname, sizeof(fname), "%s/TOK_OBJ/", data_store); + strcat((char *) fname, (char *) tmp); + + fp2 = fopen((char *) fname, "r"); + if (!fp2) + continue; + + read_size = fread(&size, sizeof(CK_ULONG_32), 1, fp2); + if (read_size != 1) { + fprintf(stderr, "Cannot read size\n"); + goto cleanup; + } + read_size = fread(&priv, sizeof(CK_BBOOL), 1, fp2); + if (read_size != 1) { + fprintf(stderr, "Cannot read boolean\n"); + goto cleanup; + } + + size = size - sizeof(CK_ULONG_32) - sizeof(CK_BBOOL); + buf = (unsigned char *) malloc(size); + if (!buf) { + fprintf(stderr, "Cannot malloc for object %s " + "(ignoring it).\n", tmp); + goto cleanup; + } + + read_size = fread((char *) buf, 1, size, fp2); + if (read_size != size) { + fprintf(stderr, "Cannot read object %s " "(ignoring it).\n", tmp); + goto cleanup; + } + + fclose(fp2); + fp2 = NULL; + + if (priv != FALSE) { + /* private token object */ + new_cipher_len = size * 2; /* obj may grow during processing ! */ + new_cipher = malloc(new_cipher_len); + if (!new_cipher) { + fprintf(stderr, "Cannot malloc space for new " + "cipher (ignoring object %s).\n", tmp); + goto cleanup; + } + + /* After reading the private token object, + * decrypt it using CCA des3 and then re-encrypt it + * using software des3. + */ + memset(new_cipher, 0, new_cipher_len); + rc = reencrypt_private_token_object(buf, size, + new_cipher, &new_cipher_len, + masterkey); + if (rc) + goto cleanup; + } else { + /* public token object */ + rc = adjust_key_object_attributes(buf, size, &new_cipher, + &new_cipher_len); + if (rc) + goto cleanup; + + /* Only save if the object has been changed */ + if (new_cipher == NULL) + goto cleanup; + } + + /* now save the newly re-encrypted object back to + * disk in its original file. + */ + fp2 = fopen((char *) fname, "w"); + if (fp2 == NULL) { + printf("Failed to open file %s: %s", fname, strerror(errno)); + rc = CKR_FUNCTION_FAILED; + goto cleanup; + } + size = sizeof(CK_ULONG_32) + sizeof(CK_BBOOL) + new_cipher_len; + (void) fwrite(&size, sizeof(CK_ULONG_32), 1, fp2); + (void) fwrite(&priv, sizeof(CK_BBOOL), 1, fp2); + (void) fwrite(new_cipher, new_cipher_len, 1, fp2); + rc = 0; + +cleanup: + if (fp2) + fclose(fp2); + if (buf) { + free(buf); + buf = NULL; + } + if (new_cipher) { + free(new_cipher); + new_cipher = NULL; + } + + if (rc) { + if (v_flag) + printf("Failed to process %s\n", fname); + fcount++; + } else { + if (v_flag) + printf("Processed %s.\n", fname); + scount++; + } + } + fclose(fp1); + printf("Successfully migrated %d object(s).\n", scount); + + if (v_flag && fcount) + printf("Failed to migrate %d object(s).\n", fcount); + + return 0; +} + +int load_masterkey(char *mkfile, char *pin, char *masterkey) +{ + unsigned char des3_key[3 * DES_KEY_SIZE]; + char hash_sha[SHA1_HASH_SIZE]; + char pin_md5_hash[MD5_HASH_SIZE]; + unsigned char *cipher = NULL; + char *clear = NULL; + unsigned long cipher_len, clear_len; + int ret; + CK_RV rc; + FILE *fp = NULL; + + clear_len = cipher_len = + (MASTER_KEY_SIZE + SHA1_HASH_SIZE + + (DES_BLOCK_SIZE - 1)) & ~(DES_BLOCK_SIZE - 1); + + fp = fopen((char *) mkfile, "r"); + if (!fp) { + print_error("Could not open %s: %s\n", mkfile, strerror(errno)); + return -1; + } + + cipher = malloc(cipher_len); + clear = malloc(clear_len); + if (cipher == NULL || clear == NULL) { + ret = -1; + goto done; + } + + ret = fread(cipher, cipher_len, 1, fp); + if (ret != 1) { + print_error("Could not read %s: %s\n", mkfile, strerror(errno)); + ret = -1; + goto done; + } + + /* decrypt the masterkey */ + + ret = compute_md5(pin, strlen(pin), pin_md5_hash); + if (ret) { + print_error("Error calculating MD5 of PIN!\n"); + goto done; + } + + memcpy(des3_key, pin_md5_hash, MD5_HASH_SIZE); + memcpy(des3_key + MD5_HASH_SIZE, pin_md5_hash, DES_KEY_SIZE); + + rc = sw_des3_cbc_decrypt(cipher, cipher_len, (unsigned char *)clear, + &clear_len, (unsigned char *) "12345678", + des3_key); + if (rc != CKR_OK) { + print_error("Error decrypting master key file after read"); + ret = -1; + goto done; + } + + /* + * technically should strip PKCS padding here but since I already know + * what the length should be, I don't bother. + * + * compare the hashes to verify integrity + */ + + ret = compute_sha1(clear, MASTER_KEY_SIZE, hash_sha); + if (ret) { + print_error("Failed to compute sha for masterkey.\n"); + goto done; + } + + if (memcmp(hash_sha, clear + MASTER_KEY_SIZE, SHA1_HASH_SIZE) != 0) { + print_error("%s appears to have been tampered!\n", mkfile); + print_error("Cannot migrate.\n"); + ret = -1; + goto done; + } + + memcpy(masterkey, clear, MASTER_KEY_SIZE); + ret = 0; + +done: + if (fp) + fclose(fp); + if (clear) + free(clear); + if (cipher) + free(cipher); + + return ret; +} + +int get_pin(char **pin, size_t *pinlen) +{ + struct termios old, new; + int nread; + char *buff = NULL; + size_t buflen; + int rc = 0; + + /* turn echoing off */ + if (tcgetattr(fileno(stdin), &old) != 0) + return -1; + + new = old; + new.c_lflag &= ~ECHO; + if (tcsetattr(fileno(stdin), TCSAFLUSH, &new) != 0) + return -1; + + /* read the pin + * Note: getline will allocate memory for buff. free it when done. + */ + nread = getline(&buff, &buflen, stdin); + if (nread == -1) { + rc = -1; + goto done; + } + + /* Restore terminal */ + (void) tcsetattr(fileno(stdin), TCSAFLUSH, &old); + + /* start a newline */ + printf("\n"); + fflush(stdout); + + /* Allocate PIN. + * Note: nread includes carriage return. + * Replace with terminating NULL. + */ + *pin = (char *) malloc(nread); + if (*pin == NULL) { + rc = -ENOMEM; + goto done; + } + + /* strip the carriage return since not part of pin. */ + buff[nread - 1] = '\0'; + memcpy(*pin, buff, nread); + /* don't include the terminating null in the pinlen */ + *pinlen = nread - 1; + +done: + if (buff) + free(buff); + + return rc; +} + +int verify_pins(char *data_store, char *sopin, unsigned long sopinlen, + char *userpin, unsigned long userpinlen) +{ + TOKEN_DATA td; + char fname[PATH_MAX]; + char pin_sha[SHA1_HASH_SIZE]; + FILE *fp = NULL; + int ret, tdnew; + struct stat stbuf; + size_t tdlen; + int fd; + + /* read the NVTOK.DAT */ + snprintf(fname, PATH_MAX, "%s/NVTOK.DAT", data_store); + fp = fopen((char *) fname, "r"); + if (!fp) { + print_error("Could not open %s: %s\n", fname, strerror(errno)); + return -1; + } + + fd = fileno(fp); + if ((fstat(fd, &stbuf) != 0) || (!S_ISREG(stbuf.st_mode))) { + ret = -1; + goto done; + } + + if (stbuf.st_size == sizeof(TOKEN_DATA_OLD)) { + /* old data store/pin format */ + tdnew = 0; + tdlen = sizeof(TOKEN_DATA_OLD); + } else if (stbuf.st_size == sizeof(TOKEN_DATA)) { + /* new data store/pin format */ + tdnew = 1; + tdlen = sizeof(TOKEN_DATA); + } else { + print_error("%s: invalid size.\n", fname); + ret = -1; + goto done; + } + + ret = fread(&td, tdlen, 1, fp); + if (ret != 1) { + print_error("Could not read %s: %s\n", fname, strerror(errno)); + ret = -1; + goto done; + } + + if (tdnew == 0) { + /* Now compute the SHAs for the SO and USER pins entered. + * Compare with the SHAs for SO and USER PINs saved in + * NVTOK.DAT to verify. + */ + + if (sopin != NULL) { + ret = compute_sha1(sopin, sopinlen, pin_sha); + if (ret) { + print_error("Failed to compute sha for SO.\n"); + goto done; + } + + if (memcmp(td.so_pin_sha, pin_sha, SHA1_HASH_SIZE) != 0) { + print_error("SO PIN is incorrect.\n"); + ret = -1; + goto done; + } + } + + if (userpin != NULL) { + ret = compute_sha1(userpin, userpinlen, pin_sha); + if (ret) { + print_error("Failed to compute sha for USER.\n"); + goto done; + } + + if (memcmp(td.user_pin_sha, pin_sha, SHA1_HASH_SIZE) != 0) { + print_error("USER PIN is incorrect.\n"); + ret = -1; + goto done; + } + } + } else if (tdnew == 1) { + if (sopin != NULL) { + unsigned char so_login_key[32]; + + ret = PKCS5_PBKDF2_HMAC(sopin, sopinlen, + td.dat.so_login_salt, 64, + td.dat.so_login_it, EVP_sha512(), + 256 / 8, so_login_key); + if (ret != 1) { + print_error("PBKDF2 failed.\n"); + goto done; + } + + if (CRYPTO_memcmp(td.dat.so_login_key, so_login_key, 32) != 0) { + print_error("USER PIN is incorrect.\n"); + ret = -1; + goto done; + } + } + if (userpin != NULL) { + unsigned char user_login_key[32]; + + ret = PKCS5_PBKDF2_HMAC(userpin, userpinlen, + td.dat.user_login_salt, 64, + td.dat.user_login_it, EVP_sha512(), + 256 / 8, user_login_key); + if (ret != 1) { + print_error("PBKDF2 failed.\n"); + goto done; + } + + if (CRYPTO_memcmp(td.dat.user_login_key, user_login_key, 32) != 0) { + print_error("USER PIN is incorrect.\n"); + ret = -1; + goto done; + } + } + } else { + print_error("Unknown format.\n"); + ret = -1; + goto done; + } + ret = 0; + +done: + /* clear out the hash */ + memset(pin_sha, 0, SHA1_HASH_SIZE); + if (fp) + fclose(fp); + + return ret; +} + + +CK_FUNCTION_LIST *p11_init(void) +{ + CK_RV rv; + CK_RV (*pfoo) (); + char *loc1_lib = "/usr/lib/pkcs11/PKCS11_API.so64"; + char *loc2_lib = "libopencryptoki.so"; + CK_FUNCTION_LIST *funcs = NULL; + + + p11_lib = dlopen(loc1_lib, RTLD_NOW); + if (p11_lib != NULL) + goto get_list; + + p11_lib = dlopen(loc2_lib, RTLD_NOW); + if (p11_lib == NULL) { + print_error("Couldn't get a handle to the PKCS#11 library."); + return NULL; + } + +get_list: + *(void **)(&pfoo) = dlsym(p11_lib, "C_GetFunctionList"); + if (pfoo == NULL) { + print_error("Couldn't get the address of the C_GetFunctionList " + "routine."); + dlclose(p11_lib); + return NULL; + } + + rv = pfoo(&funcs); + if (rv != CKR_OK) { + p11_error("C_GetFunctionList", rv); + dlclose(p11_lib); + return NULL; + } + + rv = funcs->C_Initialize(NULL_PTR); + if (rv != CKR_OK) { + p11_error("C_Initialize", rv); + dlclose(p11_lib); + return NULL; + } + + if (v_flag) + printf("PKCS#11 library initialized\n"); + + return funcs; +} + +void p11_fini(CK_FUNCTION_LIST *funcs) +{ + funcs->C_Finalize(NULL_PTR); + + if (p11_lib) + dlclose(p11_lib); +} + +/* Expect attribute array to have 3 entries, + * 0 CKA_IBM_OPAQUE + * 1 CKA_KEY_TYPE + * 2 CKA_LABEL + */ +int add_key(CK_OBJECT_HANDLE handle, CK_ATTRIBUTE *attrs, struct key **keys) +{ + struct key *new_key; + CK_ULONG key_type = *(CK_ULONG *) attrs[1].pValue; + + new_key = malloc(sizeof(struct key)); + if (!new_key) { + print_error("Malloc of %zd bytes failed!", sizeof(struct key)); + return 1; + } + + switch (key_type) { + case CKK_AES: + case CKK_DES: + case CKK_DES2: + case CKK_DES3: + case CKK_EC: + case CKK_GENERIC_SECRET: + case CKK_RSA: + break; + default: + free(new_key); + return 0; + } + + new_key->type = key_type; + new_key->opaque_attr = malloc(attrs[0].ulValueLen); + if (!new_key->opaque_attr) { + print_error("Malloc of %lu bytes failed!", attrs[0].ulValueLen); + free(new_key); + return 2; + } + new_key->handle = handle; + new_key->attr_len = attrs[0].ulValueLen; + memcpy(new_key->opaque_attr, attrs[0].pValue, attrs[0].ulValueLen); + new_key->label = malloc(attrs[2].ulValueLen + 1); + if (!new_key->label) { + print_error("Malloc of %lu bytes failed!", attrs[2].ulValueLen + 1); + free(new_key); + return 2; + } + + memset(new_key->label, 0, attrs[2].ulValueLen + 1); + memcpy(new_key->label, attrs[2].pValue, attrs[2].ulValueLen); + + new_key->next = *keys; + *keys = new_key; + + if (v_flag) { + char *type_name; + switch (new_key->type) { + case CKK_AES: + type_name = AES_NAME; + break; + case CKK_DES: + type_name = DES_NAME; + break; + case CKK_DES2: + type_name = DES2_NAME; + break; + case CKK_DES3: + type_name = DES3_NAME; + break; + case CKK_EC: + type_name = ECC_NAME; + break; + case CKK_GENERIC_SECRET: + type_name = HMAC_NAME; + break; + case CKK_RSA: + type_name = RSA_NAME; + break; + default: + type_name = BAD_NAME; + } + + printf("Migratable key found: type=%s, label=%s, handle=%lu\n", + type_name, new_key->label, handle); + } + + return 0; +} + +int find_wrapped_keys(CK_FUNCTION_LIST *funcs, CK_SESSION_HANDLE sess, + CK_KEY_TYPE *key_type, struct key **keys) +{ + CK_RV rv; + void *ptr; + CK_OBJECT_HANDLE *handles = NULL, tmp; + CK_ULONG ulObjectCount = 0, ulTotalCount = 0; + CK_BBOOL true = TRUE; + CK_ATTRIBUTE key_tmpl[] = { + {CKA_KEY_TYPE, key_type, sizeof(*key_type)}, + {CKA_TOKEN, &true, sizeof(true)}, + {CKA_EXTRACTABLE, &true, sizeof(true)} + }; + + CK_ATTRIBUTE attrs[] = { + {CKA_IBM_OPAQUE, NULL, 0}, + {CKA_KEY_TYPE, NULL, 0}, + {CKA_LABEL, NULL, 0} + }; + int i, rc, num_attrs = 3; + + + /* Find all objects in the store */ + rv = funcs->C_FindObjectsInit(sess, key_tmpl, 3); + if (rv != CKR_OK) { + p11_error("C_FindObjectsInit", rv); + print_error("Error finding CCA key objects"); + return 1; + } + + while (1) { + rv = funcs->C_FindObjects(sess, &tmp, 1, &ulObjectCount); + if (rv != CKR_OK) { + p11_error("C_FindObjects", rv); + print_error("Error finding CCA key objects"); + if (handles != NULL) + free(handles); + return 1; + } + + if (ulObjectCount == 0) + break; + + ptr = realloc(handles, sizeof(CK_OBJECT_HANDLE) * (++ulTotalCount)); + if (!ptr) { + print_error("Malloc of %lu bytes failed!", + sizeof(CK_OBJECT_HANDLE) * ulTotalCount); + funcs->C_FindObjectsFinal(sess); + if (handles != NULL) + free(handles); + return 1; + } + handles = ptr; + + handles[ulTotalCount - 1] = tmp; + } + if (v_flag) + printf("Found %lu keys to examine\n", ulTotalCount); + + /* Don't care if this fails */ + funcs->C_FindObjectsFinal(sess); + + /* At this point we have an array with handles to every object in the + * store. We only care about those with a CKA_IBM_OPAQUE attribute, + * so whittle down the list accordingly */ + for (tmp = 0; tmp < ulTotalCount; tmp++) { + rv = funcs->C_GetAttributeValue(sess, handles[tmp], attrs, num_attrs); + if (rv != CKR_OK) { + p11_error("C_GetAttributeValue", rv); + print_error("Error finding CCA key objects"); + free(handles); + return 1; + } + + /* If the opaque attr DNE, move to the next key */ + if (attrs[0].ulValueLen == ((CK_ULONG) - 1)) { + continue; + } + + /* Allocate space in the template for the actual data */ + for (i = 0; i < num_attrs; i++) { + attrs[i].pValue = malloc(attrs[i].ulValueLen); + if (!attrs[i].pValue) { + print_error("Malloc of %lu bytes failed!", attrs[i].ulValueLen); + free(handles); + return 1; + } + } + + /* Pull in the actual data */ + rv = funcs->C_GetAttributeValue(sess, handles[tmp], attrs, num_attrs); + if (rv != CKR_OK) { + p11_error("C_GetAttributeValue", rv); + print_error("Error getting object attributes"); + free(handles); + return 1; + } + + rc = add_key(handles[tmp], attrs, keys); + if (rc) { + free(handles); + return 1; + } + + for (i = 0; i < num_attrs; i++) { + free(attrs[i].pValue); + attrs[i].pValue = NULL_PTR; + attrs[i].ulValueLen = 0; + } + } + + free(handles); + + return 0; +} + +int replace_keys(CK_FUNCTION_LIST *funcs, CK_SESSION_HANDLE sess, + struct key *keys) +{ + CK_RV rv; + CK_ATTRIBUTE new_attr[] = { {CKA_IBM_OPAQUE, NULL, 0} }; + struct key *key; + + for (key = keys; key; key = key->next) { + new_attr->pValue = key->opaque_attr; + new_attr->ulValueLen = key->attr_len; + + rv = funcs->C_SetAttributeValue(sess, key->handle, new_attr, 1); + if (rv != CKR_OK) { + p11_error("C_SetAttributeValue", rv); + print_error("Error replacing old key with " "migrated key."); + return 1; + } + } + + return 0; +} + +int cca_migrate_asymmetric(struct key *key, char **out, struct algo algo) +{ + long return_code, reason_code, exit_data_length, key_identifier_length; + unsigned char *key_identifier; + + exit_data_length = 0; + key_identifier_length = key->attr_len; + + key_identifier = calloc(1, key->attr_len); + if (!key_identifier) { + print_error("Malloc of %lu bytes failed!", key->attr_len); + return 1; + } + memcpy(key_identifier, (char *) key->opaque_attr, key->attr_len); + + CSNDKTC(&return_code, + &reason_code, + &exit_data_length, + NULL, + &(algo.rule_array_count), + algo.rule_array, &key_identifier_length, key_identifier); + + if (return_code != CCA_SUCCESS) { + cca_error("CSNDKTC (Key Token Change)", return_code, reason_code); + print_error("Migrating %s key failed. label=%s, handle=%lu", + algo.name, key->label, key->handle); + return 1; + } else if (v_flag) { + printf("Successfully migrated %s key. label=%s, handle=%lu\n", + algo.name, key->label, key->handle); + } + + *out = (char *) key_identifier; + + if (!memcmp((CK_BYTE *) key->opaque_attr, + (CK_BYTE *) key_identifier, key_identifier_length)) { + printf("Skipping, %s token is wrapped with current master key. " + "label=%s, handle=%lu\n", + algo.name, key->label, key->handle); + } + + return 0; +} + +int cca_migrate_symmetric(struct key *key, char **out, struct algo algo) +{ + long return_code, reason_code, exit_data_length; + unsigned char *key_identifier; + + exit_data_length = 0; + + key_identifier = calloc(1, key->attr_len); + if (!key_identifier) { + print_error("Malloc of %lu bytes failed!", key->attr_len); + return 1; + } + memcpy(key_identifier, (char *) key->opaque_attr, key->attr_len); + + CSNBKTC(&return_code, + &reason_code, + &exit_data_length, + NULL, &(algo.rule_array_count), algo.rule_array, key_identifier); + + if (return_code != CCA_SUCCESS) { + cca_error("CSNBKTC (Key Token Change)", return_code, reason_code); + print_error("Migrating %s key failed. label=%s, handle=%lu", + algo.name, key->label, key->handle); + return 1; + } else if (v_flag) { + printf("Successfully migrated %s key. label=%s, handle=%lu\n", + algo.name, key->label, key->handle); + } + + *out = (char *) key_identifier; + + if (!memcmp((CK_BYTE *) key->opaque_attr, + (CK_BYTE *) key_identifier, key->attr_len)) { + printf("Skipping, %s token is wrapped with current master key. " + "label=%s, handle=%lu\n", + algo.name, key->label, key->handle); + } + return 0; +} + +int cca_migrate_hmac(struct key *key, char **out, struct algo algo) +{ + long return_code, reason_code, exit_data_length, key_identifier_length; + unsigned char *key_identifier; + + exit_data_length = 0; + key_identifier_length = key->attr_len; + + key_identifier = calloc(1, key->attr_len); + if (!key_identifier) { + print_error("Malloc of %lu bytes failed!", key->attr_len); + return 1; + } + memcpy(key_identifier, (char *) key->opaque_attr, key->attr_len); + + CSNBKTC2(&return_code, + &reason_code, + &exit_data_length, + NULL, + &(algo.rule_array_count), + algo.rule_array, &key_identifier_length, key_identifier); + + if (return_code != CCA_SUCCESS) { + cca_error("CSNBKTC2 (Key Token Change)", return_code, reason_code); + print_error("Migrating %s key failed. label=%s, handle=%lu", + algo.name, key->label, key->handle); + return 1; + } else if (v_flag) { + printf("Successfully migrated %s key. label=%s, handle=%lu\n", + algo.name, key->label, key->handle); + } + + *out = (char *) key_identifier; + + if (!memcmp((CK_BYTE *) key->opaque_attr, + (CK_BYTE *) key_identifier, key_identifier_length)) { + printf("Skipping, %s token is wrapped with current master key. " + "label=%s, handle=%lu\n", + algo.name, key->label, key->handle); + } + + return 0; +} + +/* @keys: A linked list of data to migrate and the PKCS#11 handle for the + * object in the data store. + * @count: counter for number of keys migrated + * @count_failed: counter for number of keys that failed to migrate + */ +int cca_migrate(struct key *keys, struct key_count *count, + struct key_count *count_failed) +{ + struct key *key; + char *migrated_data; + int rc; + + for (key = keys; key; key = key->next) { + migrated_data = NULL; + + switch (key->type) { + case CKK_AES: + rc = cca_migrate_symmetric(key, &migrated_data, aes); + if (rc) + count_failed->aes++; + else + count->aes++; + break; + case CKK_DES: + case CKK_DES2: + case CKK_DES3: + rc = cca_migrate_symmetric(key, &migrated_data, des); + if (rc) + count_failed->des++; + else + count->des++; + break; + case CKK_EC: + rc = cca_migrate_asymmetric(key, &migrated_data, ecc); + if (rc) + count_failed->ecc++; + else + count->ecc++; + break; + case CKK_GENERIC_SECRET: + rc = cca_migrate_hmac(key, &migrated_data, hmac); + if (rc) + count_failed->hmac++; + else + count->hmac++; + break; + case CKK_RSA: + rc = cca_migrate_asymmetric(key, &migrated_data, rsa); + if (rc) + count_failed->rsa++; + else + count->rsa++; + break; + default: + rc = 1; + break; + } + + /* replace the original key with the migrated key */ + if (!rc && migrated_data) { + free(key->opaque_attr); + key->opaque_attr = (CK_BYTE *) migrated_data; + } + } + + return 0; +} + +int migrate_keytype(CK_FUNCTION_LIST *funcs, CK_SESSION_HANDLE sess, + CK_KEY_TYPE *k_type, struct key_count *count, + struct key_count *count_failed) +{ + struct key *keys = NULL, *tmp, *to_free; + int rc; + + rc = find_wrapped_keys(funcs, sess, k_type, &keys); + if (rc) { + goto done; + } + + rc = cca_migrate(keys, count, count_failed); + if (rc) { + goto done; + } + + rc = replace_keys(funcs, sess, keys); + if (rc) { + goto done; + } + +done: + for (to_free = keys; to_free; to_free = tmp) { + tmp = to_free->next; + free(to_free->opaque_attr); + free(to_free); + } + + return rc; +} + +void key_migration_results(struct key_count migrated, struct key_count failed) +{ + if (migrated.aes || migrated.des || migrated.des2 || migrated.des3 || + migrated.ecc || migrated.hmac || migrated.rsa) + printf("Successfully migrated: "); + if (migrated.aes) + printf("AES: %d. ", migrated.aes); + if (migrated.des) + printf("DES: %d. ", migrated.des); + if (migrated.des2) + printf("DES2: %d. ", migrated.des2); + if (migrated.des3) + printf("DES3: %d. ", migrated.des3); + if (migrated.ecc) + printf("ECC: %d. ", migrated.ecc); + if (migrated.hmac) + printf("HMAC: %d. ", migrated.hmac); + if (migrated.rsa) + printf("RSA: %d. ", migrated.rsa); + + if (failed.aes || failed.des || failed.des2 || failed.des3 || + failed.ecc || failed.hmac || failed.rsa) + printf("\nFailed to migrate: "); + if (failed.aes) + printf("AES: %d. ", failed.aes); + if (failed.des) + printf("DES: %d. ", failed.des); + if (failed.des2) + printf("DES2: %d. ", failed.des2); + if (failed.des3) + printf("DES3: %d. ", failed.des3); + if (failed.ecc) + printf("ECC: %d. ", failed.ecc); + if (failed.hmac) + printf("HMAC: %d. ", failed.hmac); + if (failed.rsa) + printf("RSA: %d. ", failed.rsa); + + printf("\n"); +} + +int migrate_wrapped_keys(CK_SLOT_ID slot_id, char *userpin, int masterkey) +{ + CK_FUNCTION_LIST *funcs; + CK_KEY_TYPE key_type = 0; + CK_ULONG slot_count; + CK_SESSION_HANDLE sess; + CK_RV rv; + struct key_count count = { 0, 0, 0, 0, 0, 0, 0 }; + struct key_count count_failed = { 0, 0, 0, 0, 0, 0, 0 }; + int exit_code = 0, rc; + + funcs = p11_init(); + if (!funcs) { + return 2; + } + + rv = funcs->C_GetSlotList(TRUE, NULL_PTR, &slot_count); + if (rv != CKR_OK) { + p11_error("C_GetSlotList", rv); + exit_code = 3; + goto finalize; + } + + if (slot_id >= slot_count) { + print_error("%lu is not a valid slot ID.", slot_id); + exit_code = 4; + goto finalize; + } + + rv = funcs->C_OpenSession(slot_id, CKF_RW_SESSION | + CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &sess); + if (rv != CKR_OK) { + p11_error("C_OpenSession", rv); + exit_code = 5; + goto finalize; + } + + rv = funcs->C_Login(sess, CKU_USER, (CK_BYTE *) userpin, strlen(userpin)); + if (rv != CKR_OK) { + p11_error("C_Login (USER)", rv); + exit_code = 8; + goto finalize; + } + + switch (masterkey) { + case MK_AES: + if (v_flag) + printf("Search for AES keys\n"); + key_type = CKK_AES; + rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed); + if (rc) { + goto done; + } + if (v_flag) + printf("Search for HMAC keys\n"); + key_type = CKK_GENERIC_SECRET; + rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed); + if (rc) { + goto done; + } + break; + case MK_APKA: + if (v_flag) + printf("Search for ECC keys\n"); + key_type = CKK_EC; + rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed); + if (rc) { + goto done; + } + break; + case MK_ASYM: + if (v_flag) + printf("Search for RSA keys\n"); + key_type = CKK_RSA; + rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed); + if (rc) { + goto done; + } + break; + case MK_SYM: + if (v_flag) + printf("Search for DES keys\n"); + key_type = CKK_DES; + rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed); + if (rc) { + goto done; + } + if (v_flag) + printf("Search for DES2 keys\n"); + key_type = CKK_DES2; + rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed); + if (rc) { + goto done; + } + if (v_flag) + printf("Search for DES3 keys\n"); + key_type = CKK_DES3; + rc = migrate_keytype(funcs, sess, &key_type, &count, &count_failed); + if (rc) { + goto done; + } + break; + default: + print_error("unknown key type (%lu)\n", key_type); + return -1; + } + + key_migration_results(count, count_failed); + +done: + funcs->C_CloseSession(sess); +finalize: + p11_fini(funcs); + return exit_code; +} + +int migrate_version(char *sopin, char *userpin, unsigned char *data_store) +{ + char masterkey[MASTER_KEY_SIZE]; + char fname[PATH_MAX]; + struct stat statbuf; + int ret = 0; + + /* Verify that the data store is valid by looking for + * MK_SO, MK_USER, and TOK_OBJ/OBJ.IDX. + */ + memset(fname, 0, PATH_MAX); + snprintf(fname, PATH_MAX, "%s/MK_SO", data_store); + if (stat(fname, &statbuf) != 0) { + fprintf(stderr, "Cannot find %s.\n", fname); + ret = -1; + goto done; + } + + memset(fname, 0, PATH_MAX); + snprintf(fname, PATH_MAX, "%s/MK_USER", data_store); + if (stat(fname, &statbuf) != 0) { + fprintf(stderr, "Cannot find %s.\n", fname); + ret = -1; + goto done; + } + + memset(fname, 0, PATH_MAX); + snprintf(fname, PATH_MAX, "%s/TOK_OBJ/OBJ.IDX", data_store); + if (stat(fname, &statbuf) != 0) { + fprintf(stderr, "Cannot find %s.\n", fname); + ret = -1; + goto done; + } + + /* If the OBJ.IDX is empty, then no objects to migrate. */ + if (statbuf.st_size == 0) { + printf("OBJ.IDX file is empty. Thus no objects to migrate.\n"); + goto done; + } + + if (v_flag) + printf("%s has an MK_SO, MK_USER and TOK/OBJ.IDX\n", data_store); + /* Get the masterkey from MK_SO. + * This also helps verify that correct SO pin was entered. + */ + memset(masterkey, 0, MASTER_KEY_SIZE); + memset(fname, 0, PATH_MAX); + snprintf(fname, PATH_MAX, "%s/MK_SO", data_store); + ret = load_masterkey(fname, sopin, masterkey); + if (ret) { + fprintf(stderr, "Could not load masterkey from MK_SO.\n"); + goto done; + } + + if (v_flag) + printf("Successfully verified SO Pin.\n"); + + /* Get the masterkey from MK_USER. + * This also helps verift that correct USER pin was entered. + */ + memset(masterkey, 0, MASTER_KEY_SIZE); + memset(fname, 0, PATH_MAX); + snprintf(fname, PATH_MAX, "%s/MK_USER", data_store); + ret = load_masterkey(fname, userpin, masterkey); + if (ret) { + fprintf(stderr, "Could not load masterkey from MK_USER.\n"); + goto done; + } + + if (v_flag) + printf("Successfully verified USER Pin.\n"); + + /* Load all the private token objects and re-encrypt them + * using software des3, instead of CSNBENC. + * For private and public token objects, migrate the key object's + * attributes to IBM_OPAQUE. + */ + (void)load_token_objects(data_store, (CK_BYTE *)masterkey); + +done: + return ret; +} + +void usage(char *progname) +{ + printf(" Help:\t\t\t\t%s -h\n", progname); + printf(" -h\t\t\t\tShow this help\n\n"); + printf(" Migrate Object Version:\t%s -m v2objectsv3 [OPTIONS] \n", + progname); + printf(" -m v2objectsv3.\t\tMigrates CCA private token objects from"); + printf(" CCA\n\t\t\t\tencryption (used in v2) to software encryption"); + printf(" \n\t\t\t\t(used in v3). \n"); + printf(" Migrate Wrapped Keys:\t\t%s -m keys -s SLOTID -k KEYTYPE " + "[OPTIONS] \n", progname); + printf(" -m keys.\t\t\tUnwraps private keys with the"); + printf(" old CCA master\n\t\t\t\tkey and wraps them with the"); + printf(" new CCA master key\n"); + printf(" -s, --slotid SLOTID\t\tPKCS slot number\n"); + printf(" -k aes|apka|asym|sym\t\tMigrate selected keytype\n\n"); + printf(" Options:\n"); + printf(" -d, --datastore DATASTORE\tCCA token datastore location\n"); + printf(" -v, --verbose\t\t\tProvide more detailed output\n"); + printf(" \n\t\t\t\tthe migrated data\n\n"); + return; +} + +int main(int argc, char **argv) +{ + int ret = 0, opt = 0, c_flag = 0, masterkey = 0; + int data_store_len = 0; + CK_SLOT_ID slot_id = 0; + char *sopin = NULL, *userpin = NULL; + size_t sopinlen, userpinlen; + char *data_store = NULL; + char *m_type = NULL; + char *mk_type = NULL; + void *lib_csulcca; + + int m_version = 0; + int m_keys = 0; + + struct option long_opts[] = { + {"datastore", required_argument, NULL, 'd'}, + {"slotid", required_argument, NULL, 's'}, + {"verbose", no_argument, NULL, 'v'}, + {0, 0, 0, 0} + }; + + while ((opt = getopt_long(argc, argv, "m:d:s:k:hv", long_opts, NULL)) + != -1) { + switch (opt) { + case 'd': + data_store = strdup(optarg); + break; + case 'h': + usage(argv[0]); + return 0; + case 'k': + mk_type = strdup(optarg); + if (!memcmp(mk_type, "aes", 3)) { + masterkey = MK_AES; + } else if (!memcmp(mk_type, "apka", 4)) { + masterkey = MK_APKA; + } else if (!memcmp(mk_type, "asym", 4)) { + masterkey = MK_ASYM; + } else if (!memcmp(mk_type, "sym", 3)) { + masterkey = MK_SYM; + } else { + print_error("unknown key type (%s)\n", mk_type); + usage(argv[0]); + return -1; + } + break; + case 'm': + m_type = strdup(optarg); + if (!memcmp(m_type, "v2objectsv3", 11)) { + m_version = 1; + } else if (!memcmp(m_type, "keys", 4)) { + m_keys = 1; + } else { + print_error("unknown migration type (%s)\n", m_type); + usage(argv[0]); + return -1; + } + break; + case 's': + c_flag++; + slot_id = atoi(optarg); + break; + case 'v': + v_flag++; + break; + default: + usage(argv[0]); + return -1; + } + } + + /* check for missing parameters */ + if (!m_version && !m_keys) { + print_error("missing migration type\n"); + usage(argv[0]); + return -1; + } + + /* use default data_store if one is not given */ + if (data_store == NULL) { + data_store_len = strlen(TOK_DATASTORE); + data_store = malloc(data_store_len + 1); + if (data_store == NULL) { + fprintf(stderr, "malloc failed: %s\n", strerror(errno)); + return -1; + } + memset(data_store, 0, data_store_len + 1); + memcpy(data_store, TOK_DATASTORE, data_store_len); + } + + /* get the SO pin to authorize migration */ + printf("Enter the SO PIN: "); + fflush(stdout); + ret = get_pin(&sopin, &sopinlen); + if (ret != 0) { + print_error("Could not get SO PIN.\n"); + goto done; + } + + /* get the USER pin to authorize migration */ + printf("Enter the USER PIN: "); + fflush(stdout); + ret = get_pin(&userpin, &userpinlen); + if (ret != 0) { + print_error("Could not get USER PIN.\n"); + goto done; + } + + /* verify the SO and USER PINs entered. */ + ret = verify_pins(data_store, sopin, sopinlen, userpin, userpinlen); + if (ret) + goto done; + + lib_csulcca = dlopen(CCA_LIBRARY, (RTLD_GLOBAL | RTLD_NOW)); + if (lib_csulcca == NULL) { + fprintf(stderr, "dlopen(%s) failed: %s\n", CCA_LIBRARY, + strerror(errno)); + return -1; + } + + if (m_version) { + *(void **)(&CSNBDEC) = dlsym(lib_csulcca, "CSNBDEC"); + ret = migrate_version(sopin, userpin, (CK_BYTE *)data_store); + } else if (m_keys) { + if (!slot_id) { + print_error("missing slot number\n"); + usage(argv[0]); + return -1; + } + + if (!masterkey) { + print_error("missing key type\n"); + usage(argv[0]); + return -1; + } + + *(void **)(&CSNDKTC) = dlsym(lib_csulcca, "CSNDKTC"); + *(void **)(&CSNBKTC) = dlsym(lib_csulcca, "CSNBKTC"); + *(void **)(&CSNBKTC2) = dlsym(lib_csulcca, "CSNBKTC2"); + ret = migrate_wrapped_keys(slot_id, userpin, masterkey); + } + +done: + if (sopin) + free(sopin); + if (userpin) + free(userpin); + if (data_store) + free(data_store); + + return ret; +} + +char *p11strerror(CK_RV rc) +{ + switch (rc) { + case CKR_OK: + return "CKR_OK"; + case CKR_CANCEL: + return "CKR_CANCEL"; + case CKR_HOST_MEMORY: + return "CKR_HOST_MEMORY"; + case CKR_SLOT_ID_INVALID: + return "CKR_SLOT_ID_INVALID"; + case CKR_GENERAL_ERROR: + return "CKR_GENERAL_ERROR"; + case CKR_FUNCTION_FAILED: + return "CKR_FUNCTION_FAILED"; + case CKR_ARGUMENTS_BAD: + return "CKR_ARGUMENTS_BAD"; + case CKR_NO_EVENT: + return "CKR_NO_EVENT"; + case CKR_NEED_TO_CREATE_THREADS: + return "CKR_NEED_TO_CREATE_THREADS"; + case CKR_CANT_LOCK: + return "CKR_CANT_LOCK"; + case CKR_ATTRIBUTE_READ_ONLY: + return "CKR_ATTRIBUTE_READ_ONLY"; + case CKR_ATTRIBUTE_SENSITIVE: + return "CKR_ATTRIBUTE_SENSITIVE"; + case CKR_ATTRIBUTE_TYPE_INVALID: + return "CKR_ATTRIBUTE_TYPE_INVALID"; + case CKR_ATTRIBUTE_VALUE_INVALID: + return "CKR_ATTRIBUTE_VALUE_INVALID"; + case CKR_DATA_INVALID: + return "CKR_DATA_INVALID"; + case CKR_DATA_LEN_RANGE: + return "CKR_DATA_LEN_RANGE"; + case CKR_DEVICE_ERROR: + return "CKR_DEVICE_ERROR"; + case CKR_DEVICE_MEMORY: + return "CKR_DEVICE_MEMORY"; + case CKR_DEVICE_REMOVED: + return "CKR_DEVICE_REMOVED"; + case CKR_ENCRYPTED_DATA_INVALID: + return "CKR_ENCRYPTED_DATA_INVALID"; + case CKR_ENCRYPTED_DATA_LEN_RANGE: + return "CKR_ENCRYPTED_DATA_LEN_RANGE"; + case CKR_FUNCTION_CANCELED: + return "CKR_FUNCTION_CANCELED"; + case CKR_FUNCTION_NOT_PARALLEL: + return "CKR_FUNCTION_NOT_PARALLEL"; + case CKR_FUNCTION_NOT_SUPPORTED: + return "CKR_FUNCTION_NOT_SUPPORTED"; + case CKR_KEY_HANDLE_INVALID: + return "CKR_KEY_HANDLE_INVALID"; + case CKR_KEY_SIZE_RANGE: + return "CKR_KEY_SIZE_RANGE"; + case CKR_KEY_TYPE_INCONSISTENT: + return "CKR_KEY_TYPE_INCONSISTENT"; + case CKR_KEY_NOT_NEEDED: + return "CKR_KEY_NOT_NEEDED"; + case CKR_KEY_CHANGED: + return "CKR_KEY_CHANGED"; + case CKR_KEY_NEEDED: + return "CKR_KEY_NEEDED"; + case CKR_KEY_INDIGESTIBLE: + return "CKR_KEY_INDIGESTIBLE"; + case CKR_KEY_FUNCTION_NOT_PERMITTED: + return "CKR_KEY_FUNCTION_NOT_PERMITTED"; + case CKR_KEY_NOT_WRAPPABLE: + return "CKR_KEY_NOT_WRAPPABLE"; + case CKR_KEY_UNEXTRACTABLE: + return "CKR_KEY_UNEXTRACTABLE"; + case CKR_MECHANISM_INVALID: + return "CKR_MECHANISM_INVALID"; + case CKR_MECHANISM_PARAM_INVALID: + return "CKR_MECHANISM_PARAM_INVALID"; + case CKR_OBJECT_HANDLE_INVALID: + return "CKR_OBJECT_HANDLE_INVALID"; + case CKR_OPERATION_ACTIVE: + return "CKR_OPERATION_ACTIVE"; + case CKR_OPERATION_NOT_INITIALIZED: + return "CKR_OPERATION_NOT_INITIALIZED"; + case CKR_PIN_INCORRECT: + return "CKR_PIN_INCORRECT"; + case CKR_PIN_INVALID: + return "CKR_PIN_INVALID"; + case CKR_PIN_LEN_RANGE: + return "CKR_PIN_LEN_RANGE"; + case CKR_PIN_EXPIRED: + return "CKR_PIN_EXPIRED"; + case CKR_PIN_LOCKED: + return "CKR_PIN_LOCKED"; + case CKR_SESSION_CLOSED: + return "CKR_SESSION_CLOSED"; + case CKR_SESSION_COUNT: + return "CKR_SESSION_COUNT"; + case CKR_SESSION_HANDLE_INVALID: + return "CKR_SESSION_HANDLE_INVALID"; + case CKR_SESSION_PARALLEL_NOT_SUPPORTED: + return "CKR_SESSION_PARALLEL_NOT_SUPPORTED"; + case CKR_SESSION_READ_ONLY: + return "CKR_SESSION_READ_ONLY"; + case CKR_SESSION_EXISTS: + return "CKR_SESSION_EXISTS"; + case CKR_SESSION_READ_ONLY_EXISTS: + return "CKR_SESSION_READ_ONLY_EXISTS"; + case CKR_SESSION_READ_WRITE_SO_EXISTS: + return "CKR_SESSION_READ_WRITE_SO_EXISTS"; + case CKR_SIGNATURE_INVALID: + return "CKR_SIGNATURE_INVALID"; + case CKR_SIGNATURE_LEN_RANGE: + return "CKR_SIGNATURE_LEN_RANGE"; + case CKR_TEMPLATE_INCOMPLETE: + return "CKR_TEMPLATE_INCOMPLETE"; + case CKR_TEMPLATE_INCONSISTENT: + return "CKR_TEMPLATE_INCONSISTENT"; + case CKR_TOKEN_NOT_PRESENT: + return "CKR_TOKEN_NOT_PRESENT"; + case CKR_TOKEN_NOT_RECOGNIZED: + return "CKR_TOKEN_NOT_RECOGNIZED"; + case CKR_TOKEN_WRITE_PROTECTED: + return "CKR_TOKEN_WRITE_PROTECTED"; + case CKR_UNWRAPPING_KEY_HANDLE_INVALID: + return "CKR_UNWRAPPING_KEY_HANDLE_INVALID"; + case CKR_UNWRAPPING_KEY_SIZE_RANGE: + return "CKR_UNWRAPPING_KEY_SIZE_RANGE"; + case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT: + return "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT"; + case CKR_USER_ALREADY_LOGGED_IN: + return "CKR_USER_ALREADY_LOGGED_IN"; + case CKR_USER_NOT_LOGGED_IN: + return "CKR_USER_NOT_LOGGED_IN"; + case CKR_USER_PIN_NOT_INITIALIZED: + return "CKR_USER_PIN_NOT_INITIALIZED"; + case CKR_USER_TYPE_INVALID: + return "CKR_USER_TYPE_INVALID"; + case CKR_USER_ANOTHER_ALREADY_LOGGED_IN: + return "CKR_USER_ANOTHER_ALREADY_LOGGED_IN"; + case CKR_USER_TOO_MANY_TYPES: + return "CKR_USER_TOO_MANY_TYPES"; + case CKR_WRAPPED_KEY_INVALID: + return "CKR_WRAPPED_KEY_INVALID"; + case CKR_WRAPPED_KEY_LEN_RANGE: + return "CKR_WRAPPED_KEY_LEN_RANGE"; + case CKR_WRAPPING_KEY_HANDLE_INVALID: + return "CKR_WRAPPING_KEY_HANDLE_INVALID"; + case CKR_WRAPPING_KEY_SIZE_RANGE: + return "CKR_WRAPPING_KEY_SIZE_RANGE"; + case CKR_WRAPPING_KEY_TYPE_INCONSISTENT: + return "CKR_WRAPPING_KEY_TYPE_INCONSISTENT"; + case CKR_RANDOM_SEED_NOT_SUPPORTED: + return "CKR_RANDOM_SEED_NOT_SUPPORTED"; + case CKR_RANDOM_NO_RNG: + return "CKR_RANDOM_NO_RNG"; + case CKR_BUFFER_TOO_SMALL: + return "CKR_BUFFER_TOO_SMALL"; + case CKR_SAVED_STATE_INVALID: + return "CKR_SAVED_STATE_INVALID"; + case CKR_INFORMATION_SENSITIVE: + return "CKR_INFORMATION_SENSITIVE"; + case CKR_STATE_UNSAVEABLE: + return "CKR_STATE_UNSAVEABLE"; + case CKR_CRYPTOKI_NOT_INITIALIZED: + return "CKR_CRYPTOKI_NOT_INITIALIZED"; + case CKR_CRYPTOKI_ALREADY_INITIALIZED: + return "CKR_CRYPTOKI_ALREADY_INITIALIZED"; + case CKR_MUTEX_BAD: + return "CKR_MUTEX_BAD"; + case CKR_MUTEX_NOT_LOCKED: + return "CKR_MUTEX_NOT_LOCKED"; + default: + return "UNKNOWN"; + } + + return "UNKNOWN"; +} diff --git a/usr/sbin/pkcscca/pkcscca.h b/usr/sbin/pkcscca/pkcscca.h new file mode 100644 index 0000000..0ca3f7b --- /dev/null +++ b/usr/sbin/pkcscca/pkcscca.h @@ -0,0 +1,230 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2014-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 + */ + +/* + * pkcscca - A tool for PKCS#11 CCA token. + * Currently, only migrates CCA private token objects from using a + * CCA cipher to using a software cipher. + * + */ + +#ifndef __PKCSCCA_H_ +#define __PKCSCCA_H_ + +#include + +#define CCA_LIBRARY "libcsulcca.so" +#define TOK_DATASTORE CONFIG_PATH "/ccatok" +#define MASTER_KEY_SIZE 64 +#define SHA1_HASH_SIZE 20 +#define MD5_HASH_SIZE 16 +#define DES_BLOCK_SIZE 8 +#define DES_KEY_SIZE 8 +#define CCA_SUCCESS 0 + +#define AES_NAME "AES" +#define DES_NAME "DES" +#define DES2_NAME "2DES" +#define DES3_NAME "3DES" +#define ECC_NAME "ECC" +#define HMAC_NAME "HMAC" +#define RSA_NAME "RSA" +#define BAD_NAME "Unknown" + +#define MK_AES 1 +#define MK_APKA 2 +#define MK_ASYM 3 +#define MK_SYM 4 + +int compute_hash(int hash_type, int buf_size, char *buf, char *digest); + +#define compute_sha1(a,b,c) compute_hash(HASH_SHA1,b,a,c) +#define compute_md5(a,b,c) compute_hash(HASH_MD5,b,a,c) +#define HASH_SHA1 1 +#define HASH_MD5 2 + +CK_RV sw_des3_cbc(CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, CK_BYTE *, + CK_BYTE *, CK_BYTE); + +#define sw_des3_cbc_encrypt(clear, len, cipher, len2, iv, key) \ + sw_des3_cbc(clear, len, cipher, len2, iv, key, 1) + +#define sw_des3_cbc_decrypt(clear, len, cipher, len2, iv, key) \ + sw_des3_cbc(clear, len, cipher, len2, iv, key, 0) + +#define EVP_SUCCESS 1 +#define print_openssl_errors() \ + do { \ + ERR_load_crypto_strings(); \ + ERR_print_errors_fp(stderr); \ + } while (0) + +char *p11strerror(CK_RV); + +#define p11_error(s,rc) fprintf(stderr, "%s:%d %s failed: rc=0x%lX (%s)\n", \ + __FILE__, __LINE__, s, rc, p11strerror(rc)) + +static inline void _print_error(const char *file, int line, + const char *fmt, ...) { + char buf[512]; + size_t off; + va_list ap; + + snprintf(buf, sizeof(buf), "%s:%d ", file, line); + off = strlen("%s:%d "); + + va_start(ap, fmt); + vsnprintf(buf + off, sizeof(buf) - off, fmt, ap); + va_end(ap); + + fprintf(stderr, "%s", buf); +} +#define print_error(...) _print_error(__FILE__, __LINE__, __VA_ARGS__) + +#define cca_error(f,rc,rsn) fprintf(stderr, "%s:%d " f " failed. return code: "\ + "%ld, reason code: %ld\n", __FILE__, \ + __LINE__, rc, rsn) +#define print_hex(x, y) \ + do { \ + unsigned char *hex = x; \ + int i; \ + for (i = 0; i < y; i++) { \ + printf("%02x", hex[i]); \ + if (((i+1) % 32) == 0) \ + printf("\n"); \ + else if (((i+1) % 4) == 0) \ + printf(" "); \ + } \ + } while (0) + + +typedef struct _MASTER_KEY_FILE_T { + CK_BYTE key[MASTER_KEY_SIZE]; + CK_BYTE sha_hash[SHA1_HASH_SIZE]; +} MASTER_KEY_FILE_T; + +/* from host_defs.h */ +#include "pkcs32.h" +typedef struct _TWEAK_VEC { + int allow_weak_des; + int check_des_parity; + int allow_key_mods; + int netscape_mods; +} TWEAK_VEC; + +typedef struct _TOKEN_DATA_VERSION { + uint32_t version; /* major<<16|minor */ + /* --- PBKDF2 --- */ + /* SO login */ + uint64_t so_login_it; + unsigned char so_login_salt[64]; + unsigned char so_login_key[32]; + /* User login */ + uint64_t user_login_it; + unsigned char user_login_salt[64]; + unsigned char user_login_key[32]; + /* SO MK wrap */ + uint64_t so_wrap_it; + unsigned char so_wrap_salt[64]; + /* User MK wrap */ + uint64_t user_wrap_it; + unsigned char user_wrap_salt[64]; +} TOKEN_DATA_VERSION; + +typedef struct _TOKEN_DATA { + CK_TOKEN_INFO_32 token_info; + + CK_BYTE user_pin_sha[3 * DES_BLOCK_SIZE]; + CK_BYTE so_pin_sha[3 * DES_BLOCK_SIZE]; + CK_BYTE next_token_object_name[8]; + TWEAK_VEC tweak_vector; + + /* new for tokversion >= 3.12 */ + TOKEN_DATA_VERSION dat; +} TOKEN_DATA; + +typedef struct _TOKEN_DATA_OLD { + CK_TOKEN_INFO_32 token_info; + + CK_BYTE user_pin_sha[3 * DES_BLOCK_SIZE]; + CK_BYTE so_pin_sha[3 * DES_BLOCK_SIZE]; + CK_BYTE next_token_object_name[8]; + TWEAK_VEC tweak_vector; +} TOKEN_DATA_OLD; + +struct key { + CK_OBJECT_HANDLE handle; + CK_ULONG type; + CK_BYTE *opaque_attr; + CK_ULONG attr_len; + CK_CHAR_PTR label; + + struct key *next; +}; + +struct algo { + unsigned char *rule_array; + unsigned char *name; + long rule_array_count; +}; + +struct key_count { + int aes; + int des; + int des2; + int des3; + int ecc; + int hmac; + int rsa; +}; + +typedef struct _DL_NODE +{ + struct _DL_NODE *next; + struct _DL_NODE *prev; + void *data; +} DL_NODE; + +typedef struct _TEMPLATE +{ + DL_NODE *attribute_list; +} TEMPLATE; + +typedef void *SESSION; + +typedef struct _OBJECT +{ + CK_OBJECT_CLASS class; + CK_BYTE name[8]; // for token objects + + SESSION *session; // creator; only for session objects + TEMPLATE *template; + CK_ULONG count_hi; // only significant for token objects + CK_ULONG count_lo; // only significant for token objects + CK_ULONG index; // SAB Index into the SHM + CK_OBJECT_HANDLE map_handle; +} OBJECT; + +struct secaeskeytoken { + unsigned char type; /* 0x01 for internal key token */ + unsigned char res0[3]; + unsigned char version; /* should be 0x04 */ + unsigned char res1[1]; + unsigned char flag; /* key flags */ + unsigned char res2[1]; + unsigned long mkvp; /* master key verification pattern */ + unsigned char key[32]; /* key value (encrypted) */ + unsigned char cv[8]; /* control vector */ + unsigned short bitsize; /* key bit size */ + unsigned short keysize; /* key byte size */ + unsigned char tvv[4]; /* token validation value */ +} __packed; + +#endif diff --git a/usr/sbin/pkcscca/pkcscca.mk b/usr/sbin/pkcscca/pkcscca.mk new file mode 100644 index 0000000..9f3253b --- /dev/null +++ b/usr/sbin/pkcscca/pkcscca.mk @@ -0,0 +1,13 @@ +sbin_PROGRAMS += usr/sbin/pkcscca/pkcscca +noinst_HEADERS += usr/sbin/pkcscca/pkcscca.h + +usr_sbin_pkcscca_pkcscca_LDFLAGS = -lcrypto -ldl + +usr_sbin_pkcscca_pkcscca_CFLAGS = \ + -DSTDLL_NAME=\"pkcscca\" \ + -I${srcdir}/usr/include -I${srcdir}/usr/lib/common \ + -I${srcdir}/usr/sbin/pkcscca + +usr_sbin_pkcscca_pkcscca_SOURCES = \ + usr/lib/common/p11util.c usr/lib/common/sw_crypt.c \ + usr/lib/common/trace.c usr/sbin/pkcscca/pkcscca.c diff --git a/usr/sbin/pkcsconf/pkcsconf.c b/usr/sbin/pkcsconf/pkcsconf.c new file mode 100644 index 0000000..a164183 --- /dev/null +++ b/usr/sbin/pkcsconf/pkcsconf.c @@ -0,0 +1,1195 @@ +/* + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "slotmgr.h" +#include "pkcsconf_msg.h" +#include "p11util.h" +#include "defs.h" + +#define LEEDS_DEFAULT_PIN "87654321" +#define PIN_SIZE 80 +#define BACK_SPACE 8 +#define DELETE 127 +#define LINE_FEED 10 + +#define CFG_SO_PIN 0x0001 +#define CFG_USER_PIN 0x0002 +#define CFG_SLOT 0x0004 +#define CFG_PKCS_INFO 0x0008 +#define CFG_TOKEN_INFO 0x0010 +#define CFG_SLOT_INFO 0x0020 +#define CFG_MECHANISM_INFO 0x0040 +#define CFG_INITIALIZE 0x0080 +#define CFG_INIT_USER 0x0100 +#define CFG_SET_USER 0x0200 +#define CFG_SET_SO 0x0400 +#define CFG_NEW_PIN 0x0800 +#define CFG_SHARED_MEM 0x1000 +#define CFG_LIST_SLOT 0x2000 + +CK_RV init(void); +void usage(char *); +int echo(int); +int get_pin(CK_CHAR **); +int get_slot(char *); +CK_RV cleanup(void); +CK_RV display_pkcs11_info(void); +CK_RV get_slot_list(void); +CK_RV display_slot_info(int); +CK_RV display_token_info(int); +CK_RV display_mechanism_info(int); +CK_RV init_token(int, CK_CHAR_PTR); +CK_RV init_user_pin(int, CK_CHAR_PTR, CK_CHAR_PTR); +CK_RV list_slot(int); +CK_RV set_user_pin(int, CK_USER_TYPE, CK_CHAR_PTR, CK_CHAR_PTR); + +void *dllPtr; +CK_FUNCTION_LIST_PTR FunctionPtr = NULL; +CK_SLOT_ID_PTR SlotList = NULL; +CK_ULONG SlotCount = 0; +Slot_Mgr_Shr_t *shmp = NULL; +int in_slot; + +int main(int argc, char *argv[]) +{ + CK_RV rv = CKR_OK; // Return Code + CK_FLAGS flags = 0; // Bit mask for what options were passed in + CK_CHAR_PTR sopin = NULL, // The Security Office PIN + pin = NULL, // The User PIN + newpin = NULL, // To store PIN changes + newpin2 = NULL; // To store validation of PIN change + + int c, // To store passed in options + newpinlen, newpin2len, errflag = 0; // Error Flag + + /* Parse the command line parameters */ + while ((c = getopt(argc, argv, "itsmIc:S:U:upPn:lh")) != (-1)) { + switch (c) { + case 'c': /* a specific card (slot) is specified */ + if (flags & CFG_SLOT) { + printf("Must specify a single slot.\n"); + fflush(stdout); + errflag++; + } else { + flags |= CFG_SLOT; + in_slot = get_slot(optarg); + if (in_slot < 0) { + printf("Must specify a decimal number as slot.\n"); + errflag++; + } + } + break; + case 'S': /* the SO pin */ + if (flags & CFG_SO_PIN) { + printf("Must specify a single SO PIN.\n"); + fflush(stdout); + errflag++; + } else { + flags |= CFG_SO_PIN; + sopin = (CK_CHAR_PTR) malloc(strlen(optarg) + 1); + memcpy(sopin, optarg, strlen(optarg) + 1); + } + break; + case 'U': /* the user pin */ + if (flags & CFG_USER_PIN) { + printf("Must specify a single user PIN.\n"); + fflush(stdout); + errflag++; + } else { + flags |= CFG_USER_PIN; + pin = (CK_CHAR_PTR) malloc(strlen(optarg) + 1); + memcpy(pin, optarg, strlen(optarg) + 1); + } + break; + case 'n': /* the new pin */ + if (flags & CFG_NEW_PIN) { + printf("Must specify a single new PIN.\n"); + fflush(stdout); + errflag++; + } else { + flags |= CFG_NEW_PIN; + newpin = (CK_CHAR_PTR) malloc(strlen(optarg) + 1); + memcpy(newpin, optarg, strlen(optarg) + 1); + } + break; + case 'i': /* display PKCS11 info */ + flags |= CFG_PKCS_INFO; + break; + case 't': /* display token info */ + flags |= CFG_TOKEN_INFO; + break; + case 's': /* display slot info */ + flags |= CFG_SLOT_INFO; + break; + case 'm': /* display mechanism info */ + flags |= CFG_MECHANISM_INFO; + break; + case 'I': /* initialize the token */ + flags |= CFG_INITIALIZE; + break; + case 'u': /* initialize the user PIN */ + flags |= CFG_INIT_USER; + break; + case 'p': /* set the user PIN */ + flags |= CFG_SET_USER; + break; + case 'P': /* set the SO PIN */ + flags |= CFG_SET_SO; + break; + case 'l': /* display slot description */ + flags |= CFG_LIST_SLOT; + break; + case 'h': /* display command line options */ + usage(argv[0]); + break; + default: /* if something else was passed in it's an error */ + errflag++; + break; + } + } + if (errflag != 0) /* If there was an error print the usage statement */ + usage(argv[0]); + + if (!flags) /* If there was no options print the usage statement */ + usage(argv[0]); + + /* Eliminate the ability to specify -I -p -u -P without a slot number */ + if ((flags & (CFG_INITIALIZE | CFG_INIT_USER | CFG_SET_USER | CFG_SET_SO)) + && !(flags & CFG_SLOT)) { + usage(argv[0]); + } + /* Load the PKCS11 library and start the slotmanager if it is not running */ + if (init() != CKR_OK) { + rv = CKR_FUNCTION_FAILED; + goto done; + } + + /* Get the slot list and indicate if a slot number was passed in or not */ + if ((rv = get_slot_list())) + goto done; + + /* If the user tries to set the user and SO pin at the same time print an + * error massage and exit indicating the function failed */ + if ((flags & CFG_SET_USER) && (flags & CFG_SET_SO)) { + printf("Setting the SO and user PINs are mutually exclusive.\n"); + fflush(stdout); + rv = CKR_FUNCTION_FAILED; + goto done; + } + + /* If the user wants to display PKCS11 info call the function to do so */ + if (flags & CFG_PKCS_INFO) + if ((rv = display_pkcs11_info())) + goto done; + + /* If the user wants to display token info call the function to do so */ + if (flags & CFG_TOKEN_INFO) + if ((rv = display_token_info((flags & CFG_SLOT) ? in_slot : -1))) + goto done; + + /* If the user wants to display slot info call the function to do so */ + if (flags & CFG_SLOT_INFO) + if ((rv = display_slot_info((flags & CFG_SLOT) ? in_slot : -1))) + goto done; + + /* If the user wants to display slot info call the function to do so */ + if (flags & CFG_LIST_SLOT) + if ((rv = list_slot((flags & CFG_SLOT) ? in_slot : -1))) + goto done; + + /* If the user wants to display mechanism info call the function to do so */ + if (flags & CFG_MECHANISM_INFO) + if ((rv = display_mechanism_info((flags & CFG_SLOT) ? in_slot : -1))) + goto done; + + /* If the user wants to initialize the card check to see if they passed in + * the SO pin, if not ask for the PIN */ + if (flags & CFG_INITIALIZE) { + if (flags & CFG_SLOT) { + if (~flags & CFG_SO_PIN) { + int rc; + do { + printf("Enter the SO PIN: "); + fflush(stdout); + rc = get_pin(&(sopin)); + } while (rc == -EINVAL); + } + rv = init_token(in_slot, sopin); + } else { + printf("Must specify one slot"); + fflush(stdout); + rv = CKR_FUNCTION_FAILED; + } + } + + /* If the user wants to initialize the User PIN, check to see if they have + * passed in the SO PIN, if not ask for it. Then check to see if they + * passed the New User PIN on the command line if not ask for the PIN and + * verify it + */ + if (flags & CFG_INIT_USER) { + if (flags & CFG_SLOT) { + if (~flags & CFG_SO_PIN) { + int rc; + + do { + printf("Enter the SO PIN: "); + fflush(stdout); + rc = get_pin(&sopin); + } while (rc == -EINVAL); + } + if (~flags & CFG_NEW_PIN) { + int rc; + + do { + printf("Enter the new user PIN: "); + fflush(stdout); + rc = get_pin(&newpin); + } while (rc == -EINVAL); + newpinlen = strlen((char *) newpin); + do { + printf("Re-enter the new user PIN: "); + fflush(stdout); + rc = get_pin(&newpin2); + } while (rc == -EINVAL); + newpin2len = strlen((char *) newpin2); + if (newpinlen != newpin2len + || memcmp(newpin, newpin2, strlen((char *) newpin)) != 0) { + printf("New PINs do not match.\n"); + fflush(stdout); + exit(CKR_PIN_INVALID); + } + } + rv = init_user_pin(in_slot, newpin, sopin); + } else { + printf("Must specify one slot"); + fflush(stdout); + rv = CKR_FUNCTION_FAILED; + } + } + + /* If the user wants to set the SO PIN, check to see if they have passed the + * current SO PIN and the New PIN in. If not prompt and validate them. */ + if (flags & CFG_SET_SO) { + if (flags & CFG_SLOT) { + if (~flags & CFG_SO_PIN) { + int rc; + + do { + printf("Enter the SO PIN: "); + fflush(stdout); + rc = get_pin(&sopin); + } while (rc == -EINVAL); + } + if (~flags & CFG_NEW_PIN) { + int rc; + + do { + printf("Enter the new SO PIN: "); + fflush(stdout); + rc = get_pin(&newpin); + } while (rc == -EINVAL); + newpinlen = strlen((char *) newpin); + do { + printf("Re-enter the new SO PIN: "); + fflush(stdout); + rc = get_pin(&newpin2); + } while (rc == -EINVAL); + newpin2len = strlen((char *) newpin2); + if (newpinlen != newpin2len + || memcmp(newpin, newpin2, strlen((char *) newpin)) != 0) { + printf("New PINs do not match.\n"); + fflush(stdout); + exit(CKR_PIN_INVALID); + } + } + rv = set_user_pin(in_slot, CKU_SO, sopin, newpin); + } else { + printf("Must specify one slot"); + fflush(stdout); + rv = CKR_FUNCTION_FAILED; + } + } + + /* If the user wants to set the User PIN, check to see if they have passed + * the current User PIN and the New PIN in. If not prompt and validate them. + */ + if (flags & CFG_SET_USER) { + if (flags & CFG_SLOT) { + if (~flags & CFG_USER_PIN) { + int rc; + + do { + printf("Enter user PIN: "); + fflush(stdout); + rc = get_pin(&pin); + } while (rc == -EINVAL); + } + if (~flags & CFG_NEW_PIN) { + int rc; + + do { + printf("Enter the new user PIN: "); + fflush(stdout); + rc = get_pin(&newpin); + } while (rc == -EINVAL); + newpinlen = strlen((char *) newpin); + do { + printf("Re-enter the new user PIN: "); + fflush(stdout); + rc = get_pin(&newpin2); + } while (rc == -EINVAL); + newpin2len = strlen((char *) newpin2); + if (newpinlen != newpin2len + || memcmp(newpin, newpin2, strlen((char *) newpin)) != 0) { + printf("New PINs do not match.\n"); + fflush(stdout); + exit(CKR_PIN_INVALID); + } + } + rv = set_user_pin(in_slot, CKU_USER, pin, newpin); + } else { + printf("Must specify one slot"); + fflush(stdout); + rv = CKR_FUNCTION_FAILED; + } + } + + /* We are done, detach from shared memory, and free the memory we may have + * allocated. In the case of PIN's we use cleanse to ensure that they are + * not left around in system memory*/ + +done: + if (sopin) { + OPENSSL_cleanse(sopin, strlen((char *) sopin)); + free(sopin); + } + + if (pin) { + OPENSSL_cleanse(pin, strlen((char *) pin)); + free(pin); + } + + if (newpin) { + OPENSSL_cleanse(newpin, strlen((char *) newpin)); + free(newpin); + } + + if (newpin2) { + OPENSSL_cleanse(newpin2, strlen((char *) newpin2)); + free(newpin2); + } + + return rv == CKR_OK ? 0 : -1; +} + +int get_pin(CK_CHAR **pin) +{ + int count; + char buff[PIN_SIZE] = { 0 }, c = 0; + int rc = 0; + + *pin = NULL; + /* Turn off echoing to the terminal when getting the password */ + echo(FALSE); + /* Get each character and print out a '*' for each input */ + for (count = 0; (c != LINE_FEED) && (count < PIN_SIZE);) { + buff[count] = getc(stdin); + c = buff[count]; + if (c == BACK_SPACE || c == DELETE) { + if (count) + count--; + continue; + } + fflush(stdout); + count++; + } + echo(TRUE); + /* After we get the password go to the next line */ + printf("\n"); + fflush(stdout); + /* Allocate 80 bytes for the user PIN. This is large enough + * for the tokens supported in AIX 5.0 and 5.1 */ + *pin = (unsigned char *) malloc(PIN_SIZE); + if (!(*pin)) { + rc = -ENOMEM; + goto out; + } + /* Strip the carage return from the user input (it is not part + * of the PIN) and put the PIN in the return buffer */ + buff[count - 1] = '\0'; + /* keep the trailing null for the strlen */ + strncpy((char *) *pin, buff, PIN_SIZE); +out: + return rc; +} + +int get_slot(char *optarg) +{ + char *endptr; + long val; + + errno = 0; + val = strtol(optarg, &endptr, 10); + + /* Check for various possible errors */ + if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) + || (errno != 0 && val == 0)) { + perror("strtol"); + return -1; + } + + /* No digits were found in optarg, so return error */ + if (endptr == optarg) + return -1; + + /* Invalid slot id */ + if (val < INT_MIN || val >= NUMBER_SLOTS_MANAGED) + return -1; + + return (int)val; +} + +int echo(int bool) +{ + struct termios term; + + /* flush standard out to make sure everything that needs to be displayed has + * been displayed */ + fflush(stdout); + + /* get the current terminal attributes */ + if (tcgetattr(STDIN_FILENO, &term) != 0) + return -1; + + /* Since we are calling this function we must want to read in a char at a + * time. Therefore set the cc structure before setting the terminal attrs + */ + term.c_cc[VMIN] = 1; + term.c_cc[VTIME] = 0; + + /* If we are turning off the display of input characters AND with the + * inverse of the ECHO mask, if we are turning on the display OR with the + * ECHO mask. + * We also set if we are reading in canonical or noncanonical mode. */ + if (bool) + term.c_lflag |= (ECHO | ICANON); + else + term.c_lflag &= ~(ECHO | ICANON); + + /* Set the attributes, and flush the streams so that any input already + * displayed on the terminal is invalid */ + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &term) != 0) + return -1; + + return 0; +} + +CK_RV check_user_and_group(void) +{ + int i; + uid_t uid, euid; + struct passwd *pw, *epw; + struct group *grp; + + /* + * Check for root user or Group PKCS#11 Membershp. + * Only these are allowed. + */ + uid = getuid(); + euid = geteuid(); + + /* Root or effective Root is ok */ + if (uid == 0 || euid == 0) + return CKR_OK; + + /* + * Check for member of group. SAB get login seems to not work + * with some instances of application invocations (particularly + * 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"); + if (grp == NULL) { + return CKR_FUNCTION_FAILED; + } + + if (getgid() == grp->gr_gid || getegid() == grp->gr_gid) + return CKR_OK; + + /* Check if user or effective user is member of pkcs11 group */ + pw = getpwuid(uid); + epw = getpwuid(euid); + for (i = 0; grp->gr_mem[i]; i++) { + if ((pw && (strncmp(pw->pw_name, grp->gr_mem[i], + strlen(pw->pw_name)) == 0)) || + (epw && (strncmp(epw->pw_name, grp->gr_mem[i], + strlen(epw->pw_name)) == 0))) + return CKR_OK; + } + + return CKR_FUNCTION_FAILED; +} + +CK_RV display_pkcs11_info(void) +{ + + CK_RV rc; + CK_INFO CryptokiInfo; + + /* Get the PKCS11 infomation structure and if fails print message */ + rc = FunctionPtr->C_GetInfo(&CryptokiInfo); + if (rc != CKR_OK) { + printf("Error getting PKCS#11 info: 0x%lX (%s)\n", rc, p11_get_ckr(rc)); + return rc; + } + + /* display the header and information */ + printf("PKCS#11 Info\n"); + printf("\tVersion %d.%d \n", CryptokiInfo.cryptokiVersion.major, + CryptokiInfo.cryptokiVersion.minor); + printf("\tManufacturer: %.32s \n", CryptokiInfo.manufacturerID); + printf("\tFlags: 0x%lX \n", CryptokiInfo.flags); + printf("\tLibrary Description: %.32s \n", CryptokiInfo.libraryDescription); + printf("\tLibrary Version: %d.%d \n", CryptokiInfo.libraryVersion.major, + CryptokiInfo.libraryVersion.minor); + + return rc; +} + +CK_RV get_slot_list() +{ + CK_RV rc; // Return Code + + /* Find out how many tokens are present in slots */ + rc = FunctionPtr->C_GetSlotList(TRUE, NULL_PTR, &SlotCount); + if (rc != CKR_OK) { + printf("Error getting number of slots: 0x%lX (%s)\n", rc, + p11_get_ckr(rc)); + return rc; + } + + if (SlotCount == 0) { + printf("C_GetSlotList returned 0 slots. Check that your tokens" + " are installed correctly.\n"); + return -ENODEV; + } + + /* Allocate enough space for the slots information */ + SlotList = (CK_SLOT_ID_PTR) malloc(SlotCount * sizeof(CK_SLOT_ID)); + + rc = FunctionPtr->C_GetSlotList(TRUE, SlotList, &SlotCount); + if (rc != CKR_OK) { + printf("Error getting slot list: 0x%lX (%s)\n", rc, p11_get_ckr(rc)); + return rc; + } + + return CKR_OK; +} + +void display_mechanism_name(CK_MECHANISM_TYPE mech) +{ + CK_ULONG i; + + for (i = 0; pkcs11_mech_list[i].name; i++) { + if (pkcs11_mech_list[i].mech == mech) { + printf("(%s)", pkcs11_mech_list[i].name); + return; + } + } +} + +void display_mechanism_flags(CK_FLAGS flags) +{ + CK_ULONG i, firsties = 1; + char *tok = "("; + + for (i = 0; pkcs11_mech_flags[i].name; i++) { + if (pkcs11_mech_flags[i].flag & flags) { + printf("%s%s", tok, pkcs11_mech_flags[i].name); + + if (firsties) { + tok = "|"; + firsties = 0; + } + } + } + + if (!firsties) + printf(")"); +} + +CK_RV print_mech_info(int slot_id) +{ + CK_RV rc; // Return Code + CK_MECHANISM_TYPE_PTR MechanismList = NULL; // Head to Mechanism list + CK_MECHANISM_INFO MechanismInfo; // Structure to hold Mechanism Info + CK_ULONG MechanismCount = 0; // Number of supported mechanisms + unsigned int i; + + /* For each slot find out how many mechanisms are supported */ + rc = FunctionPtr->C_GetMechanismList(slot_id, NULL_PTR, &MechanismCount); + if (rc != CKR_OK) { + printf("Error getting number of mechanisms: 0x%lX (%s)\n", + rc, p11_get_ckr(rc)); + return rc; + } + + /* Allocate enough memory to store all the supported mechanisms */ + MechanismList = (CK_MECHANISM_TYPE_PTR) malloc(MechanismCount * + sizeof(CK_MECHANISM_TYPE)); + + /* This time get the mechanism list */ + rc = FunctionPtr->C_GetMechanismList(slot_id, MechanismList, + &MechanismCount); + if (rc != CKR_OK) { + printf("Error getting mechanisms list: 0x%lX (%s)\n", rc, + p11_get_ckr(rc)); + return rc; + } + + /* For each Mechanism in the List */ + for (i = 0; i < MechanismCount; i++) { + + /* Get the Mechanism Info and display it */ + rc = FunctionPtr->C_GetMechanismInfo(slot_id, + MechanismList[i], &MechanismInfo); + if (rc != CKR_OK) { + printf("Error getting mechanisms info: 0x%lX (%s)\n", rc, + p11_get_ckr(rc)); + return rc; + } + printf("Mechanism #%d\n", i); + printf("\tMechanism: 0x%lX ", MechanismList[i]); + + display_mechanism_name(MechanismList[i]); + printf("\n"); + + printf("\tKey Size: %lu-%lu\n", MechanismInfo.ulMinKeySize, + MechanismInfo.ulMaxKeySize); + printf("\tFlags: 0x%lX ", MechanismInfo.flags); + + display_mechanism_flags(MechanismInfo.flags); + printf("\n"); + } + + /* Free the memory we allocated for the mechanism list */ + free(MechanismList); + return CKR_OK; +} + +CK_RV display_mechanism_info(int slot_id) +{ + CK_ULONG lcv; + + if (slot_id == -1) { + for (lcv = 0; lcv < SlotCount; lcv++) { + printf("Mechanism Info for Slot #%lu:\n", SlotList[lcv]); + print_mech_info(SlotList[lcv]); + } + } else { + return print_mech_info(slot_id); + } + + return CKR_OK; +} + +void print_slot_info(int slot_id, CK_SLOT_INFO *SlotInfo) +{ + /* Display the slot information */ + printf("Slot #%d Info\n", slot_id); + printf("\tDescription: %.64s\n", SlotInfo->slotDescription); + printf("\tManufacturer: %.32s\n", SlotInfo->manufacturerID); + printf("\tFlags: 0x%lX (", SlotInfo->flags); + + if (SlotInfo->flags & CKF_TOKEN_PRESENT) + printf("TOKEN_PRESENT|"); + if (SlotInfo->flags & CKF_REMOVABLE_DEVICE) + printf("REMOVABLE_DEVICE|"); + if (SlotInfo->flags & CKF_HW_SLOT) + printf("HW_SLOT|"); + printf(")\n"); + + printf("\tHardware Version: %d.%d\n", SlotInfo->hardwareVersion.major, + SlotInfo->hardwareVersion.minor); + printf("\tFirmware Version: %d.%d\n", SlotInfo->firmwareVersion.major, + SlotInfo->firmwareVersion.minor); +} + +CK_RV display_slot_info(int slot_id) +{ + CK_RV rc; // Return Code + CK_SLOT_INFO SlotInfo; // Structure to hold slot information + unsigned int lcv; // Loop control Variable + + if (slot_id != -1) { + rc = FunctionPtr->C_GetSlotInfo(slot_id, &SlotInfo); + if (rc != CKR_OK) { + printf("Error getting slot info: 0x%lX (%s) \n", rc, + p11_get_ckr(rc)); + return rc; + } + + print_slot_info(slot_id, &SlotInfo); + return CKR_OK; + } + + for (lcv = 0; lcv < SlotCount; lcv++) { + /* Get the info for the slot we are examining and store in SlotInfo */ + rc = FunctionPtr->C_GetSlotInfo(SlotList[lcv], &SlotInfo); + if (rc != CKR_OK) { + printf("Error getting slot info: 0x%lX (%s) \n", rc, + p11_get_ckr(rc)); + return rc; + } + + print_slot_info(SlotList[lcv], &SlotInfo); + + } + return CKR_OK; +} + +CK_RV list_slot(int slot_id) +{ + CK_RV rc; // Return code + CK_SLOT_INFO SlotInfo; // Structure to hold slot information + unsigned int lcv; // Loop control variable + + if (slot_id != -1) { + rc = FunctionPtr->C_GetSlotInfo(slot_id, &SlotInfo); + if (rc != CKR_OK) { + printf("Error getting slot info: 0x%lX (%s)\n", rc, + p11_get_ckr(rc)); + return rc; + } + + /* Display the slot description */ + printf("%d:", slot_id); + printf("\tDescription: %.64s\n", SlotInfo.slotDescription); + + return CKR_OK; + } + + + for (lcv = 0; lcv < SlotCount; lcv++) { + /* Get the info for the slot we are examining and store in SlotInfo */ + rc = FunctionPtr->C_GetSlotInfo(SlotList[lcv], &SlotInfo); + if (rc != CKR_OK) { + printf("Error getting slot info: 0x%lX (%s)\n", rc, + p11_get_ckr(rc)); + return rc; + } + + /* Display the slot description */ + printf("%ld:", SlotList[lcv]); + printf("\tDescription: %.64s\n", SlotInfo.slotDescription); + } + return CKR_OK; +} + +static void print_value(CK_ULONG value, char *buf, CK_ULONG buf_len, + CK_BBOOL check_infinite, char *fmt) +{ + if (value == CK_UNAVAILABLE_INFORMATION) + strncpy(buf, "[information unavailable]", buf_len - 1); + else if (check_infinite && value == CK_EFFECTIVELY_INFINITE) + strncpy(buf, "[effectively infinite]", buf_len - 1); + else + snprintf(buf, buf_len, fmt, value); + buf[buf_len - 1] = '\0'; +} + +void print_token_info(int slot_id, CK_TOKEN_INFO *TokenInfo) +{ + char temp1[256]; + char temp2[256]; + + /* Display the token information */ + printf("Token #%d Info:\n", slot_id); + printf("\tLabel: %.32s\n", TokenInfo->label); + printf("\tManufacturer: %.32s\n", TokenInfo->manufacturerID); + printf("\tModel: %.16s\n", TokenInfo->model); + printf("\tSerial Number: %.16s\n", TokenInfo->serialNumber); + printf("\tFlags: 0x%lX (", TokenInfo->flags); + + /* print more informative flag message */ + if (TokenInfo->flags & CKF_RNG) + printf("RNG|"); + if (TokenInfo->flags & CKF_WRITE_PROTECTED) + printf("WRITE_PROTECTED|"); + if (TokenInfo->flags & CKF_LOGIN_REQUIRED) + printf("LOGIN_REQUIRED|"); + if (TokenInfo->flags & CKF_USER_PIN_INITIALIZED) + printf("USER_PIN_INITIALIZED|"); + if (TokenInfo->flags & CKF_RESTORE_KEY_NOT_NEEDED) + printf("RESTORE_KEY_NOT_NEEDED|"); + if (TokenInfo->flags & CKF_CLOCK_ON_TOKEN) + printf("CLOCK_ON_TOKEN|"); + if (TokenInfo->flags & CKF_PROTECTED_AUTHENTICATION_PATH) + printf("PROTECTED_AUTHENTICATION_PATH|"); + if (TokenInfo->flags & CKF_DUAL_CRYPTO_OPERATIONS) + printf("DUAL_CRYPTO_OPERATIONS|"); + if (TokenInfo->flags & CKF_TOKEN_INITIALIZED) + printf("TOKEN_INITIALIZED|"); + if (TokenInfo->flags & CKF_SECONDARY_AUTHENTICATION) + printf("SECONDARY_AUTHENTICATION|"); + if (TokenInfo->flags & CKF_USER_PIN_COUNT_LOW) + printf("USER_PIN_COUNT_LOW|"); + if (TokenInfo->flags & CKF_USER_PIN_FINAL_TRY) + printf("USER_PIN_FINAL_TRY|"); + if (TokenInfo->flags & CKF_USER_PIN_LOCKED) + printf("USER_PIN_LOCKED|"); + if (TokenInfo->flags & CKF_USER_PIN_TO_BE_CHANGED) + printf("USER_PIN_TO_BE_CHANGED|"); + if (TokenInfo->flags & CKF_SO_PIN_COUNT_LOW) + printf("SO_PIN_COUNT_LOW|"); + if (TokenInfo->flags & CKF_SO_PIN_FINAL_TRY) + printf("SO_PIN_FINAL_TRY|"); + if (TokenInfo->flags & CKF_SO_PIN_LOCKED) + printf("SO_PIN_LOCKED|"); + if (TokenInfo->flags & CKF_SO_PIN_TO_BE_CHANGED) + printf("SO_PIN_TO_BE_CHANGED|"); + printf(")\n"); + + print_value(TokenInfo->ulSessionCount, temp1, sizeof(temp1), FALSE, "%lu"); + print_value(TokenInfo->ulMaxSessionCount, temp2, sizeof(temp2), TRUE, + "%lu"); + printf("\tSessions: %s/%s\n", temp1, temp2); + print_value(TokenInfo->ulRwSessionCount, temp1, sizeof(temp1), FALSE, + "%lu"); + print_value(TokenInfo->ulMaxRwSessionCount, temp2, sizeof(temp2), TRUE, + "%lu"); + printf("\tR/W Sessions: %s/%s\n", temp1, temp2); + printf("\tPIN Length: %lu-%lu\n", TokenInfo->ulMinPinLen, + TokenInfo->ulMaxPinLen); + print_value(TokenInfo->ulFreePublicMemory, temp1, sizeof(temp1), FALSE, + "0x%lX"); + print_value(TokenInfo->ulTotalPublicMemory, temp2, sizeof(temp2), FALSE, + "0x%lX"); + printf("\tPublic Memory: %s/%s\n", temp1, temp2); + print_value(TokenInfo->ulFreePrivateMemory, temp1, sizeof(temp1), FALSE, + "0x%lX"); + print_value(TokenInfo->ulTotalPrivateMemory, temp2, sizeof(temp2), FALSE, + "0x%lX"); + printf("\tPrivate Memory: %s/%s\n", temp1, temp2); + printf("\tHardware Version: %d.%d\n", TokenInfo->hardwareVersion.major, + TokenInfo->hardwareVersion.minor); + printf("\tFirmware Version: %d.%d\n", TokenInfo->firmwareVersion.major, + TokenInfo->firmwareVersion.minor); + printf("\tTime: %.16s\n", TokenInfo->utcTime); +} + +CK_RV display_token_info(int slot_id) +{ + CK_RV rc; // Return Code + CK_TOKEN_INFO TokenInfo; // Variable to hold Token Information + unsigned int lcv; // Loop control variable + + if (slot_id != -1) { + rc = FunctionPtr->C_GetTokenInfo(slot_id, &TokenInfo); + if (rc != CKR_OK) { + printf("Error getting token info: 0x%lX (%s)\n", rc, + p11_get_ckr(rc)); + return rc; + } + + print_token_info(slot_id, &TokenInfo); + return CKR_OK; + } + + for (lcv = 0; lcv < SlotCount; lcv++) { + /* Get the Token info for each slot in the system */ + rc = FunctionPtr->C_GetTokenInfo(SlotList[lcv], &TokenInfo); + if (rc != CKR_OK) { + printf("Error getting token info: 0x%lX (%s)\n", rc, + p11_get_ckr(rc)); + return rc; + } + + print_token_info(SlotList[lcv], &TokenInfo); + } + return CKR_OK; +} + +CK_RV init_token(int slot_id, CK_CHAR_PTR pin) +{ + /* Note this function reinitializes a token to the state it was + * in just after the initial install + * It does the following actions (if SO pin is correct): + * (1) Purges all Token Objects + * (2) Resets SO PIN back to the default + * (3) Purges the USER PIN + * (4) Sets the Token Label + */ + + CK_RV rc; // Return Code + CK_ULONG pinlen; // Length of the PIN + CK_CHAR label[32], // What we want to set the Label of the card to + enteredlabel[33]; // Max size of 32 + carriage return; + + /* Find out the size of the entered PIN */ + pinlen = strlen((char *) pin); + + /* Get the token label from the user, NOTE it states to give a unique label + * but it is never verified as unique. This is becuase Netscape requires a + * unique token label; however the PKCS11 spec does not. + */ + printf("Enter a unique token label: "); + fflush(stdout); + memset(enteredlabel, 0, sizeof(enteredlabel)); + + if (fgets((char *) enteredlabel, sizeof(enteredlabel), stdin) == NULL) + printf("\n"); + else + enteredlabel[strcspn((const char *) enteredlabel, "\n")] = '\0'; + + /* First clear the label array. Per PKCS#11 spec, We must PAD this field to + * 32 bytes, and it should NOT be null-terminated */ + memset(label, ' ', sizeof(label)); + memcpy((char *) label, (char *) enteredlabel, + strlen((char *) enteredlabel)); + + rc = FunctionPtr->C_InitToken(slot_id, pin, pinlen, label); + if (rc != CKR_OK) { + if (rc == CKR_PIN_INCORRECT) { + printf("Incorrect PIN Entered.\n"); + fflush(stdout); + } else { + printf("Error initializing token: 0x%lX (%s)\n", rc, + p11_get_ckr(rc)); + fflush(stdout); + } + return rc; + } + + return CKR_OK; +} + +CK_RV init_user_pin(int slot_id, CK_CHAR_PTR pin, CK_CHAR_PTR sopin) +{ + CK_RV rc; // Return Value + CK_FLAGS flags = 0; // Mask that we will use when opening the session + CK_SESSION_HANDLE session_handle; // The session handle we get + CK_ULONG pinlen, sopinlen; // Length of the user and SO PINs + + /* get the length of the PINs */ + pinlen = strlen((char *) pin); + sopinlen = strlen((char *) sopin); + + /* set the mask we will use for Open Session */ + flags |= CKF_SERIAL_SESSION; + flags |= CKF_RW_SESSION; + + /* We need to open a read/write session to the adapter to initialize the + * user PIN. Attempt to do so */ + rc = FunctionPtr->C_OpenSession(slot_id, flags, NULL, NULL, + &session_handle); + if (rc != CKR_OK) { + printf("Error opening session: 0x%lX (%s)\n", rc, p11_get_ckr(rc)); + fflush(stdout); + return rc; + } + + /* After the session is open, we must login as the SO to initialize + * the PIN */ + rc = FunctionPtr->C_Login(session_handle, CKU_SO, sopin, sopinlen); + if (rc != CKR_OK) { + if (rc == CKR_PIN_INCORRECT) { + printf("Incorrect PIN Entered.\n"); + fflush(stdout); + } else { + printf("Error logging in: 0x%lX (%s)\n", rc, p11_get_ckr(rc)); + fflush(stdout); + } + return rc; + } + + /* Call the function to Init the PIN */ + rc = FunctionPtr->C_InitPIN(session_handle, pin, pinlen); + if (rc != CKR_OK) { + printf("Error setting PIN: 0x%lX (%s)\n", rc, p11_get_ckr(rc)); + fflush(stdout); + } + + /* Logout so that others can use the PIN */ + rc = FunctionPtr->C_Logout(session_handle); + if (rc != CKR_OK) { + printf("Error logging out: 0x%lX (%s)\n", rc, p11_get_ckr(rc)); + fflush(stdout); + } + + /* Close the session */ + rc = FunctionPtr->C_CloseSession(session_handle); + if (rc != CKR_OK) { + printf("Error closing session: 0x%lX (%s)\n", rc, p11_get_ckr(rc)); + fflush(stdout); + return rc; + } + return CKR_OK; +} + +CK_RV set_user_pin(int slot_id, CK_USER_TYPE user, CK_CHAR_PTR oldpin, + CK_CHAR_PTR newpin) +{ + CK_RV rc; // Return Value + CK_FLAGS flags = 0; // Mash ot open the session with + CK_SESSION_HANDLE session_handle; // The handle of the session we will open + CK_ULONG oldpinlen, newpinlen; // The size of the new and ole PINS + + /* NOTE: This function is used for both the setting of the SO and USER pins, + * the CK_USER_TYPE specifes which we are changing. */ + + /* Get the size of the PINs */ + oldpinlen = strlen((char *) oldpin); + newpinlen = strlen((char *) newpin); + + /* set the flags we will open the session with */ + flags |= CKF_SERIAL_SESSION; + flags |= CKF_RW_SESSION; + + /* Open the Session */ + rc = FunctionPtr->C_OpenSession(slot_id, flags, NULL, NULL, + &session_handle); + if (rc != CKR_OK) { + printf("Error opening session: 0x%lX (%s)\n", rc, p11_get_ckr(rc)); + fflush(stdout); + return rc; + } + + /* Login to the session we just created as the pkcs11 passed in USER type */ + rc = FunctionPtr->C_Login(session_handle, user, oldpin, oldpinlen); + if (rc != CKR_OK) { + if (rc == CKR_PIN_INCORRECT) { + printf("Incorrect PIN Entered.\n"); + fflush(stdout); + } else { + printf("Error logging in: 0x%lX (%s)\n", rc, p11_get_ckr(rc)); + fflush(stdout); + } + return rc; + } + + /* set the new PIN */ + rc = FunctionPtr->C_SetPIN(session_handle, oldpin, oldpinlen, + newpin, newpinlen); + if (rc != CKR_OK) { + printf("Error setting PIN: 0x%lX (%s)\n", rc, p11_get_ckr(rc)); + fflush(stdout); + } + + /* and of course clean up after ourselves */ + rc = FunctionPtr->C_CloseSession(session_handle); + if (rc != CKR_OK) { + printf("Error closing session: 0x%lX (%s)\n", rc, p11_get_ckr(rc)); + fflush(stdout); + return rc; + } + + return CKR_OK; +} + +CK_RV init(void) +{ + CK_RV rc = CKR_OK; // Return Code + void (*symPtr) (); // Pointer for the Dll + + /* Open the PKCS11 API shared library, and inform the user is there is an + * error */ + /* The host machine should have the right library in the + * LD_LIBRARY_PATH */ + dllPtr = dlopen("libopencryptoki.so", RTLD_NOW); + if (!dllPtr) { + printf("Error loading PKCS#11 library\n"); + printf("dlopen error: %s\n", dlerror()); + fflush(stdout); + return -1; + } + + /* Get the list of the PKCS11 functions this token support */ + *(void **)(&symPtr) = dlsym(dllPtr, "C_GetFunctionList"); + if (!symPtr) { + printf("Error getting function list, symbol not found, error: %s\n", + strerror(errno)); + fflush(stdout); + return rc; + } + + symPtr(&FunctionPtr); + + /* If we get here we know the slot manager is running and we can use PKCS11 + * calls, so we will execute the PKCS11 Initilize command. */ + rc = FunctionPtr->C_Initialize(NULL); + if (rc != CKR_OK) { + printf("Error initializing the PKCS11 library: 0x%lX (%s)\n", rc, + p11_get_ckr(rc)); + + if (check_user_and_group() != CKR_OK) { + printf("Note: all non-root users that require access to PKCS#11 " + "tokens using opencryptoki must be assigned to the pkcs11 " + "group to be able to communicate with the pkcsslotd " + "daemon.\n"); + } + + fflush(stdout); + cleanup(); + } + + return rc; +} + +CK_RV cleanup(void) +{ + CK_RV rc; // Return Code + + /* To clean up we will free the slot list we create, call the Finalize + * routine for PKCS11 and close the dynamically linked library */ + free(SlotList); + rc = FunctionPtr->C_Finalize(NULL); + if (dllPtr) + dlclose(dllPtr); + + exit(rc); +} + +void usage(char *progname) +{ + /* If we get here the user needs help, so give it to them */ + printf("usage:\t%s [-itsmIupPh] [-c slotnumber -U userPIN -S SOPin " + "-n newpin]\n", progname); + printf("\t-i display PKCS11 info\n"); + printf("\t-t display token info\n"); + printf("\t-s display slot info\n"); + printf("\t-m display mechanism list\n"); + printf("\t-l display slot description\n"); + printf("\t-I initialize token \n"); + printf("\t-u initialize user PIN\n"); + printf("\t-p set the user PIN\n"); + printf("\t-P set the SO PIN\n"); + printf("\t-h show this help\n"); + + exit(-1); +} diff --git a/usr/sbin/pkcsconf/pkcsconf.mk b/usr/sbin/pkcsconf/pkcsconf.mk new file mode 100644 index 0000000..3fc3bb9 --- /dev/null +++ b/usr/sbin/pkcsconf/pkcsconf.mk @@ -0,0 +1,13 @@ +sbin_PROGRAMS += usr/sbin/pkcsconf/pkcsconf +noinst_HEADERS += usr/sbin/pkcsconf/pkcsconf_msg.h + +usr_sbin_pkcsconf_pkcsconf_LDFLAGS = -lpthread -ldl -lcrypto + +usr_sbin_pkcsconf_pkcsconf_CFLAGS = \ + -D_THREAD_SAFE -DDEBUG -DDEV -DAPI \ + -I${srcdir}/usr/include -I${srcdir}/usr/lib/common \ + -I${srcdir}/usr/sbin/pkcsconf + +usr_sbin_pkcsconf_pkcsconf_SOURCES = \ + usr/lib/common/p11util.c \ + usr/sbin/pkcsconf/pkcsconf.c diff --git a/usr/sbin/pkcsconf/pkcsconf_msg.h b/usr/sbin/pkcsconf/pkcsconf_msg.h new file mode 100644 index 0000000..c13d6eb --- /dev/null +++ b/usr/sbin/pkcsconf/pkcsconf_msg.h @@ -0,0 +1,296 @@ +/* + * 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 + */ + +#ifndef _H_PKCSCONF_MSG +#define _H_PKCSCONF_MSG + +/* list of mechanism flags and their printable string names */ +struct _pkcs11_mech_flags { + char *name; + CK_FLAGS flag; +} pkcs11_mech_flags[] = { + { "CKF_HW", CKF_HW }, + { "CKF_ENCRYPT", CKF_ENCRYPT }, + { "CKF_DECRYPT", CKF_DECRYPT }, + { "CKF_DIGEST", CKF_DIGEST }, + { "CKF_SIGN", CKF_SIGN }, + { "CKF_SIGN_RECOVER", CKF_SIGN_RECOVER }, + { "CKF_VERIFY", CKF_VERIFY }, + { "CKF_VERIFY_RECOVER", CKF_VERIFY_RECOVER }, + { "CKF_GENERATE", CKF_GENERATE }, + { "CKF_GENERATE_KEY_PAIR", CKF_GENERATE_KEY_PAIR }, + { "CKF_WRAP", CKF_WRAP }, + { "CKF_UNWRAP", CKF_UNWRAP }, + { "CKF_DERIVE", CKF_DERIVE }, + { "CKF_EC_F_P", CKF_EC_F_P }, + { "CKF_EC_F_2M", CKF_EC_F_2M }, + { "CKF_EC_ECPARAMETERS", CKF_EC_ECPARAMETERS }, + { "CKF_EC_NAMEDCURVE", CKF_EC_NAMEDCURVE }, + { "CKF_EC_UNCOMPRESS", CKF_EC_UNCOMPRESS }, + { "CKF_EC_COMPRESS", CKF_EC_COMPRESS }, + { "CKF_EXTENSION", CKF_EXTENSION }, + { NULL_PTR, 0xFFFFFFFF } +}; + + +/* list of mechanisms and their printable string names */ +struct _pkcs11_mech_list { + char *name; + CK_MECHANISM_TYPE mech; +} pkcs11_mech_list[] = { + { "CKM_RSA_PKCS_KEY_PAIR_GEN", CKM_RSA_PKCS_KEY_PAIR_GEN }, + { "CKM_RSA_PKCS", CKM_RSA_PKCS }, + { "CKM_RSA_9796", CKM_RSA_9796 }, + { "CKM_RSA_X_509", CKM_RSA_X_509 }, + { "CKM_MD2_RSA_PKCS", CKM_MD2_RSA_PKCS }, + { "CKM_MD5_RSA_PKCS", CKM_MD5_RSA_PKCS }, + { "CKM_SHA1_RSA_PKCS", CKM_SHA1_RSA_PKCS }, + { "CKM_RIPEMD128_RSA_PKCS", CKM_RIPEMD128_RSA_PKCS }, + { "CKM_RIPEMD160_RSA_PKCS", CKM_RIPEMD160_RSA_PKCS }, + { "CKM_RSA_PKCS_OAEP", CKM_RSA_PKCS_OAEP }, + { "CKM_RSA_X9_31_KEY_PAIR_GEN", CKM_RSA_X9_31_KEY_PAIR_GEN }, + { "CKM_RSA_X9_31", CKM_RSA_X9_31 }, + { "CKM_SHA1_RSA_X9_31", CKM_SHA1_RSA_X9_31 }, + { "CKM_RSA_PKCS_PSS", CKM_RSA_PKCS_PSS }, + { "CKM_SHA1_RSA_PKCS_PSS", CKM_SHA1_RSA_PKCS_PSS }, + { "CKM_DSA_KEY_PAIR_GEN", CKM_DSA_KEY_PAIR_GEN }, + { "CKM_DSA", CKM_DSA }, + { "CKM_DSA_SHA1", CKM_DSA_SHA1 }, + { "CKM_DH_PKCS_KEY_PAIR_GEN", CKM_DH_PKCS_KEY_PAIR_GEN }, + { "CKM_DH_PKCS_DERIVE", CKM_DH_PKCS_DERIVE }, + { "CKM_X9_42_DH_KEY_PAIR_GEN", CKM_X9_42_DH_KEY_PAIR_GEN }, + { "CKM_X9_42_DH_DERIVE", CKM_X9_42_DH_DERIVE }, + { "CKM_X9_42_DH_HYBRID_DERIVE", CKM_X9_42_DH_HYBRID_DERIVE }, + { "CKM_X9_42_MQV_DERIVE", CKM_X9_42_MQV_DERIVE }, + { "CKM_SHA224_RSA_PKCS", CKM_SHA224_RSA_PKCS }, + { "CKM_SHA256_RSA_PKCS", CKM_SHA256_RSA_PKCS }, + { "CKM_SHA384_RSA_PKCS", CKM_SHA384_RSA_PKCS }, + { "CKM_SHA512_RSA_PKCS", CKM_SHA512_RSA_PKCS }, + { "CKM_SHA224_RSA_PKCS_PSS", CKM_SHA224_RSA_PKCS_PSS }, + { "CKM_SHA256_RSA_PKCS_PSS", CKM_SHA256_RSA_PKCS_PSS }, + { "CKM_SHA384_RSA_PKCS_PSS", CKM_SHA384_RSA_PKCS_PSS }, + { "CKM_SHA512_RSA_PKCS_PSS", CKM_SHA512_RSA_PKCS_PSS }, + { "CKM_RC2_KEY_GEN", CKM_RC2_KEY_GEN }, + { "CKM_RC2_ECB", CKM_RC2_ECB }, + { "CKM_RC2_CBC", CKM_RC2_CBC }, + { "CKM_RC2_MAC", CKM_RC2_MAC }, + { "CKM_RC2_MAC_GENERAL", CKM_RC2_MAC_GENERAL }, + { "CKM_RC2_CBC_PAD", CKM_RC2_CBC_PAD }, + { "CKM_RC4_KEY_GEN", CKM_RC4_KEY_GEN }, + { "CKM_RC4", CKM_RC4 }, + { "CKM_DES_KEY_GEN", CKM_DES_KEY_GEN }, + { "CKM_DES_ECB", CKM_DES_ECB }, + { "CKM_DES_CBC", CKM_DES_CBC }, + { "CKM_DES_MAC", CKM_DES_MAC }, + { "CKM_DES_MAC_GENERAL", CKM_DES_MAC_GENERAL }, + { "CKM_DES_CBC_PAD", CKM_DES_CBC_PAD }, + { "CKM_DES_OFB64", CKM_DES_OFB64 }, + { "CKM_DES_CFB8", CKM_DES_CFB8 }, + { "CKM_DES_CFB64", CKM_DES_CFB64 }, + { "CKM_DES2_KEY_GEN", CKM_DES2_KEY_GEN }, + { "CKM_DES3_KEY_GEN", CKM_DES3_KEY_GEN }, + { "CKM_DES3_ECB", CKM_DES3_ECB }, + { "CKM_DES3_CBC", CKM_DES3_CBC }, + { "CKM_DES3_MAC", CKM_DES3_MAC }, + { "CKM_DES3_MAC_GENERAL", CKM_DES3_MAC_GENERAL }, + { "CKM_DES3_CBC_PAD", CKM_DES3_CBC_PAD }, + { "CKM_DES3_CMAC_GENERAL", CKM_DES3_CMAC_GENERAL }, + { "CKM_DES3_CMAC", CKM_DES3_CMAC }, + { "CKM_CDMF_KEY_GEN", CKM_CDMF_KEY_GEN }, + { "CKM_CDMF_ECB", CKM_CDMF_ECB }, + { "CKM_CDMF_CBC", CKM_CDMF_CBC }, + { "CKM_CDMF_MAC", CKM_CDMF_MAC }, + { "CKM_CDMF_MAC_GENERAL", CKM_CDMF_MAC_GENERAL }, + { "CKM_CDMF_CBC_PAD", CKM_CDMF_CBC_PAD }, + { "CKM_MD2", CKM_MD2 }, + { "CKM_MD2_HMAC", CKM_MD2_HMAC }, + { "CKM_MD2_HMAC_GENERAL", CKM_MD2_HMAC_GENERAL }, + { "CKM_MD5", CKM_MD5 }, + { "CKM_MD5_HMAC", CKM_MD5_HMAC }, + { "CKM_MD5_HMAC_GENERAL", CKM_MD5_HMAC_GENERAL }, + { "CKM_SHA_1", CKM_SHA_1 }, + { "CKM_SHA_1_HMAC", CKM_SHA_1_HMAC }, + { "CKM_SHA_1_HMAC_GENERAL", CKM_SHA_1_HMAC_GENERAL }, + { "CKM_RIPEMD128", CKM_RIPEMD128 }, + { "CKM_RIPEMD128_HMAC", CKM_RIPEMD128_HMAC }, + { "CKM_RIPEMD128_HMAC_GENERAL", CKM_RIPEMD128_HMAC_GENERAL }, + { "CKM_RIPEMD160", CKM_RIPEMD160 }, + { "CKM_RIPEMD160_HMAC", CKM_RIPEMD160_HMAC }, + { "CKM_RIPEMD160_HMAC_GENERAL", CKM_RIPEMD160_HMAC_GENERAL }, + { "CKM_SHA224", CKM_SHA224 }, + { "CKM_SHA224_HMAC", CKM_SHA224_HMAC }, + { "CKM_SHA224_HMAC_GENERAL", CKM_SHA224_HMAC_GENERAL }, + { "CKM_SHA256", CKM_SHA256 }, + { "CKM_SHA256_HMAC", CKM_SHA256_HMAC }, + { "CKM_SHA256_HMAC_GENERAL", CKM_SHA256_HMAC_GENERAL }, + { "CKM_SHA384", CKM_SHA384 }, + { "CKM_SHA384_HMAC", CKM_SHA384_HMAC }, + { "CKM_SHA384_HMAC_GENERAL", CKM_SHA384_HMAC_GENERAL }, + { "CKM_SHA512", CKM_SHA512 }, + { "CKM_SHA512_HMAC", CKM_SHA512_HMAC }, + { "CKM_SHA512_HMAC_GENERAL", CKM_SHA512_HMAC_GENERAL }, + { "CKM_SHA512_224", CKM_SHA512_224 }, + { "CKM_SHA512_224_HMAC", CKM_SHA512_224_HMAC }, + { "CKM_SHA512_224_HMAC_GENERAL", CKM_SHA512_224_HMAC_GENERAL }, + { "CKM_SHA512_256", CKM_SHA512_256 }, + { "CKM_SHA512_256_HMAC", CKM_SHA512_256_HMAC }, + { "CKM_SHA512_256_HMAC_GENERAL", CKM_SHA512_256_HMAC_GENERAL }, + { "CKM_CAST_KEY_GEN", CKM_CAST_KEY_GEN }, + { "CKM_CAST_ECB", CKM_CAST_ECB }, + { "CKM_CAST_CBC", CKM_CAST_CBC }, + { "CKM_CAST_MAC", CKM_CAST_MAC }, + { "CKM_CAST_MAC_GENERAL", CKM_CAST_MAC_GENERAL }, + { "CKM_CAST_CBC_PAD", CKM_CAST_CBC_PAD }, + { "CKM_CAST3_KEY_GEN", CKM_CAST3_KEY_GEN }, + { "CKM_CAST3_ECB", CKM_CAST3_ECB }, + { "CKM_CAST3_CBC", CKM_CAST3_CBC }, + { "CKM_CAST3_MAC", CKM_CAST3_MAC }, + { "CKM_CAST3_MAC_GENERAL", CKM_CAST3_MAC_GENERAL }, + { "CKM_CAST3_CBC_PAD", CKM_CAST3_CBC_PAD }, + { "CKM_CAST5_KEY_GEN", CKM_CAST5_KEY_GEN }, + { "CKM_CAST128_KEY_GEN", CKM_CAST128_KEY_GEN }, + { "CKM_CAST5_ECB", CKM_CAST5_ECB }, + { "CKM_CAST128_ECB", CKM_CAST128_ECB }, + { "CKM_CAST5_CBC", CKM_CAST5_CBC }, + { "CKM_CAST128_CBC", CKM_CAST128_CBC }, + { "CKM_CAST5_MAC", CKM_CAST5_MAC }, + { "CKM_CAST128_MAC", CKM_CAST128_MAC }, + { "CKM_CAST5_MAC_GENERAL", CKM_CAST5_MAC_GENERAL }, + { "CKM_CAST128_MAC_GENERAL", CKM_CAST128_MAC_GENERAL }, + { "CKM_CAST5_CBC_PAD", CKM_CAST5_CBC_PAD }, + { "CKM_CAST128_CBC_PAD", CKM_CAST128_CBC_PAD }, + { "CKM_RC5_KEY_GEN", CKM_RC5_KEY_GEN }, + { "CKM_RC5_ECB", CKM_RC5_ECB }, + { "CKM_RC5_CBC", CKM_RC5_CBC }, + { "CKM_RC5_MAC", CKM_RC5_MAC }, + { "CKM_RC5_MAC_GENERAL", CKM_RC5_MAC_GENERAL }, + { "CKM_RC5_CBC_PAD", CKM_RC5_CBC_PAD }, + { "CKM_IDEA_KEY_GEN", CKM_IDEA_KEY_GEN }, + { "CKM_IDEA_ECB", CKM_IDEA_ECB }, + { "CKM_IDEA_CBC", CKM_IDEA_CBC }, + { "CKM_IDEA_MAC", CKM_IDEA_MAC }, + { "CKM_IDEA_MAC_GENERAL", CKM_IDEA_MAC_GENERAL }, + { "CKM_IDEA_CBC_PAD", CKM_IDEA_CBC_PAD }, + { "CKM_GENERIC_SECRET_KEY_GEN", CKM_GENERIC_SECRET_KEY_GEN }, + { "CKM_CONCATENATE_BASE_AND_KEY", CKM_CONCATENATE_BASE_AND_KEY }, + { "CKM_CONCATENATE_BASE_AND_DATA", CKM_CONCATENATE_BASE_AND_DATA }, + { "CKM_CONCATENATE_DATA_AND_BASE", CKM_CONCATENATE_DATA_AND_BASE }, + { "CKM_XOR_BASE_AND_DATA", CKM_XOR_BASE_AND_DATA }, + { "CKM_EXTRACT_KEY_FROM_KEY", CKM_EXTRACT_KEY_FROM_KEY }, + { "CKM_SSL3_PRE_MASTER_KEY_GEN", CKM_SSL3_PRE_MASTER_KEY_GEN }, + { "CKM_SSL3_MASTER_KEY_DERIVE", CKM_SSL3_MASTER_KEY_DERIVE }, + { "CKM_SSL3_KEY_AND_MAC_DERIVE", CKM_SSL3_KEY_AND_MAC_DERIVE }, + { "CKM_SSL3_MASTER_KEY_DERIVE_DH", CKM_SSL3_MASTER_KEY_DERIVE_DH }, + { "CKM_TLS_PRE_MASTER_KEY_GEN", CKM_TLS_PRE_MASTER_KEY_GEN }, + { "CKM_TLS_MASTER_KEY_DERIVE", CKM_TLS_MASTER_KEY_DERIVE }, + { "CKM_TLS_KEY_AND_MAC_DERIVE", CKM_TLS_KEY_AND_MAC_DERIVE }, + { "CKM_TLS_MASTER_KEY_DERIVE_DH", CKM_TLS_MASTER_KEY_DERIVE_DH }, + { "CKM_SSL3_MD5_MAC", CKM_SSL3_MD5_MAC }, + { "CKM_SSL3_SHA1_MAC", CKM_SSL3_SHA1_MAC }, + { "CKM_MD5_KEY_DERIVATION", CKM_MD5_KEY_DERIVATION }, + { "CKM_MD2_KEY_DERIVATION", CKM_MD2_KEY_DERIVATION }, + { "CKM_SHA1_KEY_DERIVATION", CKM_SHA1_KEY_DERIVATION }, + { "CKM_SHA224_KEY_DERIVATION", CKM_SHA224_KEY_DERIVATION }, + { "CKM_SHA256_KEY_DERIVATION", CKM_SHA256_KEY_DERIVATION }, + { "CKM_SHA384_KEY_DERIVATION", CKM_SHA384_KEY_DERIVATION }, + { "CKM_SHA512_KEY_DERIVATION", CKM_SHA512_KEY_DERIVATION }, + { "CKM_PBE_MD2_DES_CBC", CKM_PBE_MD2_DES_CBC }, + { "CKM_PBE_MD5_DES_CBC", CKM_PBE_MD5_DES_CBC }, + { "CKM_PBE_MD5_CAST_CBC", CKM_PBE_MD5_CAST_CBC }, + { "CKM_PBE_MD5_CAST3_CBC", CKM_PBE_MD5_CAST3_CBC }, + { "CKM_PBE_MD5_CAST5_CBC", CKM_PBE_MD5_CAST5_CBC }, + { "CKM_PBE_MD5_CAST128_CBC", CKM_PBE_MD5_CAST128_CBC }, + { "CKM_PBE_SHA1_CAST5_CBC", CKM_PBE_SHA1_CAST5_CBC }, + { "CKM_PBE_SHA1_CAST128_CBC", CKM_PBE_SHA1_CAST128_CBC }, + { "CKM_PBE_SHA1_RC4_128", CKM_PBE_SHA1_RC4_128 }, + { "CKM_PBE_SHA1_RC4_40", CKM_PBE_SHA1_RC4_40 }, + { "CKM_PBE_SHA1_DES3_EDE_CBC", CKM_PBE_SHA1_DES3_EDE_CBC }, + { "CKM_PBE_SHA1_DES2_EDE_CBC", CKM_PBE_SHA1_DES2_EDE_CBC }, + { "CKM_PBE_SHA1_RC2_128_CBC", CKM_PBE_SHA1_RC2_128_CBC }, + { "CKM_PBE_SHA1_RC2_40_CBC", CKM_PBE_SHA1_RC2_40_CBC }, + { "CKM_PKCS5_PBKD2", CKM_PKCS5_PBKD2 }, + { "CKM_PBA_SHA1_WITH_SHA1_HMAC", CKM_PBA_SHA1_WITH_SHA1_HMAC }, + { "CKM_KEY_WRAP_LYNKS", CKM_KEY_WRAP_LYNKS }, + { "CKM_KEY_WRAP_SET_OAEP", CKM_KEY_WRAP_SET_OAEP }, + { "CKM_SKIPJACK_KEY_GEN", CKM_SKIPJACK_KEY_GEN }, + { "CKM_SKIPJACK_ECB64", CKM_SKIPJACK_ECB64 }, + { "CKM_SKIPJACK_CBC64", CKM_SKIPJACK_CBC64 }, + { "CKM_SKIPJACK_OFB64", CKM_SKIPJACK_OFB64 }, + { "CKM_SKIPJACK_CFB64", CKM_SKIPJACK_CFB64 }, + { "CKM_SKIPJACK_CFB32", CKM_SKIPJACK_CFB32 }, + { "CKM_SKIPJACK_CFB16", CKM_SKIPJACK_CFB16 }, + { "CKM_SKIPJACK_CFB8", CKM_SKIPJACK_CFB8 }, + { "CKM_SKIPJACK_WRAP", CKM_SKIPJACK_WRAP }, + { "CKM_SKIPJACK_PRIVATE_WRAP", CKM_SKIPJACK_PRIVATE_WRAP }, + { "CKM_SKIPJACK_RELAYX", CKM_SKIPJACK_RELAYX }, + { "CKM_KEA_KEY_PAIR_GEN", CKM_KEA_KEY_PAIR_GEN }, + { "CKM_KEA_KEY_DERIVE", CKM_KEA_KEY_DERIVE }, + { "CKM_FORTEZZA_TIMESTAMP", CKM_FORTEZZA_TIMESTAMP }, + { "CKM_BATON_KEY_GEN", CKM_BATON_KEY_GEN }, + { "CKM_BATON_ECB128", CKM_BATON_ECB128 }, + { "CKM_BATON_ECB96", CKM_BATON_ECB96 }, + { "CKM_BATON_CBC128", CKM_BATON_CBC128 }, + { "CKM_BATON_COUNTER", CKM_BATON_COUNTER }, + { "CKM_BATON_SHUFFLE", CKM_BATON_SHUFFLE }, + { "CKM_BATON_WRAP", CKM_BATON_WRAP }, + { "CKM_ECDSA_KEY_PAIR_GEN", CKM_ECDSA_KEY_PAIR_GEN }, + { "CKM_EC_KEY_PAIR_GEN", CKM_EC_KEY_PAIR_GEN }, + { "CKM_ECDSA", CKM_ECDSA }, + { "CKM_ECDSA_SHA1", CKM_ECDSA_SHA1 }, + { "CKM_ECDSA_SHA224", CKM_ECDSA_SHA224 }, + { "CKM_ECDSA_SHA256", CKM_ECDSA_SHA256 }, + { "CKM_ECDSA_SHA384", CKM_ECDSA_SHA384 }, + { "CKM_ECDSA_SHA512", CKM_ECDSA_SHA512 }, + { "CKM_ECDH1_DERIVE", CKM_ECDH1_DERIVE }, + { "CKM_ECDH1_COFACTOR_DERIVE", CKM_ECDH1_COFACTOR_DERIVE }, + { "CKM_ECMQV_DERIVE", CKM_ECMQV_DERIVE }, + { "CKM_JUNIPER_KEY_GEN", CKM_JUNIPER_KEY_GEN }, + { "CKM_JUNIPER_ECB128", CKM_JUNIPER_ECB128 }, + { "CKM_JUNIPER_CBC128", CKM_JUNIPER_CBC128 }, + { "CKM_JUNIPER_COUNTER", CKM_JUNIPER_COUNTER }, + { "CKM_JUNIPER_SHUFFLE", CKM_JUNIPER_SHUFFLE }, + { "CKM_JUNIPER_WRAP", CKM_JUNIPER_WRAP }, + { "CKM_FASTHASH", CKM_FASTHASH }, + { "CKM_AES_KEY_GEN", CKM_AES_KEY_GEN }, + { "CKM_AES_ECB", CKM_AES_ECB }, + { "CKM_AES_CBC", CKM_AES_CBC }, + { "CKM_AES_MAC", CKM_AES_MAC }, + { "CKM_AES_MAC_GENERAL", CKM_AES_MAC_GENERAL }, + { "CKM_AES_CBC_PAD", CKM_AES_CBC_PAD }, + { "CKM_AES_CTR", CKM_AES_CTR }, + { "CKM_AES_GCM", CKM_AES_GCM }, + { "CKM_AES_CMAC_GENERAL", CKM_AES_CMAC_GENERAL }, + { "CKM_AES_CMAC", CKM_AES_CMAC }, + { "CKM_AES_OFB", CKM_AES_OFB }, + { "CKM_AES_CFB8", CKM_AES_CFB8 }, + { "CKM_AES_CFB64", CKM_AES_CFB64 }, + { "CKM_AES_CFB128", CKM_AES_CFB128 }, + { "CKM_DSA_PARAMETER_GEN", CKM_DSA_PARAMETER_GEN }, + { "CKM_DH_PKCS_PARAMETER_GEN", CKM_DH_PKCS_PARAMETER_GEN }, + { "CKM_X9_42_DH_PARAMETER_GEN", CKM_X9_42_DH_PARAMETER_GEN }, + { "CKM_VENDOR_DEFINED", CKM_VENDOR_DEFINED }, + { "CKM_IBM_SHA3_224", CKM_IBM_SHA3_224 }, + { "CKM_IBM_SHA3_256", CKM_IBM_SHA3_256 }, + { "CKM_IBM_SHA3_384", CKM_IBM_SHA3_384 }, + { "CKM_IBM_SHA3_512", CKM_IBM_SHA3_512 }, + { "CKM_IBM_SHA3_224_HMAC", CKM_IBM_SHA3_224_HMAC }, + { "CKM_IBM_SHA3_256_HMAC", CKM_IBM_SHA3_256_HMAC }, + { "CKM_IBM_SHA3_384_HMAC", CKM_IBM_SHA3_384_HMAC }, + { "CKM_IBM_SHA3_512_HMAC", CKM_IBM_SHA3_512_HMAC }, + { "CKM_IBM_CMAC", CKM_IBM_CMAC }, + { "CKM_IBM_EC_C25519", CKM_IBM_EC_C25519 }, + { "CKM_IBM_EDDSA_SHA512", CKM_IBM_EDDSA_SHA512 }, + { "CKM_IBM_EC_C448", CKM_IBM_EC_C448 }, + { "CKM_IBM_ED448_SHA3", CKM_IBM_ED448_SHA3 }, + { "CKM_IBM_DILITHIUM", CKM_IBM_DILITHIUM }, + { NULL_PTR, 0xFFFFFFFF } +}; + +#endif diff --git a/usr/sbin/pkcsep11_migrate/ep11adm.h b/usr/sbin/pkcsep11_migrate/ep11adm.h new file mode 100644 index 0000000..3386b25 --- /dev/null +++ b/usr/sbin/pkcsep11_migrate/ep11adm.h @@ -0,0 +1,124 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2011-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 + */ + +/*---------------------------------------------------------------------- + * IBM Research & Development + * Author: Gehrmann, Tobias (tobias.gehrmann@de.ibm.com) + *----------------------------------------------------------------------*/ + +#if !defined(__EP11ADM_H__) +#define __EP11ADM_H__ + +#if !defined(INT64_MIN) +#error "We need 32/64-bit types, please include before this file." +#endif + +// these numbers apply to current version, subject to change +// +#if !defined(XCP_SERIALNR_CHARS) +#define XCP_SERIALNR_CHARS 8 +#endif + +#if !defined(XCP_KEYCSUM_BYTES) +#define XCP_KEYCSUM_BYTES (256/8) /* full size of verific. pattern */ +#endif + +#if !defined(XCP_ADMCTR_BYTES) +#define XCP_ADMCTR_BYTES (128/8) /* admin transaction ctrs */ +#endif + +#if !defined(XCP_ADM_REENCRYPT) +#define XCP_ADM_REENCRYPT 25 /* transform blobs to next WK */ +#endif + +#if !defined(CK_IBM_XCPQ_DOMAIN) +#define CK_IBM_XCPQ_DOMAIN 3 /* list domain's WK hashes */ +#endif + +#if !defined(CK_IBM_DOM_COMMITTED_NWK) +#define CK_IBM_DOM_COMMITTED_NWK 8 /* next WK is active(committed) */ +#endif + + +typedef struct XCPadmresp { + uint32_t fn; + uint32_t domain; + uint32_t domainInst; + + /* module ID || module instance */ + unsigned char module[XCP_SERIALNR_CHARS + XCP_SERIALNR_CHARS]; + unsigned char modNr[XCP_SERIALNR_CHARS]; + unsigned char modInst[XCP_SERIALNR_CHARS]; + + unsigned char tctr[XCP_ADMCTR_BYTES]; /* transaction counter */ + + CK_RV rv; + uint32_t reason; + + // points to original response; NULL if no payload + // make sure it's copied if used after releasing response block + // + const unsigned char *payload; + size_t pllen; +} *XCPadmresp_t; + + +#if !defined(__XCP_H__) +typedef struct CK_IBM_DOMAIN_INFO { + CK_ULONG domain; + CK_BYTE wk[XCP_KEYCSUM_BYTES]; + CK_BYTE nextwk[XCP_KEYCSUM_BYTES]; + CK_ULONG flags; + CK_BYTE mode[8]; +} CK_IBM_DOMAIN_INFO; +#endif + + +/*---------------------------------------------------------------------- + * build a query block to (blk,blen), querying 'fn' + * (payload,plen) copied to query block if non-NULL + * + * returns written bytecount; size query if blk is NULL + * + * *minf used for module ID and transaction counter + * ignored for commands where those fields are ignored + */ +long xcpa_cmdblock(unsigned char *blk, + size_t blen, + unsigned int fn, + const struct XCPadmresp *minf, + const unsigned char *tctr, /* XCP_ADMCTR_BYTES */ + const unsigned char *payload, size_t plen) ; + + +/*---------------------------------------------------------------------- + * returns <0 if response is malformed, or contents invalid + * + * parse embedded return value from response, writes to *rv if non-NULL + * (outside envelope always reports CKR_OK, unless infrastructure failed) + */ +long xcpa_internal_rv(const unsigned char *rsp, size_t rlen, + struct XCPadmresp *rspblk, CK_RV *rv) ; + + +/*---------------------------------------------------------------------- + * in: [0] query type + * out: [0] packed info structure + * + * outputs are fixed size, except CK_IBM_XCPQ_DOMAINS, which returns a + * list therefore, infbytes is ignored by other types (we still check + * if present) + */ +CK_RV m_get_xcp_info (CK_VOID_PTR pinfo, CK_ULONG_PTR infbytes, + unsigned int query, + unsigned int subquery, target_t target) ; + + +#endif /* !defined(__EP11ADM_H__) */ diff --git a/usr/sbin/pkcsep11_migrate/pkcsep11_migrate.c b/usr/sbin/pkcsep11_migrate/pkcsep11_migrate.c new file mode 100644 index 0000000..d0dba85 --- /dev/null +++ b/usr/sbin/pkcsep11_migrate/pkcsep11_migrate.c @@ -0,0 +1,708 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2013-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 + */ + +/* Reenryption of EP11 secure keys. The secure key is reencrypted at the card + * by a new wrapping (still pending) key. Needed also for SPKIs of public + * keys. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EP11SHAREDLIB_NAME "OCK_EP11_LIBRARY" +#define EP11SHAREDLIB_V3 "libep11.so.3" +#define EP11SHAREDLIB_V2 "libep11.so.2" +#define EP11SHAREDLIB_V1 "libep11.so.1" +#define EP11SHAREDLIB "libep11.so" +#define PKCS11_MAX_PIN_LEN 128 + +CK_FUNCTION_LIST *funcs; +CK_SLOT_ID SLOT_ID = -1; +CK_LONG adapter = -1; +CK_LONG domain = -1; +CK_OBJECT_HANDLE key_store[4096]; + +typedef unsigned long int (*m_admin_t) (unsigned char *, size_t *, + unsigned char *, + size_t *, const unsigned char *, + size_t, const unsigned char *, + size_t, target_t); +typedef long (*xcpa_cmdblock_t) (unsigned char *, size_t, unsigned int, + const struct XCPadmresp *, + const unsigned char *, + const unsigned char *, size_t); +typedef long (*xcpa_internal_rv_t) (const unsigned char *, size_t, + struct XCPadmresp *, CK_RV *); +typedef int (*m_add_module_t) (XCP_Module_t, target_t *); +typedef int (*m_rm_module_t) (XCP_Module_t, target_t); +typedef CK_RV (*m_get_xcp_info_t)(CK_VOID_PTR pinfo, CK_ULONG_PTR infbytes, + unsigned int query, unsigned int subquery, + target_t target); + +m_get_xcp_info_t _m_get_xcp_info; +m_admin_t _m_admin; +xcpa_cmdblock_t _xcpa_cmdblock; +xcpa_internal_rv_t _xcpa_internal_rv; +m_add_module_t _m_add_module; +m_rm_module_t _m_rm_module; + +CK_VERSION lib_version; + +#define CK_IBM_XCPHQ_VERSION 0xff000001 + +typedef struct { + short format; + short length; + short apqns[512]; +} __attribute__ ((packed)) ep11_target_t; + + +#define BLOBSIZE 2048*4 + + + +static int reencrypt(CK_SESSION_HANDLE session, CK_ULONG obj, CK_BYTE *old, + CK_ULONG old_len) +{ + CK_BYTE req[BLOBSIZE]; + CK_BYTE resp[BLOBSIZE]; + CK_LONG req_len; + size_t resp_len; + struct XCPadmresp rb; + struct XCPadmresp lrb; + ep11_target_t target_list; + struct XCP_Module module; + target_t target = XCP_TGT_INIT; + CK_RV rc; + CK_BYTE name[256]; + unsigned char blob[BLOBSIZE]; + CK_ULONG blob_len; + + CK_ATTRIBUTE opaque_template[] = { + { CKA_IBM_OPAQUE, blob, BLOBSIZE } + }; + + CK_ATTRIBUTE name_template[] = { + {CKA_LABEL, NULL_PTR, 0} + }; + + memset(name, 0, 256); + + /* print CKA_LABEL if it exists, only informational + exist and size query */ + rc = funcs->C_GetAttributeValue(session, key_store[obj], name_template, 1); + if (rc == CKR_OK && name_template[0].ulValueLen < 256) { + name_template[0].pValue = name; + /* knowing its size, after mem allocation, get the name value */ + rc = funcs->C_GetAttributeValue(session, key_store[obj], name_template, + 1); + } + + memset(&rb, 0, sizeof(rb)); + memset(&lrb, 0, sizeof(lrb)); + + if (_m_add_module != NULL) { + memset(&module, 0, sizeof(module)); + module.version = lib_version.major >= 3 ? XCP_MOD_VERSION_2 + : XCP_MOD_VERSION_1; + module.flags = XCP_MFL_MODULE; + module.module_nr = adapter; + XCPTGTMASK_SET_DOM(module.domainmask, domain); + rc = _m_add_module(&module, &target); + if (rc != 0) + return CKR_FUNCTION_FAILED; + } else { + /* Fall back to old target handling */ + memset(&target_list, 0, sizeof(ep11_target_t)); + target_list.length = 1; + target_list.apqns[0] = adapter; + target_list.apqns[1] = domain; + target = (target_t)&target_list; + } + + rb.domain = domain; + lrb.domain = domain; + + fprintf(stderr, "going to reencrpyt key %lx with blob len %lx: '%s'\n", obj, + old_len, name); + resp_len = BLOBSIZE; + + req_len = _xcpa_cmdblock(req, BLOBSIZE, XCP_ADM_REENCRYPT, &rb, + NULL, old, old_len); + + if (req_len < 0) { + fprintf(stderr, "reencrypt cmd block construction failed\n"); + rc = -2; + goto out; + } + + rc = _m_admin(resp, &resp_len, NULL, 0, req, req_len, NULL, 0, + target); + + if (rc != CKR_OK || resp_len == 0) { + fprintf(stderr, "reencryption failed: %lx %ld\n", rc, req_len); + rc = -3; + goto out; + } + + if (_xcpa_internal_rv(resp, resp_len, &lrb, &rc) < 0) { + fprintf(stderr, "reencryption response malformed: %lx\n", rc); + rc = -4; + goto out; + } + + if (rc != 0) { + fprintf(stderr, "reencryption failed: %lx\n", rc); + rc = -7; + goto out; + } + + if (old_len != lrb.pllen) { + fprintf(stderr, "reencryption blob size changed: %lx %lx %lx %lx\n", + old_len, lrb.pllen, resp_len, req_len); + rc = -5; + goto out; + } + + memset(blob, 0, sizeof(blob)); + blob_len = old_len; + memcpy(blob, lrb.payload, blob_len); + opaque_template[0].ulValueLen = blob_len; + + rc = funcs->C_SetAttributeValue(session, key_store[obj], opaque_template, + 1); + if (rc != CKR_OK) { + fprintf(stderr, + "reencryption C_SetAttributeValue failed: obj %lx '%s' rc: %lx\n", + obj, name, rc); + rc = -6; + goto out; + } + + fprintf(stderr, "reencryption success obj: %lx '%s:\n", obj, name); + +out: + if (_m_rm_module != NULL) + _m_rm_module(&module, target); + return rc; +} + +static CK_RV get_ep11_library_version(CK_VERSION *lib_version) +{ + unsigned int host_version; + CK_ULONG version_len = sizeof(host_version); + CK_RV rc; + + rc = _m_get_xcp_info(&host_version, &version_len, + CK_IBM_XCPHQ_VERSION, 0, 0); + if (rc != CKR_OK) { + fprintf(stderr, "_m_get_xcp_info (HOST) failed: rc=0x%lx\n", rc); + return rc; + } + lib_version->major = (host_version & 0x00FF0000) >> 16; + lib_version->minor = host_version & 0x000000FF0000; + /* + * EP11 host library < v2.0 returns an invalid version (i.e. 0x100). This + * can safely be treated as version 1.0 + */ + if (lib_version->major == 0) { + lib_version->major = 1; + lib_version->minor = 0; + } + + return CKR_OK; +} + + +static int check_card_status() +{ + CK_RV rc; + ep11_target_t target_list; + struct XCP_Module module; + target_t target = XCP_TGT_INIT; + CK_IBM_DOMAIN_INFO dinf; + CK_ULONG dinf_len = sizeof(dinf); + + if (adapter == -1 || domain == -1) { + fprintf(stderr, "adapter/domain specification missing.\n"); + return -1; + } + + if (_m_add_module != NULL) { + memset(&module, 0, sizeof(module)); + module.version = lib_version.major >= 3 ? XCP_MOD_VERSION_2 + : XCP_MOD_VERSION_1; + module.flags = XCP_MFL_MODULE; + module.module_nr = adapter; + XCPTGTMASK_SET_DOM(module.domainmask, domain); + rc = _m_add_module(&module, &target); + if (rc != 0) + return CKR_FUNCTION_FAILED; + } else { + /* Fall back to old target handling */ + memset(&target_list, 0, sizeof(ep11_target_t)); + target_list.length = 1; + target_list.apqns[0] = adapter; + target_list.apqns[1] = domain; + target = (target_t)&target_list; + } + + rc = _m_get_xcp_info((CK_VOID_PTR) &dinf, &dinf_len, + CK_IBM_XCPQ_DOMAIN, 0, target); + + if (rc != CKR_OK) { + fprintf(stderr, "m_get_xcp_info rc 0x%lx, valid apapter/domain " + "0x%02lx/%ld?.\n", rc, adapter, domain); + rc = -1; + goto out; + } + + if (CK_IBM_DOM_COMMITTED_NWK & dinf.flags) { + fprintf(stderr, "Card ID 0x%02lx, domain ID %ld has committed " + "pending(next) WK\n", adapter, domain); + } else { + fprintf(stderr, + "Card ID 0x%02lx, domain ID %ld has no committed pending WK\n", + adapter, domain); + rc = -1; + goto out; + } + +out: + if (_m_rm_module != NULL) + _m_rm_module(&module, target); + + return rc; +} + + +int get_pin(char **pin, size_t *pinlen) +{ + struct termios old, new; + int nread; + char *buff = NULL; + size_t buflen; + int rc = 0; + + /* turn echoing off */ + if (tcgetattr(fileno(stdin), &old) != 0) + return -1; + + new = old; + new.c_lflag &= ~ECHO; + if (tcsetattr(fileno(stdin), TCSAFLUSH, &new) != 0) + return -1; + + /* read the pin + * Note: getline will allocate memory for buff. free it when done. + */ + nread = getline(&buff, &buflen, stdin); + if (nread == -1) { + rc = -1; + goto done; + } + + /* Restore terminal */ + tcsetattr(fileno(stdin), TCSAFLUSH, &old); + + /* start a newline */ + printf("\n"); + fflush(stdout); + + /* Allocate PIN. + * Note: nread includes carriage return. + * Replace with terminating NULL. + */ + *pin = (char *) malloc(nread); + if (*pin == NULL) { + rc = -ENOMEM; + goto done; + } + + /* strip the carriage return since not part of pin. */ + buff[nread - 1] = '\0'; + memcpy(*pin, buff, nread); + /* don't include the terminating null in the pinlen */ + *pinlen = nread - 1; + +done: + if (buff) + free(buff); + + return rc; +} + +static int get_user_pin(CK_BYTE *dest) +{ + int ret; + char *userpin = NULL; + size_t userpinlen; + + printf("Enter the USER PIN: "); + fflush(stdout); + ret = get_pin(&userpin, &userpinlen); + if (ret != 0) { + fprintf(stderr, "Could not get USER PIN.\n"); + return -1; + } + + if (userpinlen > PKCS11_MAX_PIN_LEN) { + fprintf(stderr, "The USER PIN must be less than %d chars in length.\n", + (int) PKCS11_MAX_PIN_LEN); + free(userpin); + return -1; + } + + memcpy(dest, userpin, userpinlen + 1); + free(userpin); + + return 0; +} + +static int do_GetFunctionList(void) +{ + CK_RV rc; + CK_RV (*func_list) () = NULL; + void *d; + char *evar; + char *evar_default = "libopencryptoki.so"; + + evar = getenv("PKCSLIB"); + if (evar == NULL) { + evar = evar_default; + } + + d = dlopen(evar, RTLD_NOW); + if (d == NULL) { + return 0; + } + + *(void **)(&func_list) = dlsym(d, "C_GetFunctionList"); + if (func_list == NULL) { + return 0; + } + rc = func_list(&funcs); + + if (rc != CKR_OK) { + return 0; + } + + return 1; + +} + +static void usage(char *fct) +{ + printf("usage: %s [-slot ] [-adapter ] [-domain ] [-h]\n\n", + fct); + return; +} + +static int do_ParseArgs(int argc, char **argv) +{ + int i; + + if (argc <= 1) { + printf("No Arguments given. " + "For help use the '--help' or '-h' option.\n"); + return -1; + } + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { + usage(argv[0]); + return 0; + } else if (strcmp(argv[i], "-slot") == 0) { + if (!isdigit(*argv[i + 1])) { + printf("Slot parameter is not numeric!\n"); + return -1; + } + SLOT_ID = (int) strtol(argv[i + 1], NULL, 0); + i++; + } else if (strcmp(argv[i], "-adapter") == 0) { + if (!isdigit(*argv[i + 1])) { + printf("Adapter parameter is not numeric!\n"); + return -1; + } + adapter = (int) strtol(argv[i + 1], NULL, 0); + i++; + } else if (strcmp(argv[i], "-domain") == 0) { + if (!isdigit(*argv[i + 1])) { + printf("Domain parameter is not numeric!\n"); + return -1; + } + domain = (int) strtol(argv[i + 1], NULL, 0); + i++; + } else { + printf("Invalid argument passed as option: %s\n", argv[i]); + usage(argv[0]); + return -1; + } + } + if (SLOT_ID == (CK_SLOT_ID)(-1)) { + printf("Slot-ID not set!\n"); + return -1; + } + if (adapter == -1) { + printf("Adapter-ID not set!\n"); + return -1; + } + if (domain == -1) { + printf("Domain-ID not set!\n"); + return -1; + } + + return 1; +} + +#ifdef EP11_HSMSIM +#define DLOPEN_FLAGS RTLD_GLOBAL | RTLD_NOW | RTLD_DEEPBIND +#else +#define DLOPEN_FLAGS RTLD_GLOBAL | RTLD_NOW +#endif + +static void *ep11_load_host_lib() +{ + void *lib_ep11; + char *ep11_lib_name; + char *errstr; + + ep11_lib_name = getenv(EP11SHAREDLIB_NAME); + if (ep11_lib_name != NULL) { + lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS); + + if (lib_ep11 == NULL) { + errstr = dlerror(); + fprintf(stderr, "Error loading shared library '%s' [%s]\n", + ep11_lib_name, errstr); + return NULL; + } + return lib_ep11; + } + + ep11_lib_name = EP11SHAREDLIB_V3; + lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS); + + if (lib_ep11 == NULL) { + /* Try version 2 instead */ + ep11_lib_name = EP11SHAREDLIB_V2; + lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS); + } + + if (lib_ep11 == NULL) { + /* Try version 1 instead */ + ep11_lib_name = EP11SHAREDLIB_V1; + lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS); + } + + if (lib_ep11 == NULL) { + /* Try unversioned library instead */ + ep11_lib_name = EP11SHAREDLIB; + lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS); + } + + if (lib_ep11 == NULL) { + errstr = dlerror(); + fprintf(stderr, "Error loading shared library '%s[.3|.2|.1]' [%s]\n", + EP11SHAREDLIB, errstr); + return NULL; + } + + return lib_ep11; +} + +int main(int argc, char **argv) +{ + int rc; + void *lib_ep11; + CK_C_INITIALIZE_ARGS cinit_args; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN + 1]; + CK_FLAGS flags; + CK_SESSION_HANDLE session; + CK_ULONG obj; + CK_ULONG user_pin_len; + CK_ULONG keys_found = 0; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) { + return rc; + } + + /* dynamically load in the ep11 shared library */ + lib_ep11 = ep11_load_host_lib(); + if (!lib_ep11) + return CKR_FUNCTION_FAILED; + + *(void **)(&_xcpa_cmdblock) = dlsym(lib_ep11, "xcpa_cmdblock"); + if (_xcpa_cmdblock == NULL) + *(void **)(&_xcpa_cmdblock) = dlsym(lib_ep11, "ep11a_cmdblock"); + *(void **)(&_m_admin) = dlsym(lib_ep11, "m_admin"); + *(void **)(&_xcpa_internal_rv) = dlsym(lib_ep11, "xcpa_internal_rv"); + if (_xcpa_internal_rv == NULL) + *(void **)(&_xcpa_internal_rv) = dlsym(lib_ep11, "ep11a_internal_rv"); + *(void **)(&_m_get_xcp_info) = dlsym(lib_ep11, "m_get_xcp_info"); + if (_m_get_xcp_info == NULL) + *(void **)(&_m_get_xcp_info) = dlsym(lib_ep11, "m_get_ep11_info"); + + if (!_m_get_xcp_info || !_xcpa_cmdblock || + !_m_admin || !_xcpa_internal_rv) { + fprintf(stderr, "ERROR getting function pointer from shared lib '%s'", + EP11SHAREDLIB); + return CKR_FUNCTION_FAILED; + } + + /* + * The following are only available since EP11 host library version 2. + * Ignore if they fail to load, the code will fall back to the old target + * handling in this case. + */ + *(void **)(&_m_add_module) = dlsym(lib_ep11, "m_add_module"); + *(void **)(&_m_rm_module) = dlsym(lib_ep11, "m_rm_module"); + if (_m_add_module == NULL || _m_rm_module == NULL) { + _m_add_module = NULL; + _m_rm_module = NULL; + } + + printf("Using slot #%lu...\n\n", SLOT_ID); + + rc = do_GetFunctionList(); + if (!rc) { + fprintf(stderr, "ERROR do_GetFunctionList() Failed, rx = 0x%0x\n", rc); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + funcs->C_Initialize(&cinit_args); + { + CK_SESSION_HANDLE hsess = 0; + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) { + return rc; + } + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) { + return rc; + } + } + + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(SLOT_ID, flags, NULL, NULL, &session); + if (rc != CKR_OK) { + fprintf(stderr, "C_OpenSession() rc = 0x%02x [%s]\n", rc, + p11_get_ckr(rc)); + session = CK_INVALID_HANDLE; + return rc; + } + + if (get_user_pin(user_pin)) { + fprintf(stderr, "get_user_pin() failed\n"); + rc = funcs->C_CloseAllSessions(SLOT_ID); + if (rc != CKR_OK) + fprintf(stderr, "C_CloseAllSessions() rc = 0x%02x [%s]\n", rc, + p11_get_ckr(rc)); + return rc; + } + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + rc = funcs->C_Login(session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + fprintf(stderr, "C_Login() rc = 0x%02x [%s]\n", rc, p11_get_ckr(rc)); + return rc; + } + + rc = get_ep11_library_version(&lib_version); + if (rc != CKR_OK) + return rc; + + if (check_card_status() != 0) + return 1; + + /* find all objects */ + rc = funcs->C_FindObjectsInit(session, NULL, 0); + + do { + rc = funcs->C_FindObjects(session, key_store, 4096, &keys_found); + + if (rc != CKR_OK) { + fprintf(stderr, "C_FindObjects() rc = 0x%02x [%s]\n", rc, + p11_get_ckr(rc)); + return rc; + } + + for (obj = 0; obj < keys_found; obj++) { + CK_ATTRIBUTE opaque_template[] = { + {CKA_IBM_OPAQUE, NULL_PTR, 0} + }; + + CK_KEY_TYPE keytype; + CK_ATTRIBUTE key_type_template[] = { + {CKA_KEY_TYPE, &keytype, sizeof(CK_KEY_TYPE)} + }; + + CK_BYTE *old_blob; + + /* only for keys */ + rc = funcs->C_GetAttributeValue(session, key_store[obj], + key_type_template, 1); + if (rc != CKR_OK) + continue; + + /* exist and size query CKA_IBM_QPAQUE */ + rc = funcs->C_GetAttributeValue(session, key_store[obj], + opaque_template, 1); + if (rc == CKR_OK) { + old_blob = malloc(opaque_template[0].ulValueLen); + opaque_template[0].pValue = old_blob; + /* get the blob after knowing its size */ + rc = funcs->C_GetAttributeValue(session, key_store[obj], + opaque_template, 1); + + if (rc != CKR_OK) { + fprintf(stderr, "second C_GetAttributeValue failed " + "rc = 0x%02x [%s]\n", rc, p11_get_ckr(rc)); + return rc; + } else { + if (reencrypt(session, obj, + (CK_BYTE *) opaque_template[0].pValue, + opaque_template[0].ulValueLen) != 0) { + /* reencrypt failed */ + return -1; + } + } + free(old_blob); + } + } + } + /* next 4096 objects */ + while (keys_found != 0); + + rc = funcs->C_FindObjectsFinal(session); + fprintf(stderr, "all keys successfully reencrypted\n"); + + rc = funcs->C_Logout(session); + rc = funcs->C_CloseAllSessions(SLOT_ID); + + return rc; +} diff --git a/usr/sbin/pkcsep11_migrate/pkcsep11_migrate.mk b/usr/sbin/pkcsep11_migrate/pkcsep11_migrate.mk new file mode 100644 index 0000000..22169c2 --- /dev/null +++ b/usr/sbin/pkcsep11_migrate/pkcsep11_migrate.mk @@ -0,0 +1,13 @@ +sbin_PROGRAMS += usr/sbin/pkcsep11_migrate/pkcsep11_migrate +noinst_HEADERS += usr/sbin/pkcsep11_migrate/ep11adm.h + +usr_sbin_pkcsep11_migrate_pkcsep11_migrate_LDFLAGS = -lc -ldl -lpthread + +usr_sbin_pkcsep11_migrate_pkcsep11_migrate_CFLAGS = \ + -DLINUX -DPROGRAM_NAME=\"$(@)\" \ + -I${srcdir}/usr/include -I${srcdir}/usr/lib/ep11_stdll/ \ + -I${srcdir}/usr/lib/common -I${srcdir}/usr/sbin/pkcsep11_migrate + +usr_sbin_pkcsep11_migrate_pkcsep11_migrate_SOURCES = \ + usr/lib/common/p11util.c \ + usr/sbin/pkcsep11_migrate/pkcsep11_migrate.c diff --git a/usr/sbin/pkcsep11_session/pkcsep11_session.c b/usr/sbin/pkcsep11_session/pkcsep11_session.c new file mode 100644 index 0000000..9304613 --- /dev/null +++ b/usr/sbin/pkcsep11_session/pkcsep11_session.c @@ -0,0 +1,1163 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 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 + */ + +/* Management tool for EP11 sessions. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EP11SHAREDLIB_NAME "OCK_EP11_LIBRARY" +#define EP11SHAREDLIB_V3 "libep11.so.3" +#define EP11SHAREDLIB_V2 "libep11.so.2" +#define EP11SHAREDLIB_V1 "libep11.so.1" +#define EP11SHAREDLIB "libep11.so" +#define PKCS11_MAX_PIN_LEN 128 + +#define CKH_IBM_EP11_SESSION CKH_VENDOR_DEFINED + 1 +#define CKH_IBM_EP11_VHSMPIN CKH_VENDOR_DEFINED + 2 +#define CKA_HIDDEN CKA_VENDOR_DEFINED + 0x01000000 + +#ifndef XCP_PINBLOB_BYTES +#define XCP_HMAC_BYTES ((size_t) (256 /8)) /* SHA-256 */ +#define XCP_WK_BYTES ((size_t) (256 /8)) /* keypart and session sizes */ +#define MOD_WRAP_BLOCKSIZE ((size_t) (128 /8)) /* blob crypt block bytecount */ +#define XCP_PIN_SALT_BYTES MOD_WRAP_BLOCKSIZE +#define XCP_PINBLOB_BYTES \ + (XCP_WK_BYTES +XCP_PIN_SALT_BYTES +XCP_HMAC_BYTES) +#define XCP_MIN_PINBYTES 8 +#define XCP_MAX_PINBYTES 16 +#endif + +#define CK_IBM_XCPHQ_VERSION 0xff000001 + +#define UNUSED(var) ((void)(var)) + +typedef unsigned int (*m_Logout_t) (const unsigned char *pin, size_t len, + target_t target); +typedef int (*m_add_module_t) (XCP_Module_t module, target_t *target); +typedef int (*m_rm_module_t) (XCP_Module_t module, target_t target); +typedef CK_RV (*m_get_xcp_info_t)(CK_VOID_PTR pinfo, CK_ULONG_PTR infbytes, + unsigned int query, unsigned int subquery, + target_t target); + +#define SHA256_HASH_SIZE 32 +#define EP11_SESSION_ID_SIZE 16 +#define SYSFS_DEVICES_AP "/sys/devices/ap/" +#define REGEX_CARD_PATTERN "card[0-9a-fA-F]+" +#define REGEX_SUB_CARD_PATTERN "[0-9a-fA-F]+\\.[0-9a-fA-F]+" +#define MASK_EP11 0x04000000 + +typedef struct { + short format; + short length; + short apqns[512]; +} __attribute__ ((packed)) ep11_target_t; + +typedef CK_RV (*handler_t) (CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj, + CK_BYTE *pin_blob, CK_ULONG pin_blob_size, + CK_BYTE *session_id, CK_ULONG session_id_len, + ep11_target_t *ep11_targets, + pid_t pid, CK_DATE *date); +typedef CK_RV (*adapter_handler_t) (uint_32 adapter, uint_32 domain, + void *handler_data); + +CK_FUNCTION_LIST *funcs; +m_Logout_t dll_m_Logout; +m_add_module_t dll_m_add_module; +m_rm_module_t dll_m_rm_module; +m_get_xcp_info_t dll_m_get_xcp_info; +CK_SLOT_ID SLOT_ID = -1; +int action = 0; +int force = 0; +time_t filter_date = -1; +pid_t filter_pid = 0; +char filter_sess_id[EP11_SESSION_ID_SIZE]; +int filter_sess_id_set = 0; +unsigned long count = 0; +CK_RV error = CKR_OK; +CK_VERSION lib_version; + +#define ACTION_SHOW 1 +#define ACTION_LOGOUT 2 +#define ACTION_VHSMPIN 3 + +int get_pin(char **pin, size_t *pinlen) +{ + struct termios old, new; + int nread; + char *buff = NULL; + size_t buflen; + int rc = 0; + + /* turn echoing off */ + if (tcgetattr(fileno(stdin), &old) != 0) + return -1; + + new = old; + new.c_lflag &= ~ECHO; + if (tcsetattr(fileno(stdin), TCSAFLUSH, &new) != 0) + return -1; + + /* read the pin + * Note: getline will allocate memory for buff. free it when done. + */ + nread = getline(&buff, &buflen, stdin); + if (nread == -1) { + rc = -1; + goto done; + } + + /* Restore terminal */ + tcsetattr(fileno(stdin), TCSAFLUSH, &old); + + /* start a newline */ + printf("\n"); + fflush(stdout); + + /* Allocate PIN. + * Note: nread includes carriage return. + * Replace with terminating NULL. + */ + *pin = (char *) malloc(nread); + if (*pin == NULL) { + rc = -ENOMEM; + goto done; + } + + /* strip the carriage return since not part of pin. */ + buff[nread - 1] = '\0'; + memcpy(*pin, buff, nread); + /* don't include the terminating null in the pinlen */ + *pinlen = nread - 1; + +done: + if (buff) + free(buff); + + return rc; +} + +static int get_user_pin(CK_BYTE *dest) +{ + int ret; + char *userpin = NULL; + size_t userpinlen; + + printf("Enter the USER PIN: "); + fflush(stdout); + ret = get_pin(&userpin, &userpinlen); + if (ret != 0) { + fprintf(stderr, "Could not get USER PIN.\n"); + return -1; + } + + if (userpinlen > PKCS11_MAX_PIN_LEN) { + fprintf(stderr, "The USER PIN must be less than %d chars in length.\n", + (int) PKCS11_MAX_PIN_LEN); + free(userpin); + return -1; + } + + memcpy(dest, userpin, userpinlen + 1); + free(userpin); + + return 0; +} + +static int get_vhsm_pin(CK_BYTE *dest) +{ + int ret; + char *vhsmpin = NULL; + size_t vhsmpinlen; + + printf("Enter the new VHSM PIN: "); + fflush(stdout); + ret = get_pin(&vhsmpin, &vhsmpinlen); + if (ret != 0) { + fprintf(stderr, "Could not get VHSM PIN.\n"); + return -1; + } + + if (vhsmpinlen < XCP_MIN_PINBYTES) { + fprintf(stderr, "The VHSM PIN must be at least %d chars in length.\n", + (int) XCP_MIN_PINBYTES); + free(vhsmpin); + return -1; + } + if (vhsmpinlen > XCP_MAX_PINBYTES) { + fprintf(stderr, "The VHSM PIN must be less than %d chars in length.\n", + (int) XCP_MAX_PINBYTES); + free(vhsmpin); + return -1; + } + + memcpy(dest, vhsmpin, vhsmpinlen + 1); + free(vhsmpin); + + return 0; +} + +static int do_GetFunctionList(void) +{ + CK_RV rc; + CK_RV (*func_list)() = NULL; + void *d; + char *evar; + char *evar_default = "libopencryptoki.so"; + + evar = getenv("PKCSLIB"); + if (evar == NULL) + evar = evar_default; + + d = dlopen(evar, RTLD_NOW); + if (d == NULL) + return 0; + + *(void **)(&func_list) = dlsym(d, "C_GetFunctionList"); + if (func_list == NULL) + return 0; + + rc = func_list(&funcs); + + if (rc != CKR_OK) + return 0; + + return 1; +} + +int is_ep11_token(CK_SLOT_ID slot_id) +{ + CK_RV rc; + CK_TOKEN_INFO tokinfo; + + rc = funcs->C_GetTokenInfo(slot_id, &tokinfo); + if (rc != CKR_OK) + return FALSE; + + return strstr((const char *) tokinfo.model, "EP11") != NULL; +} + +static void usage(char *fct) +{ + printf("usage: %s show|logout|vhsmpin [-date ] [-pid ] " + "[-id ] [-slot ] [-force] [-h]\n\n", fct); + return; +} + +static int do_ParseArgs(int argc, char **argv) +{ + int i, k; + struct tm tm; + char *p; + unsigned int v; + + if (argc <= 1) { + printf("No Arguments given. For help use the '--help' or '-h' " + "option.\n"); + return -1; + } + + if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) { + usage(argv[0]); + return 0; + } else if (strcmp(argv[1], "show") == 0) { + action = ACTION_SHOW; + } else if (strcmp(argv[1], "logout") == 0) { + action = ACTION_LOGOUT; + } else if (strcmp(argv[1], "vhsmpin") == 0) { + action = ACTION_VHSMPIN; + } else { + printf("Unknown Action given. For help use the '--help' or '-h' " + "option.\n"); + return -1; + } + + for (i = 2; i < argc; i++) { + if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { + usage(argv[0]); + return 0; + } else if (strcmp(argv[i], "-slot") == 0) { + if (argc <= i + 1 || !isdigit(*argv[i + 1])) { + printf("Slot parameter is not numeric!\n"); + return -1; + } + SLOT_ID = (int) strtol(argv[i + 1], NULL, 0); + i++; + } else if (strcmp(argv[i], "-force") == 0) { + force = 1; + } else if (strcmp(argv[i], "-date") == 0) { + if (argc <= i + 1 || strlen(argv[i + 1]) == 0) { + printf("Date parameter is not valid!\n"); + return -1; + } + memset(&tm, 0, sizeof(tm)); + p = strptime(argv[i + 1], "%Y/%m/%d", &tm); + if (p == NULL || *p != '\0') { + printf("Date parameter is not valid!\n"); + return -1; + } + filter_date = mktime(&tm); + if (filter_date == -1) { + printf("Date parameter is not valid!\n"); + return -1; + } + i++; + } else if (strcmp(argv[i], "-pid") == 0) { + if (argc <= i + 1 || !isdigit(*argv[i + 1])) { + printf("Pid parameter is not numeric!\n"); + return -1; + } + filter_pid = (pid_t) strtol(argv[i + 1], NULL, 0); + i++; + } else if (strcmp(argv[i], "-id") == 0) { + if (argc <= i + 1 + || strlen(argv[i + 1]) != EP11_SESSION_ID_SIZE * 2) { + printf("Id parameter is not valid!\n"); + return -1; + } + p = argv[i + 1]; + for (k = 0; k < EP11_SESSION_ID_SIZE; k++, p += 2) { + if (sscanf(p, "%02X", &v) != 1) { + printf("Id parameter is not valid!\n"); + return -1; + } + filter_sess_id[k] = v; + } + filter_sess_id_set = 1; + i++; + } else { + printf("Invalid argument passed as option: %s\n", argv[i]); + usage(argv[0]); + return -1; + } + } + if (SLOT_ID == (CK_SLOT_ID)(-1)) { + printf("Slot-ID not set!\n"); + return -1; + } + + return 1; +} + +static int is_process_running(pid_t pid) +{ + char fbuf[800]; + int fd; + + sprintf(fbuf, "/proc/%d/stat", pid); + if ((fd = open(fbuf, O_RDONLY, 0)) == -1) + return FALSE; + + close(fd); + + return TRUE; +} + +static CK_RV get_ep11_library_version(CK_VERSION *lib_version) +{ + unsigned int host_version; + CK_ULONG version_len = sizeof(host_version); + CK_RV rc; + + rc = dll_m_get_xcp_info(&host_version, &version_len, + CK_IBM_XCPHQ_VERSION, 0, 0); + if (rc != CKR_OK) { + fprintf(stderr, "dll_m_get_xcp_info (HOST) failed: rc=0x%lx\n", rc); + return rc; + } + lib_version->major = (host_version & 0x00FF0000) >> 16; + lib_version->minor = host_version & 0x000000FF0000; + /* + * EP11 host library < v2.0 returns an invalid version (i.e. 0x100). This + * can safely be treated as version 1.0 + */ + if (lib_version->major == 0) { + lib_version->major = 1; + lib_version->minor = 0; + } + + return CKR_OK; +} + +static CK_RV logout_handler(uint_32 adapter, uint_32 domain, void *handler_data) +{ + ep11_target_t target_list; + struct XCP_Module module; + target_t target = XCP_TGT_INIT; + CK_RV rc; + + if (dll_m_add_module != NULL) { + memset(&module, 0, sizeof(module)); + module.version = lib_version.major >= 3 ? XCP_MOD_VERSION_2 + : XCP_MOD_VERSION_1; + module.flags = XCP_MFL_MODULE; + module.module_nr = adapter; + XCPTGTMASK_SET_DOM(module.domainmask, domain); + rc = dll_m_add_module(&module, &target); + if (rc != 0) + return CKR_FUNCTION_FAILED; + } else { + /* Fall back to old target handling */ + memset(&target_list, 0, sizeof(ep11_target_t)); + target_list.length = 1; + target_list.apqns[0] = adapter; + target_list.apqns[1] = domain; + target = (target_t)&target_list; + } + + rc = dll_m_Logout(handler_data, XCP_PINBLOB_BYTES, target); + if (rc != CKR_OK && rc != CKR_SESSION_CLOSED) { + fprintf(stderr, + "WARNING: Logout failed for adapter %02X.%04X: 0x%lx [%s]\n", + adapter, domain, rc, p11_get_ckr(rc)); + error = rc; + } + + if (dll_m_rm_module != NULL) + dll_m_rm_module(&module, target); + + return CKR_OK; +} + +static CK_RV file_fgets(const char *fname, char *buf, size_t buflen) +{ + FILE *fp; + char *end; + CK_RV rc = CKR_OK; + + buf[0] = '\0'; + + fp = fopen(fname, "r"); + if (fp == NULL) { + fprintf(stderr, "Failed to open file '%s'\n", fname); + return CKR_FUNCTION_FAILED; + } + if (fgets(buf, buflen, fp) == NULL) { + fprintf(stderr, "Failed to read from file '%s'\n", fname); + rc = CKR_FUNCTION_FAILED; + goto out_fclose; + } + + end = memchr(buf, '\n', buflen); + if (end) + *end = 0; + else + buf[buflen - 1] = 0; + + if (strlen(buf) == 0) { + rc = CKR_FUNCTION_FAILED; + goto out_fclose; + } + +out_fclose: + fclose(fp); + + return rc; +} + +static CK_RV is_card_ep11_and_online(const char *name) +{ + char fname[290]; + char buf[250]; + CK_RV rc; + unsigned long val; + +#ifdef EP11_HSMSIM + return CKR_OK; +#endif + + sprintf(fname, "%s%s/online", SYSFS_DEVICES_AP, name); + rc = file_fgets(fname, buf, sizeof(buf)); + if (rc != CKR_OK) + return rc; + if (strcmp(buf, "1") != 0) + return CKR_FUNCTION_FAILED; + + sprintf(fname, "%s%s/ap_functions", SYSFS_DEVICES_AP, name); + rc = file_fgets(fname, buf, sizeof(buf)); + if (rc != CKR_OK) + return rc; + if (sscanf(buf, "%lx", &val) != 1) + val = 0x00000000; + if ((val & MASK_EP11) == 0) + return CKR_FUNCTION_FAILED; + + return CKR_OK; +} + +static CK_RV scan_for_card_domains(const char *name, adapter_handler_t handler, + void *handler_data) +{ + char fname[290]; + regex_t reg_buf; + regmatch_t pmatch[1]; + DIR *d; + struct dirent *de; + char *tok; + uint_32 adapter, domain; + +#ifdef EP11_HSMSIM + return handler(0, 0, handler_data); +#endif + + if (regcomp(®_buf, REGEX_SUB_CARD_PATTERN, REG_EXTENDED) != 0) { + fprintf(stderr, "Failed to compile regular expression '%s'\n", + REGEX_SUB_CARD_PATTERN); + return CKR_FUNCTION_FAILED; + } + + sprintf(fname, "%s%s/", SYSFS_DEVICES_AP, name); + d = opendir(fname); + if (d == NULL) { + fprintf(stderr, "Directory %s is not available\n", fname); + regfree(®_buf); + // ignore this error, card may have been removed in the meantime + return CKR_OK; + } + + while ((de = readdir(d)) != NULL) { + if (regexec(®_buf, de->d_name, (size_t) 1, pmatch, 0) == 0) { + tok = strtok(de->d_name, "."); + if (tok == NULL) + continue; + if (sscanf(tok, "%x", &adapter) != 1) + continue; + + tok = strtok(NULL, ","); + if (tok == NULL) + continue; + if (sscanf(tok, "%x", &domain) != 1) + continue; + + if (handler(adapter, domain, handler_data) != CKR_OK) + break; + } + } + + closedir(d); + regfree(®_buf); + + return CKR_OK; +} + +/* + * Iterate over all cards in the sysfs directorys /sys/device/ap/cardxxx + * and check if the card is online. Calls the handler function for all + * online EP11 cards. + */ +static CK_RV scan_for_ep11_cards(adapter_handler_t handler, void *handler_data) +{ + DIR *d; + struct dirent *de; + regex_t reg_buf; + regmatch_t pmatch[1]; + + if (handler == NULL) + return CKR_ARGUMENTS_BAD; + +#ifdef EP11_HSMSIM + return handler(0, 0, handler_data); +#endif + + if (regcomp(®_buf, REGEX_CARD_PATTERN, REG_EXTENDED) != 0) { + fprintf(stderr, "Failed to compile regular expression '%s'\n", + REGEX_CARD_PATTERN); + return CKR_FUNCTION_FAILED; + } + + d = opendir(SYSFS_DEVICES_AP); + if (d == NULL) { + fprintf(stderr, "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) { + if (is_card_ep11_and_online(de->d_name) != CKR_OK) + continue; + + if (scan_for_card_domains(de->d_name, handler, handler_data) != + CKR_OK) + break; + } + } + + closedir(d); + regfree(®_buf); + + return CKR_OK; +} + +static CK_RV handle_all_ep11_cards(ep11_target_t *ep11_targets, + adapter_handler_t handler, + void *handler_data) +{ + int i; + CK_RV rc; + + if (ep11_targets->length > 0) { + /* APQN_WHITELIST is specified */ + for (i = 0; i < ep11_targets->length; i++) { + rc = handler(ep11_targets->apqns[2 * i], + ep11_targets->apqns[2 * i + 1], handler_data); + if (rc != CKR_OK) + return rc; + } + } else { + /* APQN_ANY used, scan sysfs for available cards */ + return scan_for_ep11_cards(handler, handler_data); + } + + return CKR_OK; +} + +static CK_RV logout_session_obj(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj, + CK_BYTE *pin_blob, CK_ULONG pin_blob_size, + CK_BYTE *session_id, CK_ULONG session_id_len, + ep11_target_t *ep11_targets, + pid_t pid, CK_DATE *date) +{ + CK_RV rc; + CK_ULONG i; + + UNUSED(pin_blob_size); + + for (i = 0; i < session_id_len; i++) + printf("%02X", session_id[i]); + printf(":\n"); + if (is_process_running(pid)) + printf("\tPid:\t%u (still running)\n", pid); + else + printf("\tPid:\t%u\n", pid); + printf("\tDate:\t%.4s/%.2s/%.2s\n", date->year, date->month, date->day); + + if (is_process_running(pid)) { + printf("\tSession is not logged out, process %u is still running\n", + pid); + return CKR_OK; + } + + error = CKR_OK; + rc = handle_all_ep11_cards(ep11_targets, logout_handler, pin_blob); + if (rc != CKR_OK) { + fprintf(stderr, "handle_all_ep11_cards() rc = 0x%02lx [%s]\n", rc, + p11_get_ckr(rc)); + return rc; + } + if (error != CKR_OK) { + fprintf(stderr, + "WARNING: Not all APQNs were successfully logged out.\n"); + if (!force) { + fprintf(stderr, + " Session is not deleted. Specify -force to delete" + "it anyway.\n"); + return rc; + } + } + + rc = funcs->C_DestroyObject(session, obj); + if (rc != CKR_OK) { + fprintf(stderr, "C_DestroyObject() rc = 0x%02lx [%s]\n", rc, + p11_get_ckr(rc)); + return rc; + } + + if (!force) + printf("\tSession logged out successfully\n"); + else + printf("\tSession deleted due to -force option\n"); + + count++; + + return CKR_OK; +} + + + +static CK_RV show_session_obj(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj, + CK_BYTE *pin_blob, CK_ULONG pin_blob_size, + CK_BYTE *session_id, CK_ULONG session_id_len, + ep11_target_t *ep11_targets, + pid_t pid, CK_DATE *date) +{ + CK_ULONG i; + + UNUSED(session); + UNUSED(obj); + UNUSED(pin_blob); + UNUSED(pin_blob_size); + UNUSED(ep11_targets); + + for (i = 0; i < session_id_len; i++) + printf("%02X", session_id[i]); + printf(":\n"); + if (is_process_running(pid)) + printf("\tPid:\t%u (still running)\n", pid); + else + printf("\tPid:\t%u\n", pid); + printf("\tDate:\t%.4s/%.2s/%.2s\n", date->year, date->month, date->day); + + count++; + + return CKR_OK; +} + +static CK_BBOOL filter_session(CK_BYTE *session_id, CK_ULONG session_id_len, + CK_DATE *date, pid_t pid) +{ + struct tm tm; + char temp[12]; + char *p; + time_t t; + + if (filter_sess_id_set) { + if (session_id_len == sizeof(filter_sess_id) && + memcmp(session_id, filter_sess_id, session_id_len) == 0) + return TRUE; + return FALSE; + } + + if (filter_date != -1) { + memset(&tm, 0, sizeof(tm)); + memcpy(temp, date->year, 4); + temp[4] = '/'; + memcpy(temp + 5, date->month, 2); + temp[7] = '/'; + memcpy(temp + 8, date->day, 2); + temp[10] = '\0'; + + p = strptime(temp, "%Y/%m/%d", &tm); + if (p == NULL || *p != '\0') + return FALSE; + t = mktime(&tm); + if (t == -1) + return FALSE; + if (difftime(t, filter_date) <= 0) + return TRUE; + return FALSE; + } + + if (filter_pid != 0) { + if (pid == filter_pid) + return TRUE; + return FALSE; + } + + return TRUE; +} + +static CK_RV process_session_obj(CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE obj, handler_t handler) +{ + CK_RV rc; + CK_BBOOL match; + CK_BYTE pin_blob[XCP_PINBLOB_BYTES]; + CK_BYTE session_id[EP11_SESSION_ID_SIZE]; + ep11_target_t ep11_targets; + pid_t pid; + CK_DATE date; + CK_ATTRIBUTE attrs[] = { + { CKA_VALUE, pin_blob, sizeof(pin_blob) }, + { CKA_ID, session_id, sizeof(session_id) }, + { CKA_APPLICATION, &ep11_targets, sizeof(ep11_targets) }, + { CKA_OWNER, &pid, sizeof(pid) }, + { CKA_START_DATE, &date, sizeof(date) }, + }; + + rc = funcs->C_GetAttributeValue(session, obj, attrs, + sizeof(attrs) / sizeof(CK_ATTRIBUTE)); + if (rc != CKR_OK) { + fprintf(stderr, "C_GetAttributeValue() rc = 0x%02lx [%s]\n", rc, + p11_get_ckr(rc)); + + /* Invalid CKH_IBM_EP11_SESSION object */ + rc = funcs->C_DestroyObject(session, obj); + return CKR_OK; + } + + /* Ignore our own EP11 session */ + if (pid == getpid()) + return CKR_OK; + + match = filter_session(session_id, sizeof(session_id), &date, pid); + + if (match) { + rc = handler(session, obj, pin_blob, sizeof(pin_blob), + session_id, sizeof(session_id), &ep11_targets, pid, &date); + if (rc != CKR_OK) + return rc; + } + + return CKR_OK; +} + +static CK_RV find_sessions(CK_SESSION_HANDLE session, handler_t handler) +{ + CK_RV rc; + CK_OBJECT_HANDLE obj_store[4096]; + CK_ULONG objs_found = 0; + CK_ULONG obj; + CK_OBJECT_CLASS class = CKO_HW_FEATURE; + CK_HW_FEATURE_TYPE type = CKH_IBM_EP11_SESSION; + CK_BYTE true = TRUE; + CK_ATTRIBUTE session_template[] = { + { CKA_CLASS, &class, sizeof(class) }, + { CKA_TOKEN, &true, sizeof(true) }, + { CKA_PRIVATE, &true, sizeof(true) }, + { CKA_HIDDEN, &true, sizeof(true) }, + { CKA_HW_FEATURE_TYPE, &type, sizeof(type) }, + }; + + /* find all objects */ + rc = funcs->C_FindObjectsInit(session, session_template, + sizeof(session_template) / + sizeof(CK_ATTRIBUTE)); + if (rc != CKR_OK) { + fprintf(stderr, "C_FindObjectsInit() rc = 0x%02lx [%s]\n", rc, + p11_get_ckr(rc)); + goto out; + } + + do { + rc = funcs->C_FindObjects(session, obj_store, 4096, &objs_found); + if (rc != CKR_OK) { + fprintf(stderr, "C_FindObjects() rc = 0x%02lx [%s]\n", rc, + p11_get_ckr(rc)); + goto out; + } + + for (obj = 0; obj < objs_found; obj++) { + rc = process_session_obj(session, obj_store[obj], handler); + if (rc != CKR_OK) + goto out; + } + } while (objs_found != 0); + +out: + funcs->C_FindObjectsFinal(session); + + return rc; +} + +static CK_RV show_sessions(CK_SESSION_HANDLE session) +{ + CK_RV rc; + + printf("List of EP11 sessions:\n\n"); + count = 0; + rc = find_sessions(session, show_session_obj); + if (rc != CKR_OK) + return rc; + printf("\n%lu EP11-Sessions displayed\n", count); + return 0; +} + +static CK_RV logout_sessions(CK_SESSION_HANDLE session) +{ + CK_RV rc; + + printf("List of EP11 sessions:\n\n"); + count = 0; + rc = find_sessions(session, logout_session_obj); + if (rc != CKR_OK) + return rc; + printf("\n%lu EP11-Sessions logged out\n", count); + return rc; +} + +static CK_RV find_vhsmpin_object(CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE *obj) +{ + CK_RV rc; + CK_OBJECT_HANDLE obj_store[16]; + CK_ULONG objs_found = 0; + CK_OBJECT_CLASS class = CKO_HW_FEATURE; + CK_HW_FEATURE_TYPE type = CKH_IBM_EP11_VHSMPIN; + CK_BYTE true = TRUE; + CK_ATTRIBUTE vhsmpin_template[] = { + { CKA_CLASS, &class, sizeof(class) }, + { CKA_TOKEN, &true, sizeof(true) }, + { CKA_PRIVATE, &true, sizeof(true) }, + { CKA_HIDDEN, &true, sizeof(true) }, + { CKA_HW_FEATURE_TYPE, &type, sizeof(type) }, + }; + + /* find all objects */ + rc = funcs->C_FindObjectsInit(session, vhsmpin_template, + sizeof(vhsmpin_template) / + sizeof(CK_ATTRIBUTE)); + if (rc != CKR_OK) { + fprintf(stderr, "C_FindObjectsInit() rc = 0x%02lx [%s]\n", rc, + p11_get_ckr(rc)); + goto out; + } + + rc = funcs->C_FindObjects(session, obj_store, 16, &objs_found); + if (rc != CKR_OK) { + fprintf(stderr, "C_FindObjects() rc = 0x%02lx [%s]\n", rc, + p11_get_ckr(rc)); + goto out; + } + + if (objs_found > 0) + *obj = obj_store[0]; + else + *obj = CK_INVALID_HANDLE; + +out: + funcs->C_FindObjectsFinal(session); + + return rc; +} + + +static CK_RV set_vhsmpin(CK_SESSION_HANDLE session) +{ + CK_RV rc; + CK_BYTE vhsm_pin[XCP_MAX_PINBYTES + 1]; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + CK_OBJECT_CLASS class = CKO_HW_FEATURE; + CK_HW_FEATURE_TYPE type = CKH_IBM_EP11_VHSMPIN; + CK_BYTE subject[] = "EP11 VHSM-Pin Object"; + CK_BYTE true = TRUE; + + if (get_vhsm_pin(vhsm_pin)) { + fprintf(stderr, "get_vhsm_pin() failed\n"); + return CKR_FUNCTION_FAILED; + } + + CK_ATTRIBUTE attrs[] = { + { CKA_CLASS, &class, sizeof(class) }, + { CKA_TOKEN, &true, sizeof(true) }, + { CKA_PRIVATE, &true, sizeof(true) }, + { CKA_HIDDEN, &true, sizeof(true) }, + { CKA_HW_FEATURE_TYPE, &type, sizeof(type) }, + { CKA_SUBJECT, &subject, sizeof(subject) }, + { CKA_VALUE, vhsm_pin, strlen((char *)vhsm_pin) }, + }; + + rc = find_vhsmpin_object(session, &obj); + if (rc != CKR_OK) { + fprintf(stderr, "find_vhsmpin_object() failed\n"); + return CKR_FUNCTION_FAILED; + } + + if (obj != CK_INVALID_HANDLE) { + rc = funcs->C_DestroyObject(session, obj); + if (rc != CKR_OK) { + fprintf(stderr, "C_DestroyObject() rc = 0x%02lx [%s]\n", rc, + p11_get_ckr(rc)); + return rc; + } + } + + rc = funcs->C_CreateObject(session, + attrs, sizeof(attrs) / sizeof(CK_ATTRIBUTE), + &obj); + if (rc != CKR_OK) { + fprintf(stderr, "C_CreateObject() rc = 0x%02lx [%s]\n", rc, + p11_get_ckr(rc)); + return rc; + } + printf("VHSM-pin successfully set.\n"); + + return CKR_OK; +} + +#ifdef EP11_HSMSIM +#define DLOPEN_FLAGS RTLD_GLOBAL | RTLD_NOW | RTLD_DEEPBIND +#else +#define DLOPEN_FLAGS RTLD_GLOBAL | RTLD_NOW +#endif + +static void *ep11_load_host_lib() +{ + void *lib_ep11; + char *ep11_lib_name; + char *errstr; + + ep11_lib_name = getenv(EP11SHAREDLIB_NAME); + if (ep11_lib_name != NULL) { + lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS); + + if (lib_ep11 == NULL) { + errstr = dlerror(); + fprintf(stderr, "Error loading shared library '%s' [%s]\n", + ep11_lib_name, errstr); + return NULL; + } + return lib_ep11; + } + + ep11_lib_name = EP11SHAREDLIB_V3; + lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS); + + if (lib_ep11 == NULL) { + /* Try version 2 instead */ + ep11_lib_name = EP11SHAREDLIB_V2; + lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS); + } + + if (lib_ep11 == NULL) { + /* Try version 1 instead */ + ep11_lib_name = EP11SHAREDLIB_V1; + lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS); + } + + if (lib_ep11 == NULL) { + /* Try unversioned library instead */ + ep11_lib_name = EP11SHAREDLIB; + lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS); + } + + if (lib_ep11 == NULL) { + errstr = dlerror(); + fprintf(stderr, "Error loading shared library '%s[.3|.2|.1]' [%s]\n", + EP11SHAREDLIB, errstr); + return NULL; + } + + return lib_ep11; +} + +int main(int argc, char **argv) +{ + int rc; + void *lib_ep11; + CK_C_INITIALIZE_ARGS cinit_args; + CK_BYTE user_pin[PKCS11_MAX_PIN_LEN + 1]; + CK_FLAGS flags; + CK_SESSION_HANDLE session; + CK_ULONG user_pin_len; + + rc = do_ParseArgs(argc, argv); + if (rc != 1) + return rc; + + /* dynamically load in the ep11 shared library */ + lib_ep11 = ep11_load_host_lib(); + if (!lib_ep11) + return CKR_FUNCTION_FAILED; + + *(void **)(&dll_m_Logout) = dlsym(lib_ep11, "m_Logout"); + *(void **)(&dll_m_get_xcp_info) = dlsym(lib_ep11, "m_get_xcp_info"); + if (dll_m_Logout == NULL || dll_m_get_xcp_info == NULL) { + fprintf(stderr, "ERROR loading shared lib '%s' [%s]\n", + EP11SHAREDLIB, dlerror()); + return CKR_FUNCTION_FAILED; + } + /* + * The following are only available since EP11 host library version 2. + * Ignore if they fail to load, the code will fall back to the old target + * handling in this case. + */ + *(void **)(&dll_m_add_module) = dlsym(lib_ep11, "m_add_module"); + *(void **)(&dll_m_rm_module) = dlsym(lib_ep11, "m_rm_module"); + if (dll_m_add_module == NULL || dll_m_rm_module == NULL) { + dll_m_add_module = NULL; + dll_m_rm_module = NULL; + } + + rc = get_ep11_library_version(&lib_version); + if (rc != CKR_OK) + return rc; + + printf("Using slot #%lu...\n\n", SLOT_ID); + + rc = do_GetFunctionList(); + if (!rc) { + fprintf(stderr, "ERROR do_GetFunctionList() Failed, rx = 0x%0x\n", rc); + return rc; + } + + memset(&cinit_args, 0x0, sizeof(cinit_args)); + cinit_args.flags = CKF_OS_LOCKING_OK; + + funcs->C_Initialize(&cinit_args); + { + CK_SESSION_HANDLE hsess = 0; + rc = funcs->C_GetFunctionStatus(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + + rc = funcs->C_CancelFunction(hsess); + if (rc != CKR_FUNCTION_NOT_PARALLEL) + return rc; + } + + if (!is_ep11_token(SLOT_ID)) { + fprintf(stderr, "ERROR Slot %lu is not an EP11 token\n", SLOT_ID); + return CKR_FUNCTION_FAILED; + } + + flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + rc = funcs->C_OpenSession(SLOT_ID, flags, NULL, NULL, &session); + if (rc != CKR_OK) { + fprintf(stderr, "C_OpenSession() rc = 0x%02x [%s]\n", rc, + p11_get_ckr(rc)); + session = CK_INVALID_HANDLE; + return rc; + } + + if (get_user_pin(user_pin)) { + fprintf(stderr, "get_user_pin() failed\n"); + rc = funcs->C_CloseAllSessions(SLOT_ID); + if (rc != CKR_OK) + fprintf(stderr, "C_CloseAllSessions() rc = 0x%02x [%s]\n", rc, + p11_get_ckr(rc)); + return rc; + } + + user_pin_len = (CK_ULONG) strlen((char *) user_pin); + rc = funcs->C_Login(session, CKU_USER, user_pin, user_pin_len); + if (rc != CKR_OK) { + fprintf(stderr, "C_Login() rc = 0x%02x [%s]\n", rc, p11_get_ckr(rc)); + return rc; + } + + switch (action) { + case ACTION_SHOW: + rc = show_sessions(session); + break; + case ACTION_LOGOUT: + rc = logout_sessions(session); + break; + case ACTION_VHSMPIN: + rc = set_vhsmpin(session); + break; + } + if (rc != CKR_OK) + return rc; + + rc = funcs->C_Logout(session); + rc = funcs->C_CloseAllSessions(SLOT_ID); + + return rc; +} diff --git a/usr/sbin/pkcsep11_session/pkcsep11_session.mk b/usr/sbin/pkcsep11_session/pkcsep11_session.mk new file mode 100644 index 0000000..2fe0209 --- /dev/null +++ b/usr/sbin/pkcsep11_session/pkcsep11_session.mk @@ -0,0 +1,12 @@ +sbin_PROGRAMS += usr/sbin/pkcsep11_session/pkcsep11_session + +usr_sbin_pkcsep11_session_pkcsep11_session_LDFLAGS = -lc -ldl -lpthread + +usr_sbin_pkcsep11_session_pkcsep11_session_CFLAGS = \ + -DLINUX -DPROGRAM_NAME=\"$(@)\" \ + -I${srcdir}/usr/include -I${srcdir}/usr/lib/ep11_stdll/ \ + -I${srcdir}/usr/lib/common -I${srcdir}/usr/sbin/pkcsep11_session + +usr_sbin_pkcsep11_session_pkcsep11_session_SOURCES = \ + usr/lib/common/p11util.c \ + usr/sbin/pkcsep11_session/pkcsep11_session.c diff --git a/usr/sbin/pkcsicsf/pkcsicsf.c b/usr/sbin/pkcsicsf/pkcsicsf.c new file mode 100644 index 0000000..64759ad --- /dev/null +++ b/usr/sbin/pkcsicsf/pkcsicsf.c @@ -0,0 +1,689 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2012-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 + */ + +/* + * OpenCryptoki ICSF token configuration tool. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "icsf.h" +#include "slotmgr.h" +#include "pbkdf.h" +#include "defs.h" + +#define CFG_ADD 0x0001 +#define CFG_LIST 0x0002 +#define CFG_BINDDN 0x0004 +#define CFG_CERT 0x0008 +#define CFG_PRIVKEY 0x0010 +#define CFG_CACERT 0x0020 +#define CFG_URI 0x0040 +#define CFG_MECH 0x0080 +#define CFG_MECH_SASL 0x0100 +#define CFG_MECH_SIMPLE 0x0200 + +#define MAX_RECORDS 10 +#define SALT_SIZE 16 +#define SASL "sasl" +#define SLOT "slot" + +#define TMPSIZ 64 +#define LINESIZ 512 +#define TOKBUF 2056 +#define STDLL "libpkcs11_icsf.so" + +LDAP *ld; +char *binddn = NULL; +char *uri = NULL; +char *mech = NULL; +char *cert = NULL; +char *cacert = NULL; +char *privkey = NULL; +unsigned long flags = 0; + +void usage(char *progname) +{ + printf("usage:\t%s [-h] [ -l | -a token-name] [-b BINDDN]" + " [-c client-cert-file] [-C CA-cert-file] [-k key] [-u URI]" + " [-m MECHANISM]\n", progname); + printf("\t-a add specified token\n"); + printf("\t-b the distinguish name to bind for simple mode\n"); + printf("\t-C the CA certificate file for SASL mode\n"); + printf("\t-c the client certificate file for SASL mode\n"); + printf("\t-h show this help\n"); + printf("\t-k the client private key file for SASL mode\n"); + printf("\t-l list available tokens\n"); + printf("\t-m the authentication mechanism, " + "it can be 'simple' or 'sasl'\n"); + printf("\t-u the URI to connect to\n"); + + exit(-1); +} + +int get_pin(char **pin, size_t *pinlen) +{ + struct termios old, new; + int nread; + char *buff = NULL; + size_t buflen; + int rc = 0; + + /* turn echoing off */ + if (tcgetattr(fileno(stdin), &old) != 0) + return -1; + + new = old; + new.c_lflag &= ~ECHO; + if (tcsetattr(fileno(stdin), TCSAFLUSH, &new) != 0) + return -1; + + /* read the pin + * Note: getline will allocate memory for buff. free it when done. + */ + nread = getline(&buff, &buflen, stdin); + if (nread == -1) { + rc = -1; + goto done; + } + + /* Restore terminal */ + (void) tcsetattr(fileno(stdin), TCSAFLUSH, &old); + + /* start a newline */ + printf("\n"); + fflush(stdout); + + /* Allocate PIN. + * Note: nread includes carriage return. + * Replace with terminating NULL. + */ + *pin = (char *) malloc(nread); + if (*pin == NULL) { + rc = -ENOMEM; + goto done; + } + + /* strip the carriage return since not part of pin. */ + buff[nread - 1] = '\0'; + memcpy(*pin, buff, nread); + /* don't include the terminating null in the pinlen */ + *pinlen = nread - 1; + +done: + if (buff) + free(buff); + + return rc; +} + +int get_start_slot(void) +{ + + FILE *fp; + char temp[LINESIZ]; + int num; + int found = -1; + struct stat statbuf; + + /* if file doesn't exist, then first slot will be 0. */ + if ((stat(OCK_CONFIG, &statbuf) < 0) && (errno == ENOENT)) + return 0; + + fp = fopen(OCK_CONFIG, "r"); + if (fp == NULL) { + fprintf(stderr, "open failed, line %d: %s\n", + __LINE__, strerror(errno)); + return -1; + } + + /* step thru config file and get biggest slot number used */ + while (fgets(temp, LINESIZ, fp) != NULL) { + if (strstr(temp, SLOT) != NULL) { + if (sscanf(temp, "%*s %d", &num) == 1) + if (num > found) + found = num; + } + } + + /* bump up the slot number, since this will be next new slot entry. + * if it was an empty file or a file with no slot entries, + * then next new slot entry will be 0. + */ + + fclose(fp); + + return ++found; +} + +int remove_file(char *filename) +{ + struct stat statbuf; + + /* if file exists, then remove it */ + if ((stat(filename, &statbuf) < 0) && (errno == ENOENT)) { + if (unlink(filename) == -1) { + fprintf(stderr, "unlink failed for %s, line %d: %s\n", + filename, __LINE__, strerror(errno)); + return -1; + } + } + + return 0; +} + +static void add_token_config_entry(FILE *fp, const char *key, const char *value) +{ + if (!key || !value) + return; + + fprintf(fp, "%s = \"%s\"\n", key, value); +} + +int add_token_config(const char *configname, + struct icsf_token_record token, int slot) +{ + FILE *tfp; + int rc = 0; + + /* create the token config file */ + tfp = fopen(configname, "w"); + if (tfp == NULL) { + fprintf(stderr, "fopen failed, line %d: %s\n", + __LINE__, strerror(errno)); + return -1; + } + + /* add the info */ + fprintf(tfp, "slot %d {\n", slot); + add_token_config_entry(tfp, "TOKEN_NAME", token.name); + add_token_config_entry(tfp, "TOKEN_MANUFACTURE", token.manufacturer); + add_token_config_entry(tfp, "TOKEN_MODEL", token.model); + add_token_config_entry(tfp, "TOKEN_SERIAL", token.serial); + add_token_config_entry(tfp, "MECH", (flags & CFG_MECH_SIMPLE) + ? "SIMPLE" : "SASL"); + + /* add BIND info */ + if (memcmp(mech, "simple", strlen("simple")) == 0) { + add_token_config_entry(tfp, "BINDDN", binddn); + add_token_config_entry(tfp, "URI", uri); + } else { + add_token_config_entry(tfp, "URI", uri); + add_token_config_entry(tfp, "CERT", cert); + add_token_config_entry(tfp, "CACERT", cacert); + add_token_config_entry(tfp, "KEY", privkey); + } + + fprintf(tfp, "}\n"); + + fflush(tfp); + if (ferror(tfp) != 0) { + fprintf(stderr, "failed to add token named, %s\n", token.name); + rc = -1; + } + + fclose(tfp); + + return rc; +} + +int config_add_slotinfo(int num_of_slots, struct icsf_token_record *tokens) +{ + struct stat statbuf; + FILE *fp; + int start_slot = -1; + char configname[LINESIZ]; + int i, rc; + + /* get the starting slot for next entry */ + start_slot = get_start_slot(); + if (start_slot == -1) + return -1; + + /* open the config file. if it doesn't exist, create it */ + if ((stat(OCK_CONFIG, &statbuf) == -1) && (errno == ENOENT)) + /* doesn't exist, create it */ + fp = fopen(OCK_CONFIG, "w"); + else + fp = fopen(OCK_CONFIG, "a"); + + if (fp == NULL) { + fprintf(stderr, "open failed, line %d: %s\n", + __LINE__, strerror(errno)); + return -1; + } + + /* For each token in the list do, + * - Create a slot entry in ock config file that contains + * the stdll and token config name. + * - Create a token config file that contains the token info + * from the ICSF and the BIND authentication info. + */ + for (i = 0; i < num_of_slots; i++) { + + /* create the config name using the token's name */ + memset(configname, 0, sizeof(configname)); + snprintf(configname, sizeof(configname), "%s/%s.conf", + OCK_CONFDIR, tokens[i].name); + + /* write the token info to the token's config file */ + rc = add_token_config(configname, tokens[i], start_slot); + if (rc == -1) { + fprintf(stderr, "failed to add %s token.\n", tokens[i].name); + /* skip adding this entry */ + continue; + } + + /* add the slot entry to the ock config file */ + fprintf(fp, "\nslot %d {\n", start_slot); + fprintf(fp, "stdll = %s\n", STDLL); + fprintf(fp, "confname = %s\n", configname); + fprintf(fp, "}\n"); + fflush(fp); + if (ferror(fp) != 0) { + fprintf(stderr, "Failed to add an entry for %s token: " + "%s\n", tokens[i].name, strerror(errno)); + remove_file(configname); + continue; + } + + /* bump the slot number */ + start_slot++; + } + + fclose(fp); + + return 0; +} + +int list_tokens(void) +{ + size_t i, tokenCount = MAX_RECORDS; + struct icsf_token_record *previous = NULL; + struct icsf_token_record tokens[MAX_RECORDS]; + int rc, num_seen = 0; + + do { + /* get the token list from remote z/OS host */ + rc = icsf_list_tokens(ld, NULL, previous, tokens, &tokenCount); + if (ICSF_RC_IS_ERROR(rc)) + return -1; + + for (i = 0; i < tokenCount; i++) { + printf("Token #: %d\n" + "Token name: %s\n" + "Manufacturer: %s\n" + "Model: %s\n" + "Serial: %s\n" + "Read-only: %s\n\n", + num_seen, tokens[i].name, + tokens[i].manufacturer, + tokens[i].model, tokens[i].serial, + ICSF_IS_TOKEN_READ_ONLY(tokens[i].flags) ? "yes" : "no"); + num_seen++; + } + + if (tokenCount) + previous = &tokens[tokenCount - 1]; + + } while (tokenCount); + + return 0; +} + +int lookup_name(char *name, struct icsf_token_record *found) +{ + size_t i, tokenCount = MAX_RECORDS; + struct icsf_token_record *previous = NULL; + struct icsf_token_record tokens[MAX_RECORDS]; + int rc; + + do { + /* get the token list from remote z/OS host */ + rc = icsf_list_tokens(ld, NULL, previous, tokens, &tokenCount); + if (ICSF_RC_IS_ERROR(rc)) { + fprintf(stderr, "Could not get list of tokens.\n"); + found = NULL; + return -1; + } + + for (i = 0; i < tokenCount; i++) { + if (strncasecmp(name, tokens[i].name, + sizeof(tokens[i].name)) == 0) { + memcpy(found, &tokens[i], sizeof(struct icsf_token_record)); + return 0; + } + } + if (tokenCount) + previous = &tokens[tokenCount - 1]; + + } while (tokenCount); + + /* if we get here, we could not find the token in the list. */ + found = NULL; + + return -1; +} + +void remove_racf_file(void) +{ + char fname[PATH_MAX]; + + /* remove the so and user files */ + snprintf(fname, sizeof(fname), "%s/RACF", ICSF_CONFIG_PATH); + remove_file(fname); +} + +int retrieve_all(void) +{ + size_t tokenCount; + struct icsf_token_record *previous = NULL; + struct icsf_token_record tokens[MAX_RECORDS]; + int rc; + + + /* since pkcsslotd can only manage + * NUMBER_SLOTS_MANAGED at a time, use this as + * the maxiumum amount of tokens to retrieve... + */ + tokenCount = NUMBER_SLOTS_MANAGED; + rc = icsf_list_tokens(ld, NULL, previous, tokens, &tokenCount); + if (ICSF_RC_IS_ERROR(rc)) { + fprintf(stderr, "Could not get list of tokens.\n"); + return -1; + } + + /* add slot and token entry(ies) */ + rc = config_add_slotinfo(tokenCount, tokens); + if (rc) { + fprintf(stderr, "Could not add list of tokens.\n"); + return -1; + } + + return 0; +} + +int secure_racf_passwd(char *racfpwd, unsigned int len) +{ + char *sopin = NULL; + unsigned char masterkey[AES_KEY_SIZE_256]; + char fname[PATH_MAX]; + int rc; + size_t sopinlen; + + + /* get the SO PIN */ + printf("Enter the SO PIN: "); + fflush(stdout); + rc = get_pin(&sopin, &sopinlen); + if (rc != 0) { + fprintf(stderr, "Could not get SO PIN.\n"); + rc = -1; + goto cleanup; + } + + /* generate a masterkey */ + if ((get_randombytes(masterkey, AES_KEY_SIZE_256)) != CKR_OK) { + fprintf(stderr, "Could not generate masterkey.\n"); + rc = -1; + goto cleanup; + } + + /* use the master key to secure the racf passwd */ + rc = secure_racf((CK_BYTE *)racfpwd, len, masterkey, AES_KEY_SIZE_256); + if (rc != 0) { + fprintf(stderr, "Failed to secure racf passwd.\n"); + rc = -1; + goto cleanup; + } + + /* now secure the master key with a derived key */ + /* first get the filename to put the encrypted masterkey */ + snprintf(fname, sizeof(fname), "%s/MK_SO", ICSF_CONFIG_PATH); + rc = secure_masterkey(masterkey, AES_KEY_SIZE_256, (CK_BYTE *)sopin, + strlen(sopin), fname); + + if (rc != 0) { + fprintf(stderr, "Failed to secure masterkey.\n"); + /* remove the racf file */ + remove_racf_file(); + rc = -1; + goto cleanup; + } + +cleanup: + if (sopin) + free(sopin); + + return rc; +} + +int main(int argc, char **argv) +{ + char *racfpwd = NULL; + size_t racflen; + char *tokenname = NULL; + int c; + int rc = 0; + struct icsf_token_record found_token; + + while ((c = getopt(argc, argv, "hla:b:u:m:k:c:C:")) != (-1)) { + switch (c) { + case 'a': + flags |= CFG_ADD; + if ((tokenname = strdup(optarg)) == NULL) { + rc = -1; + fprintf(stderr, "strdup failed: line %d\n", __LINE__); + goto cleanup; + } + break; + case 'l': + flags |= CFG_LIST; + break; + case 'b': + flags |= CFG_BINDDN; + if ((binddn = strdup(optarg)) == NULL) { + rc = -1; + fprintf(stderr, "strdup failed: line %d\n", __LINE__); + goto cleanup; + } + break; + case 'c': + flags |= CFG_CERT; + if ((cert = strdup(optarg)) == NULL) { + rc = -1; + fprintf(stderr, "strdup failed: line %d\n", __LINE__); + goto cleanup; + } + break; + case 'k': + flags |= CFG_PRIVKEY; + if ((privkey = strdup(optarg)) == NULL) { + rc = -1; + fprintf(stderr, "strdup failed: line %d\n", __LINE__); + goto cleanup; + } + break; + case 'C': + flags |= CFG_CACERT; + if ((cacert = strdup(optarg)) == NULL) { + rc = -1; + fprintf(stderr, "strdup failed: line %d\n", __LINE__); + goto cleanup; + } + break; + case 'u': + flags |= CFG_URI; + if ((uri = strdup(optarg)) == NULL) { + rc = -1; + fprintf(stderr, "strdup failed: line %d\n", __LINE__); + goto cleanup; + } + break; + case 'm': + flags |= CFG_MECH; + if ((mech = strdup(optarg)) == NULL) { + rc = -1; + fprintf(stderr, "strdup failed: line %d\n", __LINE__); + goto cleanup; + } + if (memcmp(mech, SASL, sizeof(SASL)) == 0) + flags |= CFG_MECH_SASL; + else + flags |= CFG_MECH_SIMPLE; + break; + case 'h': + default: + usage(argv[0]); + break; + } + } + + /* Noticed that if a user misses an argument after an option, + * sometimes getopt misses it. + * For example, pkcsiscf -a -m -b xxxx -u xxxx" + * To catch these anomalies, check that optind == argc. + */ + if (optind != argc) + usage(argv[0]); + + /* If there were no options, print usage. */ + if ((!flags) || (!(flags & CFG_ADD) && !(flags & CFG_LIST))) + usage(argv[0]); + + /* Currently, do not allow user to add a list of tokens. + * When ready to support multiple icsf tokens, this + * check can be removed. + */ + if ((flags & CFG_ADD) && !(memcmp(tokenname, "all", strlen(tokenname)))) + usage(argv[0]); + + /* If add, then must specify a mechanism and a name */ + if ((flags & CFG_ADD) && (!(flags & CFG_MECH) || tokenname == NULL)) + usage(argv[0]); + + /* If list, then must specify a mechanism */ + if ((flags & CFG_LIST) && !(flags & CFG_MECH)) + usage(argv[0]); + + /* Cannot add and list at the same time */ + if ((flags & CFG_LIST) && (flags & CFG_ADD)) + usage(argv[0]); + + /* May only specify one mechanism */ + if ((flags & CFG_MECH_SASL) && (flags & CFG_MECH_SIMPLE)) + usage(argv[0]); + + /* Cannot specify bind DN with SASL */ + if ((flags & CFG_MECH_SASL) && (flags & CFG_BINDDN)) + usage(argv[0]); + + /* Cannot specify certs or key with SIMPLE */ + if ((flags & CFG_MECH_SIMPLE) + && (flags & (CFG_CERT | CFG_PRIVKEY | CFG_CACERT))) + usage(argv[0]); + + /* get racf password if needed */ + if ((flags & CFG_ADD) || (flags & CFG_LIST)) { + if (flags & CFG_MECH_SIMPLE) { + printf("Enter the RACF passwd: "); + fflush(stdout); + rc = get_pin(&racfpwd, &racflen); + if (rc != 0) { + fprintf(stderr, "Could not get RACF passwd.\n"); + return -1; + } + + /* bind to ldap server */ + rc = icsf_login(&ld, uri, binddn, racfpwd); + } else { + rc = icsf_sasl_login(&ld, uri, NULL, NULL, NULL, NULL); + } + if (rc) { + fprintf(stderr, "Failed to bind to the ldap server.\n"); + goto cleanup; + } + } + + + /* Add token(s) */ + if (flags & CFG_ADD) { + if (memcmp(tokenname, "all", strlen(tokenname)) == 0) { + rc = retrieve_all(); + if (rc) { + fprintf(stderr, "Could not add the list of " "tokens.\n"); + goto cleanup; + } + } else { + /* add only the specified tokenname. + * first, find it in the list. + */ + rc = lookup_name(tokenname, &found_token); + if (rc != 0) { + fprintf(stderr, + "Could not find %s in token list.\n", tokenname); + rc = -1; + goto cleanup; + } + + /* add the entry */ + rc = config_add_slotinfo(1, &found_token); + if (rc != 0) + goto cleanup; + } + if (flags & CFG_MECH_SIMPLE) { + /* when using simple auth, secure racf passwd. */ + rc = secure_racf_passwd(racfpwd, strlen(racfpwd)); + if (rc != 0) + goto cleanup; + } + } + + if (flags & CFG_LIST) { + /* print the list of available tokens */ + rc = list_tokens(); + if (rc != 0) + fprintf(stderr, "Could not get full list of tokens.\n"); + } + +cleanup: + if (ld) + icsf_logout(ld); + if (tokenname) + free(tokenname); + if (binddn) + free(binddn); + if (cert) + free(cert); + if (privkey) + free(privkey); + if (cacert) + free(cacert); + if (uri) + free(uri); + if (mech) + free(mech); + if (racfpwd) + free(racfpwd); + + return rc; +} diff --git a/usr/sbin/pkcsicsf/pkcsicsf.mk b/usr/sbin/pkcsicsf/pkcsicsf.mk new file mode 100644 index 0000000..d4b9cb2 --- /dev/null +++ b/usr/sbin/pkcsicsf/pkcsicsf.mk @@ -0,0 +1,12 @@ +sbin_PROGRAMS += usr/sbin/pkcsicsf/pkcsicsf + +usr_sbin_pkcsicsf_pkcsicsf_LDFLAGS = -lldap -lssl -llber -lcrypto + +usr_sbin_pkcsicsf_pkcsicsf_CFLAGS = \ + -D_THREAD_SAFE -DDEV -DAPI -DSTDLL_NAME=\"icsf\" \ + -I${srcdir}/usr/include -I${srcdir}/usr/lib/icsf_stdll \ + -I${srcdir}/usr/lib/common -I${srcdir}/usr/sbin/pkcsicsf + +usr_sbin_pkcsicsf_pkcsicsf_SOURCES = \ + usr/lib/icsf_stdll/icsf.c usr/lib/icsf_stdll/pbkdf.c \ + usr/lib/common/trace.c usr/sbin/pkcsicsf/pkcsicsf.c diff --git a/usr/sbin/pkcsslotd/daemon.c b/usr/sbin/pkcsslotd/daemon.c new file mode 100644 index 0000000..f3811da --- /dev/null +++ b/usr/sbin/pkcsslotd/daemon.c @@ -0,0 +1,34 @@ +/* + * 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 + */ + +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "slotmgr.h" +#include "pkcsslotd.h" +#include "err.h" + +/* + * We export Daemon so that we can daemonize or + * not based on a command-line argument + */ +BOOL Daemon = (BOOL) BECOME_DAEMON; +BOOL IveDaemonized = FALSE; + +BOOL IsDaemon(void) +{ + return (BOOL) ((Daemon) && (IveDaemonized)); +} + diff --git a/usr/sbin/pkcsslotd/err.c b/usr/sbin/pkcsslotd/err.c new file mode 100644 index 0000000..4c171d2 --- /dev/null +++ b/usr/sbin/pkcsslotd/err.c @@ -0,0 +1,777 @@ +/* + * 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 + */ + +#include +#include +#include +#include + +#include "log.h" +#include "slotmgr.h" +#include "err.h" + + +static ConstInfo SysErrorInfo[] = { + + CONSTINFO(EPERM), + CONSTINFO(ENOENT), + CONSTINFO(ESRCH), + CONSTINFO(EINTR), + CONSTINFO(EIO), + CONSTINFO(ENXIO), + CONSTINFO(E2BIG), + CONSTINFO(ENOEXEC), + CONSTINFO(EBADF), + CONSTINFO(ECHILD), + CONSTINFO(EAGAIN), + CONSTINFO(ENOMEM), + CONSTINFO(EACCES), + CONSTINFO(EFAULT), + CONSTINFO(ENOTBLK), + CONSTINFO(EBUSY), + CONSTINFO(EEXIST), + CONSTINFO(EXDEV), + CONSTINFO(ENODEV), + CONSTINFO(ENOTDIR), + CONSTINFO(EISDIR), + CONSTINFO(EINVAL), + CONSTINFO(ENFILE), + CONSTINFO(EMFILE), + CONSTINFO(ENOTTY), + CONSTINFO(ETXTBSY), + CONSTINFO(EFBIG), + CONSTINFO(ENOSPC), + CONSTINFO(ESPIPE), + CONSTINFO(EROFS), + CONSTINFO(EMLINK), + CONSTINFO(EPIPE), + CONSTINFO(EDOM), + CONSTINFO(ERANGE), + CONSTINFO(ENOMSG), + CONSTINFO(EIDRM), +#ifdef ECHRNG + CONSTINFO(ECHRNG), +#endif +#ifdef EL2NSYNC + CONSTINFO(EL2NSYNC), +#endif +#ifdef EL3HLT + CONSTINFO(EL3HLT), +#endif +#ifdef EL3RST + CONSTINFO(EL3RST), +#endif +#ifdef ELNRNG + CONSTINFO(ELNRNG), +#endif +#ifdef EUNATCH + CONSTINFO(EUNATCH), +#endif +#ifdef ENOCSI + CONSTINFO(ENOCSI), +#endif +#ifdef EL2HLT + CONSTINFO(EL2HLT), +#endif + CONSTINFO(EDEADLK), + CONSTINFO(ESTALE), + CONSTINFO(EWOULDBLOCK), + CONSTINFO(EINPROGRESS), + CONSTINFO(EALREADY), + CONSTINFO(ENOTSOCK), + CONSTINFO(EDESTADDRREQ), + CONSTINFO(EMSGSIZE), + CONSTINFO(EPROTOTYPE), + CONSTINFO(ENOPROTOOPT), + CONSTINFO(EPROTONOSUPPORT), + CONSTINFO(ESOCKTNOSUPPORT), + CONSTINFO(EOPNOTSUPP), + CONSTINFO(EPFNOSUPPORT), + CONSTINFO(EAFNOSUPPORT), + CONSTINFO(EADDRINUSE), + CONSTINFO(EADDRNOTAVAIL), + CONSTINFO(ENETDOWN), + CONSTINFO(ENETUNREACH), + CONSTINFO(ENETRESET), + CONSTINFO(ECONNABORTED), + CONSTINFO(ECONNRESET), + CONSTINFO(ENOBUFS), + CONSTINFO(EISCONN), + CONSTINFO(ENOTCONN), + CONSTINFO(ESHUTDOWN), + CONSTINFO(ETIMEDOUT), + CONSTINFO(ECONNREFUSED), + CONSTINFO(EHOSTDOWN), + CONSTINFO(EHOSTUNREACH), +#ifdef ERESTART + CONSTINFO(ERESTART), +#endif + CONSTINFO(EUSERS), + CONSTINFO(ELOOP), + CONSTINFO(ENAMETOOLONG), + CONSTINFO(ENOTEMPTY), + CONSTINFO(EDQUOT), + CONSTINFO(EREMOTE), + CONSTINFO(ENOSYS), + CONSTINFO(ETOOMANYREFS), + CONSTINFO(EILSEQ), + CONSTINFO(ECANCELED), +#ifdef ENOSR + CONSTINFO(ENOSR), +#endif +#ifdef ETIME + CONSTINFO(ETIME), +#endif +#ifdef EBADMSG + CONSTINFO(EBADMSG), +#endif +#ifdef EPROTO + CONSTINFO(EPROTO), +#endif +#ifdef ENODATA + CONSTINFO(ENODATA), +#endif +#ifdef ENOSTR + CONSTINFO(ENOSTR), +#endif + CONSTINFO(ENOTSUP), +#ifdef EMULTIHOP + CONSTINFO(EMULTIHOP), +#endif +#ifdef ENOLINK + CONSTINFO(ENOLINK), +#endif +#ifdef EOVERFLOW + CONSTINFO(EOVERFLOW), +#endif + +}; + +static int SysErrorSize = (sizeof(SysErrorInfo) / sizeof(SysErrorInfo[0])); + + + +static ConstInfo SignalInfo[] = { + + CONSTINFO(SIGHUP), + CONSTINFO(SIGINT), + CONSTINFO(SIGQUIT), + CONSTINFO(SIGILL), + CONSTINFO(SIGTRAP), + CONSTINFO(SIGABRT), + CONSTINFO(SIGFPE), + CONSTINFO(SIGKILL), + CONSTINFO(SIGBUS), + CONSTINFO(SIGSEGV), + CONSTINFO(SIGSYS), + CONSTINFO(SIGPIPE), + CONSTINFO(SIGALRM), + CONSTINFO(SIGTERM), + CONSTINFO(SIGURG), + CONSTINFO(SIGSTOP), + CONSTINFO(SIGTSTP), + CONSTINFO(SIGCONT), + CONSTINFO(SIGCHLD), + CONSTINFO(SIGTTIN), + CONSTINFO(SIGTTOU), + CONSTINFO(SIGIO), + CONSTINFO(SIGXCPU), + CONSTINFO(SIGXFSZ), + CONSTINFO(SIGWINCH), +#ifdef SIGPWR + CONSTINFO(SIGPWR), +#endif + CONSTINFO(SIGUSR1), + CONSTINFO(SIGUSR2), + CONSTINFO(SIGPROF), + CONSTINFO(SIGVTALRM), + CONSTINFO(SIGIOT), +#ifdef SIGCLD + CONSTINFO(SIGCLD), +#endif +#ifdef SIGPOLL + CONSTINFO(SIGPOLL), +#endif +#if 0 + CONSTINFO(SIG_DFL), + CONSTINFO(SIG_IGN), + CONSTINFO(SIG_HOLD), + CONSTINFO(SIG_CATCH), + CONSTINFO(SIG_ERR), +#endif /* 0 */ + +}; + +static int SignalInfoSize = (sizeof(SignalInfo) / sizeof(SignalInfo[0])); + +static ConstInfo PkcsReturnInfo[] = { + + CONSTINFO(CKR_OK), + CONSTINFO(CKR_CANCEL), + CONSTINFO(CKR_HOST_MEMORY), + CONSTINFO(CKR_SLOT_ID_INVALID), + CONSTINFO(CKR_GENERAL_ERROR), + CONSTINFO(CKR_FUNCTION_FAILED), + CONSTINFO(CKR_ARGUMENTS_BAD), + CONSTINFO(CKR_NO_EVENT), + CONSTINFO(CKR_NEED_TO_CREATE_THREADS), + CONSTINFO(CKR_CANT_LOCK), + CONSTINFO(CKR_ATTRIBUTE_READ_ONLY), + CONSTINFO(CKR_ATTRIBUTE_SENSITIVE), + CONSTINFO(CKR_ATTRIBUTE_TYPE_INVALID), + CONSTINFO(CKR_ATTRIBUTE_VALUE_INVALID), + CONSTINFO(CKR_DATA_INVALID), + CONSTINFO(CKR_DATA_LEN_RANGE), + CONSTINFO(CKR_DEVICE_ERROR), + CONSTINFO(CKR_DEVICE_MEMORY), + CONSTINFO(CKR_DEVICE_REMOVED), + CONSTINFO(CKR_ENCRYPTED_DATA_INVALID), + CONSTINFO(CKR_ENCRYPTED_DATA_LEN_RANGE), + CONSTINFO(CKR_FUNCTION_CANCELED), + CONSTINFO(CKR_FUNCTION_NOT_PARALLEL), + CONSTINFO(CKR_FUNCTION_NOT_SUPPORTED), + CONSTINFO(CKR_KEY_HANDLE_INVALID), + CONSTINFO(CKR_KEY_SIZE_RANGE), + CONSTINFO(CKR_KEY_TYPE_INCONSISTENT), + CONSTINFO(CKR_KEY_NOT_NEEDED), + CONSTINFO(CKR_KEY_CHANGED), + CONSTINFO(CKR_KEY_NEEDED), + CONSTINFO(CKR_KEY_INDIGESTIBLE), + CONSTINFO(CKR_KEY_FUNCTION_NOT_PERMITTED), + CONSTINFO(CKR_KEY_NOT_WRAPPABLE), + CONSTINFO(CKR_KEY_UNEXTRACTABLE), + CONSTINFO(CKR_MECHANISM_INVALID), + CONSTINFO(CKR_MECHANISM_PARAM_INVALID), + CONSTINFO(CKR_OBJECT_HANDLE_INVALID), + CONSTINFO(CKR_OPERATION_ACTIVE), + CONSTINFO(CKR_OPERATION_NOT_INITIALIZED), + CONSTINFO(CKR_PIN_INCORRECT), + CONSTINFO(CKR_PIN_INVALID), + CONSTINFO(CKR_PIN_LEN_RANGE), + CONSTINFO(CKR_PIN_EXPIRED), + CONSTINFO(CKR_PIN_LOCKED), + CONSTINFO(CKR_SESSION_CLOSED), + CONSTINFO(CKR_SESSION_COUNT), + CONSTINFO(CKR_SESSION_HANDLE_INVALID), + CONSTINFO(CKR_SESSION_PARALLEL_NOT_SUPPORTED), + CONSTINFO(CKR_SESSION_READ_ONLY), + CONSTINFO(CKR_SESSION_EXISTS), + CONSTINFO(CKR_SESSION_READ_ONLY_EXISTS), + CONSTINFO(CKR_SESSION_READ_WRITE_SO_EXISTS), + CONSTINFO(CKR_SIGNATURE_INVALID), + CONSTINFO(CKR_SIGNATURE_LEN_RANGE), + CONSTINFO(CKR_TEMPLATE_INCOMPLETE), + CONSTINFO(CKR_TEMPLATE_INCONSISTENT), + CONSTINFO(CKR_TOKEN_NOT_PRESENT), + CONSTINFO(CKR_TOKEN_NOT_RECOGNIZED), + CONSTINFO(CKR_TOKEN_WRITE_PROTECTED), + CONSTINFO(CKR_UNWRAPPING_KEY_HANDLE_INVALID), + CONSTINFO(CKR_UNWRAPPING_KEY_SIZE_RANGE), + CONSTINFO(CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT), + CONSTINFO(CKR_USER_ALREADY_LOGGED_IN), + CONSTINFO(CKR_USER_NOT_LOGGED_IN), + CONSTINFO(CKR_USER_PIN_NOT_INITIALIZED), + CONSTINFO(CKR_USER_TYPE_INVALID), + CONSTINFO(CKR_USER_ANOTHER_ALREADY_LOGGED_IN), + CONSTINFO(CKR_USER_TOO_MANY_TYPES), + CONSTINFO(CKR_WRAPPED_KEY_INVALID), + CONSTINFO(CKR_WRAPPED_KEY_LEN_RANGE), + CONSTINFO(CKR_WRAPPING_KEY_HANDLE_INVALID), + CONSTINFO(CKR_WRAPPING_KEY_SIZE_RANGE), + CONSTINFO(CKR_WRAPPING_KEY_TYPE_INCONSISTENT), + CONSTINFO(CKR_RANDOM_SEED_NOT_SUPPORTED), + CONSTINFO(CKR_RANDOM_NO_RNG), + CONSTINFO(CKR_DOMAIN_PARAMS_INVALID), + CONSTINFO(CKR_CURVE_NOT_SUPPORTED), + CONSTINFO(CKR_BUFFER_TOO_SMALL), + CONSTINFO(CKR_SAVED_STATE_INVALID), + CONSTINFO(CKR_INFORMATION_SENSITIVE), + CONSTINFO(CKR_STATE_UNSAVEABLE), + CONSTINFO(CKR_CRYPTOKI_NOT_INITIALIZED), + CONSTINFO(CKR_CRYPTOKI_ALREADY_INITIALIZED), + CONSTINFO(CKR_MUTEX_BAD), + CONSTINFO(CKR_MUTEX_NOT_LOCKED), + CONSTINFO(CKR_FUNCTION_REJECTED), + CONSTINFO(CKR_VENDOR_DEFINED), + +}; + + +static int PkcsReturnSize = + (sizeof(PkcsReturnInfo) / sizeof(PkcsReturnInfo[0])); + + + + +static ConstInfo PkcsFlagsInfo[] = { + + CONSTINFO((CKF_RNG | CKF_HW | CKF_LIBRARY_CANT_CREATE_OS_THREADS | + CKF_TOKEN_PRESENT)), + CONSTINFO((CKF_REMOVABLE_DEVICE | CKF_OS_LOCKING_OK | CKF_RW_SESSION | + CKF_WRITE_PROTECTED)), + CONSTINFO((CKF_SERIAL_SESSION | CKF_HW_SLOT | CKF_LOGIN_REQUIRED)), + CONSTINFO(CKF_USER_PIN_INITIALIZED), + CONSTINFO(CKF_RESTORE_KEY_NOT_NEEDED), + CONSTINFO(CKF_CLOCK_ON_TOKEN), + CONSTINFO((CKF_PROTECTED_AUTHENTICATION_PATH | CKF_ENCRYPT)), + CONSTINFO((CKF_DUAL_CRYPTO_OPERATIONS | CKF_DECRYPT)), + CONSTINFO(CKF_DIGEST), + CONSTINFO(CKF_SIGN), + CONSTINFO(CKF_SIGN_RECOVER), + CONSTINFO(CKF_VERIFY), + CONSTINFO(CKF_VERIFY_RECOVER), + CONSTINFO(CKF_GENERATE), + CONSTINFO((CKF_GENERATE_KEY_PAIR | CKF_USER_PIN_COUNT_LOW)), + CONSTINFO((CKF_USER_PIN_FINAL_TRY | CKF_WRAP)), + CONSTINFO((CKF_UNWRAP | CKF_USER_PIN_LOCKED)), + CONSTINFO((CKF_DERIVE /*| CKF_USER_PIN_MANUFACT_VALUE */ )), + CONSTINFO(CKF_SO_PIN_DERIVED), + CONSTINFO(CKF_SO_CARD), + CONSTINFO(CKF_SO_PIN_COUNT_LOW), + CONSTINFO(CKF_SO_PIN_FINAL_TRY), + CONSTINFO(CKF_SO_PIN_LOCKED), + /*CONSTINFO(CKF_SO_PIN_MANUFACT_VALUE), */ + CONSTINFO(CKF_EXTENSION), + +}; + +static int PkcsFlagsSize = (sizeof(PkcsFlagsInfo) / sizeof(PkcsFlagsInfo[0])); + + + +static ConstInfo PkcsMechanismInfo[] = { + + CONSTINFO(CKM_RSA_PKCS_KEY_PAIR_GEN), + CONSTINFO(CKM_RSA_PKCS), + CONSTINFO(CKM_RSA_9796), + CONSTINFO(CKM_RSA_X_509), + CONSTINFO(CKM_MD2_RSA_PKCS), + CONSTINFO(CKM_MD5_RSA_PKCS), + CONSTINFO(CKM_SHA1_RSA_PKCS), + CONSTINFO(CKM_DSA_KEY_PAIR_GEN), + CONSTINFO(CKM_DSA), + CONSTINFO(CKM_DSA_SHA1), + CONSTINFO(CKM_DH_PKCS_KEY_PAIR_GEN), + CONSTINFO(CKM_DH_PKCS_DERIVE), + CONSTINFO(CKM_RC2_KEY_GEN), + CONSTINFO(CKM_RC2_ECB), + CONSTINFO(CKM_RC2_CBC), + CONSTINFO(CKM_RC2_MAC), + CONSTINFO(CKM_RC2_MAC_GENERAL), + CONSTINFO(CKM_RC2_CBC_PAD), + CONSTINFO(CKM_RC4_KEY_GEN), + CONSTINFO(CKM_RC4), + CONSTINFO(CKM_DES_KEY_GEN), + CONSTINFO(CKM_DES_ECB), + CONSTINFO(CKM_DES_CBC), + CONSTINFO(CKM_DES_MAC), + CONSTINFO(CKM_DES_MAC_GENERAL), + CONSTINFO(CKM_DES_CBC_PAD), + CONSTINFO(CKM_DES2_KEY_GEN), + CONSTINFO(CKM_DES3_KEY_GEN), + CONSTINFO(CKM_DES3_ECB), + CONSTINFO(CKM_DES3_CBC), + CONSTINFO(CKM_DES3_MAC), + CONSTINFO(CKM_DES3_MAC_GENERAL), + CONSTINFO(CKM_DES3_CBC_PAD), + CONSTINFO(CKM_CDMF_KEY_GEN), + CONSTINFO(CKM_CDMF_ECB), + CONSTINFO(CKM_CDMF_CBC), + CONSTINFO(CKM_CDMF_MAC), + CONSTINFO(CKM_CDMF_MAC_GENERAL), + CONSTINFO(CKM_CDMF_CBC_PAD), + CONSTINFO(CKM_MD2), + CONSTINFO(CKM_MD2_HMAC), + CONSTINFO(CKM_MD2_HMAC_GENERAL), + CONSTINFO(CKM_MD5), + CONSTINFO(CKM_MD5_HMAC), + CONSTINFO(CKM_MD5_HMAC_GENERAL), + CONSTINFO(CKM_SHA_1), + CONSTINFO(CKM_SHA_1_HMAC), + CONSTINFO(CKM_SHA_1_HMAC_GENERAL), + CONSTINFO(CKM_SHA224), + CONSTINFO(CKM_SHA224_HMAC), + CONSTINFO(CKM_SHA224_HMAC_GENERAL), + CONSTINFO(CKM_SHA256), + CONSTINFO(CKM_SHA256_HMAC), + CONSTINFO(CKM_SHA256_HMAC_GENERAL), + CONSTINFO(CKM_SHA384), + CONSTINFO(CKM_SHA384_HMAC), + CONSTINFO(CKM_SHA384_HMAC_GENERAL), + CONSTINFO(CKM_SHA512), + CONSTINFO(CKM_SHA512_HMAC), + CONSTINFO(CKM_SHA512_HMAC_GENERAL), + CONSTINFO(CKM_SHA512_224), + CONSTINFO(CKM_SHA512_224_HMAC), + CONSTINFO(CKM_SHA512_224_HMAC_GENERAL), + CONSTINFO(CKM_SHA512_256), + CONSTINFO(CKM_SHA512_256_HMAC), + CONSTINFO(CKM_SHA512_256_HMAC_GENERAL), + CONSTINFO(CKM_CAST_KEY_GEN), + CONSTINFO(CKM_CAST_ECB), + CONSTINFO(CKM_CAST_CBC), + CONSTINFO(CKM_CAST_MAC), + CONSTINFO(CKM_CAST_MAC_GENERAL), + CONSTINFO(CKM_CAST_CBC_PAD), + CONSTINFO(CKM_CAST3_KEY_GEN), + CONSTINFO(CKM_CAST3_ECB), + CONSTINFO(CKM_CAST3_CBC), + CONSTINFO(CKM_CAST3_MAC), + CONSTINFO(CKM_CAST3_MAC_GENERAL), + CONSTINFO(CKM_CAST3_CBC_PAD), + CONSTINFO(CKM_CAST5_KEY_GEN), + CONSTINFO(CKM_CAST128_KEY_GEN), + CONSTINFO(CKM_CAST5_ECB), + CONSTINFO(CKM_CAST128_ECB), + CONSTINFO(CKM_CAST5_CBC), + CONSTINFO(CKM_CAST128_CBC), + CONSTINFO(CKM_CAST5_MAC), + CONSTINFO(CKM_CAST128_MAC), + CONSTINFO(CKM_CAST5_MAC_GENERAL), + CONSTINFO(CKM_CAST128_MAC_GENERAL), + CONSTINFO(CKM_CAST5_CBC_PAD), + CONSTINFO(CKM_CAST128_CBC_PAD), + CONSTINFO(CKM_RC5_KEY_GEN), + CONSTINFO(CKM_RC5_ECB), + CONSTINFO(CKM_RC5_CBC), + CONSTINFO(CKM_RC5_MAC), + CONSTINFO(CKM_RC5_MAC_GENERAL), + CONSTINFO(CKM_RC5_CBC_PAD), + CONSTINFO(CKM_IDEA_KEY_GEN), + CONSTINFO(CKM_IDEA_ECB), + CONSTINFO(CKM_IDEA_CBC), + CONSTINFO(CKM_IDEA_MAC), + CONSTINFO(CKM_IDEA_MAC_GENERAL), + CONSTINFO(CKM_IDEA_CBC_PAD), + CONSTINFO(CKM_GENERIC_SECRET_KEY_GEN), + CONSTINFO(CKM_CONCATENATE_BASE_AND_KEY), + CONSTINFO(CKM_CONCATENATE_BASE_AND_DATA), + CONSTINFO(CKM_CONCATENATE_DATA_AND_BASE), + CONSTINFO(CKM_XOR_BASE_AND_DATA), + CONSTINFO(CKM_EXTRACT_KEY_FROM_KEY), + CONSTINFO(CKM_SSL3_PRE_MASTER_KEY_GEN), + CONSTINFO(CKM_SSL3_MASTER_KEY_DERIVE), + CONSTINFO(CKM_SSL3_KEY_AND_MAC_DERIVE), + CONSTINFO(CKM_SSL3_MD5_MAC), + CONSTINFO(CKM_SSL3_SHA1_MAC), + CONSTINFO(CKM_MD5_KEY_DERIVATION), + CONSTINFO(CKM_MD2_KEY_DERIVATION), + CONSTINFO(CKM_SHA1_KEY_DERIVATION), + CONSTINFO(CKM_PBE_MD2_DES_CBC), + CONSTINFO(CKM_PBE_MD5_DES_CBC), + CONSTINFO(CKM_PBE_MD5_CAST_CBC), + CONSTINFO(CKM_PBE_MD5_CAST3_CBC), + CONSTINFO(CKM_PBE_MD5_CAST5_CBC), + CONSTINFO(CKM_PBE_MD5_CAST128_CBC), + CONSTINFO(CKM_PBE_SHA1_CAST5_CBC), + CONSTINFO(CKM_PBE_SHA1_CAST128_CBC), + CONSTINFO(CKM_PBE_SHA1_RC4_128), + CONSTINFO(CKM_PBE_SHA1_RC4_40), + CONSTINFO(CKM_PBE_SHA1_DES3_EDE_CBC), + CONSTINFO(CKM_PBE_SHA1_DES2_EDE_CBC), + CONSTINFO(CKM_PBE_SHA1_RC2_128_CBC), + CONSTINFO(CKM_PBE_SHA1_RC2_40_CBC), + CONSTINFO(CKM_PBA_SHA1_WITH_SHA1_HMAC), + CONSTINFO(CKM_KEY_WRAP_LYNKS), + CONSTINFO(CKM_KEY_WRAP_SET_OAEP), + CONSTINFO(CKM_SKIPJACK_KEY_GEN), + CONSTINFO(CKM_SKIPJACK_ECB64), + CONSTINFO(CKM_SKIPJACK_CBC64), + CONSTINFO(CKM_SKIPJACK_OFB64), + CONSTINFO(CKM_SKIPJACK_CFB64), + CONSTINFO(CKM_SKIPJACK_CFB32), + CONSTINFO(CKM_SKIPJACK_CFB16), + CONSTINFO(CKM_SKIPJACK_CFB8), + CONSTINFO(CKM_SKIPJACK_WRAP), + CONSTINFO(CKM_SKIPJACK_PRIVATE_WRAP), + CONSTINFO(CKM_SKIPJACK_RELAYX), + CONSTINFO(CKM_KEA_KEY_PAIR_GEN), + CONSTINFO(CKM_KEA_KEY_DERIVE), + CONSTINFO(CKM_FORTEZZA_TIMESTAMP), + CONSTINFO(CKM_BATON_KEY_GEN), + CONSTINFO(CKM_BATON_ECB128), + CONSTINFO(CKM_BATON_ECB96), + CONSTINFO(CKM_BATON_CBC128), + CONSTINFO(CKM_BATON_COUNTER), + CONSTINFO(CKM_BATON_SHUFFLE), + CONSTINFO(CKM_BATON_WRAP), + CONSTINFO(CKM_ECDSA_KEY_PAIR_GEN), + CONSTINFO(CKM_ECDSA), + CONSTINFO(CKM_ECDSA_SHA1), + CONSTINFO(CKM_ECDSA_SHA224), + CONSTINFO(CKM_ECDSA_SHA256), + CONSTINFO(CKM_ECDSA_SHA384), + CONSTINFO(CKM_ECDSA_SHA512), + CONSTINFO(CKM_SHA224_RSA_PKCS), + CONSTINFO(CKM_SHA256_RSA_PKCS), + CONSTINFO(CKM_SHA384_RSA_PKCS), + CONSTINFO(CKM_SHA512_RSA_PKCS), + CONSTINFO(CKM_SHA224_RSA_PKCS_PSS), + CONSTINFO(CKM_SHA256_RSA_PKCS_PSS), + CONSTINFO(CKM_SHA384_RSA_PKCS_PSS), + CONSTINFO(CKM_SHA512_RSA_PKCS_PSS), + CONSTINFO(CKM_SHA224_KEY_DERIVATION), + CONSTINFO(CKM_SHA256_KEY_DERIVATION), + CONSTINFO(CKM_SHA384_KEY_DERIVATION), + CONSTINFO(CKM_SHA512_KEY_DERIVATION), + CONSTINFO(CKM_JUNIPER_KEY_GEN), + CONSTINFO(CKM_JUNIPER_ECB128), + CONSTINFO(CKM_JUNIPER_CBC128), + CONSTINFO(CKM_JUNIPER_COUNTER), + CONSTINFO(CKM_JUNIPER_SHUFFLE), + CONSTINFO(CKM_JUNIPER_WRAP), + CONSTINFO(CKM_FASTHASH), + CONSTINFO(CKM_VENDOR_DEFINED), + CONSTINFO(CKM_IBM_SHA3_224), + CONSTINFO(CKM_IBM_SHA3_256), + CONSTINFO(CKM_IBM_SHA3_384), + CONSTINFO(CKM_IBM_SHA3_512), + CONSTINFO(CKM_IBM_SHA3_224_HMAC), + CONSTINFO(CKM_IBM_SHA3_256_HMAC), + CONSTINFO(CKM_IBM_SHA3_384_HMAC), + CONSTINFO(CKM_IBM_SHA3_512_HMAC), + CONSTINFO(CKM_IBM_CMAC), + CONSTINFO(CKM_IBM_EC_C25519), + CONSTINFO(CKM_IBM_EDDSA_SHA512), + CONSTINFO(CKM_IBM_EC_C448), + CONSTINFO(CKM_IBM_ED448_SHA3), + CONSTINFO(CKM_IBM_DILITHIUM), +}; + + +static unsigned int PkcsMechanismSize = + (sizeof(PkcsMechanismInfo) / sizeof(PkcsMechanismInfo[0])); + + + +static ConstInfo PkcsObjectInfo[] = { + + CONSTINFO(CKO_DATA), + CONSTINFO(CKO_CERTIFICATE), + CONSTINFO(CKO_PUBLIC_KEY), + CONSTINFO(CKO_PRIVATE_KEY), + CONSTINFO(CKO_SECRET_KEY), + CONSTINFO(CKO_VENDOR_DEFINED), + +}; + +static unsigned int PkcsObjectSize = + (sizeof(PkcsObjectInfo) / sizeof(PkcsObjectInfo[0])); + + + + + +static ConstInfo PkcsKeyInfo[] = { + + CONSTINFO(CKK_RSA), + CONSTINFO(CKK_DSA), + CONSTINFO(CKK_DH), + CONSTINFO(CKK_ECDSA), + CONSTINFO(CKK_KEA), + CONSTINFO(CKK_GENERIC_SECRET), + CONSTINFO(CKK_RC2), + CONSTINFO(CKK_RC4), + CONSTINFO(CKK_DES), + CONSTINFO(CKK_DES2), + CONSTINFO(CKK_DES3), + CONSTINFO(CKK_CAST), + CONSTINFO(CKK_CAST3), + CONSTINFO((CKK_CAST5 | CKK_CAST128)), + CONSTINFO(CKK_RC5), + CONSTINFO(CKK_IDEA), + CONSTINFO(CKK_SKIPJACK), + CONSTINFO(CKK_BATON), + CONSTINFO(CKK_JUNIPER), + CONSTINFO(CKK_CDMF), + CONSTINFO(CKK_IBM_PQC_DILITHIUM), + CONSTINFO(CKK_VENDOR_DEFINED), + +}; + +static unsigned int PkcsKeySize = + (sizeof(PkcsKeyInfo) / sizeof(PkcsKeyInfo[0])); + + + + + +static ConstInfo PkcsAttributeInfo[] = { + CONSTINFO(CKA_CLASS), + CONSTINFO(CKA_TOKEN), + CONSTINFO(CKA_PRIVATE), + CONSTINFO(CKA_LABEL), + CONSTINFO(CKA_APPLICATION), + CONSTINFO(CKA_VALUE), + CONSTINFO(CKA_CERTIFICATE_TYPE), + CONSTINFO(CKA_ISSUER), + CONSTINFO(CKA_SERIAL_NUMBER), + CONSTINFO(CKA_KEY_TYPE), + CONSTINFO(CKA_SUBJECT), + CONSTINFO(CKA_ID), + CONSTINFO(CKA_SENSITIVE), + CONSTINFO(CKA_ENCRYPT), + CONSTINFO(CKA_DECRYPT), + CONSTINFO(CKA_WRAP), + CONSTINFO(CKA_UNWRAP), + CONSTINFO(CKA_SIGN), + CONSTINFO(CKA_SIGN_RECOVER), + CONSTINFO(CKA_VERIFY), + CONSTINFO(CKA_VERIFY_RECOVER), + CONSTINFO(CKA_DERIVE), + CONSTINFO(CKA_START_DATE), + CONSTINFO(CKA_END_DATE), + CONSTINFO(CKA_MODULUS), + CONSTINFO(CKA_MODULUS_BITS), + CONSTINFO(CKA_PUBLIC_EXPONENT), + CONSTINFO(CKA_PRIVATE_EXPONENT), + CONSTINFO(CKA_PRIME_1), + CONSTINFO(CKA_PRIME_2), + CONSTINFO(CKA_EXPONENT_1), + CONSTINFO(CKA_EXPONENT_2), + CONSTINFO(CKA_COEFFICIENT), + CONSTINFO(CKA_PRIME), + CONSTINFO(CKA_SUBPRIME), + CONSTINFO(CKA_BASE), + CONSTINFO(CKA_VALUE_BITS), + CONSTINFO(CKA_VALUE_LEN), + CONSTINFO(CKA_EXTRACTABLE), + CONSTINFO(CKA_LOCAL), + CONSTINFO(CKA_NEVER_EXTRACTABLE), + CONSTINFO(CKA_ALWAYS_SENSITIVE), + CONSTINFO(CKA_MODIFIABLE), + CONSTINFO(CKA_ECDSA_PARAMS), + CONSTINFO(CKA_EC_POINT), + CONSTINFO(CKA_VENDOR_DEFINED), + CONSTINFO(CKA_IBM_OPAQUE), + CONSTINFO(CKA_IBM_RESTRICTABLE), + CONSTINFO(CKA_IBM_NEVER_MODIFIABLE), + CONSTINFO(CKA_IBM_RETAINKEY), + CONSTINFO(CKA_IBM_ATTRBOUND), + CONSTINFO(CKA_IBM_KEYTYPE), + CONSTINFO(CKA_IBM_CV), + CONSTINFO(CKA_IBM_MACKEY), + CONSTINFO(CKA_IBM_USE_AS_DATA), + CONSTINFO(CKA_IBM_STRUCT_PARAMS), + CONSTINFO(CKA_IBM_STD_COMPLIANCE1), + CONSTINFO(CKA_NSS_MOZILLA_CA_POLICY), + CONSTINFO(CKA_IBM_DILITHIUM_KEYFORM), + CONSTINFO(CKA_IBM_DILITHIUM_RHO), + CONSTINFO(CKA_IBM_DILITHIUM_SEED), + CONSTINFO(CKA_IBM_DILITHIUM_TR), + CONSTINFO(CKA_IBM_DILITHIUM_S1), + CONSTINFO(CKA_IBM_DILITHIUM_S2), + CONSTINFO(CKA_IBM_DILITHIUM_T0), + CONSTINFO(CKA_IBM_DILITHIUM_T1), +}; + + +static unsigned int PkcsAttributeSize = + (sizeof(PkcsAttributeInfo) / sizeof(PkcsAttributeInfo[0])); + +#if 0 +static ConstInfo PkcsSessionStateInfo[] = { + + CONSTINFO(CKS_RO_PUBLIC_SESSION), + CONSTINFO(CKS_RO_USER_FUNCTIONS), + CONSTINFO(CKS_RW_PUBLIC_SESSION), + CONSTINFO(CKS_RW_USER_FUNCTIONS), + CONSTINFO(CKS_RW_SO_FUNCTIONS), + + +}; +#endif + + +static ConstInfo PkcsResponseSeverityInfo[] = { + {SEV_EXPECTED, "expected"}, + {SEV_ALLOWED, "allowed"}, + {SEV_ERROR, "an error"}, + {SEV_FATAL, "fatal"}, +}; + +static unsigned int PkcsResponseSeveritySize = + (sizeof(PkcsResponseSeverityInfo) / sizeof(PkcsResponseSeverityInfo[0])); + + +const unsigned char *ConstName(pConstInfo pInfoArray, + unsigned int InfoArraySize, + unsigned int ConstValue) +{ + + unsigned int i; + unsigned const char *retval = NULL; + + + for (i = 0; i < InfoArraySize; i++) { + if (pInfoArray[i].Code == ConstValue) { + retval = (unsigned char *)&(pInfoArray[i].Name[0]); + break; + } + /* end if */ + } /* end for i */ + + if (retval == NULL) { + if (ConstValue == 0) { + retval = (const unsigned char *) "NULL"; + } else { + retval = (const unsigned char *) "\"<*>CONSTANT NOT FOUND<*>\""; + } + } + + return retval; +} + +const unsigned char *SignalConst(unsigned int Val) +{ + return ConstName(SignalInfo, SignalInfoSize, Val); +} + +const unsigned char *SysConst(unsigned int Val) +{ + return ConstName(SysErrorInfo, SysErrorSize, Val); +} + + + +const unsigned char *PkcsReturn(unsigned int Val) +{ + return ConstName(PkcsReturnInfo, PkcsReturnSize, Val); +} + +const unsigned char *PkcsFlags(unsigned int Val) +{ + return ConstName(PkcsFlagsInfo, PkcsFlagsSize, Val); +} + +const unsigned char *PkcsMechanism(unsigned int Val) +{ + return ConstName(PkcsMechanismInfo, PkcsMechanismSize, Val); +} + +const unsigned char *PkcsObject(unsigned int Val) +{ + return ConstName(PkcsObjectInfo, PkcsObjectSize, Val); +} + +const unsigned char *PkcsKey(unsigned int Val) +{ + return ConstName(PkcsKeyInfo, PkcsKeySize, Val); +} + +const unsigned char *PkcsAttribute(unsigned int Val) +{ + return ConstName(PkcsAttributeInfo, PkcsAttributeSize, Val); +} + +const unsigned char *ResponseSeverity(unsigned int Val) +{ + return ConstName(PkcsResponseSeverityInfo, PkcsResponseSeveritySize, Val); +} diff --git a/usr/sbin/pkcsslotd/err.h b/usr/sbin/pkcsslotd/err.h new file mode 100644 index 0000000..f302109 --- /dev/null +++ b/usr/sbin/pkcsslotd/err.h @@ -0,0 +1,115 @@ +/* + * 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 + */ + +#ifndef _SLOTD_ERR_H +#define _SLOTD_ERR_H + +#ifdef DEV + +#ifndef ASSERT +#define ASSERT(_expr) _ASSERT((_expr),(__FILE__),(__LINE__)) +#define _ASSERT(_expr, _fname, _line) \ + if (!(_expr)) { \ + ErrLog("****** ****** ***** ***** ***** ***** ***** " \ + "***** ***** ****** ******"); \ + ErrLog("****** ASSERTION FAILED '%s'; %s, line %d", \ + (#_expr), (_fname), (_line)); \ + ErrLog("****** ****** ***** ***** ***** ***** ***** " \ + "***** ***** ****** ******"); \ + ErrLog("Exiting."); \ + abort(); \ + } +#endif /* ASSERT */ + +#ifndef ASSERT_FUNC +#define ASSERT_FUNC(_expr, _func) \ + _ASSERT_FUNC((_expr), (_func), (__FILE__), (__LINE__)) +#define _ASSERT_FUNC(_expr, _func, _fname, _line) \ + if (!(_expr)) { \ + ErrLog("****** ****** ***** ***** ***** ***** ***** " \ + "***** ***** ****** ******"); \ + ErrLog("****** ASSERTION FAILED '%s'; %s, line %d", \ + (#_expr), (_fname), (_line)); \ + ErrLog("Additional information from '%s':\n", (#_func)); \ + { _func; } \ + ErrLog("End of additional information from '%s'\n", (#_func) ); \ + ErrLog("****** ****** ***** ***** ***** ***** ***** " \ + "***** ***** ****** ******"); \ + ErrLog("Exiting."); \ + abort(); \ + } +#endif /* ASSERT_FUNC */ + +#else + +#ifndef ASSERT +#define ASSERT(_expr) +#endif /* ASSERT */ + +#ifndef ASSERT_FUNC +#define ASSERT_FUNC(_expr, _func_to_call) +#endif /* ASSERT_FUNC */ + +#endif /* DEV */ + + +#define SEV_EXPECTED 0x01 +#define SEV_ALLOWED 0x02 +#define SEV_ERROR 0x03 +#define SEV_FATAL 0x04 + + + +typedef struct _ConstInfo { + unsigned const int Code; + const char *Name; + /* UCHAR Descrip[256]; */ +} ConstInfo, *pConstInfo; + +#define CONSTINFO(_X) { (_X), (#_X) } + + + +const unsigned char *ConstName(pConstInfo pInfoArray, + unsigned int InfoArraySize, + unsigned int ConstValue); + +#ifdef _DAE_H +const unsigned char *DAEConst(unsigned int Val); +#endif /* _DAE_H */ + +#ifndef _H_ERRNO +#define _H_ERRNO +#endif + +#ifdef _H_ERRNO +extern const unsigned char *SysConst(unsigned int Val); +#define SysError( _x ) SysConst((_x)) +#endif /* _H_ERRNO */ + +extern const unsigned char *SignalConst(unsigned int Val); + +#ifdef _H_ODMI +const unsigned char *ODMConst(unsigned int Val); +#endif /* _H_ODMI */ + +#ifdef _PKCS11TYPES_H_ +const unsigned char *PkcsReturn(unsigned int Val); +const unsigned char *PkcsFlags(unsigned int Val); +const unsigned char *PkcsMechanism(unsigned int Val); +const unsigned char *PkcsObject(unsigned int Val); +const unsigned char *PkcsKey(unsigned int Val); +const unsigned char *PkcsAttribute(unsigned int Val); +#endif /* _PKCS11TYPES_H_ */ + +const unsigned char *ResponseSeverity(unsigned int Val); + + +#endif /* _SLOTD_ERR_H */ diff --git a/usr/sbin/pkcsslotd/garbage_linux.c b/usr/sbin/pkcsslotd/garbage_linux.c new file mode 100644 index 0000000..d4878c3 --- /dev/null +++ b/usr/sbin/pkcsslotd/garbage_linux.c @@ -0,0 +1,540 @@ +/* + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "slotmgr.h" +#include "pkcsslotd.h" +#include "err.h" + +#define PROC_BASE "/proc" + +extern BOOL GCBlockSignals(void); + +#if !defined(NOGARBAGE) + +#include "garbage_linux.h" + +BOOL IsValidProcessEntry(pid_t_64 pid, time_t_64 RegTime); + +int Stat2Proc(int pid, proc_t *p); + +pthread_t GCThread; /* Garbage Collection thread's handle */ +static BOOL ThreadRunning = FALSE; /* If we're already running or not */ + +#if THREADED +static void *GCMain(void *Ptr); +static void GCCancel(void *Ptr); +#else +void *GCMain(void *Ptr); +void GCCancel(void *Ptr); +#endif + + + + + +/****************************************************************************** + * StartGCThread - + * + * Entry point that starts the garbage collection thread + * + ******************************************************************************/ + +BOOL StartGCThread(Slot_Mgr_Shr_t *MemPtr) +{ + int err; + +#if !(THREADED) + return TRUE; +#endif + + if (ThreadRunning) { + DbgLog(DL0, "StartGCThread: Thread already running."); + return FALSE; + } + + err = pthread_create(&GCThread, NULL, GCMain, ((void *) MemPtr)); + if (err != 0) { + DbgLog(DL0, "StartGCThread: pthread_create returned %s (%d; %#x)", + SysConst(err), err, err); + return FALSE; + } + + ThreadRunning = TRUE; + +#ifdef DEV + // Only development builds + LogLog("StartGCThread: garbage collection thread started as ID " + "%d (%#x) by ID %d (%#x)", + GCThread, GCThread, pthread_self(), pthread_self()); +#endif + + return TRUE; +} + + + + +/***************************************************************************** + * StopGCThread - + * + * Entry point which causes the Garbage collection thread to terminate + * Waits for the thread to terminate before continuing + * + ******************************************************************************/ + +BOOL StopGCThread(void *Ptr) +{ + int err; + + void *Status; + + UNUSED(Ptr); + +#if !(THREADED) + return TRUE; +#endif + if (!ThreadRunning) { + DbgLog(DL0, "StopGCThread was called when the garbage collection " + "thread was not running"); + return FALSE; + } + + DbgLog(DL0, "StopGCThread: tid %d is stopping the garbage collection " + "thread (tid %d)", + pthread_self(), GCThread); + + /* Cause the GC thread to be cancelled */ + if ((err = pthread_cancel(GCThread)) != 0) { + DbgLog(DL0, "StopGCThread: pthread_cancel returned %s (%d; %#x)", + SysConst(err), err, err); + return FALSE; + } + + /* Synchronize with the GC thread (aka: wait for it to terminate) */ + if ((err = pthread_join(GCThread, &Status)) != 0) { + DbgLog(DL0, "StopGCThread: pthread_join returned %s (%d; %#x)", + SysConst(err), err, err); + return FALSE; + } + + if (Status != PTHREAD_CANCELED) { + DbgLog(DL0, "Hmm. Thread was cancelled, but didn't return the " + "appropriate return status"); + } + + ThreadRunning = FALSE; + + return TRUE; +} + + + +/****************************************************************************** + * GCMain - + * + * The Garbage collection thread's main() + * Basically, run until cancelled by another thread + * + ******************************************************************************/ + +void *GCMain(void *Ptr) +{ +#if THREADED + int OrigCancelState; + int OrigCancelType; + int LastCancelState; +#endif + Slot_Mgr_Shr_t *MemPtr = (Slot_Mgr_Shr_t *) Ptr; + + + + ASSERT(MemPtr != NULL); + + + sleep(2); // SAB Linux likes to have us delay +// Linux threading model appears to have some issues with regards to +// signals.... Need to look at this FIXME.. + + /* setup */ + /* Block the signals that go to the main thread */ + /* FIXME: We probably want to make it so that signals go only to + * the main thread by default */ +// SBADE .... FIXME... remove the blocking of signals see what happens.. +// GCBlockSignals(); + + + /* Make it so that we can only be cancelled when we reach a + * cancellation point */ + /* PTHREAD_CANCEL_DEFERRED should be the default */ +#if THREADED + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &OrigCancelState); + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &OrigCancelType); + + /* push cleanup routines */ + pthread_cleanup_push(GCCancel, MemPtr); +#endif + + DbgLog(DL0, "Garbage collection running... PID %d\n", getpid()); + while (1) { + + DbgLog(DL0, "Garbage collection running..."); + + /* Don't allow cancellations while mucking with shared memory or + * holding mutexes */ +#if THREADED + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &LastCancelState); + +#endif + + CheckForGarbage(MemPtr); + +#if THREADED + /* re-enable cancellations */ + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &LastCancelState); + + /* Test for cancellation by the main thread */ + pthread_testcancel(); +#endif + + DbgLog(DL5, "Garbage collection finished."); + + /* now we pause */ + sleep(10); + } /* end while 1 */ + + +#if THREADED + /* Yeah, yeah. Has to be here because some implementations + * use macros that have to be balanced */ + pthread_cleanup_pop(0); +#endif + + /* return implicitly calls pthread_cancel() */ + /* but it'll never really get executed; pthread_testcancel() + * implicitly calls pthread_exit() if there's a cancellation pending */ + return NULL; + +} + + +/***************************************************************************** + * GCCancel - + * + * Cleanup routine called when Garbage collection thread exits/is cancelled + * + ******************************************************************************/ + +void GCCancel(void *Ptr) +{ + UNUSED(Ptr); + + /* Yeah, yeah. Doesn't do anything, but I had plans */ + DbgLog(DL3, "GCCancel: tid: %d running cleanup routine", pthread_self()); + + return; +} + + + +/***************************************************************************** + * CheckForGarbage - + * + * The routine that actually does cleanup + * + ******************************************************************************/ + +BOOL CheckForGarbage(Slot_Mgr_Shr_t *MemPtr) +{ + int SlotIndex; + int ProcIndex; + int Err; + BOOL ValidPid; + + ASSERT(MemPtr != NULL_PTR); +#ifdef DEV + DbgLog(DL5, "Thread %d is checking for garbage", pthread_self()); +#endif /* DEV */ + + +#ifdef DEV + DbgLog(DL5, "Garbage collection attempting global shared memory lock"); +#endif /* DEV */ + + /* Grab the global Shared mem mutex since we might modify + * global_session_count */ + + Err = XProcLock(); + if (Err != TRUE) { + DbgLog(DL0, "Garbage collection: Locking attempt for global " + "shmem mutex returned %s", + SysConst(Err)); + return FALSE; + } +#ifdef DEV + DbgLog(DL5, "Garbage collection: Got global shared memory lock"); +#endif /* DEV */ + + + for (ProcIndex = 0; ProcIndex < NUMBER_PROCESSES_ALLOWED; ProcIndex++) { + + Slot_Mgr_Proc_t_64 *pProc = &(MemPtr->proc_table[ProcIndex]); + + ASSERT(pProc != NULL_PTR); + + if (!(pProc->inuse)) { + continue; + } + + ValidPid = ((IsValidProcessEntry(pProc->proc_id, pProc->reg_time)) + && (pProc->proc_id != 0)); + + + if ((pProc->inuse) && (!ValidPid)) { + +#ifdef DEV + DbgLog(DL1, "Garbage collection routine found bad entry for pid " + "%d (Index: %d); removing from table", + pProc->proc_id, ProcIndex); +#endif /* DEV */ + + /* */ + /* Clean up session counts */ + /* */ + for (SlotIndex = 0; SlotIndex < NUMBER_SLOTS_MANAGED; SlotIndex++) { + + unsigned int *pGlobalSessions = + &(MemPtr->slot_global_sessions[SlotIndex]); + unsigned int *pProcSessions = + &(pProc->slot_session_count[SlotIndex]); + + if (*pProcSessions > 0) { + +#ifdef DEV + DbgLog(DL2, "GC: Invalid pid (%d) is holding %d sessions " + "open on slot %d. Global session count for this " + "slot is %d", + pProc->proc_id, *pProcSessions, SlotIndex, + *pGlobalSessions); +#endif /* DEV */ + + if (*pProcSessions > *pGlobalSessions) { +#ifdef DEV + WarnLog("Garbage Collection: Illegal values in table " + "for defunct process"); + DbgLog(DL0, "Garbage collection: A process " + "( Index: %d, pid: %d ) showed %d sessions " + "open on slot %s, but the global count for this " + "slot is only %d", + ProcIndex, pProc->proc_id, *pProcSessions, + SlotIndex, *pGlobalSessions); +#endif /* DEV */ + *pGlobalSessions = 0; + } else { + *pGlobalSessions -= *pProcSessions; + } + + *pProcSessions = 0; + + } + /* end if *pProcSessions */ + } /* end for SlotIndex */ + + + /* */ + /* NULL out everything except the mutex */ + /* */ + + memset(&(pProc->inuse), '\0', sizeof(pProc->inuse)); + memset(&(pProc->proc_id), '\0', sizeof(pProc->proc_id)); + memset(&(pProc->slotmap), '\0', sizeof(pProc->slotmap)); + memset(&(pProc->blocking), '\0', sizeof(pProc->blocking)); + memset(&(pProc->error), '\0', sizeof(pProc->error)); + memset(&(pProc->slot_session_count), '\0', + sizeof(pProc->slot_session_count)); + memset(&(pProc->reg_time), '\0', sizeof(pProc->reg_time)); + + } + /* end if inuse && ValidPid */ + } /* end for ProcIndex */ + + XProcUnLock(); + DbgLog(DL5, "Garbage collection: Released global shared memory lock"); + + return TRUE; +} + + + +/****************************************************************************** + * Stat2Proc - + * + * Fills a proc_t structure (defined in garbage_linux.h) + * with a given pid's stat information found in the /proc//stat file + * + ******************************************************************************/ + +int Stat2Proc(int pid, proc_t *p) +{ + char buf[800 + 1]; // about 40 fields, 64-bit decimal is about 20 chars + char fbuf[800]; // about 40 fields, 64-bit decimal is about 20 chars + char *tmp; + int fd, num; + // FILE *fp; + + // sprintf(buf, "%s/%d/stat", PROC_BASE, pid); + // if( (fp = fopen(buf, "r")) == NULL ) + // return FALSE; + + sprintf(fbuf, "%s/%d/stat", PROC_BASE, pid); + printf("Buff = %s \n", fbuf); + fflush(stdout); + if ((fd = open(fbuf, O_RDONLY, 0)) == -1) + return FALSE; + + num = read(fd, buf, 800); + + close(fd); + + if (num < 80) + return FALSE; + + buf[num] = '\0'; + + tmp = strrchr(buf, ')'); // split into "PID (cmd" and "" + *tmp = '\0'; // replacing trailing ')' with NULL + // Tmp now points to the rest of the buffer. + // buff points to the command... + + + /* fill in default values for older kernels */ + p->exit_signal = SIGCHLD; + p->processor = 0; + + /* now parse the two strings, tmp & buf, separately, + * skipping the leading "(" */ + memset(p->cmd, 0, sizeof(p->cmd)); + sscanf(buf, "%d (%15c", &p->pid, p->cmd); // comm[16] in kernel + num = sscanf(tmp + 2, // skip space after ')' as well + "%c " + "%d %d %d %d %d " + "%lu %lu %lu %lu %lu %lu %lu " + "%ld %ld %ld %ld %ld %ld " + "%lu %lu " + "%ld " + "%lu %lu %lu %lu %lu %lu " + "%*s %*s %*s %*s " // discard, no RT signals & + "%lu %lu %lu " // Linux 2.1 used hex (no use for RT signals) + "%d %d", + &p->state, + &p->ppid, &p->pgrp, &p->session, &p->tty, &p->tpgid, + &p->flags, &p->min_flt, &p->cmin_flt, &p->maj_flt, + &p->cmaj_flt, &p->utime, &p->stime, &p->cutime, &p->cstime, + &p->priority, &p->nice, &p->timeout, &p->it_real_value, + &p->start_time, &p->vsize, &p->rss, &p->rss_rlim, + &p->start_code, &p->end_code, &p->start_stack, &p->kstk_esp, + &p->kstk_eip, + /* p->signal, p->blocked, p->sigignore, p->sigcatch, + * can't use */ + &p->wchan, &p->nswap, &p->cnswap, + /* -- Linux 2.0.35 ends here -- */ + &p->exit_signal, &p->processor /* 2.2.1 ends with exit_signal*/ + /* -- Linux 2.2.8 and 2.3.47 end here -- */ + ); + + /* fprintf(stderr, "Stat2Proc() converted %d fields.\n", num); */ + if (p->tty == 0) + p->tty = -1; // the old notty val, + // updated elsewhere before moving to 0 + + p->vsize /= 1024; + + if (num < 30) + return FALSE; + if (p->pid != pid) + return FALSE; + + return TRUE; +} + + + +/****************************************************************************** + * IsValidProcessEntry - + * + * Checks to see if the process identifed by pid is the same process + * that registered with us + * + ******************************************************************************/ + +BOOL IsValidProcessEntry(pid_t_64 pid, time_t_64 RegTime) +{ + int Err; + int valid; + proc_t *p; + proc_t procstore; + + /* If kill(pid, 0) returns -1 and errno/Err = ESRCH the pid doesn't exist */ + if (kill(pid, 0) == -1) { + Err = errno; + if (Err == ESRCH) { + /* The process was not found */ + DbgLog(DL3, "IsValidProcessEntry: PID %d was not found in the " + "process table (kill() returned %s)", + pid, SysConst(Err)); + return FALSE; + } else { + /* some other error occurred */ + DbgLog(DL3, "IsValidProcessEntry: kill() returned %s (%d; %#x)", + SysConst(Err), Err, Err); + return FALSE; + } + } + + + /* end if kill */ + /* Okay, the process exists, now we see if it's really ours */ +#ifdef ALLOCATE + p = (proc_t *) malloc(sizeof(proc_t)); +#else + p = &procstore; + memset(p, 0, sizeof(proc_t)); +#endif + + if (!(valid = Stat2Proc((int) pid, p))) + return FALSE; + + if (p->pid == pid) { + if (RegTime >= p->start_time) { // checking for matching start times + return TRUE; + } else { + /* p->start_time contains the time at which the process began ?? + * (22nd element in /proc//stat file) */ + DbgLog(DL1, "IsValidProcessEntry: PID %d started at %lu; " + "registered at %ld", + pid, p->start_time, RegTime); + DbgLog(DL4, "IsValidProcessEntry: PID Returned %d flags at " + "%#x; state at %#x", + p->pid, p->flags, p->state); + } + } + + return FALSE; +} + +#endif // NO Garbage diff --git a/usr/sbin/pkcsslotd/garbage_linux.h b/usr/sbin/pkcsslotd/garbage_linux.h new file mode 100644 index 0000000..6dc9259 --- /dev/null +++ b/usr/sbin/pkcsslotd/garbage_linux.h @@ -0,0 +1,79 @@ + /* + * 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 + */ + +#ifndef GARBAGE_LINUX_H +#define GARBAGE_LINUX_H + +typedef struct { + int pid; /* process id */ + + char + cmd[16], /* command line string vector for /proc//cmdline */ + state; /* single-char code for process state + * [R, S, D, Z, or T] */ + + int + ppid, /* pid of parent process */ + pgrp, /* process group id */ + session, /* session id */ + tty, /* full device number of controlling terminal */ + tpgid; /* terminal process group id */ + + unsigned long + flags, /* kernel flags for the process */ + min_flt, /* number of minor page faults since process start */ + cmin_flt, /* cumulative min_flt of process and child processes */ + maj_flt, /* number of major page faults since process start */ + cmaj_flt, /* cumulative maj_flt of process and child processes */ + utime, /* user-mode CPU time accumulated by process */ + stime; /* kernel-mode CPU time accumulated by process */ + + long + cutime, /* cumulative utime of process and reaped children */ + cstime, /* cumulative stime of process and reaped children */ + priority, /* kernel scheduling priority */ + nice, /* standard unix nice level of process */ + timeout, /* ? */ + it_real_value; /* ? */ + + unsigned long + start_time, /* start time of process -- seconds since 1-1-70 */ + vsize; /* number of pages of virtual memory ... */ + + long rss; /* resident set size from /proc//stat (pages) */ + + unsigned long + rss_rlim, /* resident set size limit? */ + start_code, /* address of beginning of code segment */ + end_code, /* address of end of code segment */ + start_stack, /* address of the bottom of stack for the process */ + kstk_esp, /* kernel stack pointer */ + kstk_eip; /* kernel instruction pointer */ + + /* Linux 2.1.7x and up have more signals. This handles 88. */ + /* long long (instead of char xxxxxx[24]) handles 64 */ + char + signal[24], /* mask of pending signals */ + blocked[24], /* mask of blocked signals */ + sigignore[24], /* mask of ignored signals */ + sigcatch[24]; /* mask of caught signals */ + + unsigned long + wchan, /* address of kernel wait channel proc is sleeping in */ + nswap, /* ? */ + cnswap; /* cumulative nswap ? */ + + int + exit_signal, + processor; + +} proc_t; + +#endif diff --git a/usr/sbin/pkcsslotd/lexer.l b/usr/sbin/pkcsslotd/lexer.l new file mode 100644 index 0000000..c246dc1 --- /dev/null +++ b/usr/sbin/pkcsslotd/lexer.l @@ -0,0 +1,86 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2002-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 + */ + +%{ +/* Parser for /etc/opencryptoki.conf */ + +#include +#include +#include + +#include "parser.h" + +/* Ignore -Wsign-compare for autogenerated code. */ +#pragma GCC diagnostic ignored "-Wsign-compare" + +int line_num = 1; + +extern void yyerror(const char *s); +%} + +%option noyywrap +%option nounput +%option noinput + +%% + +[\t ]+ /* ignore spaces */ ; + += return EQUAL; + +\{ return BEGIN_DEF; + +\n\{ { + line_num++; + return BEGIN_DEF; + } + + +\} return END_DEF; + +\n|#.*\n { + line_num++; + return EOL; + } + +[0-9]+"."[0-9]+ { /* version */ + unsigned long major, minor; + char *dot = strchr(yytext, '.'); + + *dot = '\0'; + major = strtoul(yytext, NULL, 10); + minor = strtoul(dot + 1, NULL, 10); + + yylval.num = (uint32_t)major << 16 | (uint32_t)minor; + return TOKVERSION; + } + +[0-9]+ { /* number */ + yylval.num = strtoul(yytext, NULL, 10); + return INTEGER; + } + +version return OCKVERSION; +slot return SLOT; + +[^\"= \t\n]+ { + yylval.str = strdup(yytext); + return STRING; + } + +\"[^\"\n]*\" { + yylval.str = strdup(yytext+1); + if (yylval.str) yylval.str[strlen(yylval.str)-1]='\0'; + return STRING; + } + +. yyerror(yytext); + +%% diff --git a/usr/sbin/pkcsslotd/log.c b/usr/sbin/pkcsslotd/log.c new file mode 100644 index 0000000..93ce3dd --- /dev/null +++ b/usr/sbin/pkcsslotd/log.c @@ -0,0 +1,762 @@ +/* + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "err.h" +#include "slotmgr.h" +#include "pkcsslotd.h" + + +#define DEFAULT_PROGRAM_NAME "Program" + +#ifndef PROGRAM_NAME +#define PROGRAM_NAME DEFAULT_PROGRAM_NAME +#endif /* PROGRAM_NAME */ + + +#ifdef DEV + +#ifndef DEFAULT_LOG_FILE +#define DEFAULT_LOG_FILE "/tmp/" ## PROGRAM_NAME ## ".log" +#endif /* DEFAULT_LOG_FILE */ + +#else /* production build */ + +#ifndef DEFAULT_LOG_FILE +#define DEFAULT_LOG_FILE NULL +#endif /* DEFAULT_LOG_FILE */ + +#endif /* DEV */ + + +#ifndef LOG_FILE +#define LOG_FILE DEFAULT_LOG_FILE +#endif /* LOG_FILE */ + + +#ifndef DEFAULT_DEBUG_LEVEL + + /********************* + DEFAULT_DEBUG_LEVEL is generally defined in another file (pkcsslotd.h?) + The #defines here generally won't change much. + *********************/ + +#ifdef DEV +#define DEFAULT_DEBUG_LEVEL DEBUG_LEVEL0 +#else +#define DEFAULT_DEBUG_LEVEL DEBUG_NONE +#endif /* DEFAULT_DEBUG_LEVEL */ + +#endif /* DEFAULT_DEBUG_LEVEL */ + + + +static u_int32 DefaultLogOption = + (LOG_CONS | LOG_NOWAIT | LOG_ODELAY | LOG_PID); +static BOOL Initialized = FALSE; +static BOOL LoggingInitialized = FALSE; +static u_int32 SysDebugLevel = DEFAULT_DEBUG_LEVEL; +static char *ProgramName = PROGRAM_NAME; +static LoggingFacilityInfo LogInfo[MAX_LOGGING_FACILITIES]; +static LogHandle hLogDebug; +static LogHandle hLogErr; +static LogHandle hLogLog; +static LogHandle hLogTrace; +static LogHandle hLogWarn; +static LogHandle hLogInfo; + + +static LoggingFacility SystemLogFacilities[] = { + {" DEBUG", &hLogDebug, LOG_FILE, TRUE, LOG_DEBUG}, + {" INFO", &hLogInfo, LOG_FILE, TRUE, LOG_INFO}, + {" TRACE", &hLogTrace, LOG_FILE, TRUE, LOG_INFO}, + {" LOG", &hLogLog, LOG_FILE, TRUE, LOG_NOTICE}, + {"WARNING", &hLogWarn, LOG_FILE, TRUE, LOG_WARNING}, + {" ERROR", &hLogErr, LOG_FILE, TRUE, LOG_ERR} +}; + + + +/***************************************** + * Function Prototypes * + *****************************************/ + +static int InitDataStructs(void); +static BOOL InitLogging(void); +static pLoggingFacilityInfo GetLogInfoPtr(LogHandle hLog); +static BOOL GetFreeLogInfo(pLogHandle Dest); +static void CloseAllLoggingFacilities(void); +static BOOL SyslogOpen(pLoggingFacilityInfo pInfo); + + + +/************************************************************* + * GetCurrentTimeString - + * + * Writes the current date & time into *Buffer + * + *************************************************************/ + +BOOL GetCurrentTimeString(char *Buffer) +{ + /* Note: The specs for ctime_r and asctime_r say that Buffer needs + * to be 26 characters long. Not sure if that includes a triling + * NULL - SCM */ + + time_t t; + struct tm tm; + + ASSERT(Buffer != NULL); + + time(&t); + localtime_r(&t, &tm); + asctime_r(&tm, &(Buffer[0])); + /* asctime_r puts a \n at the end, so we'll remove that */ + Buffer[strlen(Buffer) - 1] = '\0'; + + return TRUE; +} + + + +/*********************************************************************** + * InitDataStructs - + * + * Called durining initalization to set up the LogInfo array + * + ***********************************************************************/ + +static int InitDataStructs(void) +{ + unsigned int i; + + for (i = 0; i < (sizeof(LogInfo) / sizeof(LogInfo[0])); i++) { + LogInfo[i].Initialized = FALSE; + LogInfo[i].Descrip[0] = '\0'; + LogInfo[i].LogOption = DefaultLogOption; + } + + Initialized = TRUE; + + return TRUE; +} + + + + + +/********************************************************************** + * GetFreeLogInfo - + * + * Return the handle for the next available Log Facility structure + * + * After calling this function, the facility will be marked as in use + * + ***********************************************************************/ + +static BOOL GetFreeLogInfo(pLogHandle Dest) +{ + u_int32 i; + + if (!Initialized) { + InitDataStructs(); + } + + for (i = 0; i < (sizeof(LogInfo) / sizeof(LogInfo[0])); i++) { + if (LogInfo[i].Initialized == FALSE) { + /* + Set this here so that we don't return the same identifier twice + in the case where GetFreeLogInfo() is called twice in a row + */ + LogInfo[i].Initialized = TRUE; + *Dest = i; + return TRUE; + } + } +#ifdef DEV + fprintf(stderr, "No available thread logging structs.\n"); +#endif + + return FALSE; +} + + + + + +/********************************************************************** + * GetLogInfoPtr - + * + * Given a handle, return a pointer to the appropriate LoggingFacilityInfo + * structure + * + ***********************************************************************/ + +static pLoggingFacilityInfo GetLogInfoPtr(LogHandle hLog) +{ + if (hLog >= (sizeof(LogInfo) / sizeof(LogInfo[0]))) { +#ifdef DEV + fprintf(stderr, "Illegal LogHandle value: %#X\n", hLog); +#endif + return NULL; + } + + if (LogInfo[hLog].Initialized != TRUE) { +#ifdef DEV + fprintf(stderr, + "GetLogInfoPtr() called for a non-initialized handle\n"); +#endif + return NULL; + } + + return &(LogInfo[hLog]); +} + + + + +/*********************************************************************** + * NewLoggingFacility - + * + * Given an ID ( char string which will appear in the messages ), + * open a logging facility and return a handle to it in + * pLoggingStuff->phLog + * + ***********************************************************************/ + +BOOL NewLoggingFacility(char *ID, pLoggingFacility pStuff) +{ + pLoggingFacilityInfo pInfo = NULL; + LogHandle hLog; + pLogHandle Result; + + /* See if there's room in the array. + * This'd be nice if it were dynamically allocated */ + if (!GetFreeLogInfo(&hLog)) { + return FALSE; + } + + /* Get a pointer to the syslog_data structure */ + if ((pInfo = GetLogInfoPtr(hLog)) == NULL) { + return FALSE; + } + + Result = pStuff->phLog; + + + /* + Set this before the filename is checked because we + may want to use the descrip and/or filename in the logs + */ + pInfo->UseSyslog = pStuff->UseSyslog; + pInfo->LogOption = DefaultLogOption; + pInfo->pid = 0; + pInfo->LogLevel = pStuff->LogLevel; + + sprintf(pInfo->Descrip, "%s %s", pStuff->Label, ID); + + /* ensure that the last character is a NULL */ + pInfo->Descrip[sizeof(pInfo->Descrip) - 1] = '\0'; + + + /* Some sanity checking on filename... */ + if ((pStuff->Filename != NULL) && (strlen(pStuff->Filename) > 0)) { + + FILE *fd; + +#if TRUNCATE_LOGS_ON_START + + /* + * Truncating files on the start will present problems if the user + * creates their own logging facilities after the program's been + * running for a while. But the non-syslog logging is intended for + * debug purposes only, anyway. + */ + + char FileMode[] = "w"; +#else + char FileMode[] = "a"; +#endif /* TRUNCATE_LOGS_ON_START */ + + if ((fd = fopen((pStuff->Filename), FileMode)) == NULL) { +#ifdef DEV + fprintf(stderr, "%s could not be opened\n", pStuff->Filename); +#endif + pInfo->Filename = NULL; + } else { + /* Tag the file */ + + char buf[100]; + + GetCurrentTimeString(&(buf[0])); + +#ifdef DEV +#if TRUNCATE_LOGS_ON_START + /* buf contains the date stamp */ + fprintf(fd, "********* %s %s truncated *********\n", buf, + pStuff->Filename); +#else + fprintf(fd, "********* %s \"%s\" logging to %s *********\n", buf, + pInfo->Descrip, pStuff->Filename); +#endif /* TRUNCATE_LOGS_ON_START */ +#endif + + fflush(fd); + fclose(fd); + pInfo->Filename = pStuff->Filename; + } + } else { + pInfo->Filename = NULL; + } + + + if (pInfo->UseSyslog) { + /* open the logging facility */ + if (!SyslogOpen(pInfo)) { + return FALSE; + } + } + + /* Redundant; Initialized is set to 1 in GetFreeLogInfo */ + pInfo->Initialized = TRUE; + *Result = hLog; + + return TRUE; +} + + + + +/*********************************************************************** + * CloseLoggingFacility - + * + * Closes the logging facility whose handle is hLog. + * Sets up the data structure for reuse later if desired + * + ***********************************************************************/ + +BOOL CloseLoggingFacility(LogHandle hLog) +{ + pLoggingFacilityInfo pInfo = NULL; + + if ((pInfo = GetLogInfoPtr(hLog)) == NULL) { + return FALSE; + } + + pInfo->Descrip[0] = '\0'; + pInfo->LogOption = 0; + pInfo->Filename = NULL; + pInfo->pid = 0; + + if (pInfo->UseSyslog) { + closelog(); + } + + pInfo->Initialized = FALSE; + + return TRUE; +} + + + + +/***************************************** + * CloseAllLoggingFacilities - + * + * Closes down all the logging stuff we've set up + *****************************************/ +static void CloseAllLoggingFacilities(void) +{ + u_int32 i = 0; + + for (i = 0; i < (sizeof(LogInfo) / sizeof(LogInfo[0])); i++) { + /* Makes assumption that these handles all are sequential. Bad Style */ + if (LogInfo[i].Initialized) { + CloseLoggingFacility(i); + } + } + + return; +} + +/*********************************************************************** + * PKCS_Log - + * + * The primitive logging function which logs a message on hLog + * + ***********************************************************************/ + +BOOL PKCS_Log(pLogHandle phLog, char *Format, va_list ap) +{ + char Buffer[PATH_MAX]; + pLoggingFacilityInfo pInfo; + + if (Format == NULL) { + return FALSE; + } + + if ((pInfo = GetLogInfoPtr(*phLog)) == NULL) { + return FALSE; + } + + if ((pInfo->pid != getpid()) && (pInfo->UseSyslog)) { + /* Looks like our PID changed since the last call. We have to re-open */ + if (!SyslogOpen(pInfo)) { + return FALSE; + } + } + + if (vsprintf(&(Buffer[0]), Format, ap) < 0) { + /* Error reporting functions should be rather robust, + * don't you think? */ + /* vsprintf reporting an error */ + //fprintf(stderr, "PKCS_ErrLog - + //vsprintf error for format string %s\n", Format); + return FALSE; + } + + /* Get rid of trailing newlines. */ + while (strlen(Buffer) && (Buffer[strlen(Buffer) - 1] == '\n')) { + Buffer[strlen(Buffer) - 1] = '\0'; + } + + + + // Development work only. No loging to anything other than syslog for + // production level code + + /* + * 1/17/00 SCM - If we're not a daemon, we need to print something to + * stderr for warnings and errors regardless of development/production. + * This is for errors that occur during startup. I'll agree that we don't + * need to write to a log file in production mode, however. + */ + + /* + * Production mode: Write to stderr if we're not a daemon, and the priority + * of the message is at least LOG_WARNING Development mode: Write to stderr + * if we're not a daemon + */ + + if (!IsDaemon()) { + BOOL WriteNow; + +#ifdef DEV + WriteNow = TRUE; +#else + WriteNow = (pInfo->LogLevel <= LOG_WARNING); +#endif /* DEV */ + + if (WriteNow) { + fprintf(stderr, "%s[%d.%d]: %s\n", pInfo->Descrip, getpid(), + (int) pthread_self(), Buffer); + } + } + + /* Don't log to a separate log file in production mode */ +#ifdef DEV + if (pInfo->Filename != NULL) { + + FILE *fd; + + if ((fd = fopen(pInfo->Filename, "a+")) == NULL) { + fprintf(stderr, "PKCS_Log: fopen failed for %s\n", pInfo->Filename); + } else { + char buf[32]; /* Specs say 26-character array */ + + GetCurrentTimeString(&(buf[0])); + + /* Date/Time stamp, descrip, Error message */ + fprintf(fd, "%s %s[%d.%d]: ", buf, pInfo->Descrip, getpid(), + pthread_self()); + fprintf(fd, "%s\n", Buffer); + fflush(fd); + fclose(fd); + } + + } /* end if pInfo->Filename */ +#endif /* DEV */ + + + + /* Always log to syslog, if we're using it */ + if (pInfo->UseSyslog) { + syslog(pInfo->LogLevel, "%s", Buffer); + } + + return TRUE; + +} + + + +/**************************************************************************** + * + * Would like to have a generic function to which I pass the hLog where I'd + * like to do the logging and have a #defined macro which passes it along... + * + * But the preprocessor and variable # args don't work & play well together + * + ****************************************************************************/ + + + +/***************************************** + * DbgLog - + * + * Log messages using the debug facility + *****************************************/ + +void DbgLog(u_int32 DebugLevel, char *Format, ...) +{ + va_list ap; + + if (DebugLevel > SysDebugLevel) { + return; + } + if (!LoggingInitialized) { + InitLogging(); + } + + va_start(ap, Format); + PKCS_Log(&hLogDebug, Format, ap); + va_end(ap); + + return; +} + + + +/***************************************** + * ErrLog - + * + * Log Messges using the error facility + *****************************************/ + +void ErrLog(char *Format, ...) +{ + va_list ap; + + if (!LoggingInitialized) { + InitLogging(); + } + va_start(ap, Format); + PKCS_Log(&hLogErr, Format, ap); + va_end(ap); + + return; +} + +/***************************************** + * LogLog - + * + * Log messages using the log facility + *****************************************/ +void LogLog(char *Format, ...) +{ + va_list ap; + + if (!LoggingInitialized) { + InitLogging(); + } + va_start(ap, Format); + PKCS_Log(&hLogLog, Format, ap); + va_end(ap); + + return; +} + +/***************************************** + * WarnLog - + * + * Log messages using the warning facility + *****************************************/ +void WarnLog(char *Format, ...) +{ + va_list ap; + + if (!LoggingInitialized) { + InitLogging(); + } + va_start(ap, Format); + PKCS_Log(&hLogWarn, Format, ap); + va_end(ap); + + return; +} + +/***************************************** + * TraceLog - + * + * Log messages using the trace facility + *****************************************/ +void TraceLog(char *Format, ...) +{ + va_list ap; + + if (!LoggingInitialized) { + InitLogging(); + } + va_start(ap, Format); + PKCS_Log(&hLogTrace, Format, ap); + va_end(ap); + + return; +} + + + + +/***************************************** + * InfoLog - + * + * Log messages using the info facility + *****************************************/ + +void InfoLog(char *Format, ...) +{ + va_list ap; + + if (!LoggingInitialized) { + InitLogging(); + } + va_start(ap, Format); + PKCS_Log(&hLogInfo, Format, ap); + va_end(ap); + + return; +} + + + +/*********************************************************************** + * InitLogging - + * + * Sets up the various logging facilities. Must be called before + * any of the logging functions can be used. + ***********************************************************************/ + +static BOOL InitLogging(void) +{ + + unsigned int i; + char *s = ProgramName; + + + /* if ProgramName is NULL, we'll just print the level... */ + if (ProgramName == NULL) { + s = ""; + } + + /* Set up logging for all the facilities in SystemLogFacilities[] */ + for (i = 0; + i < (sizeof(SystemLogFacilities) / (sizeof(SystemLogFacilities[0]))); + i++) { + + if (!NewLoggingFacility(s, &(SystemLogFacilities[i]))) { +#ifdef DEV + fprintf(stderr, "InitLogging: NewLoggingFacility failed: %s\n", s); +#endif + return FALSE; + } + + } /* end for i */ + + atexit(CloseAllLoggingFacilities); + LoggingInitialized = TRUE; + + return TRUE; +} + + + +/************************************************************* + * SetDebugLevel - + * + * + * Sets the level at which debug messages get logged to Val. + * Returns the old value + *************************************************************/ + +u_int32 SetDebugLevel(u_int32 Val) +{ + u_int32 OldVal = SysDebugLevel; + + SysDebugLevel = Val; + + return OldVal; +} + + + + +/************************************************************* + * GetDebugLevel + * + * Returns the level at which the program will log debug messages + * + *************************************************************/ + +u_int32 GetDebugLevel(void) +{ + return SysDebugLevel; +} + + + +#if 0 +int main(int argc, char *argv[], char *envp[]) +{ + + ErrLog("This is an error test, attempt 1"); + DbgLog(DEBUG_LEVEL0, "This is a DEBUG test level 0, attempt 1"); + DbgLog(DEBUG_LEVEL1, "This is a DEBUG test level 1, attempt 1"); + SetDebugLevel(DEBUG_NONE); + DbgLog(DEBUG_LEVEL1, "This is a DEBUG test level 1, attempt 2"); + DbgLog(DEBUG_LEVEL0, "This is a DEBUG test level 0, attempt 2"); + ErrLog("This is an error test, attempt 2"); + return 0; + +} +#endif /* 0 */ + + + +static BOOL SyslogOpen(pLoggingFacilityInfo pInfo) +{ + ASSERT(pInfo != NULL); + + if (!(pInfo->UseSyslog)) { + /* it's not really an error to call SyslogOpen for a facility + * that doesn't use it */ + return TRUE; + } + + if (pInfo->pid != 0) { + /* We've been initialized before, so close the previous instance */ + closelog(); + } + + /* Default to log all messages. */ + setlogmask(LOG_UPTO(LOG_DEBUG)); + + /* Mark this as having been set by this process */ + pInfo->pid = getpid(); + + return TRUE; +} diff --git a/usr/sbin/pkcsslotd/log.h b/usr/sbin/pkcsslotd/log.h new file mode 100644 index 0000000..ed57693 --- /dev/null +++ b/usr/sbin/pkcsslotd/log.h @@ -0,0 +1,107 @@ +/* + * 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 + */ + +#ifndef _LOG_H +#define _LOG_H 1 + +#ifndef FALSE +#define FALSE 0 +#endif /* FALSE */ + +#ifndef TRUE +#define TRUE (!(FALSE)) +#endif /* TRUE */ + +#ifndef MAX_LOGGING_FACILITIES +#define MAX_LOGGING_FACILITIES 16 +#endif /* MAX_LOGGING_FACILITIES */ + +#ifndef TRUNCATE_LOGS_ON_START +#define TRUNCATE_LOGS_ON_START 0 +#endif /* TRUNCATE_LOGS_ON_START */ + +/* Use an enum here? */ +#define DEBUG_NONE (0) +#define DEBUG_LEVEL0 (100) /* Less detail */ +#define DEBUG_LEVEL1 (DEBUG_LEVEL0 + 100) /* . */ +#define DEBUG_LEVEL2 (DEBUG_LEVEL1 + 100) /* v */ +#define DEBUG_LEVEL3 (DEBUG_LEVEL2 + 100) /* More detail */ +#define DEBUG_LEVEL4 (DEBUG_LEVEL3 + 100) +#define DEBUG_LEVEL5 (DEBUG_LEVEL4 + 100) + +#define DNONE (DEBUG_NONE) +#define DL0 (DEBUG_LEVEL0) +#define DL1 (DEBUG_LEVEL1) +#define DL2 (DEBUG_LEVEL2) +#define DL3 (DEBUG_LEVEL3) +#define DL4 (DEBUG_LEVEL4) +#define DL5 (DEBUG_LEVEL5) + +#ifndef DbgPrint +#define DbgPrint DbgLog +#endif /* DbgPrint */ + +/************** + * Structures * + **************/ + + + +/************************************************************************ + * Yes, the structures are somewhat redundant; this is an evolutionary + * side-effect. They should probably be combined into a single struct + * - SCM + ************************************************************************/ + +typedef unsigned int u_int32; + +typedef u_int32 LogHandle, *pLogHandle; +typedef u_int32 BOOL, bool, BOOLEAN, boolean; + +typedef struct _logging_facility_info { + BOOL Initialized; + char Descrip[255]; + u_int32 LogOption; + char *Filename; + BOOL UseSyslog; + u_int32 LogLevel; + pid_t pid; +} LoggingFacilityInfo, *pLoggingFacilityInfo; + + +typedef struct _LoggingFacility { + char *Label; + pLogHandle phLog; + char *Filename; + BOOL UseSyslog; + u_int32 LogLevel; +} LoggingFacility, *pLoggingFacility; + + +/******************************** + * Exported Function Prototypes * + ********************************/ + +void DbgLog(u_int32 DebugLevel, char *Format, ...); +void ErrLog(char *Format, ...); +void LogLog(char *Format, ...); +void WarnLog(char *Format, ...); +void TraceLog(char *Format, ...); +void InfoLog(char *Format, ...); + +BOOL PKCS_Log(LogHandle *phLog, char *Format, va_list ap); +BOOL NewLoggingFacility(char *ID, pLoggingFacility pStuff); +BOOL CloseLoggingFacility(LogHandle hLog); +BOOL GetCurrentTimeString(char *Buffer); + +u_int32 SetDebugLevel(u_int32 Val); +u_int32 GetDebugLevel(void); + +#endif /* _LOG_H */ diff --git a/usr/sbin/pkcsslotd/mutex.c b/usr/sbin/pkcsslotd/mutex.c new file mode 100644 index 0000000..28a84c7 --- /dev/null +++ b/usr/sbin/pkcsslotd/mutex.c @@ -0,0 +1,123 @@ +/* + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "slotmgr.h" + +static int xplfd = -1; + +int CreateXProcLock(void) +{ + struct group *grp; + mode_t mode = (S_IRUSR | S_IRGRP); + + if (xplfd == -1) { + xplfd = open(OCK_API_LOCK_FILE, O_CREAT | O_RDONLY, mode); + + if (xplfd != -1) { + if (fchmod(xplfd, mode) == -1) { + DbgLog(DL0, "%s:fchmod(%s):%s\n", + __func__, OCK_API_LOCK_FILE, strerror(errno)); + goto error; + } + + grp = getgrnam("pkcs11"); + if (grp != NULL) { + if (fchown(xplfd, -1, grp->gr_gid) == -1) { + DbgLog(DL0, "%s:fchown(%s):%s\n", + __func__, + OCK_API_LOCK_FILE, strerror(errno)); + goto error; + } + } else { + DbgLog(DL0, "%s:getgrnam():%s\n", + __func__, strerror(errno)); + goto error; + } + } else { + DbgLog(DL0, "open(%s): %s\n", OCK_API_LOCK_FILE, strerror(errno)); + return FALSE; + } + } + + return TRUE; + +error: + if (xplfd != -1) + close(xplfd); + + return FALSE; +} + +void DestroyXProcLock(void) +{ + close(xplfd); +} + +int XProcLock(void) +{ + if (xplfd != -1) + flock(xplfd, LOCK_EX); + + return TRUE; +} + +int XProcUnLock(void) +{ + if (xplfd != -1) + flock(xplfd, LOCK_UN); + + return TRUE; +} + +/****************************************************************************** + * + * InitializeMutexes - + * + * Initializes the global shared memory mutex, and sets up mtxattr, + * the attribute identifier used to create all the per-process mutexes + * + ******************************************************************************/ + +int InitializeMutexes(void) +{ + int err; + + if ((err = CreateXProcLock()) != TRUE) { + DbgLog(DL0, + "InitializeMutexes: CreateXProcLock() failed - returned %#x\n", + err); + return FALSE; + } + + return TRUE; +} + +/*********************************************************************** + * DestroyMutexes - + * + * Destroys all the mutexes used by the program + * + ***********************************************************************/ + +int DestroyMutexes(void) +{ + DestroyXProcLock(); + return TRUE; +} diff --git a/usr/sbin/pkcsslotd/opencryptoki.conf b/usr/sbin/pkcsslotd/opencryptoki.conf new file mode 100644 index 0000000..d11e3d4 --- /dev/null +++ b/usr/sbin/pkcsslotd/opencryptoki.conf @@ -0,0 +1,46 @@ +version opencryptoki-3.14 + +# The following defaults are defined: +# hwversion = 0.0 +# firmwareversion = 0.0 +# description = Linux +# manufacturer = IBM +# +# The slot definitions below may be overridden and/or customized. +# For example: +# slot 0 +# { +# stdll = libpkcs11_cca.so +# description = "OCK CCA Token" +# manufacturer = "MyCompany Inc." +# hwversion = 2.32 +# firmwareversion = 1.0 +# } +# +# See man(5) opencryptoki.conf for further information. +# +slot 0 +{ +stdll = libpkcs11_tpm.so +} + +slot 1 +{ +stdll = libpkcs11_ica.so +} + +slot 2 +{ +stdll = libpkcs11_cca.so +} + +slot 3 +{ +stdll = libpkcs11_sw.so +} + +slot 4 +{ +stdll = libpkcs11_ep11.so +confname = ep11tok.conf +} diff --git a/usr/sbin/pkcsslotd/parser.y b/usr/sbin/pkcsslotd/parser.y new file mode 100644 index 0000000..d8e714f --- /dev/null +++ b/usr/sbin/pkcsslotd/parser.y @@ -0,0 +1,289 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2013-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 + */ + +%{ +/* + * Parse openCryptoki's config file. + */ + +#include +#include +#include +#include + +#include "log.h" +#include "slotmgr.h" +#include "pkcsslotd.h" + +Slot_Info_t_64 sinfo_struct; +unsigned long int Index; +int slot_count = 0; + +#define ERRSTRLEN 256 +#define DEF_MANUFID "IBM" +#define DEF_SLOTDESC "Linux" + +static char errbuf[ERRSTRLEN + 1]; + +extern char *strsep(char **stringp, const char *delim); +extern FILE *yyin; +extern int yyparse(); +extern void yyerror(const char *s); +extern int line_num; +extern int yylex(); + +typedef enum { + KW_STDLL, + KW_SLOTDESC, + KW_MANUFID, + KW_HWVERSION, + KW_FWVERSION, + KW_CONFNAME, + KW_TOKNAME, + KW_TOKVERSION, + KW_MAX +} keyword_token; + +struct ock_key { + char *name; + keyword_token token; +}; + +static const struct ock_key ock_keywords[] = { + {"stdll", KW_STDLL}, + {"description", KW_SLOTDESC}, + {"manufacturer", KW_MANUFID}, + {"hwversion", KW_HWVERSION}, + {"firmwareversion", KW_FWVERSION}, + {"confname", KW_CONFNAME}, + {"tokname", KW_TOKNAME}, + {"tokversion", KW_TOKVERSION} +}; + +void set_init(void); +void set_defaults(void); +int lookup_keyword(const char *key); +int do_str(char *slotinfo, size_t size, char* kw, char *val); +int do_vers(CK_VERSION *slotinfo, char *kw, char *val); + +%} + +%union { + char *str; + unsigned int num; +} + +%token EQUAL DOT SLOT EOL OCKVERSION BEGIN_DEF END_DEF +%token STRING +%token KEYWORD +%token INTEGER +%token TOKVERSION + +%% + +config_file: + config_file sections + | + ; + +sections: + OCKVERSION STRING EOL + { + free($2); + } + | SLOT INTEGER BEGIN_DEF EOL + { + /* inititalize sinfo_struct */ + set_init(); + sinfo_struct.slot_number = $2; + Index = $2; + + } keyword_defs END_DEF + { + /* set some defaults if needed before copying */ + set_defaults(); + memcpy(&sinfo[Index], &sinfo_struct, sizeof(sinfo_struct)); + slot_count++; + } + | EOL + ; + +keyword_defs: + STRING EQUAL TOKVERSION EOL keyword_defs + { + int kw; + + kw = lookup_keyword($1); + + switch (kw) { + case KW_TOKVERSION: + sinfo_struct.version = $3; + break; + default: + yyerror("unknown config keyword"); + break; + } + } + | STRING EQUAL STRING EOL keyword_defs + { + int kw; + + kw = lookup_keyword($1); + + switch (kw) { + case KW_STDLL: + sinfo_struct.present = TRUE; + sinfo_struct.pk_slot.flags |= (CKF_TOKEN_PRESENT); + memset(sinfo_struct.dll_location, 0, sizeof(sinfo_struct.dll_location)); + memcpy(sinfo_struct.dll_location, $3, strlen($3)); + break; + case KW_SLOTDESC: + do_str((char *)sinfo_struct.pk_slot.slotDescription, + sizeof(sinfo_struct.pk_slot.slotDescription), $1, $3); + break; + case KW_MANUFID: + do_str((char *)sinfo_struct.pk_slot.manufacturerID, + sizeof(sinfo_struct.pk_slot.manufacturerID), $1, $3); + break; + case KW_HWVERSION: + do_vers(&sinfo_struct.pk_slot.hardwareVersion, $1, $3); + break; + case KW_FWVERSION: + do_vers(&sinfo_struct.pk_slot.firmwareVersion, $1, $3); + break; + case KW_CONFNAME: + memset(sinfo_struct.confname, 0, sizeof(sinfo_struct.confname)); + memcpy(sinfo_struct.confname, $3, strlen($3)); + break; + case KW_TOKNAME: + memset(sinfo_struct.tokname, 0, sizeof(sinfo_struct.tokname)); + memcpy(sinfo_struct.tokname, $3, strlen($3)); + break; + default: + yyerror("unknown config keyword"); + break; + } + free ($3); + } + | + ; + +%% + +void +yyerror(const char *s) +{ + fprintf(stderr, "parse error on line %d: %s\n", line_num, s); +} + +void +set_init(void) +{ + memset(&sinfo_struct, 0, sizeof(sinfo_struct)); +} + +void +set_defaults(void) +{ + /* set some defaults if user hasn't set these. */ + if (!sinfo_struct.pk_slot.slotDescription[0]) { + memset(&sinfo_struct.pk_slot.slotDescription[0], ' ', + sizeof(sinfo_struct.pk_slot.slotDescription)); + memcpy(&sinfo_struct.pk_slot.slotDescription[0], + DEF_SLOTDESC, strlen(DEF_SLOTDESC)); + } + if (!sinfo_struct.pk_slot.manufacturerID[0]) { + memset(&sinfo_struct.pk_slot.manufacturerID[0], ' ', + sizeof(sinfo_struct.pk_slot.manufacturerID)); + memcpy(&sinfo_struct.pk_slot.manufacturerID[0], + DEF_MANUFID, strlen(DEF_MANUFID)); + } +} + +int +do_str(char *slotinfo, size_t size, char* kw, char *val) +{ + if (strlen(val) > size) { + snprintf(errbuf, ERRSTRLEN, "%s has too many characters\n", kw); + yyerror(errbuf); + return -1 ; + } + memcpy(slotinfo, val, strlen(val)); + return 0; +} + +int +do_vers(CK_VERSION *slotinfo, char *kw, char *val) +{ + char **ap, *argp[2]; + char *valp; + + if (!val) { + snprintf(errbuf, ERRSTRLEN, "%s has no value\n", kw); + yyerror(errbuf); + return -1 ; + } + + valp = val; + for (ap = argp; (*ap = strsep(&valp, ".")) != NULL;) + if (**ap != '\0') + if (++ap >= &argp[2]) + break; + + slotinfo->major = (char) atoi(argp[0]); + if(!argp[1]) + slotinfo->minor = 0; + else + slotinfo->minor = (char) atoi(argp[1]); + + return 0; +} + +int +lookup_keyword(const char *key) +{ + int i; + + for (i = 0; i < KW_MAX ; i++ ) { + if (strncmp(key, ock_keywords[i].name, strlen(key)) == 0) + return ock_keywords[i].token; + } + /* if we get here that means did not find a match... */ + return -1; +} + +int +load_and_parse(const char *configfile) +{ + + FILE *conf; + + extern FILE *yyin; + + conf = fopen(configfile, "r"); + + if (!conf) { + fprintf(stderr, "Failed to open %s: %s\n", configfile, strerror(errno)); + return -1; + } + + yyin = conf; + + do { + yyparse(); + + } while (!feof(yyin)); + + fclose(conf); + + NumberSlotsInDB = slot_count; + + return 0; +} diff --git a/usr/sbin/pkcsslotd/pkcsslotd.h b/usr/sbin/pkcsslotd/pkcsslotd.h new file mode 100644 index 0000000..6770f12 --- /dev/null +++ b/usr/sbin/pkcsslotd/pkcsslotd.h @@ -0,0 +1,98 @@ +/* + * 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 + */ + +/*********************************************************************** + * + * Slot Manager Daemon header file + * + ***********************************************************************/ + +#ifndef _PKCSSLOTMGR_H +#define _PKCSSLOTMGR_H 1 + +/*********** + * Defines * + ***********/ + +#define UNUSED(var) ((void)(var)) + +#ifdef DEV +#ifndef BECOME_DAEMON +#define BECOME_DAEMON FALSE +#endif /* BECOME_DAEMON */ + +#ifndef DEFAULT_LOG_FILE +#define DEFAULT_LOG_FILE (TOK_PATH ".log") +#endif /* DEFAULT_LOG_FILE */ + +#ifndef DEFAULT_DEBUG_LEVEL +#define DEFAULT_DEBUG_LEVEL DEBUG_LEVEL0 +#endif /* DEFAULT_DEBUG_LEVEL */ + +#else /* DEV not defined */ +#define BECOME_DAEMON TRUE +#define DEFAULT_DEBUG_LEVEL DEBUG_NONE + +#endif /* DEV */ + +#define HASH_SHA1 1 +#define HASH_MD5 2 +#define compute_md5(a,b,c) compute_hash(HASH_MD5,b,a,c) + +int compute_hash(int hash_type, int buf_size, char *buf, char *digest); + +/******************** + * Global Variables * + ********************/ + +extern Slot_Mgr_Shr_t *shmp; // pointer to the shared memory region. +extern int shmid; +extern key_t tok; + +extern Slot_Info_t_64 sinfo[NUMBER_SLOTS_MANAGED]; + +extern unsigned int NumberSlotsInDB; + +extern int socketfd; +extern Slot_Mgr_Socket_t socketData; + + +/*********************** + * Function Prototypes * + ***********************/ + +BOOL IsDaemon(void); +BOOL StopGCThread(void *Ptr); +BOOL StartGCThread(Slot_Mgr_Shr_t *MemPtr); +BOOL CheckForGarbage(Slot_Mgr_Shr_t *MemPtr); +int InitializeMutexes(void); +int DestroyMutexes(void); +int CreateSharedMemory(void); +int AttachToSharedMemory(void); +int InitSharedMemory(Slot_Mgr_Shr_t *sp); +void DetachFromSharedMemory(void); +void DestroySharedMemory(void); +int SetupSignalHandlers(void); +void slotdGenericSignalHandler(int Signal); +void PopulateCKInfo(CK_INFO_PTR_64 ckinf); +void PopulateSlotInfo(Slot_Info_t_64 *slot_info, unsigned int *processed); + +int XProcLock(void); +int XProcUnLock(void); +int CreateXProcLock(void); + +int CreateListenerSocket(void); +int InitSocketData(Slot_Mgr_Socket_t *sp); +int SocketConnectionHandler(int socketfd, int timeout_secs); +void DetachSocketListener(int socketfd); + +int load_and_parse(const char *configfile); + +#endif /* _SLOTMGR_H */ diff --git a/usr/sbin/pkcsslotd/pkcsslotd.mk b/usr/sbin/pkcsslotd/pkcsslotd.mk new file mode 100644 index 0000000..38b8ed9 --- /dev/null +++ b/usr/sbin/pkcsslotd/pkcsslotd.mk @@ -0,0 +1,22 @@ +sbin_PROGRAMS += usr/sbin/pkcsslotd/pkcsslotd +noinst_HEADERS += \ + usr/sbin/pkcsslotd/err.h usr/sbin/pkcsslotd/garbage_linux.h \ + usr/sbin/pkcsslotd/log.h usr/sbin/pkcsslotd/pkcsslotd.h + +BUILT_SOURCES += usr/sbin/pkcsslotd/parser.h +EXTRA_DIST += usr/sbin/pkcsslotd/opencryptoki.conf +CLEANFILES += usr/sbin/pkcsslotd/parser.c usr/sbin/pkcsslotd/parser.h \ + usr/sbin/pkcsslotd/parser.output usr/sbin/pkcsslotd/lexer.c + +usr_sbin_pkcsslotd_pkcsslotd_LDFLAGS = -lpthread -lcrypto + +usr_sbin_pkcsslotd_pkcsslotd_CFLAGS = \ + -DPROGRAM_NAME=\"$(@)\" -I${srcdir}/usr/include + +usr_sbin_pkcsslotd_pkcsslotd_SOURCES = \ + usr/sbin/pkcsslotd/slotmgr.c usr/sbin/pkcsslotd/shmem.c \ + usr/sbin/pkcsslotd/signal.c usr/sbin/pkcsslotd/mutex.c usr/sbin/pkcsslotd/err.c \ + usr/sbin/pkcsslotd/log.c usr/sbin/pkcsslotd/daemon.c \ + usr/sbin/pkcsslotd/garbage_linux.c usr/sbin/pkcsslotd/pkcsslotd_util.c \ + usr/sbin/pkcsslotd/socket_server.c usr/sbin/pkcsslotd/parser.y \ + usr/sbin/pkcsslotd/lexer.l diff --git a/usr/sbin/pkcsslotd/pkcsslotd_util.c b/usr/sbin/pkcsslotd/pkcsslotd_util.c new file mode 100644 index 0000000..8cb6143 --- /dev/null +++ b/usr/sbin/pkcsslotd/pkcsslotd_util.c @@ -0,0 +1,113 @@ +/* + * 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 + */ + +/* (C) COPYRIGHT Google Inc. 2013 */ + +#include +#include +#include + +#include "slotmgr.h" +#include "log.h" +#include "pkcsslotd.h" + +void PopulateCKInfo(CK_INFO_PTR_64 ckinf) +{ + CK_VERSION_PTR ckver; + char *package_version_tmp; + char *tok_str; + CK_BYTE lib_major; + CK_BYTE lib_minor; + + ckver = &(ckinf->cryptokiVersion); + + ckver->major = CRYPTOKI_API_MAJOR_V; + ckver->minor = CRYPTOKI_API_MINOR_V; + + memset(ckinf->manufacturerID, ' ', sizeof(ckinf->manufacturerID)); + memset(ckinf->libraryDescription, ' ', sizeof(ckinf->libraryDescription)); + + memcpy(ckinf->manufacturerID, MFG, strlen(MFG)); + memcpy(ckinf->libraryDescription, LIB, strlen(LIB)); + + ckver = &(ckinf->libraryVersion); + + ckver->major = LIB_MAJOR_V; + ckver->minor = LIB_MINOR_V; + +#ifdef PACKAGE_VERSION + package_version_tmp = malloc(strlen(PACKAGE_VERSION) + 1); + if (package_version_tmp) { + strcpy(package_version_tmp, PACKAGE_VERSION); + tok_str = strtok(package_version_tmp, "."); + if (tok_str) { + lib_major = (CK_BYTE) atoi(tok_str); + tok_str = strtok(NULL, "."); + if (tok_str) { + lib_minor = (CK_BYTE) atoi(tok_str); + ckver->major = lib_major; + ckver->minor = lib_minor; + } + } + free(package_version_tmp); + } +#endif + +} + +void PopulateSlotInfo(Slot_Info_t_64 *slot_info, unsigned int *processed) +{ + CK_SLOT_ID id; + unsigned int slot_count = 0; + + /* + * populate the Slot entries... + */ + + for (id = 0; id < NUMBER_SLOTS_MANAGED; id++) { + + if (sinfo[id].present == FALSE) { + /* skip empty slots and just note the slot number */ + slot_info[id].slot_number = id; + } else { + slot_info[id].slot_number = sinfo[id].slot_number; + slot_info[id].present = sinfo[id].present; + slot_info[id].pk_slot.flags = sinfo[id].pk_slot.flags; + + memcpy(slot_info[id].dll_location, + sinfo[id].dll_location, strlen(sinfo[id].dll_location)); + + memcpy(slot_info[id].confname, sinfo[id].confname, + strlen(sinfo[id].confname)); + + memcpy(slot_info[id].tokname, sinfo[id].tokname, + strlen(sinfo[id].tokname)); + + memcpy(slot_info[id].pk_slot.slotDescription, + sinfo[id].pk_slot.slotDescription, + sizeof(sinfo[id].pk_slot.slotDescription)); + + memcpy(slot_info[id].pk_slot.manufacturerID, + sinfo[id].pk_slot.manufacturerID, + sizeof(sinfo[id].pk_slot.manufacturerID)); + + memcpy(&slot_info[id].pk_slot.hardwareVersion, + &sinfo[id].pk_slot.hardwareVersion, + sizeof(sinfo[id].pk_slot.hardwareVersion)); + + memcpy(&slot_info[id].pk_slot.firmwareVersion, + &sinfo[id].pk_slot.firmwareVersion, + sizeof(sinfo[id].pk_slot.firmwareVersion)); + + slot_info[id].version = sinfo[id].version; + + slot_count++; + } + } + *processed = slot_count; +} diff --git a/usr/sbin/pkcsslotd/shmem.c b/usr/sbin/pkcsslotd/shmem.c new file mode 100644 index 0000000..b25b07b --- /dev/null +++ b/usr/sbin/pkcsslotd/shmem.c @@ -0,0 +1,326 @@ +/* + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "slotmgr.h" +#include "log.h" +#include "pkcsslotd.h" + +#define MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) +#define MAPFILENAME CONFIG_PATH "/.apimap" + +pthread_mutexattr_t mtxattr; // Mutex attribute for the shared memory Mutex + +/*********************************************************************** + * CreateSharedMemory - + * + * Creates and initializes a shared memory file. This function will fail + * if the memory is already allocated since we're the owner of it. + * + ***********************************************************************/ + +int CreateSharedMemory(void) +{ + struct stat statbuf; + char *Path = NULL; + struct group *grp; + struct shmid_ds shm_info; + +#if !MMAP + if (((Path = getenv("PKCS11_SHMEM_FILE")) == NULL) || (Path[0] == '\0')) { + Path = TOK_PATH; + } + + // Get shared memory key token all users of the shared memory + // need to get the same token + + if (stat(Path, &statbuf) < 0) { + ErrLog("Shared Memory Key Token creation file does not exist"); + return FALSE; + } + // SAB Get the group information for the PKCS#11 group... fail if + // it does not exist + grp = getgrnam("pkcs11"); + if (!grp) { + ErrLog("Group PKCS#11 does not exist "); + return FALSE; // Group does not exist... setup is wrong.. + } + + + tok = ftok(Path, 'b'); + // Allocate the shared memory... Fail if the memory is already + // allocated since the slot mgr is the owner of it. + + // Is this some attempt at exclusivity, or is that just a side effect? + // - SCM 9/1 + + shmid = shmget(tok, sizeof(Slot_Mgr_Shr_t), + IPC_CREAT | IPC_EXCL | S_IRUSR | + S_IRGRP | S_IWUSR | S_IWGRP); + + // Explanation of options to shmget(): + + /* + * IPC_CREAT Creates the data structure if it does not already exist. + * IPC_EXCL Causes the shmget subroutine to be unsuccessful if the + * IPC_CREAT flag is also set, and the data structure already + * exists. + * S_IRUSR Permits the process that owns the data structure to read it. + * S_IWUSR Permits the process that owns the data structure to modify it. + * S_IRGRP Permits the group associated with the data structure to + * read it. + * S_IWGRP Permits the group associated with the data structure to + * modify it. + * + * + * WE DON"T WANT OTHERS + * S_IROTH Permits others to read the data structure. + * S_IWOTH Permits others to modify the data structure. + */ + + + if (shmid < 0) { + ErrLog("Shared memory creation failed (0x%X)\n", errno); + ErrLog("Reclaiming 0x%X\n", tok); + shmid = shmget(tok, sizeof(Slot_Mgr_Shr_t), 0); + DestroySharedMemory(); + shmid = shmget(tok, sizeof(Slot_Mgr_Shr_t), + IPC_CREAT | IPC_EXCL | S_IRUSR | + S_IRGRP | S_IWUSR | S_IWGRP); + if (shmid < 0) { + ErrLog("Shared memory reclamation failed (0x%X)\n", errno); + ErrLog("perform ipcrm -M 0x%X\n", tok); + return FALSE; + } + } + // SAB Set the group ownership of the shared mem segment.. + // we already have the group structure.. + + if (shmctl(shmid, IPC_STAT, &shm_info) == 0) { + + shm_info.shm_perm.gid = grp->gr_gid; + + if (shmctl(shmid, IPC_SET, &shm_info) == -1) { + ErrLog("Failed to set group ownership for shm \n"); + shmctl(shmid, IPC_RMID, NULL); + } + + } else { + ErrLog("Can't get status of shared memory %d\n", errno); + // we know it was created... we need to destroy it... + shmctl(shmid, IPC_RMID, NULL); + + } + + + + return TRUE; +#else + { +#warning "EXPERIMENTAL" + int fd; + int i; + char *buffer; + + grp = getgrnam("pkcs11"); + if (!grp) { + ErrLog("Group \"pkcs11\" does not exist! " + "Opencryptoki setup is incorrect."); + return FALSE; // Group does not exist... setup is wrong.. + } + + fd = open(MAPFILENAME, O_RDWR, MODE); + if (fd < 0) { + // File does not exist... this is cool, we creat it here + fd = open(MAPFILENAME, O_RDWR | O_CREAT, MODE); // Create the file + if (fd < 0) { // We are really hosed here, since we should be able + // to create the file now + ErrLog("%s: open(%s): %s", __func__, MAPFILENAME, + strerror(errno)); + return FALSE; + } else { + if (fchmod(fd, MODE) == -1) { + ErrLog("%s: fchmod(%s): %s", __func__, MAPFILENAME, + strerror(errno)); + close(fd); + return FALSE; + } + if (fchown(fd, 0, grp->gr_gid) == -1) { + ErrLog("%s: fchown(%s, root, pkcs11): %s", __func__, + MAPFILENAME, strerror(errno)); + close(fd); + return FALSE; + } + // Create a buffer and make the file the right length + i = sizeof(Slot_Mgr_Shr_t); + buffer = malloc(sizeof(Slot_Mgr_Shr_t)); + memset(buffer, '\0', i); + write(fd, buffer, i); + free(buffer); + close(fd); + } + } else { + ErrLog("%s: [%s] exists; you may already have a pkcsslot daemon " + "running. If this is not the case, then the prior daemon " + "was not shut down cleanly. Please delete this file and " + "try again\n", __func__, MAPFILENAME); + close(fd); + return FALSE; + } + return TRUE; + } + +#endif + +} + + + + +/*********************************************************************** + * + * AttachToSharedMemory - + * + * Called after creating the shared memory file + * Basically allows us to have access to the memory we've just created + * + ***********************************************************************/ + +int AttachToSharedMemory(void) +{ + +#if !MMAP + shmp = NULL; + shmp = (Slot_Mgr_Shr_t *) shmat(shmid, NULL, 0); + + if (!shmp) { + ErrLog("Shared memory attach failed (0x%X)\n", errno); + return FALSE; + } + + /* Initizalize the memory to 0 */ + memset(shmp, '\0', sizeof(*shmp)); + + return TRUE; +#else + { +#warning "EXPERIMENTAL" + int fd; + int i; + char *buffer; + + fd = open(MAPFILENAME, O_RDWR, MODE); + if (fd < 0) { + return FALSE; //Failed + } + shmp = + (Slot_Mgr_Shr_t *) mmap(NULL, sizeof(Slot_Mgr_Shr_t), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + close(fd); + if (!shmp) { + return FALSE; + } + return TRUE; + } +#endif + +} + + + +/*********************************************************************** + * + * DetachFromSharedMemory - + * + * Un-does AttachToSharedMemory() :) + * + ***********************************************************************/ + +void DetachFromSharedMemory(void) +{ + +#if !MMAP + if (shmp == NULL) + return; + + if (shmdt(shmp) != 0) { + ErrLog("Attempted to detach from an invalid shared memory pointer"); + } + + shmp = NULL; + return; +#else + if (shmp == NULL) + return; + + munmap((void *) shmp, sizeof(*shmp)); + + unlink(MAPFILENAME); +#endif + +} + + +/*********************************************************************** + * + * DestroySharedMemory - + * + * Closes (destroys) the shared memory file we created with + * CreateSharedMemory() + * + * We should make sure that everyone else has detached before we do this + * if we manage to exit before this gets called, you have to call ipcrm + * to clean things up... + * + ***********************************************************************/ + +void DestroySharedMemory(void) +{ + if (shmctl(shmid, IPC_RMID, 0) != 0) { + perror("error in closing shared memory segment"); + } + + return; +} + + + +/*********************************************************************** + * + * InitSharedMemory - + * + * Set up our newly allocated shared memory segment + * + * + ***********************************************************************/ + + +int InitSharedMemory(Slot_Mgr_Shr_t *sp) +{ + uint16 procindex; + + memset(sp->slot_global_sessions, 0, NUMBER_SLOTS_MANAGED * sizeof(uint32)); + + /* Initialize the process side of things. */ + /* for now don't worry about the condition variables */ + for (procindex = 0; procindex < NUMBER_PROCESSES_ALLOWED; procindex++) { + /* Initialize the mutex variables. */ + sp->proc_table[procindex].inuse = FALSE; + } + + return TRUE; +} diff --git a/usr/sbin/pkcsslotd/signal.c b/usr/sbin/pkcsslotd/signal.c new file mode 100644 index 0000000..cf7b908 --- /dev/null +++ b/usr/sbin/pkcsslotd/signal.c @@ -0,0 +1,183 @@ +/* + * 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 + */ + +#include +#include +#include + +#include "log.h" +#include "slotmgr.h" +#include "pkcsslotd.h" +#include "err.h" + + +extern BOOL IsValidProcessEntry(pid_t_64 pid, time_t_64 RegTime); + +static int SigsToIntercept[] = { + SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, + SIGTERM, SIGTSTP, SIGTTIN, + SIGTTOU, SIGUSR1, SIGUSR2, SIGPROF +}; + +/* SIGCONT - Don't want to exit on SIGCONT; it'll in fact + mask other signals - kill -HUP actually sends SIGCONT before SIGHUP */ + +/* SIGCHLD - Don't want to exit. Should never receive, but we do, apparently + * when something tries to cancel the GC Thread */ + +static int SigsToIgnore[] = { + SIGCHLD, +}; + + + +/************************************************** + * slotdGenericSignalHandler + * + * Main signal handler for the daemon. Doesn't + * allow the daemon to be killed unless we're + * not in use + ***************************************************/ +void slotdGenericSignalHandler(int Signal) +{ + + int procindex; + BOOL OkToExit = TRUE; + + /******************************************************** + * DbgLog calls (possibly) printf, syslog_r, etc. + * The behavior of these functions is "undefined" + * when called from a signal handler according to + * the sigaction man page. + * + * Thus, they're only called in development + * versions of the code. + ********************************************************/ + +#ifdef DEV + DbgLog(DL2, "slotdGenericSignalHandler got %s (%d; %#x)", + SignalConst(Signal), Signal, Signal); +#endif /* DEV */ + +#if !defined(NOGARBAGE) + StopGCThread(shmp); + CheckForGarbage(shmp); +#endif + + for (procindex = 0; (procindex < NUMBER_PROCESSES_ALLOWED); procindex++) { + + Slot_Mgr_Proc_t_64 *pProc = &(shmp->proc_table[procindex]); + + if (shmp == NULL) { + break; + } + if ((pProc->inuse) +#if !(NOGARBAGE) + && (IsValidProcessEntry(pProc->proc_id, pProc->reg_time)) +#endif + ) { + /* Someone's still using us... Log it */ + OkToExit = FALSE; +#ifdef DEV + WarnLog("Process %d is still registered", pProc->proc_id); +#endif + } + } + + if (!OkToExit) { + DbgLog(DL1, "Continuing execution"); +#if !defined(NOGARBAGE) + StartGCThread(shmp); +#endif + return; + } + + InfoLog("Exiting on %s (%d; %#x)", SignalConst(Signal), Signal, Signal); + + DetachSocketListener(socketfd); + DestroyMutexes(); + DetachFromSharedMemory(); + DestroySharedMemory(); + exit(0); + +} + + +/*************************************************** + * SetupSignalHandlers - + * + * Installs slotdGenericSignalHandler for the listed signals + * + ***************************************************/ +int SetupSignalHandlers(void) +{ + unsigned int i; + struct sigaction new_action; + + new_action.sa_handler = slotdGenericSignalHandler; + sigemptyset(&(new_action.sa_mask)); + sigaddset(&(new_action.sa_mask), SIGCHLD); + /* sigaddset(&(new_action.sa_mask), SA_NOCLDWAIT); */ + /* sigaddset(&(new_action.sa_mask), SA_NOCLDSTOP); */ + + new_action.sa_flags = (RESTART_SYS_CALLS ? SA_RESTART : 0); + + + for (i = 0; + i < (sizeof(SigsToIntercept) / sizeof(SigsToIntercept[0])); i++) { + + if (sigaction(SigsToIntercept[i], &new_action, NULL) != 0) { + //DbgLog("SetupSignalHandlers - sigaction failed for %s (%d; %#x)", + //SignalConst(SigsToIntercept[i]), + //SigsToIntercept[i], SigsToIntercept[i]); + return FALSE; + } + + } + + + new_action.sa_handler = SIG_IGN; + sigemptyset(&(new_action.sa_mask)); + for (i = 0; i < (sizeof(SigsToIgnore) / sizeof(SigsToIgnore[0])); i++) { + if (sigaction(SigsToIgnore[i], &new_action, NULL) != 0) { + //DbgLog ( "Failed to ignore signal."); + return FALSE; + } + } + + return TRUE; +} + + + +/*********************************************************************** + * GCBlockSignals - + * + * Garbage collector calls this to prevent signals from getting + * sent to the GC thread. + * + ***********************************************************************/ + +BOOL GCBlockSignals(void) +{ + unsigned int i; + int ret; + sigset_t SigSet; + + sigemptyset(&SigSet); + for (i = 0; + i < (sizeof(SigsToIntercept) / sizeof(SigsToIntercept[0])); i++) { + sigaddset(&SigSet, SigsToIntercept[i]); + } + + ret = pthread_sigmask(SIG_SETMASK, &SigSet, NULL); + + return ret; +} diff --git a/usr/sbin/pkcsslotd/slotmgr.c b/usr/sbin/pkcsslotd/slotmgr.c new file mode 100644 index 0000000..347df6e --- /dev/null +++ b/usr/sbin/pkcsslotd/slotmgr.c @@ -0,0 +1,528 @@ +/* + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "slotmgr.h" +#include "pkcsslotd.h" +#include "parser.h" + +#define OBJ_DIR "TOK_OBJ" +#define MD5_HASH_SIZE 16 + +typedef char md5_hash_entry[MD5_HASH_SIZE]; +md5_hash_entry tokname_hash_table[NUMBER_SLOTS_MANAGED]; + +Slot_Mgr_Shr_t *shmp; // pointer to the shared memory region. +int shmid; +key_t tok; +Slot_Info_t_64 sinfo[NUMBER_SLOTS_MANAGED]; +Slot_Info_t_64 *psinfo; +unsigned int NumberSlotsInDB = 0; + +int socketfd; +Slot_Mgr_Socket_t socketData; + +struct dircheckinfo_s { + const char *dir; + int mode; +}; + +/* + We make main() able to modify Daemon so that we can + daemonize or not based on a command-line argument + */ +extern BOOL Daemon; +extern BOOL IveDaemonized; + +void DumpSharedMemory(void) +{ + u_int32 *p; + char Buf[PATH_MAX]; + u_int32 i; + + p = (u_int32 *) shmp; + + for (i = 0; i < 15; i++) { + sprintf(Buf, "%08X %08X %08X %08X", p[0 + (i * 4)], p[1 + (i * 4)], + p[2 + (i * 4)], p[3 + (i * 4)]); + LogLog(Buf); + } + return; +} + +int compute_hash(int hash_type, int buf_size, char *buf, char *digest) +{ + EVP_MD_CTX *md_ctx = NULL; + unsigned int result_size; + int rc; + + md_ctx = EVP_MD_CTX_create(); + + switch (hash_type) { + case HASH_SHA1: + rc = EVP_DigestInit(md_ctx, EVP_sha1()); + break; + case HASH_MD5: + rc = EVP_DigestInit(md_ctx, EVP_md5()); + break; + default: + EVP_MD_CTX_destroy(md_ctx); + return -1; + break; + } + + if (rc != 1) { + fprintf(stderr, "EVP_DigestInit() failed: rc = %d\n", rc); + return -1; + } + + rc = EVP_DigestUpdate(md_ctx, buf, buf_size); + if (rc != 1) { + fprintf(stderr, "EVP_DigestUpdate() failed: rc = %d\n", rc); + return -1; + } + + result_size = EVP_MD_CTX_size(md_ctx); + rc = EVP_DigestFinal(md_ctx, (unsigned char *) digest, &result_size); + if (rc != 1) { + fprintf(stderr, "EVP_DigestFinal() failed: rc = %d\n", rc); + return -1; + } + EVP_MD_CTX_destroy(md_ctx); + return 0; +} + +/** This function does basic sanity checks to make sure the + * eco system is in place for opencryptoki to run properly. + **/ +void run_sanity_checks() +{ + int i, ec, uid = -1; + struct group *grp = NULL; + struct stat sbuf; + struct dircheckinfo_s dircheck[] = { + //drwxrwx--- + {LOCKDIR_PATH, S_IRWXU | S_IRWXG}, + {OCK_LOGDIR, S_IRWXU | S_IRWXG}, + {NULL, 0}, + }; + + /* first check that our effective user id is root */ + uid = (int) geteuid(); + if (uid != 0) { + fprintf(stderr, "This daemon needs root privilegies, " + "but the effective user id is not 'root'.\n"); + exit(1); + } + + /* check that the pkcs11 group exists */ + grp = getgrnam("pkcs11"); + if (!grp) { + fprintf(stderr, "There is no 'pkcs11' group on this system.\n"); + exit(1); + } + + /* check effective group id */ + uid = (int) getegid(); + if (uid != 0 && uid != (int) grp->gr_gid) { + fprintf(stderr, "This daemon should have an effective group id of " + "'root' or 'pkcs11'.\n"); + exit(1); + } + + /* Create base lock and log directory here. API..Lock file is + * accessed from the daemon in CreateXProcLock() in mutex.c.*/ + for (i = 0; dircheck[i].dir != NULL; i++) { + ec = stat(dircheck[i].dir, &sbuf); + if (ec != 0 && errno == ENOENT) { + /* dir does not exist, try to create it */ + ec = mkdir(dircheck[i].dir, dircheck[i].mode); + if (ec != 0) { + fprintf(stderr, "Directory %s missing\n", dircheck[i].dir); + exit(2); + } + /* set ownership to root, and pkcs11 group */ + if (chown(dircheck[i].dir, geteuid(), grp->gr_gid) != 0) { + fprintf(stderr, + "Failed to set owner:group ownership on %s directory", + dircheck[i].dir); + exit(1); + } + /* mkdir does not set group permission right, so + * trying explictly here again */ + if (chmod(dircheck[i].dir, dircheck[i].mode) != 0) { + fprintf(stderr, + "Failed to change permissions on %s directory", + dircheck[i].dir); + exit(1); + } + } + } + + /* check if token directory is available, if not flag an error. + * We do not create token directories here as admin should + * configure and decide which tokens to expose to opencryptoki + * outside of opencryptoki and pkcsslotd */ + ec = stat(CONFIG_PATH, &sbuf); + if (ec != 0 && errno == ENOENT) { + fprintf(stderr, "Token directories missing\n"); + exit(2); + } +} + +int is_duplicate(md5_hash_entry hash, md5_hash_entry *hash_table) +{ + int i; + + for (i = 0; i < NUMBER_SLOTS_MANAGED; i++) { + if (memcmp(hash_table[i], hash, sizeof(md5_hash_entry)) == 0) + return 1; + } + + return 0; +} + +int chk_create_tokdir(Slot_Info_t_64 *psinfo) +{ + struct stat sbuf; + char tokendir[PATH_MAX]; + struct group *grp; + gid_t grpid; + int uid, rc; + mode_t proc_umask; + char *tokdir = psinfo->tokname; + char token_md5_hash[MD5_HASH_SIZE]; + + /* skip if no dedicated token directory is required */ + if (!tokdir || strlen(tokdir) == 0) + return 0; + + proc_umask = umask(0); + + /* get 'PKCS11' group id */ + uid = (int) geteuid(); + grp = getgrnam("pkcs11"); + if (!grp) { + fprintf(stderr, "PKCS11 group does not exist [errno=%d].\n", errno); + return errno; + } else { + grpid = grp->gr_gid; + } + + /* calculate md5 hash from token name */ + rc = compute_md5(tokdir, strlen(tokdir), token_md5_hash); + if (rc) { + fprintf(stderr, "Error calculating MD5 of token name!\n"); + return -1; + } + /* check for duplicate token names */ + if (is_duplicate(token_md5_hash, tokname_hash_table)) { + fprintf(stderr, "Duplicate token name '%s'!\n", tokdir); + return -1; + } + + /* add entry into hash table */ + memcpy(tokname_hash_table[psinfo->slot_number], token_md5_hash, + MD5_HASH_SIZE); + + /* Create token specific directory */ + sprintf(tokendir, "%s/%s", CONFIG_PATH, tokdir); + rc = stat(tokendir, &sbuf); + if (rc != 0 && errno == ENOENT) { + /* directory does not exist, create it */ + rc = mkdir(tokendir, S_IRWXU | S_IRWXG); + if (rc != 0) { + fprintf(stderr, + "Creating directory '%s' failed [errno=%d].\n", + tokendir, errno); + umask(proc_umask); + return rc; + } + + rc = chown(tokendir, uid, grpid); + if (rc != 0) { + fprintf(stderr, + "Could not set PKCS11 group permission [errno=%d].\n", + errno); + umask(proc_umask); + return rc; + } + + } + + /* Create TOK_OBJ directory */ + sprintf(tokendir, "%s/%s/%s", CONFIG_PATH, tokdir, OBJ_DIR); + rc = stat(tokendir, &sbuf); + if (rc != 0 && errno == ENOENT) { + /* directory does not exist, create it */ + rc = mkdir(tokendir, S_IRWXU | S_IRWXG); + if (rc != 0) { + fprintf(stderr, + "Creating directory '%s' failed [errno=%d].\n", + tokendir, errno); + umask(proc_umask); + return rc; + } + + rc = chown(tokendir, uid, grpid); + if (rc != 0) { + fprintf(stderr, + "Could not set PKCS11 group permission [errno=%d].\n", + errno); + umask(proc_umask); + return rc; + } + } + umask(proc_umask); + return 0; +} + +static int create_pid_file(pid_t pid) +{ + FILE *pidfile; + + pidfile = fopen(PID_FILE_PATH, "w"); + if (!pidfile) { + fprintf(stderr, "Could not create pid file '%s' [errno=%d].\n", + PID_FILE_PATH, errno); + return -1; + } + + fprintf(pidfile, "%d\n", (int) pid); + fflush(pidfile); + fclose(pidfile); + InfoLog("PID File created"); + + return 0; +} + +/***************************************** + * main() - + * You know what main does. + * Comment block for ease of spotting + * it when paging through file + * + *****************************************/ + +int main(int argc, char *argv[], char *envp[]) +{ + int ret, i; + + /**********************************/ + /* Read in command-line arguments */ + /**********************************/ + + /* FIXME: Argument for daemonizing or not */ + /* FIXME: Argument for debug level */ + /* FIXME: Arguments affecting the log files, whether to use syslog, etc. + * (Read conf file?) */ + + UNUSED(argc); + UNUSED(argv); + UNUSED(envp); + + /* Do some basic sanity checks */ + run_sanity_checks(); + + /* Report our debug level */ + if (GetDebugLevel() > DEBUG_NONE) { + DbgLog(GetDebugLevel(), + "Starting with debugging messages logged at level %d " + "(%d = No messages; %d = few; %d = more, etc.)", + GetDebugLevel(), DEBUG_NONE, DEBUG_LEVEL0, DEBUG_LEVEL1); + } + + ret = load_and_parse(OCK_CONFIG); + if (ret != 0) { + ErrLog("Failed to read config file.\n"); + return 1; + } else { + DbgLog(DL0, "Parse config file succeeded.\n"); + } + + /* Allocate and Attach the shared memory region */ + if (!CreateSharedMemory()) { + /* CreateSharedMemory() does it's own error logging */ + return 1; + } + + DbgLog(DL0, "SHMID %d token %#X \n", shmid, tok); + + /* Now that we've created the shared memory segment, we attach to it */ + if (!AttachToSharedMemory()) { + /* AttachToSharedMemory() does it's own error logging */ + DestroySharedMemory(); + return 2; + } + + /* Initialize the global shared memory mutex (and the attribute + * used to create the per-process mutexes */ + if (!InitializeMutexes()) { + DetachFromSharedMemory(); + DestroySharedMemory(); + return 3; + } + + /* Get the global shared memory mutex */ + if (!XProcLock()) + return 4; + + /* Populate the Shared Memory Region */ + if (!InitSharedMemory(shmp)) { + XProcUnLock(); + + DetachFromSharedMemory(); + DestroySharedMemory(); + return 4; + } + + /* Release the global shared memory mutex */ + if (!XProcUnLock()) + return 4; + + if ((socketfd = CreateListenerSocket()) < 0) { + DestroyMutexes(); + DetachFromSharedMemory(); + DestroySharedMemory(); + return 5; + } + + if (!InitSocketData(&socketData)) { + DetachSocketListener(socketfd); + DestroyMutexes(); + DetachFromSharedMemory(); + DestroySharedMemory(); + return 6; + } + + /* Create customized token directories */ + psinfo = &socketData.slot_info[0]; + for (i = 0; i < NUMBER_SLOTS_MANAGED; i++, psinfo++) { + ret = chk_create_tokdir(psinfo); + if (ret) + return EACCES; + } + + /* + * Become a Daemon, if called for + */ + if (Daemon) { + pid_t pid; + if ((pid = fork()) < 0) { + DetachSocketListener(socketfd); + DestroyMutexes(); + DetachFromSharedMemory(); + DestroySharedMemory(); + return 7; + } else if (pid != 0) { + /* + * This is the parent + * Create the pid file for the client as systemd wants to + * see the pid file a soon as the parent terminates. + */ + create_pid_file(pid); + /* now terminate the parent */ + exit(0); + } else { + /* This is the child */ + setsid(); // Session leader +#ifndef DEV + fclose(stderr); + fclose(stdout); + fclose(stdin); +#endif + } + } else { +#ifdef DEV + // Log only on development builds + LogLog("Not becoming a daemon...\n"); +#endif + } + + /***************************************** + * + * Register Signal Handlers + * Daemon probably should ignore ALL signals possible, since termination + * while active is a bad thing... however one could check for + * any processes active in the shared memory, and destroy the shm if + * the process wishes to terminate. + * + *****************************************/ + + /* + * We have to set up the signal handlers after we daemonize because + * the daemonization process redefines our handler for (at least) SIGTERM + */ + if (!SetupSignalHandlers()) { + DetachSocketListener(socketfd); + DestroyMutexes(); + DetachFromSharedMemory(); + DestroySharedMemory(); + return 8; + } + + /* ultimatly we will create a couple of threads which monitor the slot db + * and handle the insertion and removal of tokens from the slot. + */ + + /* For Testing the Garbage collection routines */ + /* + * shmp->proc_table[3].inuse = TRUE; + * shmp->proc_table[3].proc_id = 24328; + */ + +#if !defined(NOGARBAGE) + printf("Start garbage \n"); + /* start garbage collection thread */ + if (!StartGCThread(shmp)) { + DetachSocketListener(socketfd); + DestroyMutexes(); + DetachFromSharedMemory(); + DestroySharedMemory(); + return 9; + } +#endif + + /* + * We've fully become a daemon. + * In not-daemon mode the pid file hasn't been created jet, + * so let's do this now. + */ + if (!Daemon) + create_pid_file(getpid()); + + while (1) { +#if !(THREADED) && !(NOGARBAGE) + CheckForGarbage(shmp); +#endif + SocketConnectionHandler(socketfd, 10); + } + + /************************************************************* + * + * Here we need to actualy go through the processes and verify that thye + * still exist. If not, then they terminated with out properly calling + * C_Finalize and therefore need to be removed from the system. + * Look for a system routine to determine if the shared memory is held by + * the process to further verify that the proper processes are in the + * table. + * + **************************************************************/ +} /* end main */ diff --git a/usr/sbin/pkcsslotd/socket_server.c b/usr/sbin/pkcsslotd/socket_server.c new file mode 100644 index 0000000..ae0eff9 --- /dev/null +++ b/usr/sbin/pkcsslotd/socket_server.c @@ -0,0 +1,156 @@ +/* + * 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 + */ + +/* (C) COPYRIGHT Google Inc. 2013 */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "slotmgr.h" +#include "pkcsslotd.h" +#include "apictl.h" + +// Creates the daemon's listener socket, to which clients will connect and +// retrieve slot information through. Returns the file descriptor of the +// created socket. +int CreateListenerSocket(void) +{ + struct sockaddr_un address; + struct group *grp; + int socketfd; + + socketfd = socket(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); + if (socketfd < 0) { + ErrLog("Failed to create listener socket, errno 0x%X.", errno); + return -1; + } + if (unlink(SOCKET_FILE_PATH) && errno != ENOENT) { + ErrLog("Failed to unlink socket file, errno 0x%X.", errno); + close(socketfd); + return -1; + } + + memset(&address, 0, sizeof(struct sockaddr_un)); + address.sun_family = AF_UNIX; + strcpy(address.sun_path, SOCKET_FILE_PATH); + + if (bind(socketfd, + (struct sockaddr *) &address, sizeof(struct sockaddr_un)) != 0) { + ErrLog("Failed to bind to socket, errno 0x%X.", errno); + close(socketfd); + return -1; + } + // make socket file part of the pkcs11 group, and write accessable + // for that group + grp = getgrnam("pkcs11"); + if (!grp) { + ErrLog("Group PKCS#11 does not exist"); + DetachSocketListener(socketfd); + return -1; + } + if (chown(SOCKET_FILE_PATH, 0, grp->gr_gid)) { + ErrLog("Could not change file group on socket, errno 0x%X.", errno); + DetachSocketListener(socketfd); + return -1; + } + if (chmod(SOCKET_FILE_PATH, + S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP | S_IXUSR | S_IXGRP)) { + ErrLog("Could not change file permissions on socket, errno 0x%X.", + errno); + DetachSocketListener(socketfd); + return -1; + } + + if (listen(socketfd, 20) != 0) { + ErrLog("Failed to listen to socket, errno 0x%X.", errno); + DetachSocketListener(socketfd); + return -1; + } + + return socketfd; +} + +int InitSocketData(Slot_Mgr_Socket_t *socketData) +{ + unsigned int processed = 0; + + PopulateCKInfo(&(socketData->ck_info)); + socketData->num_slots = NumberSlotsInDB; + PopulateSlotInfo(socketData->slot_info, &processed); + + /* check that we read in correct amount of slots */ + if (processed != NumberSlotsInDB) { + ErrLog("Failed to populate slot info.\n"); + return FALSE; + } + + return TRUE; +} + +int SocketConnectionHandler(int socketfd, int timeout_secs) +{ + int returnVal; + fd_set set; + struct timeval timeout; + + FD_ZERO(&set); + FD_SET(socketfd, &set); + + timeout.tv_sec = timeout_secs; + timeout.tv_usec = 0; + + returnVal = select(socketfd + 1, &set, NULL, NULL, &timeout); + if (returnVal == -1) { + ErrLog("select failed on socket connection, errno 0x%X.", errno); + return FALSE; + } else if (returnVal == 0) { + // select call timed out, return + return FALSE; + } else { + struct sockaddr_un address; + socklen_t address_length = sizeof(address); + + int connectionfd = accept(socketfd, + (struct sockaddr *) &address, + &address_length); + if (connectionfd < 0) { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + /* These errors are allowed since + * socket is non-blocking + */ + ErrLog("Failed to accept socket connection, errno 0x%X.", + errno); + } + return FALSE; + } + if (write(connectionfd, &socketData, sizeof(socketData)) != + sizeof(socketData)) { + ErrLog("Failed to write socket data, errno 0x%X.", errno); + close(connectionfd); + return FALSE; + } + close(connectionfd); + return TRUE; + } +} + +void DetachSocketListener(int socketfd) +{ + close(socketfd); + unlink(SOCKET_FILE_PATH); +} diff --git a/usr/sbin/sbin.mk b/usr/sbin/sbin.mk new file mode 100644 index 0000000..640308f --- /dev/null +++ b/usr/sbin/sbin.mk @@ -0,0 +1,18 @@ +if ENABLE_ICSFTOK +include usr/sbin/pkcsicsf/pkcsicsf.mk +endif +if ENABLE_PKCSEP11_MIGRATE +include usr/sbin/pkcsep11_migrate/pkcsep11_migrate.mk +endif +if ENABLE_PKCSEP11_SESSION +include usr/sbin/pkcsep11_session/pkcsep11_session.mk +endif +if ENABLE_CCATOK +include usr/sbin/pkcscca/pkcscca.mk +endif +if ENABLE_P11SAK +include usr/sbin/p11sak/p11sak.mk +endif + +include usr/sbin/pkcsslotd/pkcsslotd.mk +include usr/sbin/pkcsconf/pkcsconf.mk diff --git a/usr/usr.mk b/usr/usr.mk new file mode 100644 index 0000000..919652e --- /dev/null +++ b/usr/usr.mk @@ -0,0 +1,6 @@ +if ENABLE_DAEMON +include usr/include/include.mk +include usr/sbin/sbin.mk +endif + +include usr/lib/lib.mk